From fd369f707fcf781edbbd9f3bff3d6941d191e0f4 Mon Sep 17 00:00:00 2001 From: Filip Tibell Date: Sat, 11 Mar 2023 10:20:22 +0100 Subject: [PATCH] Implement int vector roblox types --- packages/lib-roblox/src/datatypes/mod.rs | 28 +++- .../lib-roblox/src/datatypes/vector2int16.rs | 142 +++++++++++++++++ .../lib-roblox/src/datatypes/vector3int16.rs | 145 ++++++++++++++++++ 3 files changed, 309 insertions(+), 6 deletions(-) create mode 100644 packages/lib-roblox/src/datatypes/vector2int16.rs create mode 100644 packages/lib-roblox/src/datatypes/vector3int16.rs diff --git a/packages/lib-roblox/src/datatypes/mod.rs b/packages/lib-roblox/src/datatypes/mod.rs index 49b380c..657c936 100644 --- a/packages/lib-roblox/src/datatypes/mod.rs +++ b/packages/lib-roblox/src/datatypes/mod.rs @@ -5,11 +5,15 @@ pub(crate) use rbx_dom_weak::types::{Variant as RbxVariant, VariantType as RbxVa // NOTE: We create a new inner module scope here to make imports of datatypes more ergonomic mod vector2; +mod vector2int16; mod vector3; +mod vector3int16; pub mod types { pub use super::vector2::Vector2; + pub use super::vector2int16::Vector2int16; pub use super::vector3::Vector3; + pub use super::vector3int16::Vector3int16; } // Trait definitions for conversion between rbx_dom_weak variant <-> our custom datatypes @@ -142,12 +146,12 @@ impl RbxVariantDisplayName for RbxVariant { // Generic impls for converting from lua values <-> rbx_dom_weak variants // We use a separate trait here since creating lua stuff needs the lua context -pub(crate) trait FromRbxVariantLua<'lua>: Sized { - fn from_rbx_variant_lua(variant: &RbxVariant, lua: &'lua Lua) -> RbxConversionResult; +pub(crate) trait RbxVariantToLua<'lua>: Sized { + fn rbx_variant_to_lua(variant: &RbxVariant, lua: &'lua Lua) -> RbxConversionResult; } -impl<'lua> FromRbxVariantLua<'lua> for LuaValue<'lua> { - fn from_rbx_variant_lua(variant: &RbxVariant, lua: &'lua Lua) -> RbxConversionResult { +impl<'lua> RbxVariantToLua<'lua> for LuaValue<'lua> { + fn rbx_variant_to_lua(variant: &RbxVariant, lua: &'lua Lua) -> RbxConversionResult { use self::types::*; use base64::engine::general_purpose::STANDARD_NO_PAD; use base64::engine::Engine as _; @@ -179,9 +183,15 @@ impl<'lua> FromRbxVariantLua<'lua> for LuaValue<'lua> { Rbx::Vector2(_) => Vector2::from_rbx_variant(variant)? .to_lua(lua) .map_err(RbxConversionError::external), + Rbx::Vector2int16(_) => Vector2int16::from_rbx_variant(variant)? + .to_lua(lua) + .map_err(RbxConversionError::external), Rbx::Vector3(_) => Vector3::from_rbx_variant(variant)? .to_lua(lua) .map_err(RbxConversionError::external), + Rbx::Vector3int16(_) => Vector3int16::from_rbx_variant(variant)? + .to_lua(lua) + .map_err(RbxConversionError::external), // Not yet implemented datatypes Rbx::Axes(_) => todo!(), Rbx::BrickColor(_) => todo!(), @@ -201,8 +211,6 @@ impl<'lua> FromRbxVariantLua<'lua> for LuaValue<'lua> { Rbx::Region3int16(_) => todo!(), Rbx::UDim(_) => todo!(), Rbx::UDim2(_) => todo!(), - Rbx::Vector2int16(_) => todo!(), - Rbx::Vector3int16(_) => todo!(), v => Err(RbxConversionError::FromRbxVariant { from: v.display_name(), to: "LuaValue", @@ -256,8 +264,12 @@ impl<'lua> ToRbxVariant for LuaValue<'lua> { (LuaValue::UserData(u), d) => { if let Ok(v2) = u.borrow::() { v2.to_rbx_variant(Some(d)) + } else if let Ok(v2i) = u.borrow::() { + v2i.to_rbx_variant(Some(d)) } else if let Ok(v3) = u.borrow::() { v3.to_rbx_variant(Some(d)) + } else if let Ok(v3i) = u.borrow::() { + v3i.to_rbx_variant(Some(d)) } else { Err(RbxConversionError::ToRbxVariant { to: d.display_name(), @@ -289,8 +301,12 @@ impl<'lua> ToRbxVariant for LuaValue<'lua> { LuaValue::UserData(u) => { if let Ok(v2) = u.borrow::() { v2.to_rbx_variant(None) + } else if let Ok(v2i) = u.borrow::() { + v2i.to_rbx_variant(None) } else if let Ok(v3) = u.borrow::() { v3.to_rbx_variant(None) + } else if let Ok(v3i) = u.borrow::() { + v3i.to_rbx_variant(None) } else { Err(RbxConversionError::ToRbxVariant { to: "Variant", diff --git a/packages/lib-roblox/src/datatypes/vector2int16.rs b/packages/lib-roblox/src/datatypes/vector2int16.rs new file mode 100644 index 0000000..5117b3c --- /dev/null +++ b/packages/lib-roblox/src/datatypes/vector2int16.rs @@ -0,0 +1,142 @@ +use core::fmt; + +use glam::IVec2; +use mlua::prelude::*; +use rbx_dom_weak::types::Vector2int16 as RbxVector2int16; + +use super::*; + +/** + An implementation of the [Vector2int16](https://create.roblox.com/docs/reference/engine/datatypes/Vector2int16) + Roblox datatype, backed by [`glam::IVec2`]. + + This implements all documented properties, methods & + constructors of the Vector2int16 class as of March 2023. +*/ +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Vector2int16(pub IVec2); + +impl fmt::Display for Vector2int16 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}, {}", self.0.x, self.0.y) + } +} + +impl LuaUserData for Vector2int16 { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("X", |_, this| Ok(this.0.x)); + fields.add_field_method_get("Y", |_, this| Ok(this.0.y)); + } + + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_meta_method(LuaMetaMethod::Eq, datatype_impl_eq); + methods.add_meta_method(LuaMetaMethod::ToString, datatype_impl_to_string); + methods.add_meta_method(LuaMetaMethod::Unm, |_, this, ()| Ok(Vector2int16(-this.0))); + methods.add_meta_method(LuaMetaMethod::Add, |_, this, rhs: Vector2int16| { + Ok(Vector2int16(this.0 + rhs.0)) + }); + methods.add_meta_method(LuaMetaMethod::Sub, |_, this, rhs: Vector2int16| { + Ok(Vector2int16(this.0 - rhs.0)) + }); + methods.add_meta_method(LuaMetaMethod::Mul, |_, this, rhs: LuaValue| { + match &rhs { + LuaValue::Number(n) => return Ok(Vector2int16(this.0 * IVec2::splat(*n as i32))), + LuaValue::UserData(ud) => { + if let Ok(vec) = ud.borrow::() { + return Ok(Vector2int16(this.0 * vec.0)); + } + } + _ => {} + }; + Err(LuaError::FromLuaConversionError { + from: rhs.type_name(), + to: "Vector2int16", + message: Some(format!( + "Expected Vector2int16 or number, got {}", + rhs.type_name() + )), + }) + }); + methods.add_meta_method(LuaMetaMethod::Div, |_, this, rhs: LuaValue| { + match &rhs { + LuaValue::Number(n) => return Ok(Vector2int16(this.0 / IVec2::splat(*n as i32))), + LuaValue::UserData(ud) => { + if let Ok(vec) = ud.borrow::() { + return Ok(Vector2int16(this.0 / vec.0)); + } + } + _ => {} + }; + Err(LuaError::FromLuaConversionError { + from: rhs.type_name(), + to: "Vector2int16", + message: Some(format!( + "Expected Vector2int16 or number, got {}", + rhs.type_name() + )), + }) + }); + } +} + +impl DatatypeTable for Vector2int16 { + fn make_dt_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { + datatype_table.set( + "new", + lua.create_function(|_, (x, y): (Option, Option)| { + Ok(Vector2int16(IVec2 { + x: x.unwrap_or_default() as i32, + y: y.unwrap_or_default() as i32, + })) + })?, + ) + } +} + +impl From<&RbxVector2int16> for Vector2int16 { + fn from(v: &RbxVector2int16) -> Self { + Vector2int16(IVec2 { + x: v.x.clamp(i16::MIN, i16::MAX) as i32, + y: v.y.clamp(i16::MIN, i16::MAX) as i32, + }) + } +} + +impl From<&Vector2int16> for RbxVector2int16 { + fn from(v: &Vector2int16) -> Self { + RbxVector2int16 { + x: v.0.x.clamp(i16::MIN as i32, i16::MAX as i32) as i16, + y: v.0.y.clamp(i16::MIN as i32, i16::MAX as i32) as i16, + } + } +} + +impl FromRbxVariant for Vector2int16 { + fn from_rbx_variant(variant: &RbxVariant) -> RbxConversionResult { + if let RbxVariant::Vector2int16(v) = variant { + Ok(v.into()) + } else { + Err(RbxConversionError::FromRbxVariant { + from: variant.display_name(), + to: "Vector2int16", + detail: None, + }) + } + } +} + +impl ToRbxVariant for Vector2int16 { + fn to_rbx_variant( + &self, + desired_type: Option, + ) -> RbxConversionResult { + if matches!(desired_type, None | Some(RbxVariantType::Vector2int16)) { + Ok(RbxVariant::Vector2int16(self.into())) + } else { + Err(RbxConversionError::DesiredTypeMismatch { + can_convert_to: Some(RbxVariantType::Vector2int16.display_name()), + detail: None, + }) + } + } +} diff --git a/packages/lib-roblox/src/datatypes/vector3int16.rs b/packages/lib-roblox/src/datatypes/vector3int16.rs new file mode 100644 index 0000000..42c5893 --- /dev/null +++ b/packages/lib-roblox/src/datatypes/vector3int16.rs @@ -0,0 +1,145 @@ +use core::fmt; + +use glam::IVec3; +use mlua::prelude::*; +use rbx_dom_weak::types::Vector3int16 as RbxVector3int16; + +use super::*; + +/** + An implementation of the [Vector3int16](https://create.roblox.com/docs/reference/engine/datatypes/Vector3int16) + Roblox datatype, backed by [`glam::IVec3`]. + + This implements all documented properties, methods & + constructors of the Vector3int16 class as of March 2023. +*/ +#[derive(Debug, Clone, Copy, PartialEq)] +pub struct Vector3int16(pub IVec3); + +impl fmt::Display for Vector3int16 { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}, {}", self.0.x, self.0.y) + } +} + +impl LuaUserData for Vector3int16 { + fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) { + fields.add_field_method_get("X", |_, this| Ok(this.0.x)); + fields.add_field_method_get("Y", |_, this| Ok(this.0.y)); + } + + fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_meta_method(LuaMetaMethod::Eq, datatype_impl_eq); + methods.add_meta_method(LuaMetaMethod::ToString, datatype_impl_to_string); + methods.add_meta_method(LuaMetaMethod::Unm, |_, this, ()| Ok(Vector3int16(-this.0))); + methods.add_meta_method(LuaMetaMethod::Add, |_, this, rhs: Vector3int16| { + Ok(Vector3int16(this.0 + rhs.0)) + }); + methods.add_meta_method(LuaMetaMethod::Sub, |_, this, rhs: Vector3int16| { + Ok(Vector3int16(this.0 - rhs.0)) + }); + methods.add_meta_method(LuaMetaMethod::Mul, |_, this, rhs: LuaValue| { + match &rhs { + LuaValue::Number(n) => return Ok(Vector3int16(this.0 * IVec3::splat(*n as i32))), + LuaValue::UserData(ud) => { + if let Ok(vec) = ud.borrow::() { + return Ok(Vector3int16(this.0 * vec.0)); + } + } + _ => {} + }; + Err(LuaError::FromLuaConversionError { + from: rhs.type_name(), + to: "Vector3int16", + message: Some(format!( + "Expected Vector3int16 or number, got {}", + rhs.type_name() + )), + }) + }); + methods.add_meta_method(LuaMetaMethod::Div, |_, this, rhs: LuaValue| { + match &rhs { + LuaValue::Number(n) => return Ok(Vector3int16(this.0 / IVec3::splat(*n as i32))), + LuaValue::UserData(ud) => { + if let Ok(vec) = ud.borrow::() { + return Ok(Vector3int16(this.0 / vec.0)); + } + } + _ => {} + }; + Err(LuaError::FromLuaConversionError { + from: rhs.type_name(), + to: "Vector3int16", + message: Some(format!( + "Expected Vector3int16 or number, got {}", + rhs.type_name() + )), + }) + }); + } +} + +impl DatatypeTable for Vector3int16 { + fn make_dt_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> { + datatype_table.set( + "new", + lua.create_function(|_, (x, y, z): (Option, Option, Option)| { + 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 From<&RbxVector3int16> for Vector3int16 { + fn from(v: &RbxVector3int16) -> Self { + Vector3int16(IVec3 { + x: v.x.clamp(i16::MIN, i16::MAX) as i32, + y: v.y.clamp(i16::MIN, i16::MAX) as i32, + z: v.z.clamp(i16::MIN, i16::MAX) as i32, + }) + } +} + +impl From<&Vector3int16> for RbxVector3int16 { + fn from(v: &Vector3int16) -> Self { + RbxVector3int16 { + x: v.0.x.clamp(i16::MIN as i32, i16::MAX as i32) as i16, + y: v.0.y.clamp(i16::MIN as i32, i16::MAX as i32) as i16, + z: v.0.z.clamp(i16::MIN as i32, i16::MAX as i32) as i16, + } + } +} + +impl FromRbxVariant for Vector3int16 { + fn from_rbx_variant(variant: &RbxVariant) -> RbxConversionResult { + if let RbxVariant::Vector3int16(v) = variant { + Ok(v.into()) + } else { + Err(RbxConversionError::FromRbxVariant { + from: variant.display_name(), + to: "Vector3int16", + detail: None, + }) + } + } +} + +impl ToRbxVariant for Vector3int16 { + fn to_rbx_variant( + &self, + desired_type: Option, + ) -> RbxConversionResult { + if matches!(desired_type, None | Some(RbxVariantType::Vector3int16)) { + Ok(RbxVariant::Vector3int16(self.into())) + } else { + Err(RbxConversionError::DesiredTypeMismatch { + can_convert_to: Some(RbxVariantType::Vector3int16.display_name()), + detail: None, + }) + } + } +}