Skip to content
This repository has been archived by the owner on Jul 22, 2023. It is now read-only.

Add CFrame type #48

Merged
merged 7 commits into from
May 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased Changes

* Added support for CFrame ([#48](https://github.com/rojo-rbx/remodel/pull/48))
* Added support for Vector3, and improved Vector3int16 ([#46](https://github.com/rojo-rbx/remodel/pull/46))
* Added Color3.fromRGB(red, blue, green) ([#44](https://github.com/rojo-rbx/remodel/pull/44))

Expand Down
72 changes: 72 additions & 0 deletions src/roblox_api/cframe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use rbx_dom_weak::types::{CFrame, Matrix3, Vector3};
use rlua::{UserData, UserDataMethods, Value as LuaValue};

use crate::value::{CFrameValue, Vector3Value};

pub struct CFrameUserData;

impl CFrameUserData {
fn from_position(x: f32, y: f32, z: f32) -> CFrameValue {
CFrameValue::new(CFrame::new(
Vector3::new(x as f32, y as f32, z as f32),
// TODO: replace with `Matrix3::identity()` once
// a version higher than 0.3.0 of rbx_types ships
Matrix3::new(
Vector3::new(1.0, 0.0, 0.0),
Vector3::new(0.0, 1.0, 0.0),
Vector3::new(0.0, 0.0, 1.0),
),
))
}
}

fn try_into_f32(value: LuaValue<'_>) -> Option<f32> {
match value {
LuaValue::Number(num) => Some(num as f32),
LuaValue::Integer(int) => Some(int as f32),
_ => None,
}
}

impl UserData for CFrameUserData {
fn add_methods<'lua, T: UserDataMethods<'lua, Self>>(methods: &mut T) {
methods.add_function(
"new",
|_context,
arguments: (
Option<LuaValue<'_>>,
Option<LuaValue<'_>>,
Option<LuaValue<'_>>,
)| {
match arguments {
(None, None, None) => return Ok(Self::from_position(0.0, 0.0, 0.0)),
(Some(LuaValue::UserData(user_data)), None, None) => {
let position = &*user_data.borrow::<Vector3Value>()?;
return Ok(CFrameValue::new(CFrame::new(
position.inner(),
// TODO: replace with `rbx_dom_weak::types::Matrix3::identity()` once
// a version higher than 0.3.0 of rbx_types ships
Matrix3::new(
Vector3::new(1.0, 0.0, 0.0),
Vector3::new(0.0, 1.0, 0.0),
Vector3::new(0.0, 0.0, 1.0),
),
)));
}
_ => {}
};

let x = arguments.0.and_then(try_into_f32);
let y = arguments.1.and_then(try_into_f32);
let z = arguments.2.and_then(try_into_f32);

match (x, y, z) {
(Some(x), Some(y), Some(z)) => Ok(Self::from_position(x, y, z)),
_ => Err(rlua::Error::external(
"invalid argument #1 to 'new' (Vector3 expected)",
)),
}
},
);
}
}
3 changes: 3 additions & 0 deletions src/roblox_api/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod cframe;
mod instance;

use std::sync::Arc;
Expand All @@ -10,6 +11,7 @@ use crate::{
value::{Color3Value, Vector3Value, Vector3int16Value},
};

use cframe::CFrameUserData;
pub use instance::LuaInstance;

pub struct RobloxApi;
Expand All @@ -20,6 +22,7 @@ impl RobloxApi {
context.globals().set("Vector3", Vector3)?;
context.globals().set("Vector3int16", Vector3int16)?;
context.globals().set("Color3", Color3)?;
context.globals().set("CFrame", CFrameUserData)?;

Ok(())
}
Expand Down
99 changes: 97 additions & 2 deletions src/value.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
//! Defines how to turn Variant values into Lua values and back.

use rbx_dom_weak::types::{Color3, Color3uint8, Variant, VariantType, Vector3, Vector3int16};
use rbx_dom_weak::types::{
CFrame, Color3, Color3uint8, Variant, VariantType, Vector3, Vector3int16,
};
use rlua::{
Context, MetaMethod, Result as LuaResult, ToLua, UserData, UserDataMethods, Value as LuaValue,
};
Expand All @@ -21,7 +23,7 @@ pub fn rbxvalue_to_lua<'lua>(context: Context<'lua>, value: &Variant) -> LuaResu
}
Variant::BrickColor(_) => unimplemented_type("BrickColor"),
Variant::Bool(value) => value.to_lua(context),
Variant::CFrame(_) => unimplemented_type("CFrame"),
Variant::CFrame(cframe) => CFrameValue::new(*cframe).to_lua(context),
Variant::Color3(value) => Color3Value::new(*value).to_lua(context),
Variant::Color3uint8(value) => Color3uint8Value::new(*value).to_lua(context),
Variant::ColorSequence(_) => unimplemented_type("ColorSequence"),
Expand Down Expand Up @@ -234,6 +236,10 @@ impl Vector3Value {
Self(value)
}

pub fn inner(&self) -> Vector3 {
self.0
}

fn meta_index<'lua>(
&self,
context: Context<'lua>,
Expand Down Expand Up @@ -379,3 +385,92 @@ impl UserData for Vector3int16Value {
});
}
}

#[derive(Debug, Clone, Copy)]
pub struct CFrameValue(CFrame);

impl CFrameValue {
pub fn new(value: CFrame) -> Self {
Self(value)
}

fn meta_index<'lua>(
&self,
context: Context<'lua>,
key: &str,
) -> rlua::Result<rlua::Value<'lua>> {
match key {
"X" => self.0.position.x.to_lua(context),
"Y" => self.0.position.y.to_lua(context),
"Z" => self.0.position.z.to_lua(context),
"RightVector" => Vector3Value::new(Vector3::new(
self.0.orientation.x.x,
self.0.orientation.y.x,
self.0.orientation.z.x,
))
.to_lua(context),
"UpVector" => Vector3Value::new(Vector3::new(
self.0.orientation.x.y,
self.0.orientation.y.y,
self.0.orientation.z.y,
))
.to_lua(context),
"LookVector" => Vector3Value::new(Vector3::new(
-self.0.orientation.x.z,
-self.0.orientation.y.z,
-self.0.orientation.z.z,
))
.to_lua(context),
"XVector" => Vector3Value::new(self.0.orientation.x).to_lua(context),
"YVector" => Vector3Value::new(self.0.orientation.y).to_lua(context),
"ZVector" => Vector3Value::new(self.0.orientation.z).to_lua(context),
_ => Err(rlua::Error::external(format!(
"'{}' is not a valid member of CFrame",
key
))),
}
}
}

