mirror of
https://github.com/lune-org/lune.git
synced 2024-12-12 13:00:37 +00:00
Implement Faces roblox datatype
This commit is contained in:
parent
cfc9299165
commit
75188d3e35
7 changed files with 223 additions and 28 deletions
|
@ -122,7 +122,6 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> {
|
|||
Ok(match variant.clone() {
|
||||
// Not yet implemented datatypes
|
||||
// Rbx::CFrame(_) => todo!(),
|
||||
// Rbx::Faces(_) => todo!(),
|
||||
// Rbx::NumberRange(_) => todo!(),
|
||||
// Rbx::NumberSequence(_) => todo!(),
|
||||
// Rbx::OptionalCFrame(_) => todo!(),
|
||||
|
@ -132,7 +131,8 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> {
|
|||
// Rbx::Region3(_) => todo!(),
|
||||
// Rbx::Region3int16(_) => todo!(),
|
||||
|
||||
Rbx::Axes(value) => lua.create_userdata(Axes::from(value))?,
|
||||
Rbx::Axes(value) => lua.create_userdata(Axes::from(value))?,
|
||||
Rbx::Faces(value) => lua.create_userdata(Faces::from(value))?,
|
||||
|
||||
Rbx::BrickColor(value) => lua.create_userdata(BrickColor::from(value))?,
|
||||
Rbx::Color3(value) => lua.create_userdata(Color3::from(value))?,
|
||||
|
@ -169,7 +169,8 @@ impl<'lua> LuaToRbxVariant<'lua> for LuaAnyUserData<'lua> {
|
|||
use rbx_dom_weak::types as rbx;
|
||||
|
||||
let f = match variant_type {
|
||||
RbxVariantType::Axes => convert::<Axes, rbx::Axes>,
|
||||
RbxVariantType::Axes => convert::<Axes, rbx::Axes>,
|
||||
RbxVariantType::Faces => convert::<Faces, rbx::Faces>,
|
||||
|
||||
RbxVariantType::BrickColor => convert::<BrickColor, rbx::BrickColor>,
|
||||
RbxVariantType::Color3 => convert::<Color3, rbx::Color3>,
|
||||
|
|
|
@ -1,7 +1,26 @@
|
|||
use std::{any::type_name, ops};
|
||||
use std::{any::type_name, cell::RefCell, fmt, ops};
|
||||
|
||||
use mlua::prelude::*;
|
||||
|
||||
// Utility functions
|
||||
|
||||
type ListWriter = dyn Fn(&mut fmt::Formatter<'_>, bool, &str) -> fmt::Result;
|
||||
pub(super) fn make_list_writer() -> Box<ListWriter> {
|
||||
let first = RefCell::new(true);
|
||||
Box::new(move |f, flag, literal| {
|
||||
if flag {
|
||||
if first.take() {
|
||||
write!(f, "{}", literal)?;
|
||||
} else {
|
||||
write!(f, ", {}", literal)?;
|
||||
}
|
||||
}
|
||||
Ok::<_, fmt::Error>(())
|
||||
})
|
||||
}
|
||||
|
||||
// Userdata metamethod implementations
|
||||
|
||||
pub(super) fn userdata_impl_to_string<D>(_: &Lua, datatype: &D, _: ()) -> LuaResult<String>
|
||||
where
|
||||
D: LuaUserData + ToString + 'static,
|
||||
|
|
|
@ -88,26 +88,10 @@ impl LuaUserData for Axes {
|
|||
|
||||
impl fmt::Display for Axes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut got_value = false;
|
||||
if self.x {
|
||||
write!(f, "X")?;
|
||||
got_value = true;
|
||||
}
|
||||
if self.y {
|
||||
if got_value {
|
||||
write!(f, ", Y")?;
|
||||
} else {
|
||||
write!(f, "Y")?;
|
||||
got_value = true;
|
||||
}
|
||||
}
|
||||
if self.z {
|
||||
if got_value {
|
||||
write!(f, ", Z")?;
|
||||
} else {
|
||||
write!(f, "Z")?;
|
||||
}
|
||||
}
|
||||
let write = make_list_writer();
|
||||
write(f, self.x, "X")?;
|
||||
write(f, self.y, "Y")?;
|
||||
write(f, self.z, "Z")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -115,10 +99,11 @@ impl fmt::Display for Axes {
|
|||
impl From<RbxAxes> for Axes {
|
||||
fn from(v: RbxAxes) -> Self {
|
||||
let bits = v.bits();
|
||||
let x = (bits & 1) == 1;
|
||||
let y = ((bits >> 1) & 1) == 1;
|
||||
let z = ((bits >> 2) & 1) == 1;
|
||||
Self { x, y, z }
|
||||
Self {
|
||||
x: (bits & 1) == 1,
|
||||
y: ((bits >> 1) & 1) == 1,
|
||||
z: ((bits >> 2) & 1) == 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
133
packages/lib-roblox/src/datatypes/types/faces.rs
Normal file
133
packages/lib-roblox/src/datatypes/types/faces.rs
Normal file
|
@ -0,0 +1,133 @@
|
|||
use core::fmt;
|
||||
|
||||
use mlua::prelude::*;
|
||||
use rbx_dom_weak::types::Faces as RbxFaces;
|
||||
|
||||
use super::{super::*, EnumItem};
|
||||
|
||||
/**
|
||||
An implementation of the [Faces](https://create.roblox.com/docs/reference/engine/datatypes/Faces) Roblox datatype.
|
||||
|
||||
This implements all documented properties, methods & constructors of the Faces class as of March 2023.
|
||||
*/
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub struct Faces {
|
||||
pub(crate) right: bool,
|
||||
pub(crate) top: bool,
|
||||
pub(crate) back: bool,
|
||||
pub(crate) left: bool,
|
||||
pub(crate) bottom: bool,
|
||||
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()
|
||||
)));
|
||||
}
|
||||
}
|
||||
Ok(Faces {
|
||||
right,
|
||||
top,
|
||||
back,
|
||||
left,
|
||||
bottom,
|
||||
front,
|
||||
})
|
||||
})?,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl LuaUserData for Faces {
|
||||
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||
fields.add_field_method_get("Right", |_, this| Ok(this.right));
|
||||
fields.add_field_method_get("Top", |_, this| Ok(this.top));
|
||||
fields.add_field_method_get("Back", |_, this| Ok(this.back));
|
||||
fields.add_field_method_get("Left", |_, this| Ok(this.left));
|
||||
fields.add_field_method_get("Bottom", |_, this| Ok(this.bottom));
|
||||
fields.add_field_method_get("Front", |_, this| Ok(this.front));
|
||||
}
|
||||
|
||||
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(LuaMetaMethod::Eq, userdata_impl_eq);
|
||||
methods.add_meta_method(LuaMetaMethod::ToString, userdata_impl_to_string);
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Faces {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let write = make_list_writer();
|
||||
write(f, self.right, "Right")?;
|
||||
write(f, self.top, "Top")?;
|
||||
write(f, self.back, "Back")?;
|
||||
write(f, self.left, "Left")?;
|
||||
write(f, self.bottom, "Bottom")?;
|
||||
write(f, self.front, "Front")?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RbxFaces> for Faces {
|
||||
fn from(v: RbxFaces) -> Self {
|
||||
let bits = v.bits();
|
||||
Self {
|
||||
right: (bits & 1) == 1,
|
||||
top: ((bits >> 1) & 1) == 1,
|
||||
back: ((bits >> 2) & 1) == 1,
|
||||
left: ((bits >> 3) & 1) == 1,
|
||||
bottom: ((bits >> 4) & 1) == 1,
|
||||
front: ((bits >> 5) & 1) == 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Faces> for RbxFaces {
|
||||
fn from(v: Faces) -> Self {
|
||||
let mut bits = 0;
|
||||
bits += v.right as u8;
|
||||
bits += (v.top as u8) << 1;
|
||||
bits += (v.back as u8) << 2;
|
||||
bits += (v.left as u8) << 3;
|
||||
bits += (v.bottom as u8) << 4;
|
||||
bits += (v.front as u8) << 5;
|
||||
RbxFaces::from_bits(bits).expect("Invalid bits")
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ mod color_sequence_keypoint;
|
|||
mod r#enum;
|
||||
mod r#enum_item;
|
||||
mod r#enums;
|
||||
mod faces;
|
||||
mod udim;
|
||||
mod udim2;
|
||||
mod vector2;
|
||||
|
@ -18,6 +19,7 @@ pub use brick_color::BrickColor;
|
|||
pub use color3::Color3;
|
||||
pub use color_sequence::ColorSequence;
|
||||
pub use color_sequence_keypoint::ColorSequenceKeypoint;
|
||||
pub use faces::Faces;
|
||||
pub use r#enum::Enum;
|
||||
pub use r#enum_item::EnumItem;
|
||||
pub use r#enums::Enums;
|
||||
|
@ -76,6 +78,7 @@ mod tests {
|
|||
color_sequence: "datatypes/ColorSequence",
|
||||
color_sequence_keypoint: "datatypes/ColorSequenceKeypoint",
|
||||
r#enum: "datatypes/Enum",
|
||||
faces: "datatypes/Faces",
|
||||
udim: "datatypes/UDim",
|
||||
udim2: "datatypes/UDim2",
|
||||
vector2: "datatypes/Vector2",
|
||||
|
|
|
@ -24,6 +24,7 @@ fn make_all_datatypes(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
|
|||
("Color3", make_dt(lua, Color3::make_table)?),
|
||||
("ColorSequence", make_dt(lua, ColorSequence::make_table)?),
|
||||
("ColorSequenceKeypoint", make_dt(lua, ColorSequenceKeypoint::make_table)?),
|
||||
("Faces", make_dt(lua, Faces::make_table)?),
|
||||
("UDim", make_dt(lua, UDim::make_table)?),
|
||||
("UDim2", make_dt(lua, UDim2::make_table)?),
|
||||
("Vector2", make_dt(lua, Vector2::make_table)?),
|
||||
|
|
53
tests/roblox/datatypes/Faces.luau
Normal file
53
tests/roblox/datatypes/Faces.luau
Normal file
|
@ -0,0 +1,53 @@
|
|||
-- HACK: Make luau happy, with the mlua rust
|
||||
-- crate all globals are also present in _G
|
||||
local Faces = _G.Faces
|
||||
local Enum = _G.Enum
|
||||
|
||||
-- Constructors & properties
|
||||
|
||||
Faces.new()
|
||||
Faces.new(Enum.NormalId.Top)
|
||||
Faces.new(Enum.NormalId.Left, Enum.NormalId.Top)
|
||||
|
||||
assert(not pcall(function()
|
||||
return Faces.new(false)
|
||||
end))
|
||||
assert(not pcall(function()
|
||||
return Faces.new({})
|
||||
end))
|
||||
assert(not pcall(function()
|
||||
return Faces.new(newproxy(true))
|
||||
end))
|
||||
|
||||
assert(Faces.new().Left == false)
|
||||
assert(Faces.new().Right == false)
|
||||
assert(Faces.new().Top == false)
|
||||
assert(Faces.new().Bottom == false)
|
||||
assert(Faces.new().Front == false)
|
||||
assert(Faces.new().Back == false)
|
||||
|
||||
assert(Faces.new(Enum.NormalId.Left).Left == true)
|
||||
assert(Faces.new(Enum.NormalId.Right).Right == true)
|
||||
|
||||
local f = Faces.new(
|
||||
Enum.NormalId.Left,
|
||||
Enum.NormalId.Right,
|
||||
Enum.NormalId.Top,
|
||||
Enum.NormalId.Bottom,
|
||||
Enum.NormalId.Back
|
||||
)
|
||||
assert(f.Left == true)
|
||||
assert(f.Right == true)
|
||||
assert(f.Top == true)
|
||||
assert(f.Bottom == true)
|
||||
assert(f.Front == false)
|
||||
assert(f.Back == true)
|
||||
|
||||
-- Ops
|
||||
|
||||
assert(not pcall(function()
|
||||
return Faces.new() + Faces.new()
|
||||
end))
|
||||
assert(not pcall(function()
|
||||
return Faces.new() / Faces.new()
|
||||
end))
|
Loading…
Reference in a new issue