diff --git a/packages/lib-roblox/src/datatypes/conversion.rs b/packages/lib-roblox/src/datatypes/conversion.rs index 30abe2c..e09f264 100644 --- a/packages/lib-roblox/src/datatypes/conversion.rs +++ b/packages/lib-roblox/src/datatypes/conversion.rs @@ -122,8 +122,6 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> { // Rbx::Font(_) => todo!(), // Rbx::PhysicalProperties(_) => todo!(), // Rbx::Ray(_) => todo!(), - // Rbx::Region3(_) => todo!(), - // Rbx::Region3int16(_) => todo!(), Rbx::Axes(value) => lua.create_userdata(Axes::from(value))?, Rbx::Faces(value) => lua.create_userdata(Faces::from(value))?, @@ -146,6 +144,8 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> { Rbx::UDim(value) => lua.create_userdata(UDim::from(value))?, Rbx::UDim2(value) => lua.create_userdata(UDim2::from(value))?, + Rbx::Region3(value) => lua.create_userdata(Region3::from(value))?, + Rbx::Region3int16(value) => lua.create_userdata(Region3int16::from(value))?, Rbx::Vector2(value) => lua.create_userdata(Vector2::from(value))?, Rbx::Vector2int16(value) => lua.create_userdata(Vector2int16::from(value))?, Rbx::Vector3(value) => lua.create_userdata(Vector3::from(value))?, @@ -189,13 +189,15 @@ impl<'lua> LuaToRbxVariant<'lua> for LuaAnyUserData<'lua> { RbxVariantType::Enum => convert::, + RbxVariantType::NumberRange => convert::, + RbxVariantType::NumberSequence => convert::, + RbxVariantType::Rect => convert::, RbxVariantType::UDim => convert::, RbxVariantType::UDim2 => convert::, - RbxVariantType::NumberRange => convert::, - RbxVariantType::NumberSequence => convert::, - + RbxVariantType::Region3 => convert::, + RbxVariantType::Region3int16 => convert::, RbxVariantType::Vector2 => convert::, RbxVariantType::Vector2int16 => convert::, RbxVariantType::Vector3 => convert::, diff --git a/packages/lib-roblox/src/datatypes/types/cframe.rs b/packages/lib-roblox/src/datatypes/types/cframe.rs index 8fced77..e2bf880 100644 --- a/packages/lib-roblox/src/datatypes/types/cframe.rs +++ b/packages/lib-roblox/src/datatypes/types/cframe.rs @@ -15,7 +15,7 @@ use super::{super::*, Vector3}; constructors of the CFrame class as of March 2023. */ #[derive(Debug, Clone, Copy, PartialEq)] -pub struct CFrame(Mat4); +pub struct CFrame(pub Mat4); impl CFrame { pub const IDENTITY: Self = Self(Mat4::IDENTITY); diff --git a/packages/lib-roblox/src/datatypes/types/mod.rs b/packages/lib-roblox/src/datatypes/types/mod.rs index 7206969..ca9a307 100644 --- a/packages/lib-roblox/src/datatypes/types/mod.rs +++ b/packages/lib-roblox/src/datatypes/types/mod.rs @@ -12,6 +12,8 @@ mod number_range; mod number_sequence; mod number_sequence_keypoint; mod rect; +mod region3; +mod region3int16; mod udim; mod udim2; mod vector2; @@ -33,6 +35,8 @@ pub use r#enum::Enum; pub use r#enum_item::EnumItem; pub use r#enums::Enums; pub use rect::Rect; +pub use region3::Region3; +pub use region3int16::Region3int16; pub use udim::UDim; pub use udim2::UDim2; pub use vector2::Vector2; @@ -96,6 +100,8 @@ mod tests { rect: "datatypes/Rect", udim: "datatypes/UDim", udim2: "datatypes/UDim2", + region3: "datatypes/Region3", + region3int16: "datatypes/Region3int16", vector2: "datatypes/Vector2", vector2int16: "datatypes/Vector2int16", vector3: "datatypes/Vector3", diff --git a/packages/lib-roblox/src/datatypes/types/region3.rs b/packages/lib-roblox/src/datatypes/types/region3.rs new file mode 100644 index 0000000..48fcab4 --- /dev/null +++ b/packages/lib-roblox/src/datatypes/types/region3.rs @@ -0,0 +1,79 @@ +use core::fmt; + +use glam::{Mat4, Vec3}; +use mlua::prelude::*; +use rbx_dom_weak::types::Region3 as RbxRegion3; + +use super::{super::*, CFrame, Vector3}; + +/** + An implementation of the [Region3](https://create.roblox.com/docs/reference/engine/datatypes/Region3) + Roblox datatype, backed by [`glam::Vec3`]. + + This implements all documented properties, methods & constructors of the Region3 class as of March 2023. +*/ +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Region3 { + pub(crate) min: Vec3, + 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): (Vector3, Vector3)| { + Ok(Region3 { + min: min.0, + max: max.0, + }) + })?, + ) + } +} + +impl LuaUserData for Region3 { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("CFrame", |_, this| { + Ok(CFrame(Mat4::from_translation(this.min.lerp(this.max, 0.5)))) + }); + fields.add_field_method_get("Size", |_, this| Ok(Vector3(this.max - this.min))); + } + + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + // Methods + methods.add_method("ExpandToGrid", |_, this, resolution: f32| { + Ok(Region3 { + min: (this.min / resolution).floor() * resolution, + max: (this.max / resolution).ceil() * resolution, + }) + }); + // Metamethods + methods.add_meta_method(LuaMetaMethod::Eq, userdata_impl_eq); + methods.add_meta_method(LuaMetaMethod::ToString, userdata_impl_to_string); + } +} + +impl fmt::Display for Region3 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}, {}", Vector3(self.min), Vector3(self.max)) + } +} + +impl From for Region3 { + fn from(v: RbxRegion3) -> Self { + Region3 { + min: Vector3::from(v.min).0, + max: Vector3::from(v.max).0, + } + } +} + +impl From for RbxRegion3 { + fn from(v: Region3) -> Self { + RbxRegion3 { + min: Vector3(v.min).into(), + max: Vector3(v.max).into(), + } + } +} diff --git a/packages/lib-roblox/src/datatypes/types/region3int16.rs b/packages/lib-roblox/src/datatypes/types/region3int16.rs new file mode 100644 index 0000000..fba32aa --- /dev/null +++ b/packages/lib-roblox/src/datatypes/types/region3int16.rs @@ -0,0 +1,69 @@ +use core::fmt; + +use glam::IVec3; +use mlua::prelude::*; +use rbx_dom_weak::types::Region3int16 as RbxRegion3int16; + +use super::{super::*, Vector3int16}; + +/** + An implementation of the [Region3int16](https://create.roblox.com/docs/reference/engine/datatypes/Region3int16) + Roblox datatype, backed by [`glam::IVec3`]. + + This implements all documented properties, methods & constructors of the Region3int16 class as of March 2023. +*/ +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Region3int16 { + pub(crate) min: IVec3, + 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): (Vector3int16, Vector3int16)| { + Ok(Region3int16 { + min: min.0, + max: max.0, + }) + })?, + ) + } +} + +impl LuaUserData for Region3int16 { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("Min", |_, this| Ok(Vector3int16(this.min))); + fields.add_field_method_get("Max", |_, this| Ok(Vector3int16(this.max))); + } + + 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 Region3int16 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}, {}", Vector3int16(self.min), Vector3int16(self.max)) + } +} + +impl From for Region3int16 { + fn from(v: RbxRegion3int16) -> Self { + Region3int16 { + min: Vector3int16::from(v.min).0, + max: Vector3int16::from(v.max).0, + } + } +} + +impl From for RbxRegion3int16 { + fn from(v: Region3int16) -> Self { + RbxRegion3int16 { + min: Vector3int16(v.min).into(), + max: Vector3int16(v.max).into(), + } + } +} diff --git a/packages/lib-roblox/src/lib.rs b/packages/lib-roblox/src/lib.rs index 9387669..44a594a 100644 --- a/packages/lib-roblox/src/lib.rs +++ b/packages/lib-roblox/src/lib.rs @@ -32,6 +32,8 @@ fn make_all_datatypes(lua: &Lua) -> LuaResult> { ("Rect", make_dt(lua, Rect::make_table)?), ("UDim", make_dt(lua, UDim::make_table)?), ("UDim2", make_dt(lua, UDim2::make_table)?), + ("Region3", make_dt(lua, Region3::make_table)?), + ("Region3int16", make_dt(lua, Region3int16::make_table)?), ("Vector2", make_dt(lua, Vector2::make_table)?), ("Vector2int16", make_dt(lua, Vector2int16::make_table)?), ("Vector3", make_dt(lua, Vector3::make_table)?), diff --git a/tests/roblox/datatypes/Region3.luau b/tests/roblox/datatypes/Region3.luau new file mode 100644 index 0000000..f1cc0f9 --- /dev/null +++ b/tests/roblox/datatypes/Region3.luau @@ -0,0 +1,53 @@ +-- HACK: Make luau happy, with the mlua rust +-- crate all globals are also present in _G +local Region3 = _G.Region3 +local Vector3 = _G.Vector3 +local CFrame = _G.CFrame + +local min = Vector3.new(-2, -2, -2) +local max = Vector3.new(2, 2, 2) + +-- Constructors & properties + +Region3.new(min, max) + +assert(not pcall(function() + return Region3.new(false) +end)) +assert(not pcall(function() + return Region3.new("", "") +end)) +assert(not pcall(function() + return Region3.new(newproxy(true)) +end)) + +assert(Region3.new(min, max).CFrame == CFrame.new(0, 0, 0)) +assert(Region3.new(min, max).Size == Vector3.new(4, 4, 4)) + +-- Ops + +assert(not pcall(function() + return Region3.new(min, max) + Region3.new(min, max) +end)) +assert(not pcall(function() + return Region3.new(min, max) / Region3.new(min, max) +end)) + +-- Methods + +assert(Region3.new(min, max):ExpandToGrid(1) == Region3.new(min, max)) + +assert( + Region3.new(min, max):ExpandToGrid(3) + == Region3.new(Vector3.new(-3, -3, -3), Vector3.new(3, 3, 3)) +) + +assert( + Region3.new(min, max):ExpandToGrid(4) + == Region3.new(Vector3.new(-4, -4, -4), Vector3.new(4, 4, 4)) +) + +assert( + Region3.new(min, max):ExpandToGrid(7.5) + == Region3.new(Vector3.new(-7.5, -7.5, -7.5), Vector3.new(7.5, 7.5, 7.5)) +) diff --git a/tests/roblox/datatypes/Region3int16.luau b/tests/roblox/datatypes/Region3int16.luau new file mode 100644 index 0000000..cfb4c48 --- /dev/null +++ b/tests/roblox/datatypes/Region3int16.luau @@ -0,0 +1,37 @@ +-- HACK: Make luau happy, with the mlua rust +-- crate all globals are also present in _G +local Region3int16 = _G.Region3int16 +local Vector3int16 = _G.Vector3int16 +local Vector3 = _G.Vector3 + +local min = Vector3int16.new(0, 0, 0) +local max = Vector3int16.new(2, 2, 2) + +-- Constructors & properties + +Region3int16.new(min, max) + +assert(not pcall(function() + return Region3int16.new(false) +end)) +assert(not pcall(function() + return Region3int16.new("", "") +end)) +assert(not pcall(function() + return Region3int16.new(newproxy(true)) +end)) +assert(not pcall(function() + return Region3int16.new(Vector3.new(), Vector3.new()) +end)) + +assert(Region3int16.new(min, max).Min == min) +assert(Region3int16.new(min, max).Max == max) + +-- Ops + +assert(not pcall(function() + return Region3int16.new(min, max) + Region3int16.new(min, max) +end)) +assert(not pcall(function() + return Region3int16.new(min, max) / Region3int16.new(min, max) +end))