Formatting improvements and modularisation of terrain plugins

This commit is contained in:
Lewin Kelly 2024-04-10 07:44:11 +01:00
parent ca31246727
commit 98561c76e0
12 changed files with 1087 additions and 1198 deletions

View File

@ -0,0 +1,34 @@
local New = require("../New").New
-- Create a standard dropdown. Use this for all dropdowns in the popup so it is easy to standardize.
-- name - What to use.
-- pos - Where to position the button. Should be of type UDim2.
-- text - Text to show in the button.
-- funcOnPress - Function to run when the button is pressed.
-- parent - What to set the parent as.
-- Return:
-- button - The button gui.
return function(
name: string,
pos: UDim2,
text: string,
funcOnPress: (...any) -> (),
parent: Instance,
size: UDim2?
)
local button = New "TextButton" {
Name = name,
Position = pos,
Size = size or UDim2.new(0, 120, 0, 40),
Text = text,
Style = Enum.ButtonStyle.RobloxButton,
TextColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size18,
}
button.MouseButton1Click:connect(funcOnPress)
button.Parent = parent
return button
end

View File

@ -0,0 +1,30 @@
local New = require("../New").New
-- 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.
return function(
labelName: string,
pos: UDim2,
size: UDim2,
text: string,
parent: Instance?
)
return New "TextLabel" {
Name = labelName,
Position = pos,
Size = size,
Text = text,
TextColor3 = Color3.new(0.95, 0.95, 0.95),
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size14,
TextXAlignment = Enum.TextXAlignment.Left,
BackgroundTransparency = 1,
Parent = parent,
}
end

View File

