Implement Rect roblox datatype

This commit is contained in:
Filip Tibell 2023-03-16 09:56:37 +01:00
parent 75188d3e35
commit 72f3e2157b
No known key found for this signature in database
6 changed files with 167 additions and 2 deletions

View file

@ -127,7 +127,6 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> {
// Rbx::OptionalCFrame(_) => todo!(), // Rbx::OptionalCFrame(_) => todo!(),
// Rbx::PhysicalProperties(_) => todo!(), // Rbx::PhysicalProperties(_) => todo!(),
// Rbx::Ray(_) => todo!(), // Rbx::Ray(_) => todo!(),
// Rbx::Rect(_) => todo!(),
// Rbx::Region3(_) => todo!(), // Rbx::Region3(_) => todo!(),
// Rbx::Region3int16(_) => todo!(), // Rbx::Region3int16(_) => todo!(),
@ -139,6 +138,7 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> {
Rbx::Color3uint8(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))?, Rbx::ColorSequence(value) => lua.create_userdata(ColorSequence::from(value))?,
Rbx::Rect(value) => lua.create_userdata(Rect::from(value))?,
Rbx::UDim(value) => lua.create_userdata(UDim::from(value))?, Rbx::UDim(value) => lua.create_userdata(UDim::from(value))?,
Rbx::UDim2(value) => lua.create_userdata(UDim2::from(value))?, Rbx::UDim2(value) => lua.create_userdata(UDim2::from(value))?,
@ -179,6 +179,7 @@ impl<'lua> LuaToRbxVariant<'lua> for LuaAnyUserData<'lua> {
RbxVariantType::Enum => convert::<EnumItem, rbx::Enum>, RbxVariantType::Enum => convert::<EnumItem, rbx::Enum>,
RbxVariantType::Rect => convert::<Rect, rbx::Rect>,
RbxVariantType::UDim => convert::<UDim, rbx::UDim>, RbxVariantType::UDim => convert::<UDim, rbx::UDim>,
RbxVariantType::UDim2 => convert::<UDim2, rbx::UDim2>, RbxVariantType::UDim2 => convert::<UDim2, rbx::UDim2>,

View file

@ -7,6 +7,7 @@ mod r#enum;
mod r#enum_item; mod r#enum_item;
mod r#enums; mod r#enums;
mod faces; mod faces;
mod rect;
mod udim; mod udim;
mod udim2; mod udim2;
mod vector2; mod vector2;
@ -23,6 +24,7 @@ pub use faces::Faces;
pub use r#enum::Enum; pub use r#enum::Enum;
pub use r#enum_item::EnumItem; pub use r#enum_item::EnumItem;
pub use r#enums::Enums; pub use r#enums::Enums;
pub use rect::Rect;
pub use udim::UDim; pub use udim::UDim;
pub use udim2::UDim2; pub use udim2::UDim2;
pub use vector2::Vector2; pub use vector2::Vector2;
@ -79,6 +81,7 @@ mod tests {
color_sequence_keypoint: "datatypes/ColorSequenceKeypoint", color_sequence_keypoint: "datatypes/ColorSequenceKeypoint",
r#enum: "datatypes/Enum", r#enum: "datatypes/Enum",
faces: "datatypes/Faces", faces: "datatypes/Faces",
rect: "datatypes/Rect",
udim: "datatypes/UDim", udim: "datatypes/UDim",
udim2: "datatypes/UDim2", udim2: "datatypes/UDim2",
vector2: "datatypes/Vector2", vector2: "datatypes/Vector2",

View file

@ -0,0 +1,118 @@
use core::fmt;
use std::ops;
use glam::Vec2;
use mlua::prelude::*;
use rbx_dom_weak::types::Rect as RbxRect;
use super::{super::*, Vector2};
/**
An implementation of the [Rect](https://create.roblox.com/docs/reference/engine/datatypes/Rect)
Roblox datatype, backed by [`glam::Vec2`].
This implements all documented properties, methods & constructors of the Rect class as of March 2023.
*/
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Rect {
pub(crate) min: Vec2,
pub(crate) max: Vec2,
}
impl Rect {
fn new(lhs: Vec2, rhs: Vec2) -> Self {
Self {
min: lhs.min(rhs),
max: lhs.max(rhs),
}
}
}
impl Rect {
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
type ArgsVector2s = (Option<Vector2>, Option<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.unwrap_or_default().0,
max.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(),
))
}
})?,
)
}
}
impl LuaUserData for Rect {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("Min", |_, this| Ok(Vector2(this.min)));
fields.add_field_method_get("Max", |_, this| Ok(Vector2(this.max)));
fields.add_field_method_get("Width", |_, this| Ok(this.max.x - this.min.x));
fields.add_field_method_get("Height", |_, this| Ok(this.max.y - this.min.y));
}
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);
methods.add_meta_method(LuaMetaMethod::Unm, userdata_impl_unm);
methods.add_meta_method(LuaMetaMethod::Add, userdata_impl_add);
methods.add_meta_method(LuaMetaMethod::Sub, userdata_impl_sub);
}
}
impl fmt::Display for Rect {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}, {}", self.min, self.max)
}
}
impl ops::Neg for Rect {
type Output = Self;
fn neg(self) -> Self::Output {
Rect::new(-self.min, -self.max)
}
}
impl ops::Add for Rect {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Rect::new(self.min + rhs.min, self.max + rhs.max)
}
}
impl ops::Sub for Rect {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Rect::new(self.min - rhs.min, self.max - rhs.max)
}
}
impl From<RbxRect> for Rect {
fn from(v: RbxRect) -> Self {
Rect {
min: Vec2::new(v.min.x, v.min.y),
max: Vec2::new(v.max.x, v.max.y),
}
}
}
impl From<Rect> for RbxRect {
fn from(v: Rect) -> Self {
RbxRect {
min: Vector2(v.min).into(),
max: Vector2(v.max).into(),
}
}
}

View file

@ -14,7 +14,7 @@ use super::super::*;
This implements all documented properties, methods & This implements all documented properties, methods &
constructors of the Vector2 class as of March 2023. constructors of the Vector2 class as of March 2023.
*/ */
#[derive(Debug, Clone, Copy, PartialEq)] #[derive(Debug, Clone, Copy, PartialEq, Default)]
pub struct Vector2(pub Vec2); pub struct Vector2(pub Vec2);
impl Vector2 { impl Vector2 {

View file

@ -25,6 +25,7 @@ fn make_all_datatypes(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
("ColorSequence", make_dt(lua, ColorSequence::make_table)?), ("ColorSequence", make_dt(lua, ColorSequence::make_table)?),
("ColorSequenceKeypoint", make_dt(lua, ColorSequenceKeypoint::make_table)?), ("ColorSequenceKeypoint", make_dt(lua, ColorSequenceKeypoint::make_table)?),
("Faces", make_dt(lua, Faces::make_table)?), ("Faces", make_dt(lua, Faces::make_table)?),
("Rect", make_dt(lua, Rect::make_table)?),
("UDim", make_dt(lua, UDim::make_table)?), ("UDim", make_dt(lua, UDim::make_table)?),
("UDim2", make_dt(lua, UDim2::make_table)?), ("UDim2", make_dt(lua, UDim2::make_table)?),
("Vector2", make_dt(lua, Vector2::make_table)?), ("Vector2", make_dt(lua, Vector2::make_table)?),

View file

@ -0,0 +1,42 @@
-- HACK: Make luau happy, with the mlua rust
-- crate all globals are also present in _G
local Vector2 = _G.Vector2
local Rect = _G.Rect
-- Constructors & properties
Rect.new()
Rect.new(0)
Rect.new(0, 0)
Rect.new(0, 0, 0)
Rect.new(0, 0, 0, 0)
Rect.new(0 / 0, 0, 0 / 0, 0)
Rect.new(Vector2.zero)
Rect.new(Vector2.zero, Vector2.zero)
assert(not pcall(function()
return Rect.new(false)
end))
assert(not pcall(function()
return Rect.new("", "")
end))
assert(not pcall(function()
return Rect.new(newproxy(true))
end))
assert(Rect.new(1, 0, 2, 4).Min == Vector2.new(1, 0))
assert(Rect.new(1, 0, 2, 4).Max == Vector2.new(2, 4))
assert(Rect.new(0, 0, 1, 2).Width == 1)
assert(Rect.new(0, 0, 1, 2).Height == 2)
assert(Rect.new(Vector2.new(1, 0), Vector2.new(2, 4)).Min == Vector2.new(1, 0))
assert(Rect.new(Vector2.new(1, 0), Vector2.new(2, 4)).Max == Vector2.new(2, 4))
assert(Rect.new(Vector2.new(1, 0), Vector2.new(2, 4)).Width == 1)
assert(Rect.new(Vector2.new(1, 0), Vector2.new(2, 4)).Height == 4)
-- Ops
assert(Rect.new(2, 4, 6, 8) + Rect.new(1, 1, 1, 1) == Rect.new(3, 5, 7, 9))
assert(Rect.new(2, 4, 6, 8) - -Rect.new(1, 1, 1, 1) == Rect.new(3, 5, 7, 9))
assert(Rect.new(2, 4, 6, 8) - Rect.new(1, 1, 1, 1) == Rect.new(1, 3, 5, 7))