while game == nil do wait(1 / 30) end local ChangeHistoryService = game:GetService "ChangeHistoryService" local CoreGui = game:GetService "CoreGui" --------------- --PLUGIN SETUP- --------------- local loaded = false -- True if the plugin is on, false if not. local on = false local On, Off local plugin = PluginManager():CreatePlugin() local mouse = plugin:GetMouse() mouse.Button1Down:connect(function() onClicked(mouse) end) local toolbar = plugin:CreateToolbar "Terrain" local toolbarbutton = toolbar:CreateButton("Builder", "Builder", "builder.png") toolbarbutton.Click:connect(function() if on then Off() elseif loaded then On() end end) game:WaitForChild "Workspace" game.Workspace:WaitForChild "Terrain" local c = game.Workspace.Terrain local SetCell = c.SetCell local GetCell = c.GetCell local WorldToCellPreferSolid = c.WorldToCellPreferSolid local CellCenterToWorld = c.CellCenterToWorld local AutoWedge = c.AutowedgeCells local WorldToCellPreferEmpty = c.WorldToCellPreferEmpty local GetWaterCell = c.GetWaterCell local SetWaterCell = c.SetWaterCell ----------------- --DEFAULT VALUES- ----------------- -- Stores selection properties. local selectionProps = {} selectionProps.isWater = nil -- True if what will be built is water. selectionProps.waterForce = nil -- Water force. selectionProps.waterDirection = nil -- Water direction. selectionProps.terrainMaterial = 0 -- Terrain material to use -- What color to use for the mouse highlighter. local mouseHighlightColor = BrickColor.new "Lime green" -- Used to create a highlighter that follows the mouse. -- It is a class mouse highlighter. To use, call MouseHighlighter.Create(mouse) where mouse is the mouse to track. local MouseHighlighter = {} MouseHighlighter.__index = MouseHighlighter local PlaneIntersection, UpdatePosition -- Create a mouse movement highlighter. -- plugin - Plugin to get the mouse from. function MouseHighlighter.Create(mouseUse) local highlighter = {} local mouseH = mouseUse highlighter.OnClicked = nil highlighter.mouseDown = false -- Store the last point used to draw. highlighter.lastUsedPoint = nil -- Will hold a part the highlighter will be attached to. This will be moved where the mouse is. highlighter.selectionPart = nil -- Function to call when the mouse has moved. Updates where to display the highlighter. local function MouseMoved() if on then UpdatePosition(mouseH.Hit) end end -- Hook the mouse up to check for movement. mouseH.Move:connect(function() MouseMoved() end) mouseH.Button1Down:connect(function() highlighter.mouseDown = true end) mouseH.Button1Up:connect(function() highlighter.mouseDown = false end) -- Create the part that the highlighter will be attached to. highlighter.selectionPart = Instance.new "Part" highlighter.selectionPart.Name = "SelectionPart" highlighter.selectionPart.Archivable = false highlighter.selectionPart.Transparency = 1 highlighter.selectionPart.Anchored = true highlighter.selectionPart.Locked = true highlighter.selectionPart.CanCollide = false highlighter.selectionPart.FormFactor = Enum.FormFactor.Custom highlighter.selectionBox = Instance.new "SelectionBox" highlighter.selectionBox.Archivable = false highlighter.selectionBox.Color = mouseHighlightColor highlighter.selectionBox.Adornee = highlighter.selectionPart mouseH.TargetFilter = highlighter.selectionPart setmetatable(highlighter, MouseHighlighter) -- Do a line/plane intersection. The line starts at the camera. The plane is at y == 0, normal(0, 1, 0) -- -- vectorPos - End point of the line. -- -- Return: -- success - Value is true if there was a plane intersection, false if not. -- cellPos - Value is the terrain cell intersection point if there is one, vectorPos if there isn't. PlaneIntersection = function(vectorPos) local currCamera = game.Workspace.CurrentCamera local startPos = Vector3.new( currCamera.CoordinateFrame.p.X, currCamera.CoordinateFrame.p.Y, currCamera.CoordinateFrame.p.Z ) local endPos = Vector3.new(vectorPos.X, vectorPos.Y, vectorPos.Z) local normal = Vector3.new(0, 1, 0) local p3 = Vector3.new(0, 0, 0) local startEndDot = normal:Dot(endPos - startPos) local cellPos = vectorPos local success = false if startEndDot ~= 0 then local t = normal:Dot(p3 - startPos) / startEndDot if t >= 0 and t <= 1 then local intersection = ((endPos - startPos) * t) + startPos cellPos = c:WorldToCell(intersection) success = true end end return success, cellPos end -- Update where the highlighter is displayed. -- position - Where to display the highlighter, in world space. UpdatePosition = function(position) if not position then return end -- NOTE: -- Change this gui to be the one you want to use. highlighter.selectionBox.Parent = CoreGui local vectorPos = Vector3.new(position.x, position.y, position.z) local cellPos = WorldToCellPreferEmpty(c, vectorPos) local solidCell = WorldToCellPreferSolid(c, vectorPos) local success = false -- If nothing was hit, do the plane intersection. if 0 == GetCell(c, solidCell.X, solidCell.Y, solidCell.Z).Value then success, cellPos = PlaneIntersection(vectorPos) if not success then cellPos = solidCell end else highlighter.lastUsedPoint = cellPos end local regionToSelect local lowVec = CellCenterToWorld(c, cellPos.x, cellPos.y - 1, cellPos.z) local highVec = CellCenterToWorld(c, cellPos.x, cellPos.y + 1, cellPos.z) regionToSelect = Region3.new(lowVec, highVec) highlighter.selectionPart.Size = regionToSelect.Size - Vector3.new(-4, 4, -4) highlighter.selectionPart.CFrame = regionToSelect.CFrame if nil ~= highlighter.OnClicked and highlighter.mouseDown then if nil == highlighter.lastUsedPoint then highlighter.lastUsedPoint = WorldToCellPreferEmpty( c, Vector3.new(mouseH.Hit.x, mouseH.Hit.y, mouseH.Hit.z) ) else cellPos = WorldToCellPreferEmpty( c, Vector3.new(mouseH.Hit.x, mouseH.Hit.y, mouseH.Hit.z) ) end end end return highlighter end -- Hide the highlighter. function MouseHighlighter:DisablePreview() self.selectionBox.Parent = nil end -- Show the highlighter. function MouseHighlighter:EnablePreview() self.selectionBox.Parent = CoreGui -- This will make it not show up in workspace. end -- Create the mouse movement highlighter. local mouseHighlighter = MouseHighlighter.Create(mouse) mouseHighlighter:DisablePreview() -- Create a standard text label. Use this for all lables in the popup so it is easy to standardize. -- labelName - What to set the text label name as. -- pos - Where to position the label. Should be of type UDim2. -- size - How large to make the label. Should be of type UDim2. -- text - Text to display. -- parent - What to set the text parent as. -- Return: -- Value is the created label. function CreateStandardLabel(labelName, pos, size, text, parent) local label = Instance.new "TextLabel" label.Name = labelName label.Position = pos label.Size = size label.Text = text label.TextColor3 = Color3.new(0.95, 0.95, 0.95) label.Font = Enum.Font.ArialBold label.FontSize = Enum.FontSize.Size14 label.TextXAlignment = Enum.TextXAlignment.Left label.BackgroundTransparency = 1 label.Parent = parent return label end ------ --GUI- ------ --screengui local g = Instance.new "ScreenGui" g.Name = "BuilderGui" g.Parent = CoreGui -- UI gui load. Required for sliders. local RbxGui = LoadLibrary "RbxGui" -- Store properties here. local properties = { autoWedgeEnabled = false } -- Gui frame for the plugin. local builderPropertiesDragBar, builderFrame, builderHelpFrame, builderCloseEvent = RbxGui.CreatePluginFrame( "Builder", UDim2.new(0, 123, 0, 40), UDim2.new(0, 0, 0, 0), false, g ) builderPropertiesDragBar.Visible = false builderCloseEvent.Event:connect(function() Off() end) builderHelpFrame.Size = UDim2.new(0, 160, 0, 85) local builderHelpText = Instance.new "TextLabel" builderHelpText.Name = "HelpText" builderHelpText.Font = Enum.Font.ArialBold builderHelpText.FontSize = Enum.FontSize.Size12 builderHelpText.TextColor3 = Color3.new(227 / 255, 227 / 255, 227 / 255) builderHelpText.TextXAlignment = Enum.TextXAlignment.Left builderHelpText.TextYAlignment = Enum.TextYAlignment.Top builderHelpText.Position = UDim2.new(0, 4, 0, 4) builderHelpText.Size = UDim2.new(1, -8, 0, 177) builderHelpText.BackgroundTransparency = 1 builderHelpText.TextWrap = true builderHelpText.Text = [[ Clicking terrain adds a single block into the selection box shown. The terrain material and type will be the same as the cell that was clicked on.]] builderHelpText.Parent = builderHelpFrame CreateStandardLabel( "AddText", UDim2.new(0, 8, 0, 10), UDim2.new(0, 67, 0, 14), "Click to add terrain.", builderFrame ) -- Function to connect to the mouse button 1 down event. This is what will run when the user clicks. -- Adding and autowedging done here. -- mouse - Mouse data. function onClicked(mouseC) if on then local cellPos = WorldToCellPreferEmpty( c, Vector3.new(mouseC.Hit.x, mouseC.Hit.y, mouseC.Hit.z) ) local x = cellPos.x local y = cellPos.y local z = cellPos.z local solidCellPos = WorldToCellPreferSolid( c, Vector3.new(mouseC.Hit.x, mouseC.Hit.y, mouseC.Hit.z) ) local celMat = GetCell(c, solidCellPos.x, solidCellPos.y, solidCellPos.z) local success = false if celMat.Value > 0 then selectionProps.terrainMaterial = celMat.Value selectionProps.isWater, selectionProps.waterForce, selectionProps.waterDirection = GetWaterCell(c, solidCellPos.X, solidCellPos.Y, solidCellPos.Z) else if 0 == selectionProps.terrainMaterial then -- It was nothing, give it a default type and the plane intersection. selectionProps.isWater = false selectionProps.terrainMaterial = 1 end success, cellPos = PlaneIntersection( Vector3.new(mouseC.Hit.x, mouseC.Hit.y, mouseC.Hit.z) ) if not success then cellPos = solidCellPos end x = cellPos.x y = cellPos.y z = cellPos.z end if selectionProps.isWater and 17 == selectionProps.terrainMaterial then SetWaterCell( c, x, y, z, selectionProps.waterForce, selectionProps.waterDirection ) else SetCell(c, x, y, z, selectionProps.terrainMaterial, 0, 0) end if properties.autoWedgeEnabled then AutoWedge( c, Region3int16.new( Vector3int16.new(x - 1, y - 1, z - 1), Vector3int16.new(x + 1, y + 1, z + 1) ) ) end -- Mark undo point. ChangeHistoryService:SetWaypoint "Builder" UpdatePosition(mouseC.Hit) end end mouseHighlighter.OnClicked = onClicked -- Run when the popup is activated. On = function() if not c then return end plugin:Activate(true) toolbarbutton:SetActive(true) builderPropertiesDragBar.Visible = true on = true end -- Run when the popup is deactivated. Off = function() toolbarbutton:SetActive(false) on = false -- Hide the popup gui. builderPropertiesDragBar.Visible = false mouseHighlighter:DisablePreview() end plugin.Deactivation:connect(function() Off() end) loaded = true