@ -1,11 +1,17 @@
-- Local function definitions
while game == nil do
--!strict
while not game do
wait()
end
local ChangeHistoryService = game:GetService "ChangeHistoryService"
local CoreGui = game:GetService "CoreGui"
local CreateStandardButton = require "../Modules/Terrain/CreateStandardButton"
local CreateStandardLabel = require "../Modules/Terrain/CreateStandardLabel"
local News = require "../Modules/New"
local New = News.New
local Hydrate = News.Hydrate
---------------
--PLUGIN SETUP-
---------------
@ -147,18 +153,20 @@ end)
terrainHelpFrame.Size = UDim2.new(0, 300, 0, 350)
local terrainHelpText = Instance.new "TextLabel"
terrainHelpText.Name = "HelpText"
terrainHelpText.Font = Enum.Font.ArialBold
terrainHelpText.FontSize = Enum.FontSize.Size12
terrainHelpText.TextColor3 = Color3.new(227 / 255, 227 / 255, 227 / 255)
terrainHelpText.TextXAlignment = Enum.TextXAlignment.Left
terrainHelpText.TextYAlignment = Enum.TextYAlignment.Top
terrainHelpText.Position = UDim2.new(0, 4, 0, 4)
terrainHelpText.Size = UDim2.new(1, -8, 0, 157)
terrainHelpText.BackgroundTransparency = 1
terrainHelpText.TextWrap = true
terrainHelpText.Text = [[Create terrain with hills, water.
local function helpText()
return New "TextLabel" {
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size12,
TextColor3 = Color3.new(227 / 255, 227 / 255, 227 / 255),
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
BackgroundTransparency = 1,
TextWrap = true,
Parent = terrainHelpFrame,
}
end
local helpText1 = [[Create terrain with hills, water.
X-Offset and Z-Offset:
Center point of terrain that will be created.
Terrain must be in a specific region. If part of the terrain is outside that region, it won't be created.
@ -170,13 +178,7 @@ Length: Terrain size in the Z direction
Amplitude:
Maximum height of hills.
]]
terrainHelpText.Parent = terrainHelpFrame
local helpSecondText = terrainHelpText:clone()
helpSecondText.Name = "HelpSecondText"
helpSecondText.Position = UDim2.new(0, 0, 1, 0)
helpSecondText.Size = UDim2.new(1, 0, 0, 180)
helpSecondText.Text = [[Frequency:
local helpText2 = [[Frequency:
How often hills are made.
Base Height:
@ -185,21 +187,34 @@ How high the base of terrain should be.
Water Height:
How high water should be. Terrain will overwrite water.
]]
helpSecondText.Parent = terrainHelpText
local helpThirdText = helpSecondText:clone()
helpThirdText.Name = "HelpThirdText"
helpThirdText.Position = UDim2.new(0, 0, 0.6, 0)
helpThirdText.Size = UDim2.new(1, 0, 0, 180)
helpThirdText.Text = [[
local helpText3 = [[
Generate Button:
Create the terrain.
Clear Button:
Remove all terrain.
]]
helpThirdText.Parent = helpSecondText
Hydrate(helpText()) {
Name = "HelpText",
Position = UDim2.new(0, 4, 0, 4),
Size = UDim2.new(1, -8, 0, 157),
Text = helpText1,
Parent = terrainHelpFrame,
Hydrate(helpText()) {
Name = "HelpSecondText",
Position = UDim2.new(0, 0, 1, 0),
Size = UDim2.new(1, 0, 0, 180),
Text = helpText2,
Hydrate(helpText()) {
Name = "HelpThirdText",
Position = UDim2.new(0, 0, 0.6, 0),
Size = UDim2.new(1, 0, 0, 180),
Text = helpText3,
},
},
}
-- Used to create a highlighter.
-- A highlighter is a open, rectuangular area displayed in 3D.
@ -225,21 +240,22 @@ function Highlighter.Create(_, ID, color)
highlighter.z = 0
-- 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.selectionPart = New "Part" {
Name = "SelectionPart",
Archivable = false,
Transparency = 1,
Anchored = true,
Locked = true,
CanCollide = false,
FormFactor = Enum.FormFactor.Custom,
}
highlighter.selectionBox = Instance.new "SelectionBox"
highlighter.selectionBox.Name = "box" .. ID
highlighter.selectionBox.Archivable = false
highlighter.selectionBox.Color = color
highlighter.selectionBox.Adornee = highlighter.selectionPart
highlighter.selectionBox = New "SelectionBox" {
Name = "box" .. ID,
Archivable = false,
Color = color,
Adornee = highlighter.selectionPart,
}
setmetatable(highlighter, Highlighter)
return highlighter
@ -257,7 +273,7 @@ end
-- Update where the highlighter is displayed.
-- cellPos - Where to display the highlighter, in cells.
function Highlighter:UpdatePosition(cellPos)
function Highlighter:UpdatePosition(cellPos: Vector3)
if not cellPos then
self:DisablePreview()
return
@ -269,17 +285,20 @@ function Highlighter:UpdatePosition(cellPos)
self.y = cellPos.y
self.z = cellPos.z
local width, length, height =
self.width :: number, self.length :: number, self.height :: number
local lowVec = CellCenterToWorld(
c,
cellPos.x - self.width / 2,
cellPos.x - width / 2,
cellPos.y - 1,
cellPos.z - self.length / 2
cellPos.z - length / 2
)
local highVec = CellCenterToWorld(
c,
cellPos.x + self.width / 2,
cellPos.y + self.height,
cellPos.z + self.length / 2
cellPos.x + width / 2,
cellPos.y + height,
cellPos.z + length / 2
)
regionToSelect = Region3.new(lowVec, highVec)
@ -292,37 +311,17 @@ end
-- length - Length of the area (z direction)
-- width - Width of the area (x direction)
-- height - Height of the area (y direction)
function Highlighter:UpdateDimensions(length, width, height)
function Highlighter:UpdateDimensions(
length: number,
width: number,
height: number
)
self.length = length
self.width = width
self.height = height
self:UpdatePosition(Vector3.new(self.x, self.y, self.z))
end
-- 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
-- Create a standardized slider.
-- name - Name to use for the slider.
-- pos - Position to display the slider at.
@ -333,7 +332,7 @@ end
-- Return:
-- sliderGui - Slider gui object.
-- sliderPosition - Object that can set the slider value.
function CreateStandardSlider(
local function CreateStandardSlider(
name,
pos,
lengthBarPos,
@ -345,21 +344,24 @@ function CreateStandardSlider(
local sliderGui, sliderPosition =
RbxGui.CreateSlider(steps, 0, UDim2.new(0, 0, 0, 0))
sliderGui.Name = name
sliderGui.Parent = parent
sliderGui.Position = pos
sliderGui.Size = UDim2.new(1, 0, 0, 20)
local lengthBar = sliderGui:FindFirstChild "Bar"
lengthBar.Size = UDim2.new(1, -21, 0, 5)
lengthBar.Position = lengthBarPos
Hydrate(sliderGui) {
Name = name,
Parent = parent,
Position = pos,
Size = UDim2.new(1, 0, 0, 20),
}
Hydrate(sliderGui.Bar) {
Size = UDim2.new(1, -21, 0, 5),
Position = lengthBarPos,
}
if nil ~= funcOnChange then
if funcOnChange then
sliderPosition.Changed:connect(function()
funcOnChange(sliderPosition)
end)
end
if nil ~= initValue then
if initValue then
sliderPosition.Value = initValue
end
@ -390,44 +392,6 @@ end
-- return dropdown, updateSelection
-- end
-- Keep common button properties here to make it easer to change them all at once.
-- These are the default properties to use for a button.
local buttonTextColor = Color3.new(1, 1, 1)
local buttonFont = Enum.Font.ArialBold
local buttonFontSize = Enum.FontSize.Size18
-- Create a standard dropdown. Use this for all dropdowns in the popup so it is easy to standardize.
-- name - What to use.
-- pos - Where to position the button. Should be of type UDim2.
-- text - Text to show in the button.
-- funcOnPress - Function to run when the button is pressed.
-- parent - What to set the parent as.
-- Return:
-- button - The button gui.
function CreateStandardButton(name, pos, text, funcOnPress, parent, size)
local button = Instance.new "TextButton"
button.Name = name
button.Position = pos
button.Size = UDim2.new(0, 120, 0, 40)
button.Text = text
if size then
button.Size = size
end
button.Style = Enum.ButtonStyle.RobloxButton
button.TextColor3 = buttonTextColor
button.Font = buttonFont
button.FontSize = buttonFontSize
button.MouseButton1Click:connect(funcOnPress)
button.Parent = parent
return button
end
local cancelValues = {
cancelAction = false, -- Used to cancel currently occuring actions. If set to true then terrain generation will stop.
progressBar = nil, -- Will store the progress bar when needed.
@ -437,30 +401,31 @@ local cancelValues = {
-- Load the progress bar to display when drawing a river.
-- text - Text to display.
function LoadProgressBar(text)
if cancelValues.progressBar == nil then
cancelValues.isDrawing = true
-- Start the progress bar.
cancelValues.progressBar, cancelValues.setAmountFunc, cancelValues.bindForCancel =
RbxGui.CreateLoadingFrame(text)
cancelValues.progressBar.Position =
UDim2.new(0.5, -cancelValues.progressBar.Size.X.Offset / 2, 0, 15)
cancelValues.progressBar.Parent = g
cancelValues.bindForCancel.Event:connect(function(_)
cancelValues.cancelActions = true -- Set the flag that everything should stop.
coroutine.yield()
end)
else
local function LoadProgressBar(text)
if cancelValues.progressBar then
print "Tried to start the progress bar when it was already running."
return
end
cancelValues.isDrawing = true
-- Start the progress bar.
cancelValues.progressBar, cancelValues.setAmountFunc, cancelValues.bindForCancel =
RbxGui.CreateLoadingFrame(text)
cancelValues.progressBar.Position =
UDim2.new(0.5, -cancelValues.progressBar.Size.X.Offset / 2, 0, 15)
cancelValues.progressBar.Parent = g
cancelValues.bindForCancel.Event:connect(function(_)
cancelValues.cancelActions = true -- Set the flag that everything should stop.
coroutine.yield()
end)
end
-- Unload the progress bar.
function UnloadProgressBar()
local function UnloadProgressBar()
cancelValues.isDrawing = false
cancelValues.cancelActions = false
@ -520,8 +485,8 @@ offsetZSliderPosition.Value = (terrainOptions.zpos + 252) / 4 + 1
--FUNCTION DEFINITIONS-
-----------------------
--makes a column of blocks from 1 up to height at location (x,z) in cluster c
function coordHeight(x, z, height)
-- makes a column of blocks from 1 up to height at location (x,z) in cluster c
local function coordHeight(x, z, height)
SetCells(
c,
Region3int16.new(
@ -534,10 +499,10 @@ function coordHeight(x, z, height)
)
end
--makes a heightmap for a layer of mountains (width x depth)
--with a width frequency wf and depthfrequency df (width should be divisible by wf, depth should be divisible by df) (for unsquished results, width/wf = depth/df)
--with a range of amplitudes between 0 and a
function mountLayer(width, depth, wf, df, a)
-- makes a heightmap for a layer of mountains (width x depth)
-- with a width frequency wf and depthfrequency df (width should be divisible by wf, depth should be divisible by df) (for unsquished results, width/wf = depth/df)
-- with a range of amplitudes between 0 and a
local function mountLayer(width, depth, wf, df, a)
local heightmap = {}
for i = 0, width - 1 do
heightmap[i] = {}
@ -599,8 +564,8 @@ function mountLayer(width, depth, wf, df, a)
return heightmap
end
--makes a shell around block at coordinate x, z using heightmap
function makeShell(x, z, heightmap, shellheightmap)
-- makes a shell around block at coordinate x, z using heightmap
local function makeShell(x, z, heightmap, shellheightmap)
local originalheight = heightmap[x][z]
for i = x - 1, x + 1 do
for k = z - 1, z + 1 do
@ -628,13 +593,13 @@ end
-- Set the camera to look at the terrain from a distance so that all terrain will be in view.
-- centerX, centerZ - Center coordinate of land. This doesn't take into account clipping.
-- length, width - Land dimensions.
function SetCamera(centerX, centerZ, length, width, height)
local function SetCamera(centerX, centerZ, length, width, height)
local currCamera = game.Workspace.CurrentCamera
local cameraPos = Vector3.new(0, 400, 1600)
local cameraFocus = Vector3.new(0, height * 4, 0)
-- Nothing set so use the default.
if nil ~= centerX then
if centerX then
local scale = 0
local lengthScale = 0
local widthScale = 0
@ -657,11 +622,7 @@ function SetCamera(centerX, centerZ, length, width, height)
widthScale = 0.7
end
if widthScale > lengthScale then
scale = widthScale
else
scale = lengthScale
end
scale = widthScale > lengthScale and widthScale or lengthScale
local distance = Vector3.new(0, (200 * scale) + 200, (1100 * scale))
cameraPos =
@ -675,12 +636,11 @@ function SetCamera(centerX, centerZ, length, width, height)
end
-- Create terrain based on the current properties.
function GenerateTerrain()
local function GenerateTerrain()
toolbarbutton:SetActive(false)
generateOptions = terrainOptions:Clone()
-- Turn off the plugin
Off()
-- Create the progress bar that will track terrain creation completion.
@ -977,37 +937,45 @@ end
local ConfirmationPopup
-- Unload the conformation popup if it exists.
-- Does nothing if the popup isn't set.
local function ClearConformation()
if ConfirmationPopupObject then
ConfirmationPopupObject:Clear()
ConfirmationPopupObject = nil
end
end
-- Function used by the generate button. Prompts the user first.
-- Will not show if disabled or terrain is being processed.
function ConfirmGenerateTerrain()
local function ConfirmGenerateTerrain()
-- Only do if something isn't already being processed.
if nil == cancelValues.progressBar then
if nil == ConfirmationPopupObject then
if not hideGenerateConformation then
ConfirmationPopupObject = ConfirmationPopup.Create(
"Generate Terrain?",
"Generate",
"Cancel",
function()
ClearConformation()
GenerateTerrain()
end,
ClearConformation,
function()
hideGenerateConformation = not hideGenerateConformation
return not hideGenerateConformation
end
)
else
GenerateTerrain()
end
end
if cancelValues.progressBar or ConfirmationPopupObject then
return
elseif hideGenerateConformation then
GenerateTerrain()
return
end
ConfirmationPopupObject = ConfirmationPopup.Create(
"Generate Terrain?",
"Generate",
"Cancel",
function()
ClearConformation()
GenerateTerrain()
end,
ClearConformation,
function()
hideGenerateConformation = not hideGenerateConformation
return not hideGenerateConformation
end
)
end
-- Clears all terrain.
-- Clearing is immediate.
function ClearTerrain()
local function ClearTerrain()
toolbarbutton:SetActive(false)
Off()
@ -1024,30 +992,29 @@ end
-- Function used by the clear button. Prompts the user first.
-- Will not show if disabled or terrain is being processed.
function ConfirmClearTerrain()
local function ConfirmClearTerrain()
-- Only do if something isn't already being processed.
if nil == cancelValues.progressBar then
if nil == ConfirmationPopupObject then
if not hideClearConformation then
ConfirmationPopupObject = ConfirmationPopup.Create(
"Clear Terrain?",
"Clear",
"Cancel",
function()
ClearConformation()
ClearTerrain()
end,
ClearConformation,
function()
hideClearConformation = not hideClearConformation
return not hideClearConformation
end
)
else
ClearTerrain()
end
end
if cancelValues.progressBar or ConfirmationPopupObject then
return
elseif hideClearConformation then
ClearTerrain()
return
end
ConfirmationPopupObject = ConfirmationPopup.Create(
"Clear Terrain?",
"Clear",
"Cancel",
function()
ClearConformation()
ClearTerrain()
end,
ClearConformation,
function()
hideClearConformation = not hideClearConformation
return not hideClearConformation
end
)
end
-- Used to create a highlighter.
@ -1072,34 +1039,39 @@ function ConfirmationPopup.Create(
confirmFunction,
declineFunction
)
local popup = {}
popup.confirmButton = nil -- Hold the button to confirm a choice.
popup.declineButton = nil -- Hold the button to decline a choice.
popup.confirmationFrame = nil -- Hold the conformation frame.
popup.confirmationText = nil -- Hold the text label to display the conformation message.
popup.confirmationHelpText = nil -- Hold the text label to display the conformation message help.
local popup = {
confirmButton = nil, -- Hold the button to confirm a choice.
declineButton = nil, -- Hold the button to decline a choice.
confirmationFrame = nil, -- Hold the conformation frame.
confirmationText = nil, -- Hold the text label to display the conformation message.
confirmationHelpText = nil, -- Hold the text label to display the conformation message help.
}
popup.confirmationFrame = Instance.new "Frame"
popup.confirmationFrame.Name = "ConfirmationFrame"
popup.confirmationFrame.Size = UDim2.new(0, 280, 0, 140)
popup.confirmationFrame.Position = UDim2.new(
0.5,
-popup.confirmationFrame.Size.X.Offset / 2,
0.5,
-popup.confirmationFrame.Size.Y.Offset / 2
)
popup.confirmationFrame.Style = Enum.FrameStyle.RobloxRound
popup.confirmationFrame.Parent = g
popup.confirmationFrame = New "Frame" {
Name = "ConfirmationFrame",
Size = UDim2.new(0, 280, 0, 140),
Position = UDim2.new(
0.5,
-popup.confirmationFrame.Size.X.Offset / 2,
0.5,
-popup.confirmationFrame.Size.Y.Offset / 2
),
Style = Enum.FrameStyle.RobloxRound,
Parent = g,
}
popup.confirmLabel = CreateStandardLabel(
"ConfirmLabel",
UDim2.new(0, 0, 0, 15),
UDim2.new(1, 0, 0, 24),
confirmText,
popup.confirmationFrame
)
popup.confirmLabel.FontSize = Enum.FontSize.Size18
popup.confirmLabel.TextXAlignment = Enum.TextXAlignment.Center
popup.confirmLabel = Hydrate(
CreateStandardLabel(
"ConfirmLabel",
UDim2.new(0, 0, 0, 15),
UDim2.new(1, 0, 0, 24),
confirmText,
popup.confirmationFrame
)
) {
FontSize = Enum.FontSize.Size18,
TextXAlignment = Enum.TextXAlignment.Center,
}
-- Confirm
popup.confirmButton = CreateStandardButton(
@ -1126,19 +1098,19 @@ end
-- Clear the popup, free up assets.
function ConfirmationPopup:Clear()
if nil ~= self.confirmButton then
if self.confirmButton then
self.confirmButton.Parent = nil
end
if nil ~= self.declineButton then
if self.declineButton then
self.declineButton.Parent = nil
end
if nil ~= self.confirmationFrame then
if self.confirmationFrame then
self.confirmationFrame.Parent = nil
end
if nil ~= self.confirmLabel then
if self.confirmLabel then
self.confirmLabel.Parent = nil
end
@ -1163,7 +1135,8 @@ local widthLabel = CreateStandardLabel(
"",
terrainFrame
)
local _, _ --[[widthSliderGui, widthSliderPosition]] = CreateStandardSlider(
-- local _, _ widthSliderGui, widthSliderPosition =
CreateStandardSlider(
"WidthSliderGui",
UDim2.new(0, 1, 0, 108),
UDim2.new(0, 10, 0.5, -2),
@ -1184,7 +1157,8 @@ local lengthLabel = CreateStandardLabel(
"",
terrainFrame
)
local _, _ --[[lengthSliderGui, lengthSliderPosition]] = CreateStandardSlider(
-- local _, _ lengthSliderGui, lengthSliderPosition =
CreateStandardSlider(
"LengthSliderGui",
UDim2.new(0, 1, 0, 149),
UDim2.new(0, 10, 0.5, -2),
@ -1305,17 +1279,8 @@ CreateStandardButton(
UDim2.new(0, 150, 0, 40)
)
-- Unload the conformation popup if it exists.
-- Does nothing if the popup isn't set.
function ClearConformation()
if nil ~= ConfirmationPopupObject then
ConfirmationPopupObject:Clear()
ConfirmationPopupObject = nil
end
end
-- Run when the popup is activated.
On = function()
function On()
if not c then
return
end
@ -1326,7 +1291,7 @@ On = function()
end
-- Run when the popup is deactivated.
Off = function()
function Off()
toolbarbutton:SetActive(false)
ClearConformation()
on = false

View File

@ -1,10 +1,13 @@
while game == nil do
while not game do
wait()
end
local ChangeHistoryService = game:GetService "ChangeHistoryService"
local CoreGui = game:GetService "CoreGui"
local CreateStandardLabel = require "../Modules/Terrain/CreateStandardLabel"
local New = require("../Modules/New").New
---------------
--PLUGIN SETUP-
---------------
@ -96,19 +99,21 @@ function MouseHighlighter.Create(mouseUse)
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.selectionPart = New "Part" {
Name = "SelectionPart",
Archivable = false,
Transparency = 1,
Anchored = true,
Locked = true,
CanCollide = false,
FormFactor = Enum.FormFactor.Custom,
}
highlighter.selectionBox = New "SelectionBox" {
Archivable = false,
Color = mouseHighlightColor,
Adornee = highlighter.selectionPart,
}
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)
@ -119,7 +124,7 @@ function MouseHighlighter.Create(mouseUse)
-- 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)
function PlaneIntersection(vectorPos)
local currCamera = game.Workspace.CurrentCamera
local startPos = Vector3.new(
currCamera.CoordinateFrame.p.X,
@ -147,7 +152,7 @@ function MouseHighlighter.Create(mouseUse)
-- Update where the highlighter is displayed.
-- position - Where to display the highlighter, in world space.
UpdatePosition = function(position)
function UpdatePosition(position)
if not position then
return
end
@ -214,30 +219,6 @@ end
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-
------
@ -372,7 +353,7 @@ mouse.Button1Down:connect(onClicked)
mouseHighlighter.OnClicked = onClicked
-- Run when the popup is activated.
On = function()
function On()
if not c then
return
end
@ -383,7 +364,7 @@ On = function()
end
-- Run when the popup is deactivated.
Off = function()
function Off()
toolbarbutton:SetActive(false)
on = false

View File

@ -1,10 +1,12 @@
while game == nil do
while not game do
wait()
end
local ChangeHistoryService = game:GetService "ChangeHistoryService"
local CoreGui = game:GetService "CoreGui"
local CreateStandardLabel = require "../Modules/Terrain/CreateStandardLabel"
-----------------
--DEFAULT VALUES-
-----------------
@ -170,30 +172,6 @@ end
-- Create the mouse movement highlighter.
local mouseHighlighter = MouseHighlighter.Create(mouse)
-- 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-
------
@ -283,11 +261,10 @@ mouse.Button1Down:connect(onClicked)
mouseHighlighter.OnClicked = onClicked
-- Run when the popup is activated.
On = function()
function On()
if not c then
return
end
if plugin then
elseif plugin then
plugin:Activate(true)
end
if toolbarbutton then
@ -300,7 +277,7 @@ On = function()
end
-- Run when the popup is deactivated.
Off = function()
function Off()
on = false
if toolbarbutton then

View File

@ -1,10 +1,12 @@
while game == nil do
while not game do
wait()
end
local ChangeHistoryService = game:GetService "ChangeHistoryService"
local CoreGui = game:GetService "CoreGui"
local CreateStandardLabel = require "../Modules/Terrain/CreateStandardLabel"
---------------
--PLUGIN SETUP-
---------------
@ -116,45 +118,9 @@ function MouseHighlighter.Create(mouseUse)
-- 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)
-- Update where the highlighter is displayed.
-- position - Where to display the highlighter, in world space.
function UpdatePosition(position)
local function UpdatePosition(position)
if not position then
return
end
@ -204,6 +170,42 @@ function MouseHighlighter.Create(mouseUse)
end
end
-- 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)
return highlighter
end
@ -231,30 +233,6 @@ g.Parent = CoreGui
-- UI gui load. Required for sliders.
local RbxGui = LoadLibrary "RbxGui"
-- 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
-- Create a standardized slider.
-- name - Name to use for the slider.
-- pos - Position to display the slider at.
@ -639,7 +617,7 @@ mouse.Button1Up:connect(function()
end)
-- Run when the popup is activated.
On = function()
function On()
if not c then
return
end
@ -651,7 +629,7 @@ On = function()
end
-- Run when the popup is deactivated.
Off = function()
function Off()
toolbarbutton:SetActive(false)
on = false

View File

@ -1,10 +1,12 @@
while game == nil do
while not game do
wait()
end
local ChangeHistoryService = game:GetService "ChangeHistoryService"
local CoreGui = game:GetService "CoreGui"
-- local CreateStandardLabel = require "../Modules/Terrain/CreateStandardLabel"
---------------
--PLUGIN SETUP-
---------------
@ -133,9 +135,7 @@ end
function brush(x, y, z)
if depth == 0 then
return
end
if depth > 0 then
elseif depth > 0 then
local findY = findLowPoint(x, y + depth, z)
local yWithDepth = y + depth
@ -171,9 +171,7 @@ end
function updatePreviewSelection(position)
if not position then
return
end
--if not mouse.Target then disablePreview() return end
if depth == 0 then
elseif depth == 0 then -- or not mouse.Target
disablePreview()
return
end
@ -307,21 +305,21 @@ function doFillCells(position, mouseDrag, needsCellPos)
end
function mouseMoved()
if on then
if mousedown == true then
if mousemoving then
return
end
mousemoving = true
local currMousePos = Vector2.new(mouse.X, mouse.Y)
local mouseDrag = currMousePos - lastMousePos
doFillCells(mouse.Hit, mouseDrag, true)
lastMousePos = currMousePos
mousemoving = false
if not on then
return
elseif mousedown == true then
if mousemoving then
return
end
updatePreviewSelection(mouse.Hit)
mousemoving = true
local currMousePos = Vector2.new(mouse.X, mouse.Y)
local mouseDrag = currMousePos - lastMousePos
doFillCells(mouse.Hit, mouseDrag, true)
lastMousePos = currMousePos
mousemoving = false
end
updatePreviewSelection(mouse.Hit)
end
-- Do a line/plane intersection. The line starts at the camera. The plane is at y == 0, normal(0, 1, 0)
@ -403,11 +401,10 @@ end
local brushDragBar
On = function()
function On()
if not c then
return
end
if this then
elseif this then
this:Activate(true)
end
if toolbarbutton then
@ -422,7 +419,7 @@ On = function()
on = true
end
Off = function()
function Off()
if toolbarbutton then
toolbarbutton:SetActive(false)
end
@ -474,30 +471,6 @@ function CreateStandardDropdown(
return dropdown, updateSelection
end
-- 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.
-- local 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
-- Create a standardized slider.
-- name - Name to use for the slider.
-- pos - Position to display the slider at.
@ -546,6 +519,7 @@ local g = Instance.new "ScreenGui"
g.Name = "TerrainBrushGui"
g.Parent = CoreGui
local elevationFrame, elevationHelpFrame, elevationCloseEvent
brushDragBar, elevationFrame, elevationHelpFrame, elevationCloseEvent =
RbxGui.CreatePluginFrame(
"Terrain Brush",

View File

@ -1,4 +1,5 @@
while game == nil do
--!strict
while not game do
wait()
end
@ -47,9 +48,13 @@ local craterDragBar, craterFrame, craterHelpFrame, craterCloseEvent = nil
--FUNCTION DEFINITIONS-
-----------------------
--makes a crater at point (x, y, z) in cluster c
--cd is the depth factor, a percent of the depth of a perfect sphere
function makeCrater(x, y, z, cr, cd)
local function dist(x1, y1, x2, y2)
return math.sqrt(math.pow(x2 - x1, 2) + math.pow(y2 - y1, 2))
end
-- makes a crater at point (x, y, z) in cluster c
-- cd is the depth factor, a percent of the depth of a perfect sphere
local function makeCrater(x, y, z, cr, cd)
local heightmap = {}
for i = x - (cr + 1), x + (cr + 1) do
heightmap[i] = {}
@ -112,10 +117,6 @@ function makeCrater(x, y, z, cr, cd)
end
end
function dist(x1, y1, x2, y2)
return math.sqrt(math.pow(x2 - x1, 2) + math.pow(y2 - y1, 2))
end
local debounce = false
mouse.Button1Down:connect(function()
@ -139,11 +140,10 @@ mouse.Button1Down:connect(function()
ChangeHistoryService:SetWaypoint "Crater"
end)
On = function()
function On()
if not c then
return
end
if this then
elseif this then
this:Activate(true)
end
if toolbarbutton then
@ -155,7 +155,7 @@ On = function()
on = true
end
Off = function()
function Off()
if toolbarbutton then
toolbarbutton:SetActive(false)
end

View File

@ -1,4 +1,5 @@
while game == nil do
--!strict
while not game do
wait()
end
@ -272,11 +273,10 @@ mouse.Button1Down:connect(function()
end
end)
On = function()
function On()
if not c then
return
end
if this then
elseif this then
this:Activate(true)
end
if toolbarbutton then
@ -290,7 +290,7 @@ On = function()
on = true
end
Off = function()
function Off()
if toolbarbutton then
toolbarbutton:SetActive(false)
end
@ -311,6 +311,7 @@ local g = Instance.new "ScreenGui"
g.Name = "RoadGui"
g.Parent = game:GetService "CoreGui"
local roadHelpFrame
roadDragBar, roadFrame, roadHelpFrame, roadCloseEvent =
RbxGui.CreatePluginFrame(
"Roads",

View File

@ -1,4 +1,4 @@
while game == nil do
while not game do
wait()
end
@ -12,6 +12,7 @@ local loaded = false
local on = false
local On, Off
local mouseDown, mouseUp, mouseMove
local this = PluginManager():CreatePlugin()
local mouse = this:GetMouse()
@ -82,29 +83,173 @@ local RbxUtil = LoadLibrary "RbxUtility"
--FUNCTION DEFINITIONS-
-----------------------
function paintWaterfall(setCells)
if setCells then
for i = 1, #setCells do
SetWaterCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
mediumWaterForce,
Enum.WaterDirection.NegY
)
end
end
end
function setWaterDirection(mouseCellPos, setCells)
if not setCells then
return
end
if #setCells <= 0 then
return
for i = 1, #setCells do
SetWaterCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
mediumWaterForce,
Enum.WaterDirection.NegY
)
end
end
-- Factored out this stuff because I didn't like the mutability of the setCells arrays. - Heliodex
local function getSquareCell(x: number, y: number, z: number)
-- local tempCellPos = Vector3.new(x, y, z)
local oldMaterial, oldType, oldOrientation = GetCell(c, x, y, z)
if oldMaterial.Value <= 0 then
return nil
end
return {
xPos = x,
yPos = y,
zPos = z,
theType = oldType,
orientation = oldOrientation,
}
end
local function getSquare(cellPos)
local setCells = {}
local finalX = cellPos.x + radius - 1
local finalZ = cellPos.z + radius - 1
local finalY = cellPos.y + radius - 1
for x = cellPos.x - radius + 1, finalX do
for z = cellPos.z - radius + 1, finalZ do
for y = cellPos.y - radius + 1, finalY do
table.insert(setCells, getSquareCell(x, y, z))
end
end
end
if directionIsDown(lastCell, mouseCellPos) then
return setCells
end
local function getCircularCell(
x: number,
y: number,
z: number,
cellPos,
radiusSquared
)
local tempCellPos = Vector3.new(x, y, z)
local holdDist = tempCellPos - cellPos
local distSq = (holdDist):Dot(holdDist)
if distSq >= radiusSquared then
return nil
end
local oldMaterial, oldType, oldOrientation = GetCell(c, x, y, z)
if oldMaterial.Value <= 0 then
return nil
end
return {
xPos = x,
yPos = y,
zPos = z,
theType = oldType,
orientation = oldOrientation,
}
end
local function getCircular(cellPos)
local setCells = {}
local finalX = cellPos.x + radius
local finalZ = cellPos.z + radius
local finalY = cellPos.y + radius
for x = cellPos.x - radius, finalX do
for z = cellPos.z - radius, finalZ do
for y = cellPos.y - radius, finalY do
table.insert(
setCells,
getCircularCell(x, y, z, cellPos, radius * radius)
)
end
end
end
return setCells
end
local function getAffectedCells(startPos)
if startPos and c then
if brushType == "Circular" then
return getCircular(startPos)
elseif brushType == "Square" then
return getSquare(startPos)
end
end
return {}
end
local function directionIsDown(fromCell, toCell)
if not toCell then
return false
end
if toCell and fromCell then
local direction = (toCell - fromCell).unit
local absX, absY, absZ =
math.abs(direction.X), math.abs(direction.Y), math.abs(direction.Z)
if absY > absX and absY > absZ then
return true
end
end
local viableCells = getAffectedCells(toCell)
if not viableCells or #viableCells < 2 then
return false
end
local lowX, lowY, lowZ =
viableCells[1].xPos, viableCells[1].yPos, viableCells[1].zPos
local highX, highY, highZ = lowX, lowY, lowZ
for i = 2, #viableCells do
if viableCells[i].xPos < lowX then
lowX = viableCells[i].xPos
end
if viableCells[i].xPos > highX then
highX = viableCells[i].xPos
end
if viableCells[i].yPos < lowY then
lowY = viableCells[i].yPos
end
if viableCells[i].yPos > highY then
highY = viableCells[i].yPos
end
if viableCells[i].zPos < lowZ then
lowZ = viableCells[i].zPos
end
if viableCells[i].zPos > highZ then
highZ = viableCells[i].zPos
end
end
local xRange, yRange, zRange =
math.abs(highX - lowX), math.abs(highY - lowY), math.abs(highZ - lowZ)
local xzPlaneArea = xRange * zRange
local xyPlaneArea = xRange * yRange
local yzPlaneArea = yRange * zRange
return xyPlaneArea > xzPlaneArea or yzPlaneArea > xzPlaneArea
end
local function setWaterDirection(mouseCellPos, setCells)
if not setCells or #setCells <= 0 then
return
elseif directionIsDown(lastCell, mouseCellPos) then
paintWaterfall(setCells)
return
end
@ -209,197 +354,122 @@ function setWaterDirection(mouseCellPos, setCells)
)
end
end
else
for i = 1, #setCells do
if setCells[i].xPos == initX then
return
end
for i = 1, #setCells do
if setCells[i].xPos == initX then
SetWaterCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
mediumWaterForce,
down
)
elseif setCells[i].xPos == endX then
SetWaterCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
mediumWaterForce,
up
)
else
if setCells[i].zPos < zMiddle then
SetWaterCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
mediumWaterForce,
down
right
)
elseif setCells[i].xPos == endX then
elseif setCells[i].zPos > zMiddle then
SetWaterCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
mediumWaterForce,
up
left
)
else
if setCells[i].zPos < zMiddle then
if setCells[i].xPos < xMiddle then
SetWaterCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
mediumWaterForce,
right
down
)
elseif setCells[i].zPos > zMiddle then
elseif setCells[i].xPos > xMiddle then
SetWaterCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
mediumWaterForce,
left
up
)
else
if setCells[i].xPos < xMiddle then
SetWaterCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
mediumWaterForce,
down
)
elseif setCells[i].xPos > xMiddle then
SetWaterCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
mediumWaterForce,
up
)
end
end
end
end
end
end
function getSquare(cellPos, setCells)
local finalX = cellPos.x + radius - 1
local finalZ = cellPos.z + radius - 1
local finalY = cellPos.y + radius - 1
for x = cellPos.x - radius + 1, finalX do
for z = cellPos.z - radius + 1, finalZ do
for y = cellPos.y - radius + 1, finalY do
-- local tempCellPos = Vector3.new(x, y, z)
local oldMaterial, oldType, oldOrientation = GetCell(c, x, y, z)
if oldMaterial.Value > 0 then
table.insert(setCells, {
xPos = x,
yPos = y,
zPos = z,
theType = oldType,
orientation = oldOrientation,
})
end
end
end
end
end
function getCircular(cellPos, setCells)
local radiusSquared = radius * radius
local finalX = cellPos.x + radius
local finalZ = cellPos.z + radius
local finalY = cellPos.y + radius
for x = cellPos.x - radius, finalX do
for z = cellPos.z - radius, finalZ do
for y = cellPos.y - radius, finalY do
local tempCellPos = Vector3.new(x, y, z)
local holdDist = tempCellPos - cellPos
local distSq = (holdDist):Dot(holdDist)
if distSq < radiusSquared then
local oldMaterial, oldType, oldOrientation =
GetCell(c, x, y, z)
if oldMaterial.Value > 0 then
table.insert(setCells, {
xPos = x,
yPos = y,
zPos = z,
theType = oldType,
orientation = oldOrientation,
})
end
end
end
end
end
end
function paintCircular(cellPos, setCells)
getCircular(cellPos, setCells)
if currentMaterial ~= waterMaterial then
for i = 1, #setCells do
SetCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
currentMaterial,
setCells[i].theType,
setCells[i].orientation
)
end
end
end
function paintSquare(cellPos, setCells)
getSquare(cellPos, setCells)
if currentMaterial ~= waterMaterial then
for i = 1, #setCells do
SetCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
currentMaterial,
setCells[i].theType,
setCells[i].orientation
)
end
end
end
function paint(startPos)
if startPos and c then
local cellPos = startPos
local setCells = {}
if brushType == "Circular" then
paintCircular(cellPos, setCells)
elseif brushType == "Square" then
paintSquare(cellPos, setCells)
end
if currentMaterial == waterMaterial then
setWaterDirection(cellPos, setCells)
end
return setCells
end
return
end
function getAffectedCells(startPos)
local setCells = {}
if startPos and c then
if brushType == "Circular" then
getCircular(startPos, setCells)
elseif brushType == "Square" then
getSquare(startPos, setCells)
end
end
return setCells
end
function calculateRegion(mouseR)
local function paintWith(
fn: (
Vector3
) -> { xPos: number, yPos: number, zPos: number },
cellPos: Vector3
)
local setCells = fn(cellPos)
if currentMaterial == waterMaterial then
return
end
for i = 1, #setCells do
SetCell(
c,
setCells[i].xPos,
setCells[i].yPos,
setCells[i].zPos,
currentMaterial,
setCells[i].theType,
setCells[i].orientation
)
end
return setCells
end
local function paint(startPos)
if not (startPos and c) then
return
end
local cellPos = startPos
local setCells
if brushType == "Circular" then
setCells = paintWith(getCircular, cellPos)
elseif brushType == "Square" then
setCells = paintWith(getSquare, cellPos)
end
if currentMaterial == waterMaterial then
return setWaterDirection(cellPos, setCells)
end
return setCells
end
local function calculateRegion(mouseR)
local cellPos = WorldToCellPreferSolid(c, mouseR.Hit.p)
local lowVec =
@ -415,7 +485,7 @@ function calculateRegion(mouseR)
)
end
function createSelection(mouseS, massSelection)
local function createSelection(mouseS, massSelection)
currSelectionUpdate, currSelectionDestroy = RbxUtil.SelectTerrainRegion(
calculateRegion(mouseS),
BrickColor.new "Lime green",
@ -424,24 +494,19 @@ function createSelection(mouseS, massSelection)
)
end
function updateSelection(mouseS)
local function updateSelection(mouseS)
if not currSelectionUpdate then
createSelection(mouseS, radius > 4)
else
currSelectionUpdate(
calculateRegion(mouseS),
BrickColor.new "Lime green"
)
end
end
function setPositionDirectionality()
if nil == lastCell then
return
end
currSelectionUpdate(calculateRegion(mouseS), BrickColor.new "Lime green")
end
-- no dragging occured, lets set our water to be stagnant or be a waterfall
if lastCell and not lastLastCell then
local function setPositionDirectionality()
if nil == lastCell then
return
elseif lastCell and not lastLastCell then
-- no dragging occured, lets set our water to be stagnant or be a waterfall
local cellsToSet = paint(lastCell)
if directionIsDown(nil, lastCell) then
paintWaterfall(cellsToSet)
@ -476,23 +541,14 @@ function setPositionDirectionality()
local direction
if absX > absY and absX > absZ then
if overallDirection.X > 0 then
direction = Enum.WaterDirection.X
else
direction = Enum.WaterDirection.NegX
end
direction = overallDirection.X > 0 and Enum.WaterDirection.X
or Enum.WaterDirection.NegX
elseif absY > absX and absY > absZ then
if overallDirection.Y > 0 then
direction = Enum.WaterDirection.Y
else
direction = Enum.WaterDirection.NegY
end
direction = overallDirection.Y > 0 and Enum.WaterDirection.Y
or Enum.WaterDirection.NegY
elseif absZ > absX and absZ > absY then
if overallDirection.Z > 0 then
direction = Enum.WaterDirection.Z
else
direction = Enum.WaterDirection.NegZ
end
direction = overallDirection.Z > 0 and Enum.WaterDirection.Z
or Enum.WaterDirection.NegZ
end
if not direction then -- this should never be hit, but just in case
@ -512,24 +568,27 @@ function setPositionDirectionality()
end
function mouseDown(mouseD)
if on and mouseD.Target == game.Workspace.Terrain then
dragging = true
if mouseD and mouseD.Hit then
if mouseD.Target == game.Workspace.Terrain then
local newCell = WorldToCellPreferSolid(c, mouseD.Hit.p)
if newCell then
local setCells = paint(newCell)
if
currentMaterial == waterMaterial
and directionIsDown(lastCell, newCell)
then
paintWaterfall(setCells)
end
lastCell = newCell
end
end
end
if not (on and mouseD.Target == game.Workspace.Terrain) then
return
end
dragging = true
if
not (mouseD and mouseD.Hit and mouseD.Target == game.Workspace.Terrain)
then
return
end
local newCell = WorldToCellPreferSolid(c, mouseD.Hit.p)
if not newCell then
return
elseif
currentMaterial == waterMaterial
and directionIsDown(lastCell, newCell)
then
paintWaterfall(paint(newCell))
end
lastCell = newCell
end
function mouseUp(_)
@ -547,96 +606,29 @@ function mouseUp(_)
end
function mouseMove(mouseM)
if on then
if mouseM.Target == game.Workspace.Terrain then
if lastCell ~= WorldToCellPreferSolid(c, mouseM.Hit.p) then
updateSelection(mouseM)
local newCell = WorldToCellPreferSolid(c, mouseM.Hit.p)
if dragging then
-- local painting = true
paint(newCell)
if lastCell and newCell then
if (lastCell - newCell).magnitude > 1 then
paintBetweenPoints(lastCell, newCell)
end
end
lastLastCell = lastCell
lastCell = newCell
-- painting = false
end
end
else
destroySelection()
if not on then
return
elseif mouseM.Target == game.Workspace.Terrain then
if lastCell == WorldToCellPreferSolid(c, mouseM.Hit.p) then
return
end
end
end
updateSelection(mouseM)
local newCell = WorldToCellPreferSolid(c, mouseM.Hit.p)
function directionIsDown(fromCell, toCell)
if not toCell then
return false
end
if toCell and fromCell then
local direction = (toCell - fromCell).unit
local absX, absY, absZ =
math.abs(direction.X), math.abs(direction.Y), math.abs(direction.Z)
if absY > absX and absY > absZ then
return true
if not dragging then
return
end
end
local viableCells = getAffectedCells(toCell)
if not viableCells then
return false
end
if #viableCells < 2 then
return false
end
local lowX, lowY, lowZ =
viableCells[1].xPos, viableCells[1].yPos, viableCells[1].zPos
local highX, highY, highZ = lowX, lowY, lowZ
for i = 2, #viableCells do
if viableCells[i].xPos < lowX then
lowX = viableCells[i].xPos
end
if viableCells[i].xPos > highX then
highX = viableCells[i].xPos
end
if viableCells[i].yPos < lowY then
lowY = viableCells[i].yPos
end
if viableCells[i].yPos > highY then
highY = viableCells[i].yPos
end
if viableCells[i].zPos < lowZ then
lowZ = viableCells[i].zPos
end
if viableCells[i].zPos > highZ then
highZ = viableCells[i].zPos
-- local painting = true
paint(newCell)
if lastCell and newCell and (lastCell - newCell).magnitude > 1 then
paintBetweenPoints(lastCell, newCell)
end
lastLastCell = lastCell
lastCell = newCell
-- painting = false
else
destroySelection()
end
local xRange, yRange, zRange =
math.abs(highX - lowX), math.abs(highY - lowY), math.abs(highZ - lowZ)
local xzPlaneArea = xRange * zRange
local xyPlaneArea = xRange * yRange
local yzPlaneArea = yRange * zRange
if xyPlaneArea > xzPlaneArea then
return true
end
if yzPlaneArea > xzPlaneArea then
return true
end
return false
end
function destroySelection()
@ -649,31 +641,33 @@ function destroySelection()
end
end
function moveTowardsGoal(direction, currPos, goalPos, currCell)
if currPos ~= goalPos then
if currPos < goalPos then
if direction == "X" then
currCell = Vector3.new(currCell.X + 1, currCell.Y, currCell.Z)
elseif direction == "Y" then
currCell = Vector3.new(currCell.X, currCell.Y + 1, currCell.Z)
elseif direction == "Z" then
currCell = Vector3.new(currCell.X, currCell.Y, currCell.Z + 1)
end
elseif currPos > goalPos then
if direction == "X" then
currCell = Vector3.new(currCell.X - 1, currCell.Y, currCell.Z)
elseif direction == "Y" then
currCell = Vector3.new(currCell.X, currCell.Y - 1, currCell.Z)
elseif direction == "Z" then
currCell = Vector3.new(currCell.X, currCell.Y, currCell.Z - 1)
end
local function moveTowardsGoal(direction: string, currPos, goalPos, currCell)
if currPos == goalPos then
return currCell
end
if currPos < goalPos then
if direction == "X" then
currCell = Vector3.new(currCell.X + 1, currCell.Y, currCell.Z)
elseif direction == "Y" then
currCell = Vector3.new(currCell.X, currCell.Y + 1, currCell.Z)
elseif direction == "Z" then
currCell = Vector3.new(currCell.X, currCell.Y, currCell.Z + 1)
end
elseif currPos > goalPos then
if direction == "X" then
currCell = Vector3.new(currCell.X - 1, currCell.Y, currCell.Z)
elseif direction == "Y" then
currCell = Vector3.new(currCell.X, currCell.Y - 1, currCell.Z)
elseif direction == "Z" then
currCell = Vector3.new(currCell.X, currCell.Y, currCell.Z - 1)
end
end
return currCell
end
function interpolateOneDim(direction, currPos, goalPos, currCell)
local function interpolateOneDim(direction, currPos, goalPos, currCell)
if currPos ~= goalPos then
currCell = moveTowardsGoal(direction, currPos, goalPos, currCell)
paint(currCell)
@ -696,7 +690,7 @@ function paintBetweenPoints(lastCellP, newCell)
end
end
On = function()
function On()
if not c then
return
end
@ -707,7 +701,7 @@ On = function()
on = true
end
Off = function()
function Off()
toolbarbutton:SetActive(false)
destroySelection()
@ -724,6 +718,7 @@ local g = Instance.new "ScreenGui"
g.Name = "MaterialPainterGui"
g.Parent = CoreGui
local containerFrame
dragBar, containerFrame, helpFrame, closeEvent = RbxGui.CreatePluginFrame(
"Material Brush",
UDim2.new(0, 163, 0, 285),

View File

@ -1,9 +1,12 @@
while game == nil do
while not game do
wait()
end
local ContentProvider = game:GetService "ContentProvider"
local CoreGui = game:GetService "CoreGui"
local News = require "../Modules/New"
local New = News.New
local Hydrate = News.Hydrate
---------------
--PLUGIN SETUP-
@ -113,11 +116,10 @@ function hideLoadingDialog()
currStampGui.LoadingFrame.Visible = false
end
local partSelected = function(name, id, terrainShape)
if not id then
return
end
if not name then
local stampCon
local function partSelected(name, id, terrainShape)
if not (id and name) then
return
end
@ -146,21 +148,23 @@ local partSelected = function(name, id, terrainShape)
and clusterTag:isA "Vector3Value"
and clusterTag.Value.X == 17
then
local waterForceTag = Instance.new("StringValue", lastStampModel)
waterForceTag.Name = "WaterForceTag"
waterForceTag.Value = waterForceAndDirection[1]
local waterForceDirectionTag =
Instance.new("StringValue", lastStampModel)
waterForceDirectionTag.Name = "WaterForceDirectionTag"
waterForceDirectionTag.Value = waterForceAndDirection[2]
New "StringValue" {
Name = "WaterForceTag",
Value = waterForceAndDirection[1],
Parent = lastStampModel,
}
New "StringValue" {
Name = "WaterForceDirectionTag",
Value = waterForceAndDirection[2],
Parent = lastStampModel,
}
end
end
setupStamper(lastStampModel, mouse)
setupStamper(lastStampModel)
end
function updateWaterInfo()
local function updateWaterInfo()
if stampControl then
stampControl.Destroy()
end
@ -177,70 +181,203 @@ function updateWaterInfo()
local clusterTag = lastStampModel:FindFirstChild "ClusterMaterial"
-- we are going to stamp water, send info to stamper about this
if clusterTag and clusterTag.Value.X == 17 then
local waterForceTag = Instance.new("StringValue", lastStampModel)
waterForceTag.Name = "WaterForceTag"
waterForceTag.Value = waterForceAndDirection[1]
local waterForceDirectionTag =
Instance.new("StringValue", lastStampModel)
waterForceDirectionTag.Name = "WaterForceDirectionTag"
waterForceDirectionTag.Value = waterForceAndDirection[2]
New "StringValue" {
Name = "WaterForceTag",
Value = waterForceAndDirection[1],
Parent = lastStampModel,
}
New "StringValue" {
Name = "WaterForceDirectionTag",
Value = waterForceAndDirection[2],
Parent = lastStampModel,
}
end
end
setupStamper(lastStampModel, mouse)
setupStamper(lastStampModel)
end
local dialogClosed = function()
if lastStampModel then
if stampControl then
stampControl.Destroy()
end
setupStamper(lastStampModel, mouse)
local function dialogClosed()
if not lastStampModel then
return
elseif stampControl then
stampControl.Destroy()
end
setupStamper(lastStampModel)
end
function pickPart()
local function pickPart()
if stampControl then
stampControl.Destroy()
end
setPanelVisibility(true)
end
function keyHandler(key)
if key == "f" then
handlePartShow()
end
end
function partOn()
pickPart()
end
function partOff()
setPanelVisibility(false)
if lastStampModel then
if stampControl then
stampControl.Destroy()
local function keyHandler(key)
if key ~= "f" then
return
elseif getPanelVisibility() then
-- handlePartShow
setPanelVisibility(false)
if lastStampModel then
if stampControl then
stampControl.Destroy()
end
setupStamper(lastStampModel)
end
setupStamper(lastStampModel, mouse)
end
end
function handlePartShow()
if getPanelVisibility() then
partOff()
else
partOn()
pickPart()
end
end
On = function()
if not game.Workspace.Terrain then
function setupStamper(model)
if not model then
return
end
stampControl = getRbxStamper().SetupStamperDragger(model, mouse)
if not stampControl then
return
end
stampCon = stampControl.Stamped.Changed:connect(function()
if stampControl.Stamped.Value then
stampControl.ReloadModel()
end
end)
end
function updateRecentParts(newName, newId, newTerrainShape)
if not newId then
return
end
if this then
for i = 1, #recentButtonStack do
if recentButtonStack[i].Id == newId then -- already have item, nothing to do
return
end
end
for i = #recentButtonStack - 1, 1, -1 do
recentButtonStack[i + 1].Id = recentButtonStack[i].Id
recentButtonStack[i + 1].Name = recentButtonStack[i].Name
recentButtonStack[i + 1].TerrainShape =
recentButtonStack[i].TerrainShape
recentButtonStack[i + 1].Button.Image =
recentButtonStack[i].Button.Image
end
recentButtonStack[1].Id = newId
recentButtonStack[1].Name = newName
recentButtonStack[1].TerrainShape = newTerrainShape
recentButtonStack[1].Button.Image = BaseUrl
.. "Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=75&ht=75&aid="
.. tostring(newId)
end
------
--GUI-
------
function createGui()
--Insert Panel
currStampGui, setPanelVisibility, getPanelVisibility, waterTypeChangedEvent =
getRbxGui().CreateSetPanel(
userSetIds,
partSelected,
dialogClosed,
UDim2.new(0.8, 0, 0.9, 0),
UDim2.new(0.1, 0, 0.05, 0),
true
)
setPanelVisibility(false)
currStampGui.Parent = CoreGui
waterTypeChangedEvent.Event:connect(function(waterTable)
waterForceAndDirection = waterTable
updateWaterInfo()
end)
-- Loading Gui
New "Frame" {
Name = "LoadingFrame",
Style = Enum.FrameStyle.RobloxRound,
Size = UDim2.new(0, 350, 0, 60),
Visible = false,
Position = UDim2.new(0.5, -175, 0.5, -30),
Parent = currStampGui,
New "TextLabel" {
Name = "LoadingText",
BackgroundTransparency = 1,
Size = UDim2.new(0, 155, 1, 0),
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size36,
Text = "Loading...",
TextColor3 = Color3.new(1, 1, 1),
TextStrokeTransparency = 0,
},
}
-- Recents Stack Gui
recentsFrame = New "Frame" {
BackgroundTransparency = 0.5,
Name = "RecentsFrame",
BackgroundColor3 = Color3.new(0, 0, 0),
Size = UDim2.new(0, 50, 0, 150),
Visible = false,
Parent = currStampGui,
}
local function recentButton()
return New "ImageButton" {
Style = Enum.ButtonStyle.RobloxButton,
}
end
for i = 1, 3 do
recentButtonStack[i] = {}
recentButtonStack[i].Name = nil
recentButtonStack[i].Id = nil
recentButtonStack[i].TerrainShape = nil
end
recentButtonStack[1].Button = Hydrate(recentButton()) {
Name = "RecentButtonOne",
Size = UDim2.new(0, 50, 0, 50),
Parent = recentsFrame,
}
recentButtonStack[2].Button = Hydrate(recentButton()) {
Name = "RecentButtonTwo",
Position = UDim2.new(0, 0, 0, 50),
Parent = recentsFrame,
}
recentButtonStack[3].Button = Hydrate(recentButton()) {
Name = "RecentButtonThree",
Position = UDim2.new(0, 0, 0, 100),
Parent = recentsFrame,
}
local buttonClicked = false
for i = 1, #recentButtonStack do
recentButtonStack[i].Button.MouseButton1Click:connect(function()
if buttonClicked then
return
end
buttonClicked = true
partSelected(
recentButtonStack[i].Name,
recentButtonStack[i].Id,
recentButtonStack[i].TerrainShape
)
buttonClicked = false
end)
end
end
function On()
if not game.Workspace.Terrain then
return
elseif this then
this:Activate(true)
mouse = this:GetMouse()
end
@ -268,7 +405,7 @@ On = function()
on = true
end
Off = function()
function Off()
if toolbarbutton then
toolbarbutton:SetActive(false)
end
@ -301,144 +438,6 @@ Off = function()
on = false
end
function setupStamper(model, mouse)
if model then
stampControl = getRbxStamper().SetupStamperDragger(model, mouse)
if stampControl then
stampCon = stampControl.Stamped.Changed:connect(function()
if stampControl.Stamped.Value then
stampControl.ReloadModel()
end
end)
end
end
end
function updateRecentParts(newName, newId, newTerrainShape)
if newId then
for i = 1, #recentButtonStack do
if recentButtonStack[i].Id == newId then -- already have item, nothing to do
return
end
end
for i = #recentButtonStack - 1, 1, -1 do
recentButtonStack[i + 1].Id = recentButtonStack[i].Id
recentButtonStack[i + 1].Name = recentButtonStack[i].Name
recentButtonStack[i + 1].TerrainShape =
recentButtonStack[i].TerrainShape
recentButtonStack[i + 1].Button.Image =
recentButtonStack[i].Button.Image
end
recentButtonStack[1].Id = newId
recentButtonStack[1].Name = newName
recentButtonStack[1].TerrainShape = newTerrainShape
recentButtonStack[1].Button.Image = BaseUrl
.. "Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=75&ht=75&aid="
.. tostring(newId)
end
end
------
--GUI-
------
function createGui()
--Insert Panel
currStampGui, setPanelVisibility, getPanelVisibility, waterTypeChangedEvent =
getRbxGui().CreateSetPanel(
userSetIds,
partSelected,
dialogClosed,
UDim2.new(0.8, 0, 0.9, 0),
UDim2.new(0.1, 0, 0.05, 0),
true
)
setPanelVisibility(false)
currStampGui.Parent = CoreGui
waterTypeChangedEvent.Event:connect(function(waterTable)
waterForceAndDirection = waterTable
updateWaterInfo()
end)
-- Loading Gui
local loadingFrame = Instance.new "Frame"
loadingFrame.Name = "LoadingFrame"
loadingFrame.Style = Enum.FrameStyle.RobloxRound
loadingFrame.Size = UDim2.new(0, 350, 0, 60)
loadingFrame.Visible = false
loadingFrame.Position = UDim2.new(0.5, -175, 0.5, -30)
local loadingText = Instance.new "TextLabel"
loadingText.Name = "LoadingText"
loadingText.BackgroundTransparency = 1
loadingText.Size = UDim2.new(0, 155, 1, 0)
loadingText.Font = Enum.Font.ArialBold
loadingText.FontSize = Enum.FontSize.Size36
loadingText.Text = "Loading..."
loadingText.TextColor3 = Color3.new(1, 1, 1)
loadingText.TextStrokeTransparency = 0
loadingText.Parent = loadingFrame
loadingFrame.Parent = currStampGui
-- Recents Stack Gui
recentsFrame = Instance.new "Frame"
recentsFrame.BackgroundTransparency = 0.5
recentsFrame.Name = "RecentsFrame"
recentsFrame.BackgroundColor3 = Color3.new(0, 0, 0)
recentsFrame.Size = UDim2.new(0, 50, 0, 150)
recentsFrame.Visible = false
recentsFrame.Parent = currStampGui
local recentButtonOne = Instance.new "ImageButton"
recentButtonOne.Style = Enum.ButtonStyle.RobloxButton
recentButtonOne.Name = "RecentButtonOne"
recentButtonOne.Size = UDim2.new(0, 50, 0, 50)
recentButtonOne.Parent = recentsFrame
local recentButtonTwo = recentButtonOne:clone()
recentButtonTwo.Name = "RecentButtonTwo"
recentButtonTwo.Position = UDim2.new(0, 0, 0, 50)
recentButtonTwo.Parent = recentsFrame
local recentButtonThree = recentButtonOne:clone()
recentButtonThree.Name = "RecentButtonThree"
recentButtonThree.Position = UDim2.new(0, 0, 0, 100)
recentButtonThree.Parent = recentsFrame
for i = 1, 3 do
recentButtonStack[i] = {}
recentButtonStack[i].Name = nil
recentButtonStack[i].Id = nil
recentButtonStack[i].TerrainShape = nil
end
recentButtonStack[1].Button = recentButtonOne
recentButtonStack[2].Button = recentButtonTwo
recentButtonStack[3].Button = recentButtonThree
local buttonClicked = false
for i = 1, #recentButtonStack do
recentButtonStack[i].Button.MouseButton1Click:connect(function()
if buttonClicked then
return
end
buttonClicked = true
partSelected(
recentButtonStack[i].Name,
recentButtonStack[i].Id,
recentButtonStack[i].TerrainShape
)
buttonClicked = false
end)
end
end
--------------------------
--SUCCESSFUL LOAD MESSAGE-
--------------------------

View File

@ -1,4 +1,4 @@
while game == nil do
while not game do
wait()
end
@ -6,6 +6,12 @@ local ChangeHistoryService = game:GetService "ChangeHistoryService"
local ContentProvider = game:GetService "ContentProvider"
local CoreGui = game:GetService "CoreGui"
local CreateStandardButton = require "../Modules/Terrain/CreateStandardButton"
local CreateStandardLabel = require "../Modules/Terrain/CreateStandardLabel"
local News = require "../Modules/New"
local New = News.New
local Hydrate = News.Hydrate
---------------
--PLUGIN SETUP-
---------------
@ -13,6 +19,7 @@ local loaded = false
local on = false
local On, Off
local mouseDown, mouseUp
local this = PluginManager():CreatePlugin()
local mouse = this:GetMouse()
@ -139,9 +146,6 @@ function MouseHighlighter.Create(mouseUse)
highlighter.selectionPart = nil
-- Hook the mouse up to check for movement.
mouseH.Move:connect(function()
MouseMoved()
end)
mouseH.Button1Down:connect(function()
highlighter.mouseDown = true
@ -239,9 +243,7 @@ function MouseHighlighter.Create(mouseUse)
local function UpdatePosition(position)
if not position then
return
end
if not mouseH.Target then
elseif not mouseH.Target then
stopTween()
highlighter.selectionPart.Parent = nil
return
@ -297,12 +299,12 @@ function MouseHighlighter.Create(mouseUse)
end
end
-- Function to call when the mouse has moved. Updates where to display the highlighter.
function MouseMoved()
-- Function to call when the mouse has moved. Updates where to display the highlighter.
mouseH.Move:connect(function()
if on and not processing then
UpdatePosition(mouseH.Hit)
end
end
end)
return highlighter
end
@ -338,68 +340,6 @@ mouseHighlighter:DisablePreview()
local ConfirmationPopup = {}
ConfirmationPopup.__index = ConfirmationPopup
-- 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
-- Keep common button properties here to make it easer to change them all at once.
-- These are the default properties to use for a button.
local buttonTextColor = Color3.new(1, 1, 1)
local buttonFont = Enum.Font.ArialBold
local buttonFontSize = Enum.FontSize.Size18
-- Create a standard dropdown. Use this for all dropdowns in the popup so it is easy to standardize.
-- name - What to use.
-- pos - Where to position the button. Should be of type UDim2.
-- text - Text to show in the button.
-- funcOnPress - Function to run when the button is pressed.
-- parent - What to set the parent as.
-- Return:
-- button - The button gui.
function CreateStandardButton(name, pos, text, funcOnPress, parent, size)
local button = Instance.new "TextButton"
button.Name = name
button.Position = pos
button.Size = UDim2.new(0, 120, 0, 40)
button.Text = text
if size then
button.Size = size
end
button.Style = Enum.ButtonStyle.RobloxButton
button.TextColor3 = buttonTextColor
button.Font = buttonFont
button.FontSize = buttonFontSize
button.Parent = parent
button.MouseButton1Click:connect(funcOnPress)
return button
end
-- Create a confirmation popup.
--
-- confirmText - What to display in the popup.
@ -417,46 +357,54 @@ function ConfirmationPopup.Create(
confirmFunction,
declineFunction
)
local popup = {}
popup.confirmButton = nil -- Hold the button to confirm a choice.
popup.declineButton = nil -- Hold the button to decline a choice.
popup.confirmationFrame = nil -- Hold the conformation frame.
popup.confirmationText = nil -- Hold the text label to display the conformation message.
popup.confirmationHelpText = nil -- Hold the text label to display the conformation message help.
local popup = {
confirmButton = nil, -- Hold the button to confirm a choice.
declineButton = nil, -- Hold the button to decline a choice.
confirmationFrame = nil, -- Hold the conformation frame.
confirmationText = nil, -- Hold the text label to display the conformation message.
confirmationHelpText = nil, -- Hold the text label to display the conformation message help.
}
popup.confirmationFrame = Instance.new "Frame"
popup.confirmationFrame.Name = "ConfirmationFrame"
popup.confirmationFrame.Size = UDim2.new(0, 280, 0, 160)
popup.confirmationFrame.Position = UDim2.new(
0.5,
-popup.confirmationFrame.Size.X.Offset / 2,
0.5,
-popup.confirmationFrame.Size.Y.Offset / 2
)
popup.confirmationFrame.Style = Enum.FrameStyle.RobloxRound
popup.confirmationFrame.Parent = screenGui
popup.confirmationFrame = New "Frame" {
Name = "ConfirmationFrame",
Size = UDim2.new(0, 280, 0, 160),
Position = UDim2.new(
0.5,
-popup.confirmationFrame.Size.X.Offset / 2,
0.5,
-popup.confirmationFrame.Size.Y.Offset / 2
),
Style = Enum.FrameStyle.RobloxRound,
Parent = screenGui,
}
popup.confirmLabel = CreateStandardLabel(
"ConfirmLabel",
UDim2.new(0, 0, 0, 15),
UDim2.new(1, 0, 0, 24),
confirmText,
popup.confirmationFrame
)
popup.confirmLabel.FontSize = Enum.FontSize.Size18
popup.confirmLabel.TextXAlignment = Enum.TextXAlignment.Center
popup.confirmLabel = Hydrate(
CreateStandardLabel(
"ConfirmLabel",
UDim2.new(0, 0, 0, 15),
UDim2.new(1, 0, 0, 24),
confirmText,
popup.confirmationFrame
)
) {
FontSize = Enum.FontSize.Size18,
TextXAlignment = Enum.TextXAlignment.Center,
}
popup.confirmationHelpText = CreateStandardLabel(
"ConfirmSmallLabel",
UDim2.new(0, 0, 0, 40),
UDim2.new(1, 0, 0, 28),
confirmSmallText,
popup.confirmationFrame
)
popup.confirmationHelpText.FontSize = Enum.FontSize.Size14
popup.confirmationHelpText.TextWrap = true
popup.confirmationHelpText.Font = Enum.Font.Arial
popup.confirmationHelpText.TextXAlignment = Enum.TextXAlignment.Center
popup.confirmationHelpText = Hydrate(
CreateStandardLabel(
"ConfirmSmallLabel",
UDim2.new(0, 0, 0, 40),
UDim2.new(1, 0, 0, 28),
confirmSmallText,
popup.confirmationFrame
)
) {
FontSize = Enum.FontSize.Size14,
TextWrap = true,
Font = Enum.Font.Arial,
TextXAlignment = Enum.TextXAlignment.Center,
}
-- Confirm
popup.confirmButton = CreateStandardButton(
@ -509,68 +457,11 @@ end
--FUNCTION DEFINITIONS-
-----------------------
local floodFill = function(x, y, z)
LoadProgressBar "Processing"
breadthFill(x, y, z)
UnloadProgressBar()
ChangeHistoryService:SetWaypoint "FloodFill"
end
-- Function used when we try and flood fill. Prompts the user first.
-- Will not show if disabled or terrain is being processed.
function ConfirmFloodFill(x, y, z)
-- Only do if something isn't already being processed.
if not processing then
processing = true
if nil == ConfirmationPopupObject then
ConfirmationPopupObject = ConfirmationPopup.Create(
"Flood Fill At Selected Location?",
"This operation may take some time.",
"Fill",
"Cancel",
function()
ConfirmationPopupObject:Clear()
ConfirmationPopupObject = nil
floodFill(x, y, z)
ConfirmationPopupObject = nil
end,
function()
ConfirmationPopupObject:Clear()
ConfirmationPopupObject = nil
processing = false
end
)
end
end
end
function mouseDown(mouseD)
if on and mouseD.Target == game.Workspace.Terrain then
startCell = mouseHighlighter:GetPosition()
end
end
function mouseUp(_)
if processing then
return
end
local upCell = mouseHighlighter:GetPosition()
if startCell == upCell then
ConfirmFloodFill(upCell.x, upCell.y, upCell.z)
end
end
function getMaterial(x, y, z)
local material = GetCell(c, x, y, z)
return material
end
-- function startLoadingFrame() end
-- Load the progress bar to display when drawing a river.
-- text - Text to display.
function LoadProgressBar(text)
local function LoadProgressBar(text)
processing = true
-- Start the progress bar.
@ -597,31 +488,33 @@ function LoadProgressBar(text)
-- spin = false
end)
local spinnerFrame = Instance.new "Frame"
spinnerFrame.Name = "Spinner"
spinnerFrame.Size = UDim2.new(0, 80, 0, 80)
spinnerFrame.Position = UDim2.new(0.5, -40, 0.5, -55)
spinnerFrame.BackgroundTransparency = 1
spinnerFrame.Parent = progressBar
local spinnerFrame = New "Frame" {
Name = "Spinner",
Size = UDim2.new(0, 80, 0, 80),
Position = UDim2.new(0.5, -40, 0.5, -55),
BackgroundTransparency = 1,
Parent = progressBar,
}
local spinnerIcons = {}
local spinnerNum = 1
while spinnerNum <= 8 do
local spinnerImage = Instance.new "ImageLabel"
spinnerImage.Name = "Spinner" .. spinnerNum
spinnerImage.Size = UDim2.new(0, 16, 0, 16)
spinnerImage.Position = UDim2.new(
0.5 + 0.3 * math.cos(math.rad(45 * spinnerNum)),
-8,
0.5 + 0.3 * math.sin(math.rad(45 * spinnerNum)),
-8
)
spinnerImage.BackgroundTransparency = 1
spinnerImage.Image = "http://banland.xyz/asset?id=45880710"
spinnerImage.Parent = spinnerFrame
local spinnerImage = New "ImageLabel" {
Name = "Spinner" .. spinnerNum,
Size = UDim2.new(0, 16, 0, 16),
Position = UDim2.new(
0.5 + 0.3 * math.cos(math.rad(45 * spinnerNum)),
-8,
0.5 + 0.3 * math.sin(math.rad(45 * spinnerNum)),
-8
),
BackgroundTransparency = 1,
Image = "http://banland.xyz/asset?id=45880710",
Parent = spinnerFrame,
}
spinnerIcons[spinnerNum] = spinnerImage
spinnerNum = spinnerNum + 1
spinnerNum += 1
end
--Make it spin
@ -648,7 +541,7 @@ function LoadProgressBar(text)
end
-- Unload the progress bar.
function UnloadProgressBar()
local function UnloadProgressBar()
processing = false
if progressBar then
@ -663,36 +556,68 @@ function UnloadProgressBar()
end
end
function breadthFill(x, y, z)
local yDepthChecks = doBreadthFill(x, y, z)
while yDepthChecks and #yDepthChecks > 0 do
local newYChecks = {}
for i = 1, #yDepthChecks do
local currYDepthChecks = doBreadthFill(
yDepthChecks[i].xPos,
yDepthChecks[i].yPos,
yDepthChecks[i].zPos
)
local function floodFill(x, y, z)
LoadProgressBar "Processing"
breadthFill(x, y, z)
UnloadProgressBar()
ChangeHistoryService:SetWaypoint "FloodFill"
end
if not processing then
return
end
-- Function used when we try and flood fill. Prompts the user first.
-- Will not show if disabled or terrain is being processed.
local function ConfirmFloodFill(x, y, z)
-- Only do if something isn't already being processed.
if processing then
return
end
if currYDepthChecks and #currYDepthChecks > 0 then
for j = 1, #currYDepthChecks do
table.insert(newYChecks, {
xPos = currYDepthChecks[j].xPos,
yPos = currYDepthChecks[j].yPos,
zPos = currYDepthChecks[j].zPos,
})
end
end
processing = true
if ConfirmationPopupObject then
return
end
ConfirmationPopupObject = ConfirmationPopup.Create(
"Flood Fill At Selected Location?",
"This operation may take some time.",
"Fill",
"Cancel",
function()
ConfirmationPopupObject:Clear()
ConfirmationPopupObject = nil
floodFill(x, y, z)
ConfirmationPopupObject = nil
end,
function()
ConfirmationPopupObject:Clear()
ConfirmationPopupObject = nil
processing = false
end
yDepthChecks = newYChecks
)
end
function mouseDown(mouseD)
if on and mouseD.Target == game.Workspace.Terrain then
startCell = mouseHighlighter:GetPosition()
end
end
function doBreadthFill(x, y, z)
function mouseUp(_)
if processing then
return
end
local upCell = mouseHighlighter:GetPosition()
if startCell == upCell then
ConfirmFloodFill(upCell.x, upCell.y, upCell.z)
end
end
local function getMaterial(x, y, z)
local material = GetCell(c, x, y, z)
return material
end
local function doBreadthFill(x, y, z)
if getMaterial(x, y, z) ~= emptyMaterial then
return
end
@ -735,7 +660,36 @@ function doBreadthFill(x, y, z)
return yDepthChecks
end
function cellInTerrain(x, y, z)
function breadthFill(x, y, z)
local yDepthChecks = doBreadthFill(x, y, z)
while yDepthChecks and #yDepthChecks > 0 do
local newYChecks = {}
for i = 1, #yDepthChecks do
local currYDepthChecks = doBreadthFill(
yDepthChecks[i].xPos,
yDepthChecks[i].yPos,
yDepthChecks[i].zPos
)
if
not (processing and currYDepthChecks and #currYDepthChecks > 0)
then
return
end
for j = 1, #currYDepthChecks do
table.insert(newYChecks, {
xPos = currYDepthChecks[j].xPos,
yPos = currYDepthChecks[j].yPos,
zPos = currYDepthChecks[j].zPos,
})
end
end
yDepthChecks = newYChecks
end
end
local function cellInTerrain(x, y, z)
if x < c.MaxExtents.Min.X or x >= c.MaxExtents.Max.X then
return false
end
@ -811,8 +765,7 @@ end
On = function()
if not c then
return
end
if this then
elseif this then
this:Activate(true)
end
if toolbarbutton then
@ -858,25 +811,27 @@ dragBar, containerFrame, helpFrame, closeEvent = RbxGui.CreatePluginFrame(
)
dragBar.Visible = false
helpFrame.Size = UDim2.new(0, 200, 0, 190)
local textHelp = Instance.new "TextLabel"
textHelp.Name = "TextHelp"
textHelp.Font = Enum.Font.ArialBold
textHelp.FontSize = Enum.FontSize.Size12
textHelp.TextColor3 = Color3.new(1, 1, 1)
textHelp.Size = UDim2.new(1, -6, 1, -6)
textHelp.Position = UDim2.new(0, 3, 0, 3)
textHelp.TextXAlignment = Enum.TextXAlignment.Left
textHelp.TextYAlignment = Enum.TextYAlignment.Top
textHelp.BackgroundTransparency = 1
textHelp.TextWrap = true
textHelp.Text = [[
Hydrate(helpFrame) {
Size = UDim2.new(0, 200, 0, 190),
-- "This will be pdfs in 2024" - Heliodex
New "TextLabel" {
Name = "TextHelp",
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size12,
TextColor3 = Color3.new(1, 1, 1),
Size = UDim2.new(1, -6, 1, -6),
Position = UDim2.new(0, 3, 0, 3),
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
BackgroundTransparency = 1,
TextWrap = true,
Text = [[
Quickly replace empty terrain cells with a selected material. Clicking the mouse will cause any empty terrain cells around the point clicked to be filled with the current material, and will also spread to surrounding empty cells (including any empty cells below, but not above).
Simply click on a different material to fill with that material. The floating paint bucket and cube indicate where filling will start.
]]
textHelp.Parent = helpFrame
]],
},
}
closeEvent.Event:connect(function()
Off()