Skip to content

Instantly share code, notes, and snippets.

@howmanysmall
Created October 20, 2019 16:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save howmanysmall/501672e0d5482ab2e975d4009b6c1a3e to your computer and use it in GitHub Desktop.
Save howmanysmall/501672e0d5482ab2e975d4009b6c1a3e to your computer and use it in GitHub Desktop.
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