mirror of
https://github.com/lune-org/lune.git
synced 2024-12-13 05:20:37 +00:00
Refactor export tables for roblox builtin library
This commit is contained in:
parent
57e2072bc0
commit
de0f017540
27 changed files with 999 additions and 837 deletions
|
@ -16,6 +16,8 @@ pub struct LuneError {
|
|||
disable_colors: bool,
|
||||
}
|
||||
|
||||
// TODO: Rename this struct to "RuntimeError" instead for
|
||||
// the next breaking release, it's a more fitting name
|
||||
impl LuneError {
|
||||
/**
|
||||
Enables colorization of the error message when formatted using the [`Display`] trait.
|
||||
|
|
|
@ -6,12 +6,16 @@ mod builtins;
|
|||
mod error;
|
||||
mod globals;
|
||||
mod scheduler;
|
||||
mod util;
|
||||
|
||||
pub(crate) mod util;
|
||||
|
||||
use self::scheduler::{LuaSchedulerExt, Scheduler};
|
||||
|
||||
pub use error::LuneError;
|
||||
|
||||
// TODO: Rename this struct to "Runtime" instead for the
|
||||
// next breaking release, it's a more fitting name and
|
||||
// will probably be more obvious when browsing files
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Lune {
|
||||
lua: &'static Lua,
|
||||
|
|
|
@ -3,6 +3,8 @@ use core::fmt;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Axes as DomAxes;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, EnumItem};
|
||||
|
||||
/**
|
||||
|
@ -17,53 +19,58 @@ pub struct Axes {
|
|||
pub(crate) z: bool,
|
||||
}
|
||||
|
||||
impl Axes {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, args: LuaMultiValue| {
|
||||
let mut x = false;
|
||||
let mut y = false;
|
||||
let mut z = false;
|
||||
let mut check = |e: &EnumItem| {
|
||||
if e.parent.desc.name == "Axis" {
|
||||
match &e.name {
|
||||
name if name == "X" => x = true,
|
||||
name if name == "Y" => y = true,
|
||||
name if name == "Z" => z = true,
|
||||
_ => {}
|
||||
}
|
||||
} else if e.parent.desc.name == "NormalId" {
|
||||
match &e.name {
|
||||
name if name == "Left" || name == "Right" => x = true,
|
||||
name if name == "Top" || name == "Bottom" => y = true,
|
||||
name if name == "Front" || name == "Back" => z = true,
|
||||
_ => {}
|
||||
}
|
||||
impl LuaExportsTable<'_> for Axes {
|
||||
const EXPORT_NAME: &'static str = "Axes";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let axes_new = |_, args: LuaMultiValue| {
|
||||
let mut x = false;
|
||||
let mut y = false;
|
||||
let mut z = false;
|
||||
|
||||
let mut check = |e: &EnumItem| {
|
||||
if e.parent.desc.name == "Axis" {
|
||||
match &e.name {
|
||||
name if name == "X" => x = true,
|
||||
name if name == "Y" => y = true,
|
||||
name if name == "Z" => z = true,
|
||||
_ => {}
|
||||
}
|
||||
};
|
||||
for (index, arg) in args.into_iter().enumerate() {
|
||||
if let LuaValue::UserData(u) = arg {
|
||||
if let Ok(e) = u.borrow::<EnumItem>() {
|
||||
check(&e);
|
||||
} else {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #{} to be an EnumItem, got userdata",
|
||||
index
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #{} to be an EnumItem, got {}",
|
||||
index,
|
||||
arg.type_name()
|
||||
)));
|
||||
} else if e.parent.desc.name == "NormalId" {
|
||||
match &e.name {
|
||||
name if name == "Left" || name == "Right" => x = true,
|
||||
name if name == "Top" || name == "Bottom" => y = true,
|
||||
name if name == "Front" || name == "Back" => z = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(Axes { x, y, z })
|
||||
})?,
|
||||
)?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
for (index, arg) in args.into_iter().enumerate() {
|
||||
if let LuaValue::UserData(u) = arg {
|
||||
if let Ok(e) = u.borrow::<EnumItem>() {
|
||||
check(&e);
|
||||
} else {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #{} to be an EnumItem, got userdata",
|
||||
index
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #{} to be an EnumItem, got {}",
|
||||
index,
|
||||
arg.type_name()
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Axes { x, y, z })
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", axes_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ use mlua::prelude::*;
|
|||
use rand::seq::SliceRandom;
|
||||
use rbx_dom_weak::types::BrickColor as DomBrickColor;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, Color3};
|
||||
|
||||
/**
|
||||
|
@ -20,57 +22,58 @@ pub struct BrickColor {
|
|||
pub(crate) rgb: (u8, u8, u8),
|
||||
}
|
||||
|
||||
impl BrickColor {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
impl LuaExportsTable<'_> for BrickColor {
|
||||
const EXPORT_NAME: &'static str = "BrickColor";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
type ArgsNumber = u16;
|
||||
type ArgsName = String;
|
||||
type ArgsRgb = (u8, u8, u8);
|
||||
type ArgsColor3<'lua> = LuaUserDataRef<'lua, Color3>;
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|lua, args: LuaMultiValue| {
|
||||
if let Ok(number) = ArgsNumber::from_lua_multi(args.clone(), lua) {
|
||||
Ok(color_from_number(number))
|
||||
} else if let Ok(name) = ArgsName::from_lua_multi(args.clone(), lua) {
|
||||
Ok(color_from_name(name))
|
||||
} else if let Ok((r, g, b)) = ArgsRgb::from_lua_multi(args.clone(), lua) {
|
||||
Ok(color_from_rgb(r, g, b))
|
||||
} else if let Ok(color) = ArgsColor3::from_lua_multi(args.clone(), lua) {
|
||||
Ok(Self::from(*color))
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"palette",
|
||||
lua.create_function(|_, index: u16| {
|
||||
if index == 0 {
|
||||
Err(LuaError::RuntimeError("Invalid index".to_string()))
|
||||
} else if let Some(number) = BRICK_COLOR_PALETTE.get((index - 1) as usize) {
|
||||
Ok(color_from_number(*number))
|
||||
} else {
|
||||
Err(LuaError::RuntimeError("Invalid index".to_string()))
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"random",
|
||||
lua.create_function(|_, ()| {
|
||||
let number = BRICK_COLOR_PALETTE.choose(&mut rand::thread_rng());
|
||||
Ok(color_from_number(*number.unwrap()))
|
||||
})?,
|
||||
)?;
|
||||
|
||||
let brick_color_new = |lua, args: LuaMultiValue| {
|
||||
if let Ok(number) = ArgsNumber::from_lua_multi(args.clone(), lua) {
|
||||
Ok(color_from_number(number))
|
||||
} else if let Ok(name) = ArgsName::from_lua_multi(args.clone(), lua) {
|
||||
Ok(color_from_name(name))
|
||||
} else if let Ok((r, g, b)) = ArgsRgb::from_lua_multi(args.clone(), lua) {
|
||||
Ok(color_from_rgb(r, g, b))
|
||||
} else if let Ok(color) = ArgsColor3::from_lua_multi(args.clone(), lua) {
|
||||
Ok(Self::from(*color))
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
let brick_color_palette = |_, index: u16| {
|
||||
if index == 0 {
|
||||
Err(LuaError::RuntimeError("Invalid index".to_string()))
|
||||
} else if let Some(number) = BRICK_COLOR_PALETTE.get((index - 1) as usize) {
|
||||
Ok(color_from_number(*number))
|
||||
} else {
|
||||
Err(LuaError::RuntimeError("Invalid index".to_string()))
|
||||
}
|
||||
};
|
||||
|
||||
let brick_color_random = |_, ()| {
|
||||
let number = BRICK_COLOR_PALETTE.choose(&mut rand::thread_rng());
|
||||
Ok(color_from_number(*number.unwrap()))
|
||||
};
|
||||
|
||||
let mut builder = TableBuilder::new(lua)?
|
||||
.with_function("new", brick_color_new)?
|
||||
.with_function("palette", brick_color_palette)?
|
||||
.with_function("random", brick_color_random)?;
|
||||
|
||||
for (name, number) in BRICK_COLOR_CONSTRUCTORS {
|
||||
datatype_table.set(
|
||||
*name,
|
||||
lua.create_function(|_, ()| Ok(color_from_number(*number)))?,
|
||||
)?;
|
||||
let f = |_, ()| Ok(color_from_number(*number));
|
||||
builder = builder.with_function(*name, f)?;
|
||||
}
|
||||
Ok(())
|
||||
|
||||
builder.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use glam::{EulerRot, Mat4, Quat, Vec3};
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::{CFrame as DomCFrame, Matrix3 as DomMatrix3, Vector3 as DomVector3};
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, Vector3};
|
||||
|
||||
/**
|
||||
|
@ -35,79 +37,61 @@ impl CFrame {
|
|||
fn inverse(&self) -> Self {
|
||||
Self(self.0.inverse())
|
||||
}
|
||||
}
|
||||
|
||||
impl LuaExportsTable<'_> for CFrame {
|
||||
const EXPORT_NAME: &'static str = "CFrame";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let cframe_angles = |_, (rx, ry, rz): (f32, f32, f32)| {
|
||||
Ok(CFrame(Mat4::from_euler(EulerRot::XYZ, rx, ry, rz)))
|
||||
};
|
||||
|
||||
let cframe_from_axis_angle =
|
||||
|_, (v, r): (LuaUserDataRef<Vector3>, f32)| Ok(CFrame(Mat4::from_axis_angle(v.0, r)));
|
||||
|
||||
let cframe_from_euler_angles_xyz = |_, (rx, ry, rz): (f32, f32, f32)| {
|
||||
Ok(CFrame(Mat4::from_euler(EulerRot::XYZ, rx, ry, rz)))
|
||||
};
|
||||
|
||||
let cframe_from_euler_angles_yxz = |_, (rx, ry, rz): (f32, f32, f32)| {
|
||||
Ok(CFrame(Mat4::from_euler(EulerRot::YXZ, ry, rx, rz)))
|
||||
};
|
||||
|
||||
let cframe_from_matrix = |_,
|
||||
(pos, rx, ry, rz): (
|
||||
LuaUserDataRef<Vector3>,
|
||||
LuaUserDataRef<Vector3>,
|
||||
LuaUserDataRef<Vector3>,
|
||||
Option<LuaUserDataRef<Vector3>>,
|
||||
)| {
|
||||
Ok(CFrame(Mat4::from_cols(
|
||||
rx.0.extend(0.0),
|
||||
ry.0.extend(0.0),
|
||||
rz.map(|r| r.0)
|
||||
.unwrap_or_else(|| rx.0.cross(ry.0).normalize())
|
||||
.extend(0.0),
|
||||
pos.0.extend(1.0),
|
||||
)))
|
||||
};
|
||||
|
||||
let cframe_from_orientation = |_, (rx, ry, rz): (f32, f32, f32)| {
|
||||
Ok(CFrame(Mat4::from_euler(EulerRot::YXZ, ry, rx, rz)))
|
||||
};
|
||||
|
||||
let cframe_look_at = |_,
|
||||
(from, to, up): (
|
||||
LuaUserDataRef<Vector3>,
|
||||
LuaUserDataRef<Vector3>,
|
||||
Option<LuaUserDataRef<Vector3>>,
|
||||
)| {
|
||||
Ok(CFrame(look_at(
|
||||
from.0,
|
||||
to.0,
|
||||
up.as_deref().unwrap_or(&Vector3(Vec3::Y)).0,
|
||||
)))
|
||||
};
|
||||
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
// Constants
|
||||
datatype_table.set("identity", CFrame(Mat4::IDENTITY))?;
|
||||
// Strict args constructors
|
||||
datatype_table.set(
|
||||
"lookAt",
|
||||
lua.create_function(
|
||||
|_,
|
||||
(from, to, up): (
|
||||
LuaUserDataRef<Vector3>,
|
||||
LuaUserDataRef<Vector3>,
|
||||
Option<LuaUserDataRef<Vector3>>,
|
||||
)| {
|
||||
Ok(CFrame(look_at(
|
||||
from.0,
|
||||
to.0,
|
||||
up.as_deref().unwrap_or(&Vector3(Vec3::Y)).0,
|
||||
)))
|
||||
},
|
||||
)?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromEulerAnglesXYZ",
|
||||
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
|
||||
Ok(CFrame(Mat4::from_euler(EulerRot::XYZ, rx, ry, rz)))
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromEulerAnglesYXZ",
|
||||
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
|
||||
Ok(CFrame(Mat4::from_euler(EulerRot::YXZ, ry, rx, rz)))
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"Angles",
|
||||
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
|
||||
Ok(CFrame(Mat4::from_euler(EulerRot::XYZ, rx, ry, rz)))
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromOrientation",
|
||||
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
|
||||
Ok(CFrame(Mat4::from_euler(EulerRot::YXZ, ry, rx, rz)))
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromAxisAngle",
|
||||
lua.create_function(|_, (v, r): (LuaUserDataRef<Vector3>, f32)| {
|
||||
Ok(CFrame(Mat4::from_axis_angle(v.0, r)))
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromMatrix",
|
||||
lua.create_function(
|
||||
|_,
|
||||
(pos, rx, ry, rz): (
|
||||
LuaUserDataRef<Vector3>,
|
||||
LuaUserDataRef<Vector3>,
|
||||
LuaUserDataRef<Vector3>,
|
||||
Option<LuaUserDataRef<Vector3>>,
|
||||
)| {
|
||||
Ok(CFrame(Mat4::from_cols(
|
||||
rx.0.extend(0.0),
|
||||
ry.0.extend(0.0),
|
||||
rz.map(|r| r.0)
|
||||
.unwrap_or_else(|| rx.0.cross(ry.0).normalize())
|
||||
.extend(0.0),
|
||||
pos.0.extend(1.0),
|
||||
)))
|
||||
},
|
||||
)?,
|
||||
)?;
|
||||
// Dynamic args constructor
|
||||
type ArgsPos<'lua> = LuaUserDataRef<'lua, Vector3>;
|
||||
type ArgsLook<'lua> = (
|
||||
|
@ -115,48 +99,59 @@ impl CFrame {
|
|||
LuaUserDataRef<'lua, Vector3>,
|
||||
Option<LuaUserDataRef<'lua, Vector3>>,
|
||||
);
|
||||
|
||||
type ArgsPosXYZ = (f32, f32, f32);
|
||||
type ArgsPosXYZQuat = (f32, f32, f32, f32, f32, f32, f32);
|
||||
type ArgsMatrix = (f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32);
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|lua, args: LuaMultiValue| {
|
||||
if args.clone().into_vec().is_empty() {
|
||||
Ok(CFrame(Mat4::IDENTITY))
|
||||
} else if let Ok(pos) = ArgsPos::from_lua_multi(args.clone(), lua) {
|
||||
Ok(CFrame(Mat4::from_translation(pos.0)))
|
||||
} else if let Ok((from, to, up)) = ArgsLook::from_lua_multi(args.clone(), lua) {
|
||||
Ok(CFrame(look_at(
|
||||
from.0,
|
||||
to.0,
|
||||
up.as_deref().unwrap_or(&Vector3(Vec3::Y)).0,
|
||||
)))
|
||||
} else if let Ok((x, y, z)) = ArgsPosXYZ::from_lua_multi(args.clone(), lua) {
|
||||
Ok(CFrame(Mat4::from_translation(Vec3::new(x, y, z))))
|
||||
} else if let Ok((x, y, z, qx, qy, qz, qw)) =
|
||||
ArgsPosXYZQuat::from_lua_multi(args.clone(), lua)
|
||||
{
|
||||
Ok(CFrame(Mat4::from_rotation_translation(
|
||||
Quat::from_array([qx, qy, qz, qw]),
|
||||
Vec3::new(x, y, z),
|
||||
)))
|
||||
} else if let Ok((x, y, z, r00, r01, r02, r10, r11, r12, r20, r21, r22)) =
|
||||
ArgsMatrix::from_lua_multi(args, lua)
|
||||
{
|
||||
Ok(CFrame(Mat4::from_cols_array_2d(&[
|
||||
[r00, r01, r02, 0.0],
|
||||
[r10, r11, r12, 0.0],
|
||||
[r20, r21, r22, 0.0],
|
||||
[x, y, z, 1.0],
|
||||
])))
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
})?,
|
||||
)
|
||||
|
||||
let cframe_new = |lua, args: LuaMultiValue| {
|
||||
if args.clone().into_vec().is_empty() {
|
||||
Ok(CFrame(Mat4::IDENTITY))
|
||||
} else if let Ok(pos) = ArgsPos::from_lua_multi(args.clone(), lua) {
|
||||
Ok(CFrame(Mat4::from_translation(pos.0)))
|
||||
} else if let Ok((from, to, up)) = ArgsLook::from_lua_multi(args.clone(), lua) {
|
||||
Ok(CFrame(look_at(
|
||||
from.0,
|
||||
to.0,
|
||||
up.as_deref().unwrap_or(&Vector3(Vec3::Y)).0,
|
||||
)))
|
||||
} else if let Ok((x, y, z)) = ArgsPosXYZ::from_lua_multi(args.clone(), lua) {
|
||||
Ok(CFrame(Mat4::from_translation(Vec3::new(x, y, z))))
|
||||
} else if let Ok((x, y, z, qx, qy, qz, qw)) =
|
||||
ArgsPosXYZQuat::from_lua_multi(args.clone(), lua)
|
||||
{
|
||||
Ok(CFrame(Mat4::from_rotation_translation(
|
||||
Quat::from_array([qx, qy, qz, qw]),
|
||||
Vec3::new(x, y, z),
|
||||
)))
|
||||
} else if let Ok((x, y, z, r00, r01, r02, r10, r11, r12, r20, r21, r22)) =
|
||||
ArgsMatrix::from_lua_multi(args, lua)
|
||||
{
|
||||
Ok(CFrame(Mat4::from_cols_array_2d(&[
|
||||
[r00, r01, r02, 0.0],
|
||||
[r10, r11, r12, 0.0],
|
||||
[r20, r21, r22, 0.0],
|
||||
[x, y, z, 1.0],
|
||||
])))
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("Angles", cframe_angles)?
|
||||
.with_value("identity", CFrame(Mat4::IDENTITY))?
|
||||
.with_function("fromAxisAngle", cframe_from_axis_angle)?
|
||||
.with_function("fromEulerAnglesXYZ", cframe_from_euler_angles_xyz)?
|
||||
.with_function("fromEulerAnglesYXZ", cframe_from_euler_angles_yxz)?
|
||||
.with_function("fromMatrix", cframe_from_matrix)?
|
||||
.with_function("fromOrientation", cframe_from_orientation)?
|
||||
.with_function("lookAt", cframe_look_at)?
|
||||
.with_function("new", cframe_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use glam::Vec3;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::{Color3 as DomColor3, Color3uint8 as DomColor3uint8};
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::super::*;
|
||||
|
||||
/**
|
||||
|
@ -22,88 +24,87 @@ pub struct Color3 {
|
|||
pub(crate) b: f32,
|
||||
}
|
||||
|
||||
impl Color3 {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, (r, g, b): (Option<f32>, Option<f32>, Option<f32>)| {
|
||||
Ok(Color3 {
|
||||
r: r.unwrap_or_default(),
|
||||
g: g.unwrap_or_default(),
|
||||
b: b.unwrap_or_default(),
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromRGB",
|
||||
lua.create_function(|_, (r, g, b): (Option<u8>, Option<u8>, Option<u8>)| {
|
||||
Ok(Color3 {
|
||||
r: (r.unwrap_or_default() as f32) / 255f32,
|
||||
g: (g.unwrap_or_default() as f32) / 255f32,
|
||||
b: (b.unwrap_or_default() as f32) / 255f32,
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromHSV",
|
||||
lua.create_function(|_, (h, s, v): (f32, f32, f32)| {
|
||||
// https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
|
||||
let i = (h * 6.0).floor();
|
||||
let f = h * 6.0 - i;
|
||||
let p = v * (1.0 - s);
|
||||
let q = v * (1.0 - f * s);
|
||||
let t = v * (1.0 - (1.0 - f) * s);
|
||||
impl LuaExportsTable<'_> for Color3 {
|
||||
const EXPORT_NAME: &'static str = "Color3";
|
||||
|
||||
let (r, g, b) = match (i % 6.0) as u8 {
|
||||
0 => (v, t, p),
|
||||
1 => (q, v, p),
|
||||
2 => (p, v, t),
|
||||
3 => (p, q, v),
|
||||
4 => (t, p, v),
|
||||
5 => (v, p, q),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let color3_from_rgb = |_, (r, g, b): (Option<u8>, Option<u8>, Option<u8>)| {
|
||||
Ok(Color3 {
|
||||
r: (r.unwrap_or_default() as f32) / 255f32,
|
||||
g: (g.unwrap_or_default() as f32) / 255f32,
|
||||
b: (b.unwrap_or_default() as f32) / 255f32,
|
||||
})
|
||||
};
|
||||
|
||||
Ok(Color3 { r, g, b })
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromHex",
|
||||
lua.create_function(|_, hex: String| {
|
||||
let trimmed = hex.trim_start_matches('#').to_ascii_uppercase();
|
||||
let chars = if trimmed.len() == 3 {
|
||||
(
|
||||
u8::from_str_radix(&trimmed[..1].repeat(2), 16),
|
||||
u8::from_str_radix(&trimmed[1..2].repeat(2), 16),
|
||||
u8::from_str_radix(&trimmed[2..3].repeat(2), 16),
|
||||
)
|
||||
} else if trimmed.len() == 6 {
|
||||
(
|
||||
u8::from_str_radix(&trimmed[..2], 16),
|
||||
u8::from_str_radix(&trimmed[2..4], 16),
|
||||
u8::from_str_radix(&trimmed[4..6], 16),
|
||||
)
|
||||
} else {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Hex color string must be 3 or 6 characters long, got {} character{}",
|
||||
trimmed.len(),
|
||||
if trimmed.len() == 1 { "" } else { "s" }
|
||||
)));
|
||||
};
|
||||
match chars {
|
||||
(Ok(r), Ok(g), Ok(b)) => Ok(Color3 {
|
||||
r: (r as f32) / 255f32,
|
||||
g: (g as f32) / 255f32,
|
||||
b: (b as f32) / 255f32,
|
||||
}),
|
||||
_ => Err(LuaError::RuntimeError(format!(
|
||||
"Hex color string '{}' contains invalid character",
|
||||
trimmed
|
||||
))),
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
Ok(())
|
||||
let color3_from_hsv = |_, (h, s, v): (f32, f32, f32)| {
|
||||
// https://axonflux.com/handy-rgb-to-hsl-and-rgb-to-hsv-color-model-c
|
||||
let i = (h * 6.0).floor();
|
||||
let f = h * 6.0 - i;
|
||||
let p = v * (1.0 - s);
|
||||
let q = v * (1.0 - f * s);
|
||||
let t = v * (1.0 - (1.0 - f) * s);
|
||||
|
||||
let (r, g, b) = match (i % 6.0) as u8 {
|
||||
0 => (v, t, p),
|
||||
1 => (q, v, p),
|
||||
2 => (p, v, t),
|
||||
3 => (p, q, v),
|
||||
4 => (t, p, v),
|
||||
5 => (v, p, q),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
Ok(Color3 { r, g, b })
|
||||
};
|
||||
|
||||
let color3_from_hex = |_, hex: String| {
|
||||
let trimmed = hex.trim_start_matches('#').to_ascii_uppercase();
|
||||
let chars = if trimmed.len() == 3 {
|
||||
(
|
||||
u8::from_str_radix(&trimmed[..1].repeat(2), 16),
|
||||
u8::from_str_radix(&trimmed[1..2].repeat(2), 16),
|
||||
u8::from_str_radix(&trimmed[2..3].repeat(2), 16),
|
||||
)
|
||||
} else if trimmed.len() == 6 {
|
||||
(
|
||||
u8::from_str_radix(&trimmed[..2], 16),
|
||||
u8::from_str_radix(&trimmed[2..4], 16),
|
||||
u8::from_str_radix(&trimmed[4..6], 16),
|
||||
)
|
||||
} else {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Hex color string must be 3 or 6 characters long, got {} character{}",
|
||||
trimmed.len(),
|
||||
if trimmed.len() == 1 { "" } else { "s" }
|
||||
)));
|
||||
};
|
||||
match chars {
|
||||
(Ok(r), Ok(g), Ok(b)) => Ok(Color3 {
|
||||
r: (r as f32) / 255f32,
|
||||
g: (g as f32) / 255f32,
|
||||
b: (b as f32) / 255f32,
|
||||
}),
|
||||
_ => Err(LuaError::RuntimeError(format!(
|
||||
"Hex color string '{}' contains invalid character",
|
||||
trimmed
|
||||
))),
|
||||
}
|
||||
};
|
||||
|
||||
let color3_new = |_, (r, g, b): (Option<f32>, Option<f32>, Option<f32>)| {
|
||||
Ok(Color3 {
|
||||
r: r.unwrap_or_default(),
|
||||
g: g.unwrap_or_default(),
|
||||
b: b.unwrap_or_default(),
|
||||
})
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("fromRGB", color3_from_rgb)?
|
||||
.with_function("fromHSV", color3_from_hsv)?
|
||||
.with_function("fromHex", color3_from_hex)?
|
||||
.with_function("new", color3_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use rbx_dom_weak::types::{
|
|||
ColorSequence as DomColorSequence, ColorSequenceKeypoint as DomColorSequenceKeypoint,
|
||||
};
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, Color3, ColorSequenceKeypoint};
|
||||
|
||||
/**
|
||||
|
@ -17,52 +19,56 @@ pub struct ColorSequence {
|
|||
pub(crate) keypoints: Vec<ColorSequenceKeypoint>,
|
||||
}
|
||||
|
||||
impl ColorSequence {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
impl LuaExportsTable<'_> for ColorSequence {
|
||||
const EXPORT_NAME: &'static str = "ColorSequence";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
type ArgsColor<'lua> = LuaUserDataRef<'lua, Color3>;
|
||||
type ArgsColors<'lua> = (LuaUserDataRef<'lua, Color3>, LuaUserDataRef<'lua, Color3>);
|
||||
type ArgsKeypoints<'lua> = Vec<LuaUserDataRef<'lua, ColorSequenceKeypoint>>;
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|lua, args: LuaMultiValue| {
|
||||
if let Ok(color) = ArgsColor::from_lua_multi(args.clone(), lua) {
|
||||
Ok(ColorSequence {
|
||||
keypoints: vec![
|
||||
ColorSequenceKeypoint {
|
||||
time: 0.0,
|
||||
color: *color,
|
||||
},
|
||||
ColorSequenceKeypoint {
|
||||
time: 1.0,
|
||||
color: *color,
|
||||
},
|
||||
],
|
||||
})
|
||||
} else if let Ok((c0, c1)) = ArgsColors::from_lua_multi(args.clone(), lua) {
|
||||
Ok(ColorSequence {
|
||||
keypoints: vec![
|
||||
ColorSequenceKeypoint {
|
||||
time: 0.0,
|
||||
color: *c0,
|
||||
},
|
||||
ColorSequenceKeypoint {
|
||||
time: 1.0,
|
||||
color: *c1,
|
||||
},
|
||||
],
|
||||
})
|
||||
} else if let Ok(keypoints) = ArgsKeypoints::from_lua_multi(args, lua) {
|
||||
Ok(ColorSequence {
|
||||
keypoints: keypoints.iter().map(|k| **k).collect(),
|
||||
})
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
})?,
|
||||
)
|
||||
|
||||
let color_sequence_new = |lua, args: LuaMultiValue| {
|
||||
if let Ok(color) = ArgsColor::from_lua_multi(args.clone(), lua) {
|
||||
Ok(ColorSequence {
|
||||
keypoints: vec![
|
||||
ColorSequenceKeypoint {
|
||||
time: 0.0,
|
||||
color: *color,
|
||||
},
|
||||
ColorSequenceKeypoint {
|
||||
time: 1.0,
|
||||
color: *color,
|
||||
},
|
||||
],
|
||||
})
|
||||
} else if let Ok((c0, c1)) = ArgsColors::from_lua_multi(args.clone(), lua) {
|
||||
Ok(ColorSequence {
|
||||
keypoints: vec![
|
||||
ColorSequenceKeypoint {
|
||||
time: 0.0,
|
||||
color: *c0,
|
||||
},
|
||||
ColorSequenceKeypoint {
|
||||
time: 1.0,
|
||||
color: *c1,
|
||||
},
|
||||
],
|
||||
})
|
||||
} else if let Ok(keypoints) = ArgsKeypoints::from_lua_multi(args, lua) {
|
||||
Ok(ColorSequence {
|
||||
keypoints: keypoints.iter().map(|k| **k).collect(),
|
||||
})
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", color_sequence_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ use core::fmt;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::ColorSequenceKeypoint as DomColorSequenceKeypoint;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, Color3};
|
||||
|
||||
/**
|
||||
|
@ -16,18 +18,20 @@ pub struct ColorSequenceKeypoint {
|
|||
pub(crate) color: Color3,
|
||||
}
|
||||
|
||||
impl ColorSequenceKeypoint {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, (time, color): (f32, LuaUserDataRef<Color3>)| {
|
||||
Ok(ColorSequenceKeypoint {
|
||||
time,
|
||||
color: *color,
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
Ok(())
|
||||
impl LuaExportsTable<'_> for ColorSequenceKeypoint {
|
||||
const EXPORT_NAME: &'static str = "ColorSequenceKeypoint";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let color_sequence_keypoint_new = |_, (time, color): (f32, LuaUserDataRef<Color3>)| {
|
||||
Ok(ColorSequenceKeypoint {
|
||||
time,
|
||||
color: *color,
|
||||
})
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", color_sequence_keypoint_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ use core::fmt;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Faces as DomFaces;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, EnumItem};
|
||||
|
||||
/**
|
||||
|
@ -20,59 +22,64 @@ pub struct Faces {
|
|||
pub(crate) front: bool,
|
||||
}
|
||||
|
||||
impl Faces {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, args: LuaMultiValue| {
|
||||
let mut right = false;
|
||||
let mut top = false;
|
||||
let mut back = false;
|
||||
let mut left = false;
|
||||
let mut bottom = false;
|
||||
let mut front = false;
|
||||
let mut check = |e: &EnumItem| {
|
||||
if e.parent.desc.name == "NormalId" {
|
||||
match &e.name {
|
||||
name if name == "Right" => right = true,
|
||||
name if name == "Top" => top = true,
|
||||
name if name == "Back" => back = true,
|
||||
name if name == "Left" => left = true,
|
||||
name if name == "Bottom" => bottom = true,
|
||||
name if name == "Front" => front = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
};
|
||||
for (index, arg) in args.into_iter().enumerate() {
|
||||
if let LuaValue::UserData(u) = arg {
|
||||
if let Ok(e) = u.borrow::<EnumItem>() {
|
||||
check(&e);
|
||||
} else {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #{} to be an EnumItem, got userdata",
|
||||
index
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #{} to be an EnumItem, got {}",
|
||||
index,
|
||||
arg.type_name()
|
||||
)));
|
||||
impl LuaExportsTable<'_> for Faces {
|
||||
const EXPORT_NAME: &'static str = "Faces";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let faces_new = |_, args: LuaMultiValue| {
|
||||
let mut right = false;
|
||||
let mut top = false;
|
||||
let mut back = false;
|
||||
let mut left = false;
|
||||
let mut bottom = false;
|
||||
let mut front = false;
|
||||
|
||||
let mut check = |e: &EnumItem| {
|
||||
if e.parent.desc.name == "NormalId" {
|
||||
match &e.name {
|
||||
name if name == "Right" => right = true,
|
||||
name if name == "Top" => top = true,
|
||||
name if name == "Back" => back = true,
|
||||
name if name == "Left" => left = true,
|
||||
name if name == "Bottom" => bottom = true,
|
||||
name if name == "Front" => front = true,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
Ok(Faces {
|
||||
right,
|
||||
top,
|
||||
back,
|
||||
left,
|
||||
bottom,
|
||||
front,
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
for (index, arg) in args.into_iter().enumerate() {
|
||||
if let LuaValue::UserData(u) = arg {
|
||||
if let Ok(e) = u.borrow::<EnumItem>() {
|
||||
check(&e);
|
||||
} else {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #{} to be an EnumItem, got userdata",
|
||||
index
|
||||
)));
|
||||
}
|
||||
} else {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #{} to be an EnumItem, got {}",
|
||||
index,
|
||||
arg.type_name()
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Faces {
|
||||
right,
|
||||
top,
|
||||
back,
|
||||
left,
|
||||
bottom,
|
||||
front,
|
||||
})
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", faces_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@ use rbx_dom_weak::types::{
|
|||
Font as DomFont, FontStyle as DomFontStyle, FontWeight as DomFontWeight,
|
||||
};
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, EnumItem};
|
||||
|
||||
/**
|
||||
|
@ -34,66 +36,65 @@ impl Font {
|
|||
cached_id: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(
|
||||
|_, (family, weight, style): (String, Option<FontWeight>, Option<FontStyle>)| {
|
||||
Ok(Font {
|
||||
family,
|
||||
weight: weight.unwrap_or_default(),
|
||||
style: style.unwrap_or_default(),
|
||||
cached_id: None,
|
||||
})
|
||||
},
|
||||
)?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromEnum",
|
||||
lua.create_function(|_, value: LuaUserDataRef<EnumItem>| {
|
||||
if value.parent.desc.name == "Font" {
|
||||
match Font::from_enum_item(&value) {
|
||||
Some(props) => Ok(props),
|
||||
None => Err(LuaError::RuntimeError(format!(
|
||||
"Found unknown Font '{}'",
|
||||
value.name
|
||||
))),
|
||||
}
|
||||
} else {
|
||||
Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #1 to be a Font, got {}",
|
||||
value.parent.desc.name
|
||||
)))
|
||||
impl LuaExportsTable<'_> for Font {
|
||||
const EXPORT_NAME: &'static str = "Font";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let font_from_enum = |_, value: LuaUserDataRef<EnumItem>| {
|
||||
if value.parent.desc.name == "Font" {
|
||||
match Font::from_enum_item(&value) {
|
||||
Some(props) => Ok(props),
|
||||
None => Err(LuaError::RuntimeError(format!(
|
||||
"Found unknown Font '{}'",
|
||||
value.name
|
||||
))),
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromName",
|
||||
lua.create_function(
|
||||
|_, (file, weight, style): (String, Option<FontWeight>, Option<FontStyle>)| {
|
||||
Ok(Font {
|
||||
family: format!("rbxasset://fonts/families/{}.json", file),
|
||||
weight: weight.unwrap_or_default(),
|
||||
style: style.unwrap_or_default(),
|
||||
cached_id: None,
|
||||
})
|
||||
},
|
||||
)?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromId",
|
||||
lua.create_function(
|
||||
|_, (id, weight, style): (i32, Option<FontWeight>, Option<FontStyle>)| {
|
||||
Ok(Font {
|
||||
family: format!("rbxassetid://{}", id),
|
||||
weight: weight.unwrap_or_default(),
|
||||
style: style.unwrap_or_default(),
|
||||
cached_id: None,
|
||||
})
|
||||
},
|
||||
)?,
|
||||
)
|
||||
} else {
|
||||
Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #1 to be a Font, got {}",
|
||||
value.parent.desc.name
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let font_from_name =
|
||||
|_, (file, weight, style): (String, Option<FontWeight>, Option<FontStyle>)| {
|
||||
Ok(Font {
|
||||
family: format!("rbxasset://fonts/families/{}.json", file),
|
||||
weight: weight.unwrap_or_default(),
|
||||
style: style.unwrap_or_default(),
|
||||
cached_id: None,
|
||||
})
|
||||
};
|
||||
|
||||
let font_from_id =
|
||||
|_, (id, weight, style): (i32, Option<FontWeight>, Option<FontStyle>)| {
|
||||
Ok(Font {
|
||||
family: format!("rbxassetid://{}", id),
|
||||
weight: weight.unwrap_or_default(),
|
||||
style: style.unwrap_or_default(),
|
||||
cached_id: None,
|
||||
})
|
||||
};
|
||||
|
||||
let font_new =
|
||||
|_, (family, weight, style): (String, Option<FontWeight>, Option<FontStyle>)| {
|
||||
Ok(Font {
|
||||
family,
|
||||
weight: weight.unwrap_or_default(),
|
||||
style: style.unwrap_or_default(),
|
||||
cached_id: None,
|
||||
})
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("fromEnum", font_from_enum)?
|
||||
.with_function("fromName", font_from_name)?
|
||||
.with_function("fromId", font_from_id)?
|
||||
.with_function("new", font_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ use core::fmt;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::NumberRange as DomNumberRange;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::super::*;
|
||||
|
||||
/**
|
||||
|
@ -16,20 +18,23 @@ pub struct NumberRange {
|
|||
pub(crate) max: f32,
|
||||
}
|
||||
|
||||
impl NumberRange {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, (min, max): (f32, Option<f32>)| {
|
||||
Ok(match max {
|
||||
Some(max) => NumberRange {
|
||||
min: min.min(max),
|
||||
max: min.max(max),
|
||||
},
|
||||
None => NumberRange { min, max: min },
|
||||
})
|
||||
})?,
|
||||
)
|
||||
impl LuaExportsTable<'_> for NumberRange {
|
||||
const EXPORT_NAME: &'static str = "NumberRange";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let number_range_new = |_, (min, max): (f32, Option<f32>)| {
|
||||
Ok(match max {
|
||||
Some(max) => NumberRange {
|
||||
min: min.min(max),
|
||||
max: min.max(max),
|
||||
},
|
||||
None => NumberRange { min, max: min },
|
||||
})
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", number_range_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use rbx_dom_weak::types::{
|
|||
NumberSequence as DomNumberSequence, NumberSequenceKeypoint as DomNumberSequenceKeypoint,
|
||||
};
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, NumberSequenceKeypoint};
|
||||
|
||||
/**
|
||||
|
@ -17,56 +19,60 @@ pub struct NumberSequence {
|
|||
pub(crate) keypoints: Vec<NumberSequenceKeypoint>,
|
||||
}
|
||||
|
||||
impl NumberSequence {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
impl LuaExportsTable<'_> for NumberSequence {
|
||||
const EXPORT_NAME: &'static str = "NumberSequence";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
type ArgsColor = f32;
|
||||
type ArgsColors = (f32, f32);
|
||||
type ArgsKeypoints<'lua> = Vec<LuaUserDataRef<'lua, NumberSequenceKeypoint>>;
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|lua, args: LuaMultiValue| {
|
||||
if let Ok(value) = ArgsColor::from_lua_multi(args.clone(), lua) {
|
||||
Ok(NumberSequence {
|
||||
keypoints: vec![
|
||||
NumberSequenceKeypoint {
|
||||
time: 0.0,
|
||||
value,
|
||||
envelope: 0.0,
|
||||
},
|
||||
NumberSequenceKeypoint {
|
||||
time: 1.0,
|
||||
value,
|
||||
envelope: 0.0,
|
||||
},
|
||||
],
|
||||
})
|
||||
} else if let Ok((v0, v1)) = ArgsColors::from_lua_multi(args.clone(), lua) {
|
||||
Ok(NumberSequence {
|
||||
keypoints: vec![
|
||||
NumberSequenceKeypoint {
|
||||
time: 0.0,
|
||||
value: v0,
|
||||
envelope: 0.0,
|
||||
},
|
||||
NumberSequenceKeypoint {
|
||||
time: 1.0,
|
||||
value: v1,
|
||||
envelope: 0.0,
|
||||
},
|
||||
],
|
||||
})
|
||||
} else if let Ok(keypoints) = ArgsKeypoints::from_lua_multi(args, lua) {
|
||||
Ok(NumberSequence {
|
||||
keypoints: keypoints.iter().map(|k| **k).collect(),
|
||||
})
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
})?,
|
||||
)
|
||||
|
||||
let number_sequence_new = |lua, args: LuaMultiValue| {
|
||||
if let Ok(value) = ArgsColor::from_lua_multi(args.clone(), lua) {
|
||||
Ok(NumberSequence {
|
||||
keypoints: vec![
|
||||
NumberSequenceKeypoint {
|
||||
time: 0.0,
|
||||
value,
|
||||
envelope: 0.0,
|
||||
},
|
||||
NumberSequenceKeypoint {
|
||||
time: 1.0,
|
||||
value,
|
||||
envelope: 0.0,
|
||||
},
|
||||
],
|
||||
})
|
||||
} else if let Ok((v0, v1)) = ArgsColors::from_lua_multi(args.clone(), lua) {
|
||||
Ok(NumberSequence {
|
||||
keypoints: vec![
|
||||
NumberSequenceKeypoint {
|
||||
time: 0.0,
|
||||
value: v0,
|
||||
envelope: 0.0,
|
||||
},
|
||||
NumberSequenceKeypoint {
|
||||
time: 1.0,
|
||||
value: v1,
|
||||
envelope: 0.0,
|
||||
},
|
||||
],
|
||||
})
|
||||
} else if let Ok(keypoints) = ArgsKeypoints::from_lua_multi(args, lua) {
|
||||
Ok(NumberSequence {
|
||||
keypoints: keypoints.iter().map(|k| **k).collect(),
|
||||
})
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", number_sequence_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ use core::fmt;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::NumberSequenceKeypoint as DomNumberSequenceKeypoint;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::super::*;
|
||||
|
||||
/**
|
||||
|
@ -17,19 +19,21 @@ pub struct NumberSequenceKeypoint {
|
|||
pub(crate) envelope: f32,
|
||||
}
|
||||
|
||||
impl NumberSequenceKeypoint {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, (time, value, envelope): (f32, f32, Option<f32>)| {
|
||||
Ok(NumberSequenceKeypoint {
|
||||
time,
|
||||
value,
|
||||
envelope: envelope.unwrap_or_default(),
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
Ok(())
|
||||
impl LuaExportsTable<'_> for NumberSequenceKeypoint {
|
||||
const EXPORT_NAME: &'static str = "NumberSequenceKeypoint";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let number_sequence_keypoint_new = |_, (time, value, envelope): (f32, f32, Option<f32>)| {
|
||||
Ok(NumberSequenceKeypoint {
|
||||
time,
|
||||
value,
|
||||
envelope: envelope.unwrap_or_default(),
|
||||
})
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", number_sequence_keypoint_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ use core::fmt;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::CustomPhysicalProperties as DomCustomPhysicalProperties;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, EnumItem};
|
||||
|
||||
/**
|
||||
|
@ -32,51 +34,52 @@ impl PhysicalProperties {
|
|||
elasticity_weight: props.5,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
impl LuaExportsTable<'_> for PhysicalProperties {
|
||||
const EXPORT_NAME: &'static str = "PhysicalProperties";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
type ArgsMaterial<'lua> = LuaUserDataRef<'lua, EnumItem>;
|
||||
type ArgsNumbers = (f32, f32, f32, Option<f32>, Option<f32>);
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|lua, args: LuaMultiValue| {
|
||||
if let Ok(value) = ArgsMaterial::from_lua_multi(args.clone(), lua) {
|
||||
if value.parent.desc.name == "Material" {
|
||||
match PhysicalProperties::from_material(&value) {
|
||||
Some(props) => Ok(props),
|
||||
None => Err(LuaError::RuntimeError(format!(
|
||||
"Found unknown Material '{}'",
|
||||
value.name
|
||||
))),
|
||||
}
|
||||
} else {
|
||||
Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #1 to be a Material, got {}",
|
||||
value.parent.desc.name
|
||||
)))
|
||||
|
||||
let physical_properties_new = |lua, args: LuaMultiValue| {
|
||||
if let Ok(value) = ArgsMaterial::from_lua_multi(args.clone(), lua) {
|
||||
if value.parent.desc.name == "Material" {
|
||||
match PhysicalProperties::from_material(&value) {
|
||||
Some(props) => Ok(props),
|
||||
None => Err(LuaError::RuntimeError(format!(
|
||||
"Found unknown Material '{}'",
|
||||
value.name
|
||||
))),
|
||||
}
|
||||
} else if let Ok((
|
||||
} else {
|
||||
Err(LuaError::RuntimeError(format!(
|
||||
"Expected argument #1 to be a Material, got {}",
|
||||
value.parent.desc.name
|
||||
)))
|
||||
}
|
||||
} else if let Ok((density, friction, elasticity, friction_weight, elasticity_weight)) =
|
||||
ArgsNumbers::from_lua_multi(args, lua)
|
||||
{
|
||||
Ok(PhysicalProperties {
|
||||
density,
|
||||
friction,
|
||||
friction_weight: friction_weight.unwrap_or(1.0),
|
||||
elasticity,
|
||||
friction_weight,
|
||||
elasticity_weight,
|
||||
)) = ArgsNumbers::from_lua_multi(args, lua)
|
||||
{
|
||||
Ok(PhysicalProperties {
|
||||
density,
|
||||
friction,
|
||||
friction_weight: friction_weight.unwrap_or(1.0),
|
||||
elasticity,
|
||||
elasticity_weight: elasticity_weight.unwrap_or(1.0),
|
||||
})
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
})?,
|
||||
)
|
||||
elasticity_weight: elasticity_weight.unwrap_or(1.0),
|
||||
})
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", physical_properties_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ use glam::Vec3;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Ray as DomRay;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, Vector3};
|
||||
|
||||
/**
|
||||
|
@ -26,19 +28,23 @@ impl Ray {
|
|||
let dot_product = lhs.dot(norm).max(0.0);
|
||||
self.origin + norm * dot_product
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(
|
||||
|_, (origin, direction): (LuaUserDataRef<Vector3>, LuaUserDataRef<Vector3>)| {
|
||||
Ok(Ray {
|
||||
origin: origin.0,
|
||||
direction: direction.0,
|
||||
})
|
||||
},
|
||||
)?,
|
||||
)
|
||||
impl LuaExportsTable<'_> for Ray {
|
||||
const EXPORT_NAME: &'static str = "Ray";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let ray_new =
|
||||
|_, (origin, direction): (LuaUserDataRef<Vector3>, LuaUserDataRef<Vector3>)| {
|
||||
Ok(Ray {
|
||||
origin: origin.0,
|
||||
direction: direction.0,
|
||||
})
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", ray_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use glam::Vec2;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Rect as DomRect;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, Vector2};
|
||||
|
||||
/**
|
||||
|
@ -28,33 +30,37 @@ impl Rect {
|
|||
}
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
impl LuaExportsTable<'_> for Rect {
|
||||
const EXPORT_NAME: &'static str = "Rect";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
type ArgsVector2s<'lua> = (
|
||||
Option<LuaUserDataRef<'lua, Vector2>>,
|
||||
Option<LuaUserDataRef<'lua, Vector2>>,
|
||||
);
|
||||
type ArgsNums = (Option<f32>, Option<f32>, Option<f32>, Option<f32>);
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|lua, args: LuaMultiValue| {
|
||||
if let Ok((min, max)) = ArgsVector2s::from_lua_multi(args.clone(), lua) {
|
||||
Ok(Rect::new(
|
||||
min.map(|m| *m).unwrap_or_default().0,
|
||||
max.map(|m| *m).unwrap_or_default().0,
|
||||
))
|
||||
} else if let Ok((x0, y0, x1, y1)) = ArgsNums::from_lua_multi(args, lua) {
|
||||
let min = Vec2::new(x0.unwrap_or_default(), y0.unwrap_or_default());
|
||||
let max = Vec2::new(x1.unwrap_or_default(), y1.unwrap_or_default());
|
||||
Ok(Rect::new(min, max))
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
})?,
|
||||
)
|
||||
|
||||
let rect_new = |lua, args: LuaMultiValue| {
|
||||
if let Ok((min, max)) = ArgsVector2s::from_lua_multi(args.clone(), lua) {
|
||||
Ok(Rect::new(
|
||||
min.map(|m| *m).unwrap_or_default().0,
|
||||
max.map(|m| *m).unwrap_or_default().0,
|
||||
))
|
||||
} else if let Ok((x0, y0, x1, y1)) = ArgsNums::from_lua_multi(args, lua) {
|
||||
let min = Vec2::new(x0.unwrap_or_default(), y0.unwrap_or_default());
|
||||
let max = Vec2::new(x1.unwrap_or_default(), y1.unwrap_or_default());
|
||||
Ok(Rect::new(min, max))
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", rect_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ use glam::{Mat4, Vec3};
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Region3 as DomRegion3;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, CFrame, Vector3};
|
||||
|
||||
/**
|
||||
|
@ -18,19 +20,20 @@ pub struct Region3 {
|
|||
pub(crate) max: Vec3,
|
||||
}
|
||||
|
||||
impl Region3 {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(
|
||||
|_, (min, max): (LuaUserDataRef<Vector3>, LuaUserDataRef<Vector3>)| {
|
||||
Ok(Region3 {
|
||||
min: min.0,
|
||||
max: max.0,
|
||||
})
|
||||
},
|
||||
)?,
|
||||
)
|
||||
impl LuaExportsTable<'_> for Region3 {
|
||||
const EXPORT_NAME: &'static str = "Region3";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let region3_new = |_, (min, max): (LuaUserDataRef<Vector3>, LuaUserDataRef<Vector3>)| {
|
||||
Ok(Region3 {
|
||||
min: min.0,
|
||||
max: max.0,
|
||||
})
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", region3_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ use glam::IVec3;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Region3int16 as DomRegion3int16;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, Vector3int16};
|
||||
|
||||
/**
|
||||
|
@ -18,19 +20,21 @@ pub struct Region3int16 {
|
|||
pub(crate) max: IVec3,
|
||||
}
|
||||
|
||||
impl Region3int16 {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(
|
||||
|_, (min, max): (LuaUserDataRef<Vector3int16>, LuaUserDataRef<Vector3int16>)| {
|
||||
Ok(Region3int16 {
|
||||
min: min.0,
|
||||
max: max.0,
|
||||
})
|
||||
},
|
||||
)?,
|
||||
)
|
||||
impl LuaExportsTable<'_> for Region3int16 {
|
||||
const EXPORT_NAME: &'static str = "Region3int16";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let region3int16_new =
|
||||
|_, (min, max): (LuaUserDataRef<Vector3int16>, LuaUserDataRef<Vector3int16>)| {
|
||||
Ok(Region3int16 {
|
||||
min: min.0,
|
||||
max: max.0,
|
||||
})
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", region3int16_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ use std::ops;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::UDim as DomUDim;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::super::*;
|
||||
|
||||
/**
|
||||
|
@ -21,17 +23,22 @@ impl UDim {
|
|||
pub(super) fn new(scale: f32, offset: i32) -> Self {
|
||||
Self { scale, offset }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, (scale, offset): (Option<f32>, Option<i32>)| {
|
||||
Ok(UDim {
|
||||
scale: scale.unwrap_or_default(),
|
||||
offset: offset.unwrap_or_default(),
|
||||
})
|
||||
})?,
|
||||
)
|
||||
impl LuaExportsTable<'_> for UDim {
|
||||
const EXPORT_NAME: &'static str = "UDim";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let udim_new = |_, (scale, offset): (Option<f32>, Option<i32>)| {
|
||||
Ok(UDim {
|
||||
scale: scale.unwrap_or_default(),
|
||||
offset: offset.unwrap_or_default(),
|
||||
})
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", udim_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use glam::Vec2;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::UDim2 as DomUDim2;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, UDim};
|
||||
|
||||
/**
|
||||
|
@ -18,52 +20,53 @@ pub struct UDim2 {
|
|||
pub(crate) y: UDim,
|
||||
}
|
||||
|
||||
impl UDim2 {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"fromScale",
|
||||
lua.create_function(|_, (x, y): (Option<f32>, Option<f32>)| {
|
||||
Ok(UDim2 {
|
||||
x: UDim::new(x.unwrap_or_default(), 0),
|
||||
y: UDim::new(y.unwrap_or_default(), 0),
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromOffset",
|
||||
lua.create_function(|_, (x, y): (Option<i32>, Option<i32>)| {
|
||||
Ok(UDim2 {
|
||||
x: UDim::new(0f32, x.unwrap_or_default()),
|
||||
y: UDim::new(0f32, y.unwrap_or_default()),
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
impl LuaExportsTable<'_> for UDim2 {
|
||||
const EXPORT_NAME: &'static str = "UDim2";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let udim2_from_offset = |_, (x, y): (Option<i32>, Option<i32>)| {
|
||||
Ok(UDim2 {
|
||||
x: UDim::new(0f32, x.unwrap_or_default()),
|
||||
y: UDim::new(0f32, y.unwrap_or_default()),
|
||||
})
|
||||
};
|
||||
|
||||
let udim2_from_scale = |_, (x, y): (Option<f32>, Option<f32>)| {
|
||||
Ok(UDim2 {
|
||||
x: UDim::new(x.unwrap_or_default(), 0),
|
||||
y: UDim::new(y.unwrap_or_default(), 0),
|
||||
})
|
||||
};
|
||||
|
||||
type ArgsUDims<'lua> = (
|
||||
Option<LuaUserDataRef<'lua, UDim>>,
|
||||
Option<LuaUserDataRef<'lua, UDim>>,
|
||||
);
|
||||
type ArgsNums = (Option<f32>, Option<i32>, Option<f32>, Option<i32>);
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|lua, args: LuaMultiValue| {
|
||||
if let Ok((x, y)) = ArgsUDims::from_lua_multi(args.clone(), lua) {
|
||||
Ok(UDim2 {
|
||||
x: x.map(|x| *x).unwrap_or_default(),
|
||||
y: y.map(|y| *y).unwrap_or_default(),
|
||||
})
|
||||
} else if let Ok((sx, ox, sy, oy)) = ArgsNums::from_lua_multi(args, lua) {
|
||||
Ok(UDim2 {
|
||||
x: UDim::new(sx.unwrap_or_default(), ox.unwrap_or_default()),
|
||||
y: UDim::new(sy.unwrap_or_default(), oy.unwrap_or_default()),
|
||||
})
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
})?,
|
||||
)
|
||||
let udim2_new = |lua, args: LuaMultiValue| {
|
||||
if let Ok((x, y)) = ArgsUDims::from_lua_multi(args.clone(), lua) {
|
||||
Ok(UDim2 {
|
||||
x: x.map(|x| *x).unwrap_or_default(),
|
||||
y: y.map(|y| *y).unwrap_or_default(),
|
||||
})
|
||||
} else if let Ok((sx, ox, sy, oy)) = ArgsNums::from_lua_multi(args, lua) {
|
||||
Ok(UDim2 {
|
||||
x: UDim::new(sx.unwrap_or_default(), ox.unwrap_or_default()),
|
||||
y: UDim::new(sy.unwrap_or_default(), oy.unwrap_or_default()),
|
||||
})
|
||||
} else {
|
||||
// FUTURE: Better error message here using given arg types
|
||||
Err(LuaError::RuntimeError(
|
||||
"Invalid arguments to constructor".to_string(),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("fromOffset", udim2_from_offset)?
|
||||
.with_function("fromScale", udim2_from_scale)?
|
||||
.with_function("new", udim2_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use glam::{Vec2, Vec3};
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Vector2 as DomVector2;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::super::*;
|
||||
|
||||
/**
|
||||
|
@ -17,23 +19,24 @@ use super::super::*;
|
|||
#[derive(Debug, Clone, Copy, PartialEq, Default)]
|
||||
pub struct Vector2(pub Vec2);
|
||||
|
||||
impl Vector2 {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
// Constants
|
||||
datatype_table.set("xAxis", Vector2(Vec2::X))?;
|
||||
datatype_table.set("yAxis", Vector2(Vec2::Y))?;
|
||||
datatype_table.set("zero", Vector2(Vec2::ZERO))?;
|
||||
datatype_table.set("one", Vector2(Vec2::ONE))?;
|
||||
// Constructors
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, (x, y): (Option<f32>, Option<f32>)| {
|
||||
Ok(Vector2(Vec2 {
|
||||
x: x.unwrap_or_default(),
|
||||
y: y.unwrap_or_default(),
|
||||
}))
|
||||
})?,
|
||||
)
|
||||
impl LuaExportsTable<'_> for Vector2 {
|
||||
const EXPORT_NAME: &'static str = "Vector2";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let vector2_new = |_, (x, y): (Option<f32>, Option<f32>)| {
|
||||
Ok(Vector2(Vec2 {
|
||||
x: x.unwrap_or_default(),
|
||||
y: y.unwrap_or_default(),
|
||||
}))
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_value("xAxis", Vector2(Vec2::X))?
|
||||
.with_value("yAxis", Vector2(Vec2::Y))?
|
||||
.with_value("zero", Vector2(Vec2::ZERO))?
|
||||
.with_value("one", Vector2(Vec2::ONE))?
|
||||
.with_function("new", vector2_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use glam::IVec2;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Vector2int16 as DomVector2int16;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::super::*;
|
||||
|
||||
/**
|
||||
|
@ -17,17 +19,20 @@ use super::super::*;
|
|||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Vector2int16(pub IVec2);
|
||||
|
||||
impl Vector2int16 {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, (x, y): (Option<i16>, Option<i16>)| {
|
||||
Ok(Vector2int16(IVec2 {
|
||||
x: x.unwrap_or_default() as i32,
|
||||
y: y.unwrap_or_default() as i32,
|
||||
}))
|
||||
})?,
|
||||
)
|
||||
impl LuaExportsTable<'_> for Vector2int16 {
|
||||
const EXPORT_NAME: &'static str = "Vector2int16";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let vector2int16_new = |_, (x, y): (Option<i16>, Option<i16>)| {
|
||||
Ok(Vector2int16(IVec2 {
|
||||
x: x.unwrap_or_default() as i32,
|
||||
y: y.unwrap_or_default() as i32,
|
||||
}))
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", vector2int16_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use glam::Vec3;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Vector3 as DomVector3;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::{super::*, EnumItem};
|
||||
|
||||
/**
|
||||
|
@ -20,74 +22,73 @@ use super::{super::*, EnumItem};
|
|||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Vector3(pub Vec3);
|
||||
|
||||
impl Vector3 {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
// Constants
|
||||
datatype_table.set("xAxis", Vector3(Vec3::X))?;
|
||||
datatype_table.set("yAxis", Vector3(Vec3::Y))?;
|
||||
datatype_table.set("zAxis", Vector3(Vec3::Z))?;
|
||||
datatype_table.set("zero", Vector3(Vec3::ZERO))?;
|
||||
datatype_table.set("one", Vector3(Vec3::ONE))?;
|
||||
// Constructors
|
||||
datatype_table.set(
|
||||
"fromAxis",
|
||||
lua.create_function(|_, normal_id: LuaUserDataRef<EnumItem>| {
|
||||
if normal_id.parent.desc.name == "Axis" {
|
||||
Ok(match normal_id.name.as_str() {
|
||||
"X" => Vector3(Vec3::X),
|
||||
"Y" => Vector3(Vec3::Y),
|
||||
"Z" => Vector3(Vec3::Z),
|
||||
name => {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Axis '{}' is not known",
|
||||
name
|
||||
)))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Err(LuaError::RuntimeError(format!(
|
||||
"EnumItem must be a Axis, got {}",
|
||||
normal_id.parent.desc.name
|
||||
)))
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"fromNormalId",
|
||||
lua.create_function(|_, normal_id: LuaUserDataRef<EnumItem>| {
|
||||
if normal_id.parent.desc.name == "NormalId" {
|
||||
Ok(match normal_id.name.as_str() {
|
||||
"Left" => Vector3(Vec3::X),
|
||||
"Top" => Vector3(Vec3::Y),
|
||||
"Front" => Vector3(-Vec3::Z),
|
||||
"Right" => Vector3(-Vec3::X),
|
||||
"Bottom" => Vector3(-Vec3::Y),
|
||||
"Back" => Vector3(Vec3::Z),
|
||||
name => {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"NormalId '{}' is not known",
|
||||
name
|
||||
)))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Err(LuaError::RuntimeError(format!(
|
||||
"EnumItem must be a NormalId, got {}",
|
||||
normal_id.parent.desc.name
|
||||
)))
|
||||
}
|
||||
})?,
|
||||
)?;
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, (x, y, z): (Option<f32>, Option<f32>, Option<f32>)| {
|
||||
Ok(Vector3(Vec3 {
|
||||
x: x.unwrap_or_default(),
|
||||
y: y.unwrap_or_default(),
|
||||
z: z.unwrap_or_default(),
|
||||
}))
|
||||
})?,
|
||||
)
|
||||
impl LuaExportsTable<'_> for Vector3 {
|
||||
const EXPORT_NAME: &'static str = "Vector3";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let vector3_from_axis = |_, normal_id: LuaUserDataRef<EnumItem>| {
|
||||
if normal_id.parent.desc.name == "Axis" {
|
||||
Ok(match normal_id.name.as_str() {
|
||||
"X" => Vector3(Vec3::X),
|
||||
"Y" => Vector3(Vec3::Y),
|
||||
"Z" => Vector3(Vec3::Z),
|
||||
name => {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"Axis '{}' is not known",
|
||||
name
|
||||
)))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Err(LuaError::RuntimeError(format!(
|
||||
"EnumItem must be a Axis, got {}",
|
||||
normal_id.parent.desc.name
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let vector3_from_normal_id = |_, normal_id: LuaUserDataRef<EnumItem>| {
|
||||
if normal_id.parent.desc.name == "NormalId" {
|
||||
Ok(match normal_id.name.as_str() {
|
||||
"Left" => Vector3(Vec3::X),
|
||||
"Top" => Vector3(Vec3::Y),
|
||||
"Front" => Vector3(-Vec3::Z),
|
||||
"Right" => Vector3(-Vec3::X),
|
||||
"Bottom" => Vector3(-Vec3::Y),
|
||||
"Back" => Vector3(Vec3::Z),
|
||||
name => {
|
||||
return Err(LuaError::RuntimeError(format!(
|
||||
"NormalId '{}' is not known",
|
||||
name
|
||||
)))
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Err(LuaError::RuntimeError(format!(
|
||||
"EnumItem must be a NormalId, got {}",
|
||||
normal_id.parent.desc.name
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
let vector3_new = |_, (x, y, z): (Option<f32>, Option<f32>, Option<f32>)| {
|
||||
Ok(Vector3(Vec3 {
|
||||
x: x.unwrap_or_default(),
|
||||
y: y.unwrap_or_default(),
|
||||
z: z.unwrap_or_default(),
|
||||
}))
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_value("xAxis", Vector3(Vec3::X))?
|
||||
.with_value("yAxis", Vector3(Vec3::Y))?
|
||||
.with_value("zAxis", Vector3(Vec3::Z))?
|
||||
.with_value("zero", Vector3(Vec3::ZERO))?
|
||||
.with_value("one", Vector3(Vec3::ONE))?
|
||||
.with_function("fromAxis", vector3_from_axis)?
|
||||
.with_function("fromNormalId", vector3_from_normal_id)?
|
||||
.with_function("new", vector3_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ use glam::IVec3;
|
|||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Vector3int16 as DomVector3int16;
|
||||
|
||||
use crate::{lune::util::TableBuilder, roblox::exports::LuaExportsTable};
|
||||
|
||||
use super::super::*;
|
||||
|
||||
/**
|
||||
|
@ -17,18 +19,21 @@ use super::super::*;
|
|||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Vector3int16(pub IVec3);
|
||||
|
||||
impl Vector3int16 {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|_, (x, y, z): (Option<i16>, Option<i16>, Option<i16>)| {
|
||||
Ok(Vector3int16(IVec3 {
|
||||
x: x.unwrap_or_default() as i32,
|
||||
y: y.unwrap_or_default() as i32,
|
||||
z: z.unwrap_or_default() as i32,
|
||||
}))
|
||||
})?,
|
||||
)
|
||||
impl LuaExportsTable<'_> for Vector3int16 {
|
||||
const EXPORT_NAME: &'static str = "Vector3int16";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let vector3int16_new = |_, (x, y, z): (Option<i16>, Option<i16>, Option<i16>)| {
|
||||
Ok(Vector3int16(IVec3 {
|
||||
x: x.unwrap_or_default() as i32,
|
||||
y: y.unwrap_or_default() as i32,
|
||||
z: z.unwrap_or_default() as i32,
|
||||
}))
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", vector3int16_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
68
src/roblox/exports.rs
Normal file
68
src/roblox/exports.rs
Normal file
|
@ -0,0 +1,68 @@
|
|||
use mlua::prelude::*;
|
||||
|
||||
/**
|
||||
Trait for any item that should be exported as part of the `roblox` built-in library.
|
||||
|
||||
This may be an enum or a struct that should export constants and/or constructs.
|
||||
|
||||
### Example usage
|
||||
|
||||
```rs
|
||||
use mlua::prelude::*;
|
||||
|
||||
struct MyType(usize);
|
||||
|
||||
impl MyType {
|
||||
pub fn new(n: usize) -> Self {
|
||||
Self(n)
|
||||
}
|
||||
}
|
||||
|
||||
impl LuaExportsTable<'_> for MyType {
|
||||
const EXPORT_NAME: &'static str = "MyType";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let my_type_new = |lua, n: Option<usize>| {
|
||||
Self::new(n.unwrap_or_default())
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", my_type_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
impl LuaUserData for MyType {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
*/
|
||||
pub trait LuaExportsTable<'lua> {
|
||||
const EXPORT_NAME: &'static str;
|
||||
|
||||
fn create_exports_table(lua: &'lua Lua) -> LuaResult<LuaTable<'lua>>;
|
||||
}
|
||||
|
||||
/**
|
||||
Exports a single item that implements the [`LuaExportsTable`] trait.
|
||||
|
||||
Returns the name of the export, as well as the export table.
|
||||
|
||||
### Example usage
|
||||
|
||||
```rs
|
||||
let lua: mlua::Lua::new();
|
||||
|
||||
let (name1, table1) = export::<Type1>(lua)?;
|
||||
let (name2, table2) = export::<Type2>(lua)?;
|
||||
```
|
||||
*/
|
||||
pub fn export<'lua, T>(lua: &'lua Lua) -> LuaResult<(&'static str, LuaValue<'lua>)>
|
||||
where
|
||||
T: LuaExportsTable<'lua>,
|
||||
{
|
||||
Ok((
|
||||
T::EXPORT_NAME,
|
||||
<T as LuaExportsTable>::create_exports_table(lua)?.into_lua(lua)?,
|
||||
))
|
||||
}
|
|
@ -12,7 +12,11 @@ use rbx_dom_weak::{
|
|||
Instance as DomInstance, InstanceBuilder as DomInstanceBuilder, WeakDom,
|
||||
};
|
||||
|
||||
use crate::roblox::shared::instance::{class_exists, class_is_a};
|
||||
use crate::{
|
||||
lune::util::TableBuilder,
|
||||
roblox::exports::LuaExportsTable,
|
||||
roblox::shared::instance::{class_exists, class_is_a},
|
||||
};
|
||||
|
||||
pub(crate) mod base;
|
||||
pub(crate) mod data_model;
|
||||
|
@ -686,21 +690,24 @@ impl Instance {
|
|||
}
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||
datatype_table.set(
|
||||
"new",
|
||||
lua.create_function(|lua, class_name: String| {
|
||||
if class_exists(&class_name) {
|
||||
Instance::new_orphaned(class_name).into_lua(lua)
|
||||
} else {
|
||||
Err(LuaError::RuntimeError(format!(
|
||||
"Failed to create Instance - '{}' is not a valid class name",
|
||||
class_name
|
||||
)))
|
||||
}
|
||||
})?,
|
||||
)
|
||||
impl LuaExportsTable<'_> for Instance {
|
||||
const EXPORT_NAME: &'static str = "Instance";
|
||||
|
||||
fn create_exports_table(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let instance_new = |lua, class_name: String| {
|
||||
if class_exists(&class_name) {
|
||||
Instance::new_orphaned(class_name).into_lua(lua)
|
||||
} else {
|
||||
Err(LuaError::RuntimeError(format!(
|
||||
"Failed to create Instance - '{}' is not a valid class name",
|
||||
class_name
|
||||
)))
|
||||
}
|
||||
};
|
||||
|
||||
TableBuilder::new(lua)?
|
||||
.with_function("new", instance_new)?
|
||||
.build_readonly()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,63 +1,59 @@
|
|||
use mlua::prelude::*;
|
||||
|
||||
use crate::roblox::instance::Instance;
|
||||
use crate::lune::util::TableBuilder;
|
||||
|
||||
pub mod datatypes;
|
||||
pub mod document;
|
||||
pub mod instance;
|
||||
pub mod reflection;
|
||||
|
||||
pub(crate) mod exports;
|
||||
pub(crate) mod shared;
|
||||
|
||||
fn make<F>(lua: &Lua, f: F) -> LuaResult<LuaValue>
|
||||
where
|
||||
F: Fn(&Lua, &LuaTable) -> LuaResult<()>,
|
||||
{
|
||||
let tab = lua.create_table()?;
|
||||
f(lua, &tab)?;
|
||||
tab.set_readonly(true);
|
||||
Ok(LuaValue::Table(tab))
|
||||
}
|
||||
use exports::export;
|
||||
|
||||
#[rustfmt::skip]
|
||||
fn make_all_datatypes(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
|
||||
use datatypes::types::*;
|
||||
fn create_all_exports(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
|
||||
use datatypes::types::*;
|
||||
use instance::Instance;
|
||||
Ok(vec![
|
||||
// Datatypes
|
||||
("Axes", make(lua, Axes::make_table)?),
|
||||
("BrickColor", make(lua, BrickColor::make_table)?),
|
||||
("CFrame", make(lua, CFrame::make_table)?),
|
||||
("Color3", make(lua, Color3::make_table)?),
|
||||
("ColorSequence", make(lua, ColorSequence::make_table)?),
|
||||
("ColorSequenceKeypoint", make(lua, ColorSequenceKeypoint::make_table)?),
|
||||
("Faces", make(lua, Faces::make_table)?),
|
||||
("Font", make(lua, Font::make_table)?),
|
||||
("NumberRange", make(lua, NumberRange::make_table)?),
|
||||
("NumberSequence", make(lua, NumberSequence::make_table)?),
|
||||
("NumberSequenceKeypoint", make(lua, NumberSequenceKeypoint::make_table)?),
|
||||
("PhysicalProperties", make(lua, PhysicalProperties::make_table)?),
|
||||
("Ray", make(lua, Ray::make_table)?),
|
||||
("Rect", make(lua, Rect::make_table)?),
|
||||
("UDim", make(lua, UDim::make_table)?),
|
||||
("UDim2", make(lua, UDim2::make_table)?),
|
||||
("Region3", make(lua, Region3::make_table)?),
|
||||
("Region3int16", make(lua, Region3int16::make_table)?),
|
||||
("Vector2", make(lua, Vector2::make_table)?),
|
||||
("Vector2int16", make(lua, Vector2int16::make_table)?),
|
||||
("Vector3", make(lua, Vector3::make_table)?),
|
||||
("Vector3int16", make(lua, Vector3int16::make_table)?),
|
||||
// Classes
|
||||
("Instance", make(lua, Instance::make_table)?),
|
||||
// Singletons
|
||||
// Datatypes
|
||||
export::<Axes>(lua)?,
|
||||
export::<BrickColor>(lua)?,
|
||||
export::<CFrame>(lua)?,
|
||||
export::<Color3>(lua)?,
|
||||
export::<ColorSequence>(lua)?,
|
||||
export::<ColorSequenceKeypoint>(lua)?,
|
||||
export::<Faces>(lua)?,
|
||||
export::<Font>(lua)?,
|
||||
export::<NumberRange>(lua)?,
|
||||
export::<NumberSequence>(lua)?,
|
||||
export::<NumberSequenceKeypoint>(lua)?,
|
||||
export::<PhysicalProperties>(lua)?,
|
||||
export::<Ray>(lua)?,
|
||||
export::<Rect>(lua)?,
|
||||
export::<UDim>(lua)?,
|
||||
export::<UDim2>(lua)?,
|
||||
export::<Region3>(lua)?,
|
||||
export::<Region3int16>(lua)?,
|
||||
export::<Vector2>(lua)?,
|
||||
export::<Vector2int16>(lua)?,
|
||||
export::<Vector3>(lua)?,
|
||||
export::<Vector3int16>(lua)?,
|
||||
// Classes
|
||||
export::<Instance>(lua)?,
|
||||
// Singletons
|
||||
("Enum", Enums.into_lua(lua)?),
|
||||
])
|
||||
}
|
||||
|
||||
pub fn module(lua: &Lua) -> LuaResult<LuaTable> {
|
||||
let exports = lua.create_table()?;
|
||||
for (name, tab) in make_all_datatypes(lua)? {
|
||||
exports.set(name, tab)?;
|
||||
}
|
||||
exports.set_readonly(true);
|
||||
Ok(exports)
|
||||
// FUTURE: We can probably create these lazily as users
|
||||
// index the main exports (this return value) table and
|
||||
// save some memory and startup time. The full exports
|
||||
// table is quite big and probably won't get any smaller
|
||||
// since we impl all roblox constructors for each datatype.
|
||||
let exports = create_all_exports(lua)?;
|
||||
TableBuilder::new(lua)?
|
||||
.with_values(exports)?
|
||||
.build_readonly()
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue