Implement Axes roblox datatype

This commit is contained in:
Filip Tibell 2023-03-15 22:06:53 +01:00
parent 7aef25c316
commit cfc9299165
No known key found for this signature in database
5 changed files with 188 additions and 4 deletions

View file

@ -116,11 +116,12 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> {
use super::types::*;
use RbxVariant as Rbx;
// NOTE: Enum is intentionally left out here, it has a custom
// conversion going from instance property > datatype instead,
// check `EnumItem::from_instance_property` for specifics
Ok(match variant.clone() {
// Not yet implemented datatypes
// Rbx::Axes(_) => todo!(),
// Rbx::CFrame(_) => todo!(),
// Rbx::Enum(_) => todo!(),
// Rbx::Faces(_) => todo!(),
// Rbx::NumberRange(_) => todo!(),
// Rbx::NumberSequence(_) => todo!(),
@ -131,8 +132,9 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> {
// Rbx::Region3(_) => todo!(),
// Rbx::Region3int16(_) => todo!(),
Rbx::BrickColor(value) => lua.create_userdata(BrickColor::from(value))?,
Rbx::Axes(value) => lua.create_userdata(Axes::from(value))?,
Rbx::BrickColor(value) => lua.create_userdata(BrickColor::from(value))?,
Rbx::Color3(value) => lua.create_userdata(Color3::from(value))?,
Rbx::Color3uint8(value) => lua.create_userdata(Color3::from(value))?,
Rbx::ColorSequence(value) => lua.create_userdata(ColorSequence::from(value))?,
@ -167,8 +169,9 @@ impl<'lua> LuaToRbxVariant<'lua> for LuaAnyUserData<'lua> {
use rbx_dom_weak::types as rbx;
let f = match variant_type {
RbxVariantType::BrickColor => convert::<BrickColor, rbx::BrickColor>,
RbxVariantType::Axes => convert::<Axes, rbx::Axes>,
RbxVariantType::BrickColor => convert::<BrickColor, rbx::BrickColor>,
RbxVariantType::Color3 => convert::<Color3, rbx::Color3>,
RbxVariantType::Color3uint8 => convert::<Color3, rbx::Color3uint8>,
RbxVariantType::ColorSequence => convert::<ColorSequence, rbx::ColorSequence>,

View file

@ -0,0 +1,133 @@
use core::fmt;
use mlua::prelude::*;
use rbx_dom_weak::types::Axes as RbxAxes;
use super::{super::*, EnumItem};
/**
An implementation of the [Axes](https://create.roblox.com/docs/reference/engine/datatypes/Axes) Roblox datatype.
This implements all documented properties, methods & constructors of the Axes class as of March 2023.
*/
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Axes {
pub(crate) x: bool,
pub(crate) y: bool,
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,
_ => {}
}
}
};
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 })
})?,
)?;
Ok(())
}
}
impl LuaUserData for Axes {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("X", |_, this| Ok(this.x));
fields.add_field_method_get("Y", |_, this| Ok(this.y));
fields.add_field_method_get("Z", |_, this| Ok(this.z));
fields.add_field_method_get("Left", |_, this| Ok(this.x));
fields.add_field_method_get("Right", |_, this| Ok(this.x));
fields.add_field_method_get("Top", |_, this| Ok(this.y));
fields.add_field_method_get("Bottom", |_, this| Ok(this.y));
fields.add_field_method_get("Front", |_, this| Ok(this.z));
fields.add_field_method_get("Back", |_, this| Ok(this.z));
}
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 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")?;
}
}
Ok(())
}
}
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 }
}
}
impl From<Axes> for RbxAxes {
fn from(v: Axes) -> Self {
let mut bits = 0;
bits += v.x as u8;
bits += (v.y as u8) << 1;
bits += (v.z as u8) << 2;
RbxAxes::from_bits(bits).expect("Invalid bits")
}
}

View file

@ -1,3 +1,4 @@
mod axes;
mod brick_color;
mod color3;
mod color_sequence;
@ -12,6 +13,7 @@ mod vector2int16;
mod vector3;
mod vector3int16;
pub use axes::Axes;
pub use brick_color::BrickColor;
pub use color3::Color3;
pub use color_sequence::ColorSequence;
@ -68,6 +70,7 @@ mod tests {
}
create_tests! {
axes: "datatypes/Axes",
brick_color: "datatypes/BrickColor",
color3: "datatypes/Color3",
color_sequence: "datatypes/ColorSequence",

View file

@ -19,6 +19,7 @@ fn make_all_datatypes(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
use datatypes::types::*;
Ok(vec![
// Classes
("Axes", make_dt(lua, Axes::make_table)?),
("BrickColor", make_dt(lua, BrickColor::make_table)?),
("Color3", make_dt(lua, Color3::make_table)?),
("ColorSequence", make_dt(lua, ColorSequence::make_table)?),

View file

@ -0,0 +1,44 @@
-- HACK: Make luau happy, with the mlua rust
-- crate all globals are also present in _G
local Axes = _G.Axes
local Enum = _G.Enum
-- Constructors & properties
Axes.new()
Axes.new(Enum.Axis.X)
Axes.new(Enum.Axis.X, Enum.NormalId.Top)
assert(not pcall(function()
return Axes.new(false)
end))
assert(not pcall(function()
return Axes.new({})
end))
assert(not pcall(function()
return Axes.new(newproxy(true))
end))
assert(Axes.new().X == false)
assert(Axes.new().Y == false)
assert(Axes.new().Z == false)
assert(Axes.new(Enum.Axis.X, Enum.NormalId.Top).X == true)
assert(Axes.new(Enum.Axis.X, Enum.NormalId.Top).Y == true)
assert(Axes.new(Enum.Axis.X, Enum.NormalId.Top).Z == false)
assert(Axes.new(Enum.Axis.X, Enum.NormalId.Left).X == true)
assert(Axes.new(Enum.Axis.X, Enum.NormalId.Right).X == true)
assert(Axes.new(Enum.NormalId.Front, Enum.NormalId.Back).X == false)
assert(Axes.new(Enum.NormalId.Front, Enum.NormalId.Back).Y == false)
assert(Axes.new(Enum.NormalId.Front, Enum.NormalId.Back).Z == true)
-- Ops
assert(not pcall(function()
return Axes.new() + Axes.new()
end))
assert(not pcall(function()
return Axes.new() / Axes.new()
end))