Implement Ray roblox datatype

This commit is contained in:
Filip Tibell 2023-03-17 10:18:05 +01:00
parent f0aadc6dfe
commit 6d76df7524
No known key found for this signature in database
5 changed files with 150 additions and 1 deletions

View file

@ -121,7 +121,6 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> {
// Not yet implemented datatypes // Not yet implemented datatypes
// Rbx::Font(_) => todo!(), // Rbx::Font(_) => todo!(),
// Rbx::PhysicalProperties(_) => todo!(), // Rbx::PhysicalProperties(_) => todo!(),
// Rbx::Ray(_) => todo!(),
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))?,
@ -140,6 +139,8 @@ impl<'lua> RbxVariantToLua<'lua> for LuaAnyUserData<'lua> {
Rbx::NumberRange(value) => lua.create_userdata(NumberRange::from(value))?, Rbx::NumberRange(value) => lua.create_userdata(NumberRange::from(value))?,
Rbx::NumberSequence(value) => lua.create_userdata(NumberSequence::from(value))?, Rbx::NumberSequence(value) => lua.create_userdata(NumberSequence::from(value))?,
Rbx::Ray(value) => lua.create_userdata(Ray::from(value))?,
Rbx::Rect(value) => lua.create_userdata(Rect::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))?,
@ -196,6 +197,8 @@ impl<'lua> LuaToRbxVariant<'lua> for LuaAnyUserData<'lua> {
RbxVariantType::UDim => convert::<UDim, rbx::UDim>, RbxVariantType::UDim => convert::<UDim, rbx::UDim>,
RbxVariantType::UDim2 => convert::<UDim2, rbx::UDim2>, RbxVariantType::UDim2 => convert::<UDim2, rbx::UDim2>,
RbxVariantType::Ray => convert::<Ray, rbx::Ray>,
RbxVariantType::Region3 => convert::<Region3, rbx::Region3>, RbxVariantType::Region3 => convert::<Region3, rbx::Region3>,
RbxVariantType::Region3int16 => convert::<Region3int16, rbx::Region3int16>, RbxVariantType::Region3int16 => convert::<Region3int16, rbx::Region3int16>,
RbxVariantType::Vector2 => convert::<Vector2, rbx::Vector2>, RbxVariantType::Vector2 => convert::<Vector2, rbx::Vector2>,

View file