impl From<&CFrameValue> for Variant {
fn from(cframe: &CFrameValue) -> Variant {
Variant::CFrame(cframe.0)
}
}

impl fmt::Display for CFrameValue {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}",
self.0.position.x,
self.0.position.y,
self.0.position.z,
self.0.orientation.x.x,
self.0.orientation.y.x,
self.0.orientation.z.x,
self.0.orientation.x.y,
self.0.orientation.y.y,
self.0.orientation.z.y,
self.0.orientation.x.z,
self.0.orientation.y.z,
self.0.orientation.z.z,
)
LPGhatguy marked this conversation as resolved.
Show resolved Hide resolved
}
}

impl UserData for CFrameValue {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_meta_method(MetaMethod::Eq, |context, this, rhs: Self| {
(this.0 == rhs.0).to_lua(context)
});

methods.add_meta_method(MetaMethod::Index, |context, this, key: String| {
this.meta_index(context, &key)
});

methods.add_meta_method(MetaMethod::ToString, |context, this, _arg: ()| {
this.to_string().to_lua(context)
});
}
}
35 changes: 35 additions & 0 deletions test-scripts/type-cframe.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
local function assertCFramePosition(vec, x, y, z)
assert(vec.X == x, ("%f ~= %f"):format(vec.X, x))
assert(vec.Y == y, ("%f ~= %f"):format(vec.Y, y))
assert(vec.Z == z, ("%f ~= %f"):format(vec.Z, z))
end

local function assertVector(vec, x, y, z)
assert(vec.X == x, ("x: %f ~= %f (%s)"):format(vec.X, x, tostring(vec)))
assert(vec.Y == y, ("y: %f ~= %f (%s)"):format(vec.Y, y, tostring(vec)))
assert(vec.Z == z, ("z: %f ~= %f (%s)"):format(vec.Z, z, tostring(vec)))
end

-- new with combinations of integer and floats
LPGhatguy marked this conversation as resolved.
Show resolved Hide resolved
assertCFramePosition(CFrame.new(), 0, 0, 0)
assertCFramePosition(CFrame.new(1, 2, 3), 1, 2, 3)
assertCFramePosition(CFrame.new(1.5, 2, 3), 1.5, 2, 3)
assertCFramePosition(CFrame.new(1, 2.5, 3), 1, 2.5, 3)
assertCFramePosition(CFrame.new(1, 2, 3.5), 1, 2, 3.5)
assertCFramePosition(CFrame.new(1.5, 2.5, 3), 1.5, 2.5, 3)
assertCFramePosition(CFrame.new(1, 2.5, 3.5), 1, 2.5, 3.5)
assertCFramePosition(CFrame.new(1.5, 2.5, 3.5), 1.5, 2.5, 3.5)

-- new from Vector3
assertCFramePosition(CFrame.new(Vector3.new(1, 2, 3)), 1, 2, 3)

-- properties
assertVector(CFrame.new().XVector, 1, 0, 0)
assertVector(CFrame.new().YVector, 0, 1, 0)
assertVector(CFrame.new().ZVector, 0, 0, 1)

assertVector(CFrame.new().RightVector, 1, 0, 0)
assertVector(CFrame.new().UpVector, 0, 1, 0)
assertVector(CFrame.new().LookVector, -0, -0, -1)

assert(tostring(CFrame.new(7, 8, 9)) == "7, 8, 9, 1, 0, 0, 0, 1, 0, 0, 0, 1", "got " .. tostring(CFrame.new()))