Last active
November 29, 2020 04:14
-
-
Save howmanysmall/c2feaeed73dcac18adb6bc679c0ff300 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
-- This goes in ServerStorage.MACRO_PLUGIN.Macros | |
local Workspace = game:GetService("Workspace") | |
local CollectionService = game:GetService("CollectionService") | |
local Selection = game:GetService("Selection") | |
local BuilderUtility = require(script.BuilderUtility) | |
local Macro = { } | |
function Macro:Init() | |
print("Builder's Assistant initialized") | |
end | |
local ALL_MATERIALS = { | |
wood = 512, | |
basalt = 788, | |
sandstone = 912, | |
brick = 848, | |
cobblestone = 880, | |
slate = 800, | |
woodplanks = 528, | |
plastic = 256, | |
salt = 1392, | |
crackedlava = 804, | |
grass = 1280, | |
glass = 1568, | |
neon = 288, | |
sand = 1296, | |
water = 2048, | |
marble = 784, | |
corrodedmetal = 1040, | |
glacier = 1552, | |
forcefield = 1584, | |
ground = 1360, | |
snow = 1328, | |
air = 1792, | |
pavement = 836, | |
limestone = 820, | |
leafygrass = 1284, | |
rock = 896, | |
asphalt = 1376, | |
smoothplastic = 272, | |
foil = 1072, | |
diamondplate = 1056, | |
mud = 1344, | |
granite = 832, | |
metal = 1088, | |
concrete = 816, | |
pebble = 864, | |
fabric = 1312, | |
ice = 1536 | |
} | |
local Title = { | |
Type = "Title"; | |
Text = "Builder's Assistant"; | |
} | |
local SetToThis = ALL_MATERIALS.smoothplastic | |
local Material = { | |
Type = "String"; | |
Text = "Material"; | |
SettingId = "MaterialString"; | |
Value = "SmoothPlastic"; | |
Changed = function(self, NewValue) | |
local Previous = NewValue | |
NewValue = NewValue:lower() | |
NewValue = NewValue:gsub("%s+", "") | |
if ALL_MATERIALS[NewValue] then | |
SetToThis = ALL_MATERIALS[NewValue] | |
else | |
warn(string.format("The value %q isn't a Material, defaulting to SmoothPlastic.", tostring(Previous))) | |
SetToThis = ALL_MATERIALS.smoothplastic | |
end | |
end; | |
} | |
local MaterializeAll = { | |
Type = "Button"; | |
Text = "Materialize All"; | |
Activate = function(self) | |
local Descendants = Workspace:GetDescendants() | |
for Index = 1, #Descendants do | |
local Child = Descendants[Index] | |
if Child:IsA("BasePart") then | |
Child.Material = SetToThis | |
end | |
end | |
end; | |
} | |
local MaterializeSelection = { | |
Type = "Button"; | |
Text = "Materialize Selection"; | |
Activate = function(self) | |
local Descendants = Selection:Get() | |
for Index = 1, #Descendants do | |
local Child = Descendants[Index] | |
if Child:IsA("BasePart") then | |
Child.Material = SetToThis | |
end | |
end | |
end; | |
} | |
local SearchWoodenParts = BuilderUtility.SearchWoodenParts | |
local FixGrainDirection = BuilderUtility.FixGrainDirection | |
local GrainThreshold = { | |
Type = "Number"; | |
Text = "Threshold"; | |
SettingId = "GrainThreshold"; | |
Value = 0.75; | |
Changed = function(self, Value) | |
self.Value = Value > 1 and 1 or Value < 0 and 0 or Value | |
end; | |
} | |
local FixGrainInWorkspace = { | |
Type = "Button"; | |
Text = "🔨 Fix Wood Grain in Workspace"; | |
Activate = function(self) | |
local Threshold = GrainThreshold.Value > 1 and GrainThreshold.Value / 100 or GrainThreshold.Value | |
for _, Child in ipairs(SearchWoodenParts(Workspace:GetDescendants())) do | |
FixGrainDirection(Child, Threshold) | |
end | |
end; | |
} | |
local FixGrainInSelection = { | |
Type = "Button"; | |
Text = "🔨 Fix Wood Grain in Selection"; | |
Activate = function(self) | |
local Threshold = GrainThreshold.Value > 1 and GrainThreshold.Value / 100 or GrainThreshold.Value | |
for _, Child in ipairs(SearchWoodenParts(Selection:Get())) do | |
FixGrainDirection(Child, Threshold) | |
end | |
end; | |
} | |
local GetColor3 = BuilderUtility.GetColor3 | |
local SetColor = GetColor3("136, 179, 88") | |
local SetMaterial = ALL_MATERIALS.smoothplastic | |
local TriangleRGB = { | |
Type = "String"; | |
Text = "Triangle Color"; | |
SettingId = "TriangleString"; | |
Value = "136, 179, 88"; | |
Changed = function(self, NewValue) | |
SetColor = GetColor3(NewValue) | |
end; | |
} | |
local TriangleMaterial = { | |
Type = "String"; | |
Text = "Triangle Material"; | |
SettingId = "TriangleMaterial"; | |
Value = "SmoothPlastic"; | |
Changed = function(self, NewValue) | |
local Previous = NewValue | |
NewValue = NewValue:lower() | |
NewValue = NewValue:gsub("%s+", "") | |
if ALL_MATERIALS[NewValue] then | |
SetMaterial = ALL_MATERIALS[NewValue] | |
else | |
warn(string.format("The value %q isn't a Material, defaulting to SmoothPlastic.", tostring(Previous))) | |
SetMaterial = ALL_MATERIALS.smoothplastic | |
end | |
end; | |
} | |
local NODE_SIZE = Vector3.new(1, 1, 1) | |
local BuildTriangle = BuilderUtility.BuildTriangle | |
local TriangleTerrain = { | |
Type = "Button"; | |
Text = "🔺 Create Triangle"; | |
Activate = function(self) | |
local CurrentSelection = Selection:Get() | |
if #CurrentSelection == 3 then | |
for _, BasePart in ipairs(CurrentSelection) do | |
assert(BasePart:IsA("BasePart"), ("Selection %s isn't a BasePart!"):format(tostring(BasePart))) | |
assert(BasePart.Size == NODE_SIZE, ("Selection %s isn't a 1x1x1 square!"):format(tostring(BasePart))) | |
end | |
BuildTriangle(CurrentSelection[1].Position, CurrentSelection[2].Position, CurrentSelection[3].Position, SetColor, SetMaterial) | |
end | |
end; | |
} | |
Macro.Items = { | |
Title; | |
Material; | |
MaterializeAll; | |
MaterializeSelection; | |
GrainThreshold; | |
FixGrainInWorkspace; | |
FixGrainInSelection; | |
TriangleRGB; | |
TriangleMaterial; | |
TriangleTerrain; | |
} | |
return Macro |
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
-- This goes in ServerStorage.MACRO_PLUGIN.Macros.BuilderAssistant | |
local Workspace = game:GetService("Workspace") | |
local math_min = math.min | |
local math_max = math.max | |
local math_sqrt = math.sqrt | |
local math_acos = math.acos | |
local string_split = string.split | |
local Vector3_new = Vector3.new | |
local Color3_fromRGB = Color3.fromRGB | |
local Instance_new = Instance.new | |
local CFrame_new = CFrame.new | |
local CFrame_Angles = CFrame.Angles | |
local tonumber = tonumber | |
local HALF_PI_X_ANGLES = CFrame_Angles(1.5707963267948965579989817342720925807952880859375, 0, 0) | |
local HALF_PI_Y_ANGLES = CFrame_Angles(0, 1.5707963267948965579989817342720925807952880859375, 0) | |
local HALF_PI_Z_ANGLES = CFrame_Angles(0, 0, 1.5707963267948965579989817342720925807952880859375) | |
local PI_Y_ANGLES = CFrame_Angles(0, 3.141592653589793115997963468544185161590576171875000000000000, 0) | |
local Wood = Enum.Material.Wood | |
local WoodPlanks = Enum.Material.WoodPlanks | |
local Block = Enum.PartType.Block | |
local BuilderUtility = { } | |
function BuilderUtility.SearchWoodenParts(Children, Array) | |
Array = Array or { } | |
for _, Child in ipairs(Children) do | |
if (Child:IsA("Part") or Child:IsA("SpawnLocation")) and (Child.Material == Wood or Child.Material == WoodPlanks) and Child.Shape == Block then | |
local ShouldAdd = true | |
if Child:FindFirstChildOfClass("CylinderMesh") or Child:FindFirstChildOfClass("FileMesh") then ShouldAdd = false end | |
if ShouldAdd then Array[#Array + 1] = Child end | |
else | |
Array = BuilderUtility.SearchWoodenParts(Child:GetChildren(), Array) | |
end | |
end | |
return Array | |
end | |
local function RotateMeshes(Part, RotateCFrame) | |
for _, Child in ipairs(Part:GetChildren()) do | |
if Child:IsA("BlockMesh") then | |
Child.Offset = RotateCFrame:VectorToObjectSpace(Child.Offset) | |
Child.Scale = RotateCFrame:VectorToWorldSpace(Child.Scale) | |
end | |
end | |
end | |
function BuilderUtility.FixGrainDirection(Part, Threshold) | |
local Affected = false | |
local SizeLow = math_min(Part.Size.X, Part.Size.Y, Part.Size.Z) | |
local SizeHigh = math_max(Part.Size.X, Part.Size.Y, Part.Size.Z) | |
if SizeHigh == Part.Size.X then | |
local NewLow = Part.Size.Y < Part.Size.Z and Part.Size.Y or Part.Size.Z | |
local NewHigh = Part.Size.Y < Part.Size.Z and Part.Size.Z or Part.Size.Y | |
if NewHigh == Part.Size.Y then return Affected end | |
if Threshold > NewLow / NewHigh then | |
local NewCFrame = Part.CFrame * HALF_PI_X_ANGLES | |
RotateMeshes(Part, HALF_PI_X_ANGLES) | |
Part.Size = Vector3_new(Part.Size.X, Part.Size.Z, Part.Size.Y) | |
Part.CFrame = NewCFrame | |
Affected = true | |
end | |
return Affected | |
end | |
if Threshold > SizeLow / SizeHigh then | |
if SizeHigh == Part.Size.Z then | |
local NewCFrame = Part.CFrame * HALF_PI_Y_ANGLES | |
RotateMeshes(Part, HALF_PI_Y_ANGLES) | |
Part.Size = Vector3_new(Part.Size.Z, Part.Size.Y, Part.Size.X) | |
Part.CFrame = NewCFrame | |
Affected = true | |
elseif SizeHigh == Part.Size.Y then | |
local NewCFrame = Part.CFrame * HALF_PI_Z_ANGLES | |
RotateMeshes(Part, HALF_PI_Z_ANGLES) | |
Part.Size = Vector3_new(Part.Size.Y, Part.Size.X, Part.Size.Z) | |
Part.CFrame = NewCFrame | |
Affected = true | |
end | |
end | |
SizeLow = Part.Size.Y < Part.Size.Z and Part.Size.Y or Part.Size.Z | |
SizeHigh = Part.Size.Y < Part.Size.Z and Part.Size.Z or Part.Size.Y | |
if SizeHigh == Part.Size.Y then return Affected end | |
if Threshold > SizeLow / SizeHigh then | |
local NewCFrame = Part.CFrame * HALF_PI_X_ANGLES | |
RotateMeshes(Part, HALF_PI_X_ANGLES) | |
Part.Size = Vector3_new(Part.Size.X, Part.Size.Z, Part.Size.Y) | |
Part.CFrame = NewCFrame | |
Affected = true | |
end | |
return Affected | |
end | |
function BuilderUtility.GetColor3(String) | |
local Color = string_split(String, ",") | |
return Color3_fromRGB(tonumber(Color[1]), tonumber(Color[2]), tonumber(Color[3])) | |
end | |
local LastTriangle = { Part1 = nil, Part2 = nil } | |
local TRIANGLE_WIDTH = 0.2 | |
local DEFAULT_SIZE = Vector3_new(1, 7, 7) | |
local function ParaD(A, B, C) | |
local BA = B - A | |
local CA = C - A | |
return (BA.X * CA.X + BA.Y * CA.Y + BA.Z * CA.Z) / (A - B).Magnitude | |
end | |
local function PerpD(A, B, C) | |
local BA = B - A | |
local CA = C - A | |
local Parallel = (BA.X * CA.X + BA.Y * CA.Y + BA.Z * CA.Z) / (A - B).Magnitude | |
return math_sqrt(CA.Magnitude * CA.Magnitude - Parallel * Parallel) | |
end | |
function BuilderUtility.BuildTriangle(NodeA, NodeB, NodeC, SetColor, SetMaterial) | |
local A, B, C | |
local Model = Instance_new("Model") | |
Model.Name = "Triangle" | |
Model.Parent = Workspace | |
local P0 = Instance_new("WedgePart") | |
P0.TopSurface = 0 | |
P0.BottomSurface = 0 | |
P0.Anchored = true | |
P0.Color = SetColor | |
P0.Material = SetMaterial | |
local P1 = Instance_new("WedgePart") | |
P1.TopSurface = 0 | |
P1.BottomSurface = 0 | |
P1.Anchored = true | |
P1.Color = SetColor | |
P1.Material = SetMaterial | |
local S1 = (NodeA - NodeB).Magnitude | |
local S2 = (NodeB - NodeC).Magnitude | |
local S3 = (NodeC - NodeA).Magnitude | |
local SMax = math_max(S1, S2, S3) | |
if S1 == SMax then | |
A, B, C = NodeA, NodeB, NodeC | |
elseif S2 == SMax then | |
A, B, C = NodeB, NodeC, NodeA | |
elseif S3 == SMax then | |
A, B, C = NodeC, NodeA, NodeB | |
end | |
local Perp = PerpD(A, B, C) | |
local Para = ParaD(A, B, C) | |
local DiffPara = (A - B).Magnitude - Para | |
P0.Size = Vector3_new(TRIANGLE_WIDTH, Perp, Para) | |
P0.CFrame = CFrame_new(B, A) | |
local TopLook = (P0.CFrame * HALF_PI_X_ANGLES).LookVector | |
local MidPoint = A + CFrame_new(A, B).LookVector * Para | |
local NeededLook = CFrame_new(MidPoint, C).LookVector | |
local Dot = TopLook.X * NeededLook.X + TopLook.Y * NeededLook.Y + TopLook.Z * NeededLook.Z | |
P0.CFrame = P0.CFrame * CFrame_Angles(0, 0, math_acos(Dot)) | |
if ((P0.CFrame * HALF_PI_X_ANGLES).LookVector - NeededLook).Magnitude > 0.01 then | |
P0.CFrame = P0.CFrame * CFrame_Angles(0, 0, -2 * math_acos(Dot)) | |
end | |
P0.CFrame = P0.CFrame * CFrame_new(0, Perp / 2, -(DiffPara + Para / 2)) | |
P0.Parent = Model | |
P0.Name = "Triangle" | |
P1.Size = Vector3_new(TRIANGLE_WIDTH, Perp, DiffPara) | |
P1.CFrame = CFrame_new(B, A) * CFrame_Angles(0, 0, math_acos(Dot)) * PI_Y_ANGLES | |
if ((P1.CFrame * HALF_PI_X_ANGLES).LookVector - NeededLook).Magnitude > 0.01 then | |
P1.CFrame = P1.CFrame * CFrame_Angles(0, 0, 2 * math_acos(Dot)) | |
end | |
P1.CFrame = P1.CFrame * CFrame_new(0, Perp / 2, DiffPara / 2) | |
P1.Parent = Model | |
P1.Name = "Triangle" | |
LastTriangle.Part1 = P0 | |
LastTriangle.Part2 = P1 | |
end | |
return BuilderUtility |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment