Created
October 20, 2019 16:47
-
-
Save howmanysmall/501672e0d5482ab2e975d4009b6c1a3e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using extern CFrame.new; | |
using extern CFrame.fromAxisAngle; | |
using extern Vector3.new; | |
using extern Vector3.FromNormalId; | |
using extern Instance.new; | |
using extern error; | |
typedef ArrayOfInstances table<int, RbxInstance>; | |
RbxInstance ChangeHistoryService = game::GetService @ ChangeHistoryService; | |
RbxInstance CoreGui = game::GetService @ CoreGui; | |
RbxInstance TestService = game::GetService @ TestService; | |
bool Enabled = false; | |
bool Loaded = false; | |
const double HALF_PI = Pi / 2; | |
const double MARGIN_OF_ERROR = 0.001; | |
const LuaString WAYPOINT_NAME = L"Flip"; | |
RbxInstance UNIFORM_SCALE = Vector3_new(1, 1, 1); | |
table<LuaString, bool> IS_FLIPPABLE = table( | |
(L"Brick"): true, | |
(L"Wedge"): true, | |
(L"Round"): true, | |
); | |
ArrayOfInstances MouseConnections = table(); | |
RbxInstance Toolbar | ToolbarButton | SelectionBox | Mouse; | |
entry void main(void) | |
{ | |
ChangeHistoryService::SetEnabled(true); | |
ChangeHistoryService::SetWaypoint @ PluginStart; | |
Toolbar = plugin::CreateToolbar @ GeometryTools; | |
ToolbarButton = Toolbar::CreateButton(L"MaterialFlip", L"Click parts to \"rotate\" the direction that their matieral is pointing in without modifying their position or size.", L"rbxassetid://166926591"); | |
plugin.Deactivation::Connect(Deactivate); | |
ToolbarButton.Click::Connect(ButtonClick); | |
SelectionBox = Instance_new @ SelectionBox; | |
SelectionBox.Visible = false; | |
SelectionBox.Parent = CoreGui; | |
Loaded = true; | |
} | |
void ButtonClick(void) | |
{ | |
// print(L"ButtonClick"); | |
if Enabled | |
{ | |
Deactivate(); | |
} elseif Loaded | |
{ | |
Activate(); | |
} | |
} | |
void Activate(void) | |
{ | |
// print(L"Activate"); | |
plugin::Activate(true); | |
ToolbarButton::SetActive(true); | |
Enabled = true; | |
Mouse = plugin::GetMouse(true); | |
MouseConnections<:len MouseConnections++:> = Mouse.Button1Down::Connect(MouseDown); | |
MouseConnections<:len MouseConnections++:> = Mouse.Move::Connect(MouseMove); | |
MouseConnections<:len MouseConnections++:> = Mouse.Idle::Connect(MouseMove); | |
Selected(); | |
} | |
void MouseDown(void) | |
{ | |
// print(L"MouseDown"); | |
if Mouse.Target && IsFlippable(Mouse.Target) | |
{ | |
Flip(Mouse.Target, Mouse.Hit.Position, Mouse.TargetSurface); | |
} | |
} | |
void MouseMove(void) | |
{ | |
// print(L"MouseMove"); | |
if Mouse.Target && IsFlippable(Mouse.Target) | |
{ | |
SelectionBox.Adornee = Mouse.Target; | |
} else | |
{ | |
free(SelectionBox.Adornee); | |
} | |
} | |
void Deactivate(void) | |
{ | |
// print(L"Deactivate"); | |
ToolbarButton::SetActive(false); | |
Enabled = false; | |
iterate MouseConnections with(int Index) | |
{ | |
MouseConnections<:Index:>::Disconnect(); | |
free(MouseConnections<:Index:>); | |
} | |
Deselected(); | |
} | |
void Selected(void) | |
{ | |
// print(L"Selected"); | |
SelectionBox.Visible = true; | |
if Mouse.Target && IsFlippable(Mouse.Target) | |
{ | |
SelectionBox.Adornee = Mouse.Target; | |
} else | |
{ | |
free(SelectionBox.Adornee); | |
} | |
} | |
void Deselected(void) | |
{ | |
// print(L"Deselected"); | |
SelectionBox.Visible = false; | |
free(SelectionBox.Adornee); | |
} | |
RbxInstance CFrameFromTopBack(RbxInstance At, Top, Back) | |
{ | |
// print(L"CFrameFromTopBack"); | |
RbxInstance Right = Top::Cross(Back); | |
return CFrame_new(At.X, At.Y, At.Z, Right.X, Top.X, Back.X, Right.Y, Top.Y, Back.Y, Right.Z, Top.Z, Back.Z); | |
} | |
LuaString GetShape(RbxInstance Part) | |
{ | |
// print(L"GetShape"); | |
ArrayOfInstances Children = Part::GetChildren(); | |
iterate Children with(RbxInstance Child) | |
{ | |
if Child::IsA @ SpecialMesh | |
{ | |
if Child.MeshType == Enum.MeshType.Brick | |
{ | |
return L"Brick"; | |
} elseif Child.MeshType == Enum.MeshType.CornerWedge | |
{ | |
return L"CornerWedge"; | |
} elseif Child.MeshType == Enum.MeshType.Cylinder || Child.MeshType == Enum.MeshType.Sphere | |
{ | |
return L"Round"; | |
} elseif Child.MeshType == Enum.MeshType.Wedge | |
{ | |
return L"Wedge"; | |
} else | |
{ | |
TestService::Error(L"GapFill: Unsupported Mesh Type, treating as a normal brick.", script, 128); // To avoid having to spawn a new function for an error. | |
} | |
} | |
} | |
if Part::IsA @ WedgePart | |
{ | |
return L"Wedge"; | |
} elseif Part::IsA @ CornerWedgePart | |
{ | |
return L"CornerWedge"; | |
} elseif Part::IsA @ Terrain | |
{ | |
return L"Terrain"; | |
} else | |
{ | |
if Part.Shape == Enum.PartType.Ball || Part.Shape == Enum.PartType.Cylinder | |
{ | |
return L"Round"; | |
} elseif Part.Shape == Enum.PartType.Block | |
{ | |
return L"Brick"; | |
} else | |
{ | |
error(L"Unreachable.", 1); | |
} | |
} | |
} | |
bool IsFlippable(RbxInstance BasePart) | |
{ | |
// print(L"IsFlippable"); | |
if !BasePart || BasePart.Locked | |
{ | |
return false; | |
} else | |
{ | |
return IS_FLIPPABLE<:GetShape(BasePart):>; | |
} | |
} | |
// Shouldn't be required but here we are. | |
//void TwoWaySwitchSurfaces(RbxInstance BasePart, LuaString SurfaceOne, SurfaceTwo) | |
//{ | |
// RbxInstance TemporarySurface = BasePart<:SurfaceOne:>; | |
// BasePart<:SurfaceOne:> = BasePart<:SurfaceTwo:>; | |
// BasePart<:SurfaceTwo:> = TemporarySurface; | |
// free(TemporarySurface); | |
//} | |
void Flip(RbxInstance BasePart, Point, NormalId) | |
{ | |
// print(L"Flip"); | |
RbxInstance CoordinateFrame | Size | Position | LookVector | UpVector | BackVector | BottomVector | RightVector | Rotation | Axis | TargetCFrame | TargetSize; | |
RbxInstance SurfaceOne | SurfaceTwo | SurfaceThree | SurfaceFour; | |
LuaString PartShape; | |
BasePart::BreakJoints(); | |
CoordinateFrame = BasePart.CFrame; | |
Size = BasePart.Size; | |
Position = CoordinateFrame.Position; | |
PartShape = GetShape(BasePart); | |
if PartShape == L"Wedge" | |
{ | |
LookVector = CoordinateFrame.LookVector; | |
UpVector = CoordinateFrame.UpVector; | |
SurfaceOne = BasePart.TopSurface; | |
BasePart.TopSurface = BasePart.FrontSurface; | |
BasePart.FrontSurface = SurfaceOne; | |
SurfaceOne = BasePart.BottomSurface; | |
BasePart.BottomSurface = BasePart.BackSurface; | |
BasePart.BackSurface = SurfaceOne; | |
SurfaceOne = BasePart.LeftSurface; | |
BasePart.LeftSurface = BasePart.RightSurface; | |
BasePart.RightSurface = SurfaceOne; | |
// TwoWaySwitchSurfaces(BasePart, L"TopSurface", L"FrontSurface"); | |
// TwoWaySwitchSurfaces(BasePart, L"BottomSurface", L"BackSurface"); | |
// TwoWaySwitchSurfaces(BasePart, L"LeftSurface", L"RightSurface"); | |
BasePart.Size = Vector3_new(Size.X, Size.Z, Size.Y); | |
BasePart::BreakJoints(); | |
BasePart.CFrame = CFrameFromTopBack(Position, LookVector, -UpVector); | |
} elseif PartShape == L"Round" | |
{ | |
Rotation = fromAxisAngle((Point - Position).Unit, Pi); | |
BasePart::BreakJoints(); | |
BasePart.CFrame = (Rotation * (CoordinateFrame - Position)) + Position; | |
} else | |
{ | |
Axis = CoordinateFrame::VectorToWorldSpace(FromNormalId(NormalId)); | |
Rotation = fromAxisAngle(Axis, HALF_PI); | |
TargetCFrame = (Rotation * (CoordinateFrame - Position)) + Position; | |
LookVector = CoordinateFrame.LookVector; | |
UpVector = CoordinateFrame.UpVector; | |
RightVector = CoordinateFrame.RightVector; | |
BackVector = -LookVector; | |
BottomVector = -UpVector; | |
if (LookVector - Axis).Magnitude < MARGIN_OF_ERROR || (BackVector - Axis).Magnitude < MARGIN_OF_ERROR | |
{ | |
TargetSize = Vector3_new(Size.Y, Size.X, Size.Z); | |
if (LookVector - Axis).Magnitude < MARGIN_OF_ERROR | |
{ | |
SurfaceOne = BasePart.RightSurface; | |
SurfaceTwo = BasePart.TopSurface; | |
SurfaceThree = BasePart.LeftSurface; | |
SurfaceFour = BasePart.BottomSurface; | |
BasePart.RightSurface = SurfaceFour; | |
BasePart.TopSurface = SurfaceOne; | |
BasePart.LeftSurface = SurfaceTwo; | |
BasePart.BottomSurface = SurfaceThree; | |
} else | |
{ | |
SurfaceOne = BasePart.RightSurface; | |
SurfaceTwo = BasePart.TopSurface; | |
SurfaceThree = BasePart.LeftSurface; | |
SurfaceFour = BasePart.BottomSurface; | |
BasePart.RightSurface = SurfaceTwo; | |
BasePart.TopSurface = SurfaceThree; | |
BasePart.LeftSurface = SurfaceFour; | |
BasePart.BottomSurface = SurfaceOne; | |
} | |
} elseif (UpVector - Axis).Magnitude < MARGIN_OF_ERROR || (BottomVector - Axis).Magnitude < MARGIN_OF_ERROR | |
{ | |
TargetSize = Vector3_new(Size.Z, Size.Y, Size.X); | |
if (UpVector - Axis).Magnitude < MARGIN_OF_ERROR | |
{ | |
SurfaceOne = BasePart.FrontSurface; | |
SurfaceTwo = BasePart.RightSurface; | |
SurfaceThree = BasePart.BackSurface; | |
SurfaceFour = BasePart.LeftSurface; | |
BasePart.FrontSurface = SurfaceFour; | |
BasePart.RightSurface = SurfaceOne; | |
BasePart.BackSurface = SurfaceTwo; | |
BasePart.LeftSurface = SurfaceThree; | |
} else | |
{ | |
SurfaceOne = BasePart.FrontSurface; | |
SurfaceTwo = BasePart.RightSurface; | |
SurfaceThree = BasePart.BackSurface; | |
SurfaceFour = BasePart.LeftSurface; | |
BasePart.RightSurface = SurfaceTwo; | |
BasePart.TopSurface = SurfaceThree; | |
BasePart.LeftSurface = SurfaceFour; | |
BasePart.BottomSurface = SurfaceOne; | |
} | |
} else | |
{ | |
TargetSize = Vector3_new(Size.X, Size.Z, Size.Y); | |
if (RightVector - Axis).Magnitude < MARGIN_OF_ERROR | |
{ | |
SurfaceOne = BasePart.TopSurface; | |
SurfaceTwo = BasePart.FrontSurface; | |
SurfaceThree = BasePart.BottomSurface; | |
SurfaceFour = BasePart.BackSurface; | |
BasePart.TopSurface = SurfaceFour; | |
BasePart.FrontSurface = SurfaceOne; | |
BasePart.BottomSurface = SurfaceTwo; | |
BasePart.BackSurface = SurfaceThree; | |
} else | |
{ | |
SurfaceOne = BasePart.TopSurface; | |
SurfaceTwo = BasePart.FrontSurface; | |
SurfaceThree = BasePart.BottomSurface; | |
SurfaceFour = BasePart.BackSurface; | |
BasePart.TopSurface = SurfaceTwo; | |
BasePart.FrontSurface = SurfaceThree; | |
BasePart.BottomSurface = SurfaceFour; | |
BasePart.BackSurface = SurfaceOne; | |
} | |
} | |
BasePart.Size = TargetSize; | |
BasePart::BreakJoints(); | |
BasePart.CFrame = TargetCFrame; | |
} | |
free( | |
SurfaceOne, SurfaceTwo, SurfaceThree, SurfaceFour, | |
CoordinateFrame, Size, Position, LookVector, UpVector, BackVector, BottomVector, RightVector, Rotation, Axis, TargetCFrame, TargetSize | |
); | |
ChangeHistoryService::SetWaypoint(WAYPOINT_NAME); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment