mirror of
https://github.com/CompeyDev/lune-packaging.git
synced 2025-01-10 12:39:10 +00:00
Implement CFrame roblox datatype
This commit is contained in:
parent
010f7325d1
commit
94e84d6054
5 changed files with 380 additions and 1 deletions
|
@ -121,7 +121,6 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> {
|
||||||
// check `EnumItem::from_instance_property` for specifics
|
// check `EnumItem::from_instance_property` for specifics
|
||||||
Ok(match variant.clone() {
|
Ok(match variant.clone() {
|
||||||
// Not yet implemented datatypes
|
// Not yet implemented datatypes
|
||||||
// Rbx::CFrame(_) => todo!(),
|
|
||||||
// Rbx::NumberRange(_) => todo!(),
|
// Rbx::NumberRange(_) => todo!(),
|
||||||
// Rbx::NumberSequence(_) => todo!(),
|
// Rbx::NumberSequence(_) => todo!(),
|
||||||
// Rbx::OptionalCFrame(_) => todo!(),
|
// Rbx::OptionalCFrame(_) => todo!(),
|
||||||
|
@ -133,6 +132,8 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> {
|
||||||
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::Faces(value) => lua.create_userdata(Faces::from(value))?,
|
||||||
|
|
||||||
|
Rbx::CFrame(value) => lua.create_userdata(CFrame::from(value))?,
|
||||||
|
|
||||||
Rbx::BrickColor(value) => lua.create_userdata(BrickColor::from(value))?,
|
Rbx::BrickColor(value) => lua.create_userdata(BrickColor::from(value))?,
|
||||||
Rbx::Color3(value) => lua.create_userdata(Color3::from(value))?,
|
Rbx::Color3(value) => lua.create_userdata(Color3::from(value))?,
|
||||||
Rbx::Color3uint8(value) => lua.create_userdata(Color3::from(value))?,
|
Rbx::Color3uint8(value) => lua.create_userdata(Color3::from(value))?,
|
||||||
|
@ -172,6 +173,8 @@ impl<'lua> LuaToRbxVariant<'lua> for LuaAnyUserData<'lua> {
|
||||||
RbxVariantType::Axes => convert::<Axes, rbx::Axes>,
|
RbxVariantType::Axes => convert::<Axes, rbx::Axes>,
|
||||||
RbxVariantType::Faces => convert::<Faces, rbx::Faces>,
|
RbxVariantType::Faces => convert::<Faces, rbx::Faces>,
|
||||||
|
|
||||||
|
RbxVariantType::CFrame => convert::<CFrame, rbx::CFrame>,
|
||||||
|
|
||||||
RbxVariantType::BrickColor => convert::<BrickColor, rbx::BrickColor>,
|
RbxVariantType::BrickColor => convert::<BrickColor, rbx::BrickColor>,
|
||||||
RbxVariantType::Color3 => convert::<Color3, rbx::Color3>,
|
RbxVariantType::Color3 => convert::<Color3, rbx::Color3>,
|
||||||
RbxVariantType::Color3uint8 => convert::<Color3, rbx::Color3uint8>,
|
RbxVariantType::Color3uint8 => convert::<Color3, rbx::Color3uint8>,
|
||||||
|
|
329
packages/lib-roblox/src/datatypes/types/cframe.rs
Normal file
329
packages/lib-roblox/src/datatypes/types/cframe.rs
Normal file
|
@ -0,0 +1,329 @@
|
||||||
|
use core::fmt;
|
||||||
|
use std::ops;
|
||||||
|
|
||||||
|
use glam::{EulerRot, Mat4, Quat, Vec3};
|
||||||
|
use mlua::prelude::*;
|
||||||
|
use rbx_dom_weak::types::{CFrame as RbxCFrame, Matrix3 as RbxMatrix3, Vector3 as RbxVector3};
|
||||||
|
|
||||||
|
use super::{super::*, Vector3};
|
||||||
|
|
||||||
|
/**
|
||||||
|
An implementation of the [CFrame](https://create.roblox.com/docs/reference/engine/datatypes/CFrame)
|
||||||
|
Roblox datatype, backed by [`glam::Mat4`].
|
||||||
|
|
||||||
|
This implements all documented properties, methods &
|
||||||
|
constructors of the CFrame class as of March 2023.
|
||||||
|
*/
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub struct CFrame(Mat4);
|
||||||
|
|
||||||
|
impl CFrame {
|
||||||
|
fn position(&self) -> Vec3 {
|
||||||
|
self.0.w_axis.truncate()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn orientation(&self) -> (Vec3, Vec3, Vec3) {
|
||||||
|
(
|
||||||
|
self.0.x_axis.truncate(),
|
||||||
|
self.0.y_axis.truncate(),
|
||||||
|
self.0.z_axis.truncate(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn inverse(&self) -> Self {
|
||||||
|
Self(self.0.inverse())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
|
||||||
|
// Constants
|
||||||
|
datatype_table.set("identity", CFrame(Mat4::IDENTITY))?;
|
||||||
|
// Strict args constructors
|
||||||
|
datatype_table.set(
|
||||||
|
"lookAt",
|
||||||
|
lua.create_function(
|
||||||
|
|_, (at, look_at, up): (Vector3, Vector3, Option<Vector3>)| {
|
||||||
|
Ok(CFrame(Mat4::look_at_rh(
|
||||||
|
at.0,
|
||||||
|
look_at.0,
|
||||||
|
up.unwrap_or(Vector3(Vec3::Y)).0,
|
||||||
|
)))
|
||||||
|
},
|
||||||
|
)?,
|
||||||
|
)?;
|
||||||
|
datatype_table.set(
|
||||||
|
"fromEulerAnglesXYZ",
|
||||||
|
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
|
||||||
|
Ok(CFrame(Mat4::from_euler(EulerRot::ZYX, rx, ry, rz)))
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
datatype_table.set(
|
||||||
|
"fromEulerAnglesYXZ",
|
||||||
|
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
|
||||||
|
Ok(CFrame(Mat4::from_euler(EulerRot::ZXY, rx, ry, rz)))
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
datatype_table.set(
|
||||||
|
"Angles",
|
||||||
|
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
|
||||||
|
Ok(CFrame(Mat4::from_euler(EulerRot::ZYX, rx, ry, rz)))
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
datatype_table.set(
|
||||||
|
"fromOrientation",
|
||||||
|
lua.create_function(|_, (rx, ry, rz): (f32, f32, f32)| {
|
||||||
|
Ok(CFrame(Mat4::from_euler(EulerRot::ZXY, rx, ry, rz)))
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
datatype_table.set(
|
||||||
|
"fromAxisAngle",
|
||||||
|
lua.create_function(|_, (v, r): (Vector3, f32)| {
|
||||||
|
Ok(CFrame(Mat4::from_axis_angle(v.0, r)))
|
||||||
|
})?,
|
||||||
|
)?;
|
||||||
|
datatype_table.set(
|
||||||
|
"fromMatrix",
|
||||||
|
lua.create_function(
|
||||||
|
|_, (pos, rx, ry, rz): (Vector3, Vector3, Vector3, Option<Vector3>)| {
|
||||||
|
Ok(CFrame(Mat4::from_cols(
|
||||||
|
rx.0.extend(0.0),
|
||||||
|
ry.0.extend(0.0),
|
||||||
|
rz.map(|r| r.0)
|
||||||
|
.unwrap_or_else(|| rx.0.cross(ry.0).normalize())
|
||||||
|
.extend(0.0),
|
||||||
|
pos.0.extend(1.0),
|
||||||
|
)))
|
||||||
|
},
|
||||||
|
)?,
|
||||||
|
)?;
|
||||||
|
// Dynamic args constructor
|
||||||
|
type ArgsPos = Vector3;
|
||||||
|
type ArgsLook = (Vector3, Vector3);
|
||||||
|
type ArgsPosXYZ = (f32, f32, f32);
|
||||||
|
type ArgsPosXYZQuat = (f32, f32, f32, f32, f32, f32, f32);
|
||||||
|
type ArgsMatrix = (f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32);
|
||||||
|
datatype_table.set(
|
||||||
|
"new",
|
||||||
|
lua.create_function(|lua, args: LuaMultiValue| {
|
||||||
|
if args.clone().into_vec().is_empty() {
|
||||||
|
Ok(CFrame(Mat4::IDENTITY))
|
||||||
|
} else if let Ok(pos) = ArgsPos::from_lua_multi(args.clone(), lua) {
|
||||||
|
Ok(CFrame(Mat4::from_translation(pos.0)))
|
||||||
|
} else if let Ok((pos, look_at)) = ArgsLook::from_lua_multi(args.clone(), lua) {
|
||||||
|
Ok(CFrame(Mat4::look_at_rh(pos.0, look_at.0, Vec3::Y)))
|
||||||
|
} else if let Ok((x, y, z)) = ArgsPosXYZ::from_lua_multi(args.clone(), lua) {
|
||||||
|
Ok(CFrame(Mat4::from_translation(Vec3::new(x, y, z))))
|
||||||
|
} else if let Ok((x, y, z, qx, qy, qz, qw)) =
|
||||||
|
ArgsPosXYZQuat::from_lua_multi(args.clone(), lua)
|
||||||
|
{
|
||||||
|
Ok(CFrame(Mat4::from_rotation_translation(
|
||||||
|
Quat::from_array([qx, qy, qz, qw]),
|
||||||
|
Vec3::new(x, y, z),
|
||||||
|
)))
|
||||||
|
} else if let Ok((x, y, z, r00, r01, r02, r10, r11, r12, r20, r21, r22)) =
|
||||||
|
ArgsMatrix::from_lua_multi(args, lua)
|
||||||
|
{
|
||||||
|
Ok(CFrame(Mat4::from_cols_array_2d(&[
|
||||||
|
[r00, r01, r02, 0.0],
|
||||||
|
[r10, r11, r12, 0.0],
|
||||||
|
[r20, r21, r22, 0.0],
|
||||||
|
[x, y, z, 1.0],
|
||||||
|
])))
|
||||||
|
} else {
|
||||||
|
// FUTURE: Better error message here using given arg types
|
||||||
|
Err(LuaError::RuntimeError(
|
||||||
|
"Invalid arguments to constructor".to_string(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
})?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LuaUserData for CFrame {
|
||||||
|
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
|
||||||
|
fields.add_field_method_get("Position", |_, this| Ok(Vector3(this.position())));
|
||||||
|
fields.add_field_method_get("Rotation", |_, this| {
|
||||||
|
Ok(CFrame(Mat4::from_cols(
|
||||||
|
this.0.x_axis,
|
||||||
|
this.0.y_axis,
|
||||||
|
this.0.z_axis,
|
||||||
|
Vec3::ZERO.extend(1.0),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
fields.add_field_method_get("X", |_, this| Ok(this.position().x));
|
||||||
|
fields.add_field_method_get("Y", |_, this| Ok(this.position().y));
|
||||||
|
fields.add_field_method_get("Z", |_, this| Ok(this.position().z));
|
||||||
|
fields.add_field_method_get("XVector", |_, this| Ok(Vector3(this.orientation().0)));
|
||||||
|
fields.add_field_method_get("YVector", |_, this| Ok(Vector3(this.orientation().1)));
|
||||||
|
fields.add_field_method_get("ZVector", |_, this| Ok(Vector3(this.orientation().2)));
|
||||||
|
fields.add_field_method_get("RightVector", |_, this| Ok(Vector3(this.orientation().0)));
|
||||||
|
fields.add_field_method_get("UpVector", |_, this| Ok(Vector3(this.orientation().1)));
|
||||||
|
fields.add_field_method_get("LookVector", |_, this| Ok(Vector3(-this.orientation().2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||||
|
// Methods
|
||||||
|
methods.add_method("Inverse", |_, this, ()| Ok(this.inverse()));
|
||||||
|
methods.add_method("Lerp", |_, this, (goal, alpha): (CFrame, f32)| {
|
||||||
|
let quat_this = Quat::from_mat4(&this.0);
|
||||||
|
let quat_goal = Quat::from_mat4(&goal.0);
|
||||||
|
let translation = this
|
||||||
|
.0
|
||||||
|
.w_axis
|
||||||
|
.truncate()
|
||||||
|
.lerp(goal.0.w_axis.truncate(), alpha);
|
||||||
|
let rotation = quat_this.slerp(quat_goal, alpha);
|
||||||
|
Ok(CFrame(Mat4::from_rotation_translation(
|
||||||
|
rotation,
|
||||||
|
translation,
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
methods.add_method("Orthonormalize", |_, this, ()| {
|
||||||
|
let rotation = Quat::from_mat4(&this.0);
|
||||||
|
let translation = this.0.w_axis.truncate();
|
||||||
|
Ok(CFrame(Mat4::from_rotation_translation(
|
||||||
|
rotation.normalize(),
|
||||||
|
translation,
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
methods.add_method("ToWorldSpace", |_, this, rhs: CFrame| Ok(*this * rhs));
|
||||||
|
methods.add_method("ToObjectSpace", |_, this, rhs: CFrame| {
|
||||||
|
Ok(this.inverse() * rhs)
|
||||||
|
});
|
||||||
|
methods.add_method("PointToWorldSpace", |_, this, rhs: Vector3| Ok(*this * rhs));
|
||||||
|
methods.add_method("PointToObjectSpace", |_, this, rhs: Vector3| {
|
||||||
|
Ok(this.inverse() * rhs)
|
||||||
|
});
|
||||||
|
methods.add_method("VectorToWorldSpace", |_, this, rhs: Vector3| {
|
||||||
|
Ok((*this - Vector3(this.position())) * rhs)
|
||||||
|
});
|
||||||
|
methods.add_method("VectorToObjectSpace", |_, this, rhs: Vector3| {
|
||||||
|
let inv = this.inverse();
|
||||||
|
Ok((inv - Vector3(inv.position())) * rhs)
|
||||||
|
});
|
||||||
|
#[rustfmt::skip]
|
||||||
|
methods.add_method("GetComponents", |_, this, ()| {
|
||||||
|
let pos = this.position();
|
||||||
|
let (rx, ry, rz) = this.orientation();
|
||||||
|
Ok((
|
||||||
|
pos.x, pos.y, pos.z,
|
||||||
|
rx.x, rx.y, rx.z,
|
||||||
|
ry.x, ry.y, ry.z,
|
||||||
|
rz.x, rz.y, rz.z,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
methods.add_method("ToEulerAnglesXYZ", |_, this, ()| {
|
||||||
|
Ok(Quat::from_mat4(&this.0).to_euler(EulerRot::ZYX))
|
||||||
|
});
|
||||||
|
methods.add_method("ToEulerAnglesYXZ", |_, this, ()| {
|
||||||
|
Ok(Quat::from_mat4(&this.0).to_euler(EulerRot::ZXY))
|
||||||
|
});
|
||||||
|
methods.add_method("ToOrientation", |_, this, ()| {
|
||||||
|
Ok(Quat::from_mat4(&this.0).to_euler(EulerRot::ZXY))
|
||||||
|
});
|
||||||
|
methods.add_method("ToAxisAngle", |_, this, ()| {
|
||||||
|
let (axis, angle) = Quat::from_mat4(&this.0).to_axis_angle();
|
||||||
|
Ok((Vector3(axis), angle))
|
||||||
|
});
|
||||||
|
// Metamethods
|
||||||
|
methods.add_meta_method(LuaMetaMethod::Eq, userdata_impl_eq);
|
||||||
|
methods.add_meta_method(LuaMetaMethod::ToString, userdata_impl_to_string);
|
||||||
|
methods.add_meta_method(LuaMetaMethod::Mul, |lua, this, rhs: LuaValue| {
|
||||||
|
if let LuaValue::UserData(ud) = &rhs {
|
||||||
|
if let Ok(cf) = ud.borrow::<CFrame>() {
|
||||||
|
return lua.create_userdata(*this * *cf);
|
||||||
|
} else if let Ok(vec) = ud.borrow::<Vector3>() {
|
||||||
|
return lua.create_userdata(*this * *vec);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Err(LuaError::FromLuaConversionError {
|
||||||
|
from: rhs.type_name(),
|
||||||
|
to: "userdata",
|
||||||
|
message: Some(format!(
|
||||||
|
"Expected CFrame or Vector3, got {}",
|
||||||
|
rhs.type_name()
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
});
|
||||||
|
methods.add_meta_method(LuaMetaMethod::Add, |_, this, vec: Vector3| Ok(*this + vec));
|
||||||
|
methods.add_meta_method(LuaMetaMethod::Sub, |_, this, vec: Vector3| Ok(*this - vec));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for CFrame {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
let pos = self.position();
|
||||||
|
let (rx, ry, rz) = self.orientation();
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"{}, {}, {}, {}",
|
||||||
|
Vector3(pos),
|
||||||
|
Vector3(rx),
|
||||||
|
Vector3(ry),
|
||||||
|
Vector3(rz)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul for CFrame {
|
||||||
|
type Output = Self;
|
||||||
|
fn mul(self, rhs: Self) -> Self::Output {
|
||||||
|
CFrame(self.0 * rhs.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Mul<Vector3> for CFrame {
|
||||||
|
type Output = Vector3;
|
||||||
|
fn mul(self, rhs: Vector3) -> Self::Output {
|
||||||
|
Vector3(self.0.project_point3(rhs.0))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Add<Vector3> for CFrame {
|
||||||
|
type Output = Self;
|
||||||
|
fn add(self, rhs: Vector3) -> Self::Output {
|
||||||
|
CFrame(Mat4::from_cols(
|
||||||
|
self.0.x_axis,
|
||||||
|
self.0.y_axis,
|
||||||
|
self.0.z_axis,
|
||||||
|
self.0.w_axis + rhs.0.extend(0.0),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ops::Sub<Vector3> for CFrame {
|
||||||
|
type Output = Self;
|
||||||
|
fn sub(self, rhs: Vector3) -> Self::Output {
|
||||||
|
CFrame(Mat4::from_cols(
|
||||||
|
self.0.x_axis,
|
||||||
|
self.0.y_axis,
|
||||||
|
self.0.z_axis,
|
||||||
|
self.0.w_axis - rhs.0.extend(0.0),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RbxCFrame> for CFrame {
|
||||||
|
fn from(v: RbxCFrame) -> Self {
|
||||||
|
CFrame(Mat4::from_cols(
|
||||||
|
Vector3::from(v.orientation.x).0.extend(0.0),
|
||||||
|
Vector3::from(v.orientation.y).0.extend(0.0),
|
||||||
|
Vector3::from(v.orientation.z).0.extend(0.0),
|
||||||
|
Vector3::from(v.position).0.extend(1.0),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<CFrame> for RbxCFrame {
|
||||||
|
fn from(v: CFrame) -> Self {
|
||||||
|
let (rx, ry, rz) = v.orientation();
|
||||||
|
RbxCFrame {
|
||||||
|
position: RbxVector3::from(Vector3(v.position())),
|
||||||
|
orientation: RbxMatrix3::new(
|
||||||
|
RbxVector3::from(Vector3(rx)),
|
||||||
|
RbxVector3::from(Vector3(ry)),
|
||||||
|
RbxVector3::from(Vector3(rz)),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
mod axes;
|
mod axes;
|
||||||
mod brick_color;
|
mod brick_color;
|
||||||
|
mod cframe;
|
||||||
mod color3;
|
mod color3;
|
||||||
mod color_sequence;
|
mod color_sequence;
|
||||||
mod color_sequence_keypoint;
|
mod color_sequence_keypoint;
|
||||||
|
@ -17,6 +18,7 @@ mod vector3int16;
|
||||||
|
|
||||||
pub use axes::Axes;
|
pub use axes::Axes;
|
||||||
pub use brick_color::BrickColor;
|
pub use brick_color::BrickColor;
|
||||||
|
pub use cframe::CFrame;
|
||||||
pub use color3::Color3;
|
pub use color3::Color3;
|
||||||
pub use color_sequence::ColorSequence;
|
pub use color_sequence::ColorSequence;
|
||||||
pub use color_sequence_keypoint::ColorSequenceKeypoint;
|
pub use color_sequence_keypoint::ColorSequenceKeypoint;
|
||||||
|
@ -76,6 +78,7 @@ mod tests {
|
||||||
create_tests! {
|
create_tests! {
|
||||||
axes: "datatypes/Axes",
|
axes: "datatypes/Axes",
|
||||||
brick_color: "datatypes/BrickColor",
|
brick_color: "datatypes/BrickColor",
|
||||||
|
cframe: "datatypes/CFrame",
|
||||||
color3: "datatypes/Color3",
|
color3: "datatypes/Color3",
|
||||||
color_sequence: "datatypes/ColorSequence",
|
color_sequence: "datatypes/ColorSequence",
|
||||||
color_sequence_keypoint: "datatypes/ColorSequenceKeypoint",
|
color_sequence_keypoint: "datatypes/ColorSequenceKeypoint",
|
||||||
|
|
|
@ -21,6 +21,7 @@ fn make_all_datatypes(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
|
||||||
// Classes
|
// Classes
|
||||||
("Axes", make_dt(lua, Axes::make_table)?),
|
("Axes", make_dt(lua, Axes::make_table)?),
|
||||||
("BrickColor", make_dt(lua, BrickColor::make_table)?),
|
("BrickColor", make_dt(lua, BrickColor::make_table)?),
|
||||||
|
("CFrame", make_dt(lua, CFrame::make_table)?),
|
||||||
("Color3", make_dt(lua, Color3::make_table)?),
|
("Color3", make_dt(lua, Color3::make_table)?),
|
||||||
("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)?),
|
||||||
|
|
43
tests/roblox/datatypes/CFrame.luau
Normal file
43
tests/roblox/datatypes/CFrame.luau
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
-- HACK: Make luau happy, with the mlua rust
|
||||||
|
-- crate all globals are also present in _G
|
||||||
|
local CFrame = _G.CFrame
|
||||||
|
local Vector3 = _G.Vector3
|
||||||
|
|
||||||
|
-- Constructors & properties
|
||||||
|
|
||||||
|
CFrame.new()
|
||||||
|
CFrame.new(0, 0, 0)
|
||||||
|
CFrame.new(0 / 0, 0 / 0, 0 / 0)
|
||||||
|
CFrame.new(0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1)
|
||||||
|
|
||||||
|
assert(not pcall(function()
|
||||||
|
return CFrame.new(false)
|
||||||
|
end))
|
||||||
|
assert(not pcall(function()
|
||||||
|
return CFrame.new("", "")
|
||||||
|
end))
|
||||||
|
assert(not pcall(function()
|
||||||
|
return CFrame.new(newproxy(true))
|
||||||
|
end))
|
||||||
|
|
||||||
|
assert(CFrame.new(1, 2, 3).X == 1)
|
||||||
|
assert(CFrame.new(1, 2, 3).Y == 2)
|
||||||
|
assert(CFrame.new(1, 2, 3).Z == 3)
|
||||||
|
|
||||||
|
-- Constants
|
||||||
|
|
||||||
|
assert(CFrame.identity == CFrame.new())
|
||||||
|
assert(CFrame.identity == CFrame.new(0, 0, 0))
|
||||||
|
assert(CFrame.identity == CFrame.Angles(0, 0, 0))
|
||||||
|
assert(CFrame.identity == CFrame.fromOrientation(0, 0, 0))
|
||||||
|
|
||||||
|
-- Ops
|
||||||
|
|
||||||
|
assert(CFrame.new(2, 4, 8) + Vector3.new(1, 1, 2) == CFrame.new(3, 5, 10))
|
||||||
|
assert(CFrame.new(2, 4, 8) - Vector3.new(1, 1, 2) == CFrame.new(1, 3, 6))
|
||||||
|
assert(CFrame.new(2, 4, 8) * CFrame.new(1, 1, 2) == CFrame.new(3, 5, 10))
|
||||||
|
assert(CFrame.new(2, 4, 8) * Vector3.new(1, 1, 2) == Vector3.new(3, 5, 10))
|
||||||
|
|
||||||
|
-- TODO: Check mult ops with rotated CFrames
|
||||||
|
|
||||||
|
-- TODO: Methods
|
Loading…
Reference in a new issue