@ -11,6 +11,7 @@ mod faces;
mod number_range; mod number_range;
mod number_sequence; mod number_sequence;
mod number_sequence_keypoint; mod number_sequence_keypoint;
mod ray;
mod rect; mod rect;
mod region3; mod region3;
mod region3int16; mod region3int16;
@ -34,6 +35,7 @@ pub use number_sequence_keypoint::NumberSequenceKeypoint;
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 ray::Ray;
pub use rect::Rect; pub use rect::Rect;
pub use region3::Region3; pub use region3::Region3;
pub use region3int16::Region3int16; pub use region3int16::Region3int16;
@ -97,6 +99,7 @@ mod tests {
number_range: "datatypes/NumberRange", number_range: "datatypes/NumberRange",
number_sequence: "datatypes/NumberSequence", number_sequence: "datatypes/NumberSequence",
number_sequence_keypoint: "datatypes/NumberSequenceKeypoint", number_sequence_keypoint: "datatypes/NumberSequenceKeypoint",
ray: "datatypes/Ray",
rect: "datatypes/Rect", rect: "datatypes/Rect",
udim: "datatypes/UDim", udim: "datatypes/UDim",
udim2: "datatypes/UDim2", udim2: "datatypes/UDim2",

View file

@ -0,0 +1,92 @@
use core::fmt;
use glam::Vec3;
use mlua::prelude::*;
use rbx_dom_weak::types::Ray as RbxRay;
use super::{super::*, Vector3};
/**
An implementation of the [Ray](https://create.roblox.com/docs/reference/engine/datatypes/Ray)
Roblox datatype, backed by [`glam::Vec3`].
This implements all documented properties, methods & constructors of the Ray class as of March 2023.
*/
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Ray {
pub(crate) origin: Vec3,
pub(crate) direction: Vec3,
}
impl Ray {
fn closest_point(&self, point: Vec3) -> Vec3 {
let norm = self.direction.normalize();
let lhs = point - self.origin;
let dot_product = lhs.dot(norm).max(0.0);
self.origin + norm * dot_product
}
pub(crate) fn make_table(lua: &Lua, datatype_table: &LuaTable) -> LuaResult<()> {
datatype_table.set(
"new",
lua.create_function(|_, (origin, direction): (Vector3, Vector3)| {
Ok(Ray {
origin: origin.0,
direction: direction.0,
})
})?,
)
}
}
impl LuaUserData for Ray {
fn add_fields<'lua, F: LuaUserDataFields<'lua, Self>>(fields: &mut F) {
fields.add_field_method_get("Origin", |_, this| Ok(Vector3(this.origin)));
fields.add_field_method_get("Direction", |_, this| Ok(Vector3(this.direction)));
fields.add_field_method_get("Unit", |_, this| {
Ok(Ray {
origin: this.origin,
direction: this.direction.normalize(),
})
});
}
fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
// Methods
methods.add_method("ClosestPoint", |_, this, to: Vector3| {
Ok(Vector3(this.closest_point(to.0)))
});
methods.add_method("Distance", |_, this, to: Vector3| {
let closest = this.closest_point(to.0);
Ok((closest - to.0).length())
});
// Metamethods
methods.add_meta_method(LuaMetaMethod::Eq, userdata_impl_eq);
methods.add_meta_method(LuaMetaMethod::ToString, userdata_impl_to_string);
}
}
impl fmt::Display for Ray {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}, {}", Vector3(self.origin), Vector3(self.direction))
}
}
impl From<RbxRay> for Ray {
fn from(v: RbxRay) -> Self {
Ray {
origin: Vector3::from(v.origin).0,
direction: Vector3::from(v.direction).0,
}
}
}
impl From<Ray> for RbxRay {
fn from(v: Ray) -> Self {
RbxRay {
origin: Vector3(v.origin).into(),
direction: Vector3(v.direction).into(),
}
}
}

View file

@ -29,6 +29,7 @@ fn make_all_datatypes(lua: &Lua) -> LuaResult<Vec<(&'static str, LuaValue)>> {
("NumberRange", make_dt(lua, NumberRange::make_table)?), ("NumberRange", make_dt(lua, NumberRange::make_table)?),
("NumberSequence", make_dt(lua, NumberSequence::make_table)?), ("NumberSequence", make_dt(lua, NumberSequence::make_table)?),
("NumberSequenceKeypoint", make_dt(lua, NumberSequenceKeypoint::make_table)?), ("NumberSequenceKeypoint", make_dt(lua, NumberSequenceKeypoint::make_table)?),
("Ray", make_dt(lua, Ray::make_table)?),
("Rect", make_dt(lua, Rect::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)?),

View file

@ -0,0 +1,50 @@
-- HACK: Make luau happy, with the mlua rust
-- crate all globals are also present in _G
local Ray = _G.Ray
local Vector3 = _G.Vector3
local origin = Vector3.zero
local direction = Vector3.zAxis * 10
-- Constructors & properties
Ray.new(origin, direction)
assert(not pcall(function()
return Ray.new(false)
end))
assert(not pcall(function()
return Ray.new("", "")
end))
assert(not pcall(function()
return Ray.new(newproxy(true))
end))
assert(Ray.new(origin, direction).Origin == origin)
assert(Ray.new(origin, direction).Direction == direction)
assert(Ray.new(origin, direction).Unit.Origin == origin)
assert(Ray.new(origin, direction).Unit.Direction == direction.Unit)
-- Ops
assert(not pcall(function()
return Ray.new(origin, direction) + Ray.new(origin, direction)
end))
assert(not pcall(function()
return Ray.new(origin, direction) / Ray.new(origin, direction)
end))
-- Methods
assert(Ray.new(origin, direction):ClosestPoint(origin) == origin)
assert(Ray.new(origin, direction):Distance(origin) == 0)
for z = 0, 10, 1 do
local x = if z % 2 == 0 then 2.5 else 7.5
assert(
Ray.new(origin, direction):ClosestPoint(Vector3.new(x, 0, z))
== Vector3.zero + Vector3.zAxis * z
)
assert(Ray.new(origin, direction):Distance(Vector3.new(x, 0, z)) == x)
end