2013/luau/45284430.luau

4486 lines
111 KiB
Plaintext

--!strict
-- RbxGui
print "[Mercury]: Loaded corescript 45284430"
local ContentProvider = game:GetService "ContentProvider"
local InsertService = game:GetService "InsertService"
local RunService = game:GetService "RunService"
local News = require "../Modules/New"
local New = News.New
local Hydrate = News.Hydrate
local BaseUrl = require "../Modules/BaseUrl"
local path = BaseUrl.path
local RbxGui = {}
local function ScopedConnect(
parentInstance,
instance,
event,
signalFunc,
syncFunc: (() -> ())?,
removeFunc: (() -> ())?
)
local eventConnection
--Connection on parentInstance is scoped by parentInstance (when destroyed, it goes away)
local function tryConnect()
if game:IsAncestorOf(parentInstance) and not eventConnection then
--Entering the world, make sure we are connected/synced
eventConnection = instance[event]:connect(signalFunc)
if syncFunc then
syncFunc()
end
elseif eventConnection then
--Probably leaving the world, so disconnect for now
eventConnection:disconnect()
if removeFunc then
removeFunc()
end
end
end
--Hook it up to ancestryChanged signal
local connection = parentInstance.AncestryChanged:connect(tryConnect)
--Now connect us if we're already in the world
tryConnect()
return connection
end
local function getScreenGuiAncestor(instance)
local localInstance = instance
while localInstance and not localInstance:IsA "ScreenGui" do
localInstance = localInstance.Parent
end
return localInstance
end
local function Colour3(r: number, g: number, b: number)
return Color3.new(r / 255, g / 255, b / 255)
end
local function CreateButtons(frame, buttons, yPos, ySize)
local buttonNum = 1
local buttonObjs = {}
for _, obj in ipairs(buttons) do
buttonObjs[buttonNum] = New "TextButton" {
Name = "Button" .. buttonNum,
Font = Enum.Font.Arial,
FontSize = Enum.FontSize.Size18,
AutoButtonColor = true,
Modal = true,
Style = obj.Style or Enum.ButtonStyle.RobloxButton,
Text = obj.Text,
TextColor3 = Color3.new(1, 1, 1),
Parent = frame,
}
buttonNum += 1
end
local numButtons = buttonNum - 1
if numButtons == 1 then
frame.Button1.Position = UDim2.new(0.35, 0, yPos.Scale, yPos.Offset)
frame.Button1.Size = UDim2.new(0.4, 0, ySize.Scale, ySize.Offset)
elseif numButtons == 2 then
frame.Button1.Position = UDim2.new(0.1, 0, yPos.Scale, yPos.Offset)
frame.Button1.Size = UDim2.new(0.8 / 3, 0, ySize.Scale, ySize.Offset)
frame.Button2.Position = UDim2.new(0.55, 0, yPos.Scale, yPos.Offset)
frame.Button2.Size = UDim2.new(0.35, 0, ySize.Scale, ySize.Offset)
elseif numButtons >= 3 then
local spacing = 0.1 / numButtons
local buttonSize = 0.9 / numButtons
buttonNum = 1
while buttonNum <= numButtons do
buttonObjs[buttonNum].Position = UDim2.new(
spacing * buttonNum + (buttonNum - 1) * buttonSize,
0,
yPos.Scale,
yPos.Offset
)
buttonObjs[buttonNum].Size =
UDim2.new(buttonSize, 0, ySize.Scale, ySize.Offset)
buttonNum += 1
end
end
end
local function setSliderPos(
newAbsPosX: number,
slider: ImageButton,
sliderPosition: IntValue,
bar,
steps: number
)
local newStep = steps - 1 --otherwise we really get one more step than we want
local relativePosX = math.min(
1,
math.max(0, (newAbsPosX - bar.AbsolutePosition.X) / bar.AbsoluteSize.X)
)
local wholeNum, remainder = math.modf(relativePosX * newStep)
if remainder > 0.5 then
wholeNum += 1
end
relativePosX = wholeNum / newStep
local result = math.ceil(relativePosX * newStep)
if sliderPosition.Value ~= (result + 1) then --only update if we moved a step
sliderPosition.Value = result + 1
slider.Position = UDim2.new(
relativePosX,
-slider.AbsoluteSize.X / 2,
slider.Position.Y.Scale,
slider.Position.Y.Offset
)
end
end
local areaSoakMouseMoveCon
local function cancelSlide(areaSoak)
areaSoak.Visible = false
if areaSoakMouseMoveCon then
areaSoakMouseMoveCon:disconnect()
end
end
function RbxGui.CreateMessageDialog(title, message, buttons)
local frame = New "Frame" {
Size = UDim2.new(0.5, 0, 0.5, 0),
Position = UDim2.new(0.25, 0, 0.25, 0),
Name = "MessageDialog",
Active = true,
Style = Enum.FrameStyle.RobloxRound,
New "TextLabel" {
Name = "Title",
Text = title,
BackgroundTransparency = 1,
TextColor3 = Colour3(221, 221, 221),
Position = UDim2.new(0, 0, 0, 0),
Size = UDim2.new(1, 0, 0.15, 0),
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size36,
TextXAlignment = Enum.TextXAlignment.Center,
TextYAlignment = Enum.TextYAlignment.Center,
},
New "TextLabel" {
Name = "Message",
Text = message,
TextColor3 = Colour3(221, 221, 221),
Position = UDim2.new(0.025, 0, 0.175, 0),
Size = UDim2.new(0.95, 0, 0.55, 0),
BackgroundTransparency = 1,
Font = Enum.Font.Arial,
FontSize = Enum.FontSize.Size18,
TextWrapped = true,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
},
}
CreateButtons(frame, buttons, UDim.new(0.8, 0), UDim.new(0.15, 0))
return frame
end
function RbxGui.CreateStyledMessageDialog(title, message, style, buttons)
local frame = New "Frame" {
Size = UDim2.new(0.5, 0, 0, 165),
Position = UDim2.new(0.25, 0, 0.5, -72.5),
Name = "MessageDialog",
Active = true,
Style = Enum.FrameStyle.RobloxRound,
New "TextLabel" {
Name = "Title",
Text = title,
TextStrokeTransparency = 0,
BackgroundTransparency = 1,
TextColor3 = Colour3(221, 221, 221),
Position = UDim2.new(0, 80, 0, 0),
Size = UDim2.new(1, -80, 0, 40),
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size36,
TextXAlignment = Enum.TextXAlignment.Center,
TextYAlignment = Enum.TextYAlignment.Center,
},
New "TextLabel" {
Name = "Message",
Text = message,
TextStrokeTransparency = 0,
TextColor3 = Colour3(221, 221, 221),
Position = UDim2.new(0.025, 80, 0, 45),
Size = UDim2.new(0.95, -80, 0, 55),
BackgroundTransparency = 1,
Font = Enum.Font.Arial,
FontSize = Enum.FontSize.Size18,
TextWrapped = true,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
},
}
local styleImage = New "ImageLabel" {
Name = "StyleImage",
BackgroundTransparency = 1,
Position = UDim2.new(0, 5, 0, 15),
}
if style == "error" or style == "Error" then
styleImage.Size = UDim2.new(0, 71, 0, 71)
styleImage.Image = path "asset?id=42565285"
elseif style == "notify" or style == "Notify" then
styleImage.Size = UDim2.new(0, 71, 0, 71)
styleImage.Image = path "asset?id=42604978"
elseif style == "confirm" or style == "Confirm" then
styleImage.Size = UDim2.new(0, 74, 0, 76)
styleImage.Image = path "asset?id=42557901"
else
return RbxGui.CreateMessageDialog(title, message, buttons)
end
styleImage.Parent = frame
CreateButtons(frame, buttons, UDim.new(0, 105), UDim.new(0, 40))
return frame
end
local scrollMouseCount
function RbxGui.CreateDropDownMenu(
items,
onSelect,
forRoblox: boolean?
): (Frame, (string) -> ())
local width = UDim.new(0, 100)
local height = UDim.new(0, 32)
local frame = New "Frame" {
Name = "DropDownMenu",
BackgroundTransparency = 1,
Size = UDim2.new(width, height),
}
local dropDownMenu = New "TextButton" {
Name = "DropDownMenuButton",
TextWrapped = true,
TextColor3 = Color3.new(1, 1, 1),
Text = "Choose One",
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size18,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Center,
BackgroundTransparency = 1,
AutoButtonColor = true,
Style = Enum.ButtonStyle.RobloxButton,
Size = UDim2.new(1, 0, 1, 0),
Parent = frame,
ZIndex = 2,
New "ImageLabel" {
Name = "Icon",
Active = false,
Image = path "asset?id=45732894",
BackgroundTransparency = 1,
Size = UDim2.new(0, 11, 0, 6),
Position = UDim2.new(1, -11, 0.5, -2),
ZIndex = 2,
},
}
local itemCount = #items
local dropDownItemCount = #items
local useScrollButtons = false
if dropDownItemCount > 6 then
useScrollButtons = true
dropDownItemCount = 6
end
local droppedDownMenu = New "TextButton" {
Name = "List",
Text = "",
BackgroundTransparency = 1,
-- AutoButtonColor = true
Style = Enum.ButtonStyle.RobloxButton,
Visible = false,
Active = true, --Blocks clicks
Position = UDim2.new(0, 0, 0, 0),
Size = UDim2.new(1, 0, (1 + dropDownItemCount) * 0.8, 0),
Parent = frame,
ZIndex = 2,
}
local choiceButton = New "TextButton" {
Name = "ChoiceButton",
BackgroundTransparency = 1,
BorderSizePixel = 0,
Text = "ReplaceMe",
TextColor3 = Color3.new(1, 1, 1),
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Center,
BackgroundColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.Arial,
FontSize = Enum.FontSize.Size18,
TextWrapped = true,
ZIndex = 2,
}
if useScrollButtons then
choiceButton.Size =
UDim2.new(1, -13, 0.8 / ((dropDownItemCount + 1) * 0.8), 0)
else
choiceButton.Size =
UDim2.new(1, 0, 0.8 / ((dropDownItemCount + 1) * 0.8), 0)
end
local areaSoak = New "TextButton" {
Name = "AreaSoak",
Text = "",
BackgroundTransparency = 1,
Active = true,
Size = UDim2.new(1, 0, 1, 0),
Visible = false,
ZIndex = 3,
}
local dropDownSelected = false
local scrollUpButton
local scrollDownButton
scrollMouseCount = 0
local function setZIndex(baseZIndex: number)
droppedDownMenu.ZIndex = baseZIndex + 1
if scrollUpButton then
scrollUpButton.ZIndex = baseZIndex + 3
end
if scrollDownButton then
scrollDownButton.ZIndex = baseZIndex + 3
end
local children = droppedDownMenu:GetChildren()
if not children then
return
end
for _, child in ipairs(children) do
if child.Name == "ChoiceButton" then
child.ZIndex = baseZIndex + 2
elseif child.Name == "ClickCaptureButton" then
child.ZIndex = baseZIndex
end
end
end
local scrollBarPosition = 1
local function updateScroll()
if scrollUpButton then
scrollUpButton.Active = scrollBarPosition > 1
end
if scrollDownButton then
scrollDownButton.Active = scrollBarPosition + dropDownItemCount
<= itemCount
end
local children = droppedDownMenu:GetChildren()
if not children then
return
end
local childNum = 1
for _, obj in ipairs(children) do
if obj.Name == "ChoiceButton" then
if
childNum < scrollBarPosition
or childNum >= scrollBarPosition + dropDownItemCount
then
obj.Visible = false
else
obj.Position = UDim2.new(
0,
0,
((childNum - scrollBarPosition + 1) * 0.8)
/ ((dropDownItemCount + 1) * 0.8),
0
)
obj.Visible = true
end
obj.TextColor3 = Color3.new(1, 1, 1)
obj.BackgroundTransparency = 1
childNum += 1
end
end
end
local function toggleVisibility()
dropDownSelected = not dropDownSelected
areaSoak.Visible = not areaSoak.Visible
dropDownMenu.Visible = not dropDownSelected
droppedDownMenu.Visible = dropDownSelected
setZIndex(dropDownSelected and 4 or 2)
if useScrollButtons then
updateScroll()
end
end
droppedDownMenu.MouseButton1Click:connect(toggleVisibility)
local function updateSelection(text)
local foundItem = false
local children = droppedDownMenu:GetChildren()
local childNum = 1
if children then
for _, obj in ipairs(children) do
if obj.Name == "ChoiceButton" then
if obj.Text == text then
obj.Font = Enum.Font.ArialBold
foundItem = true
scrollBarPosition = childNum
else
obj.Font = Enum.Font.Arial
end
childNum += 1
end
end
end
if not text then
dropDownMenu.Text = "Choose One"
scrollBarPosition = 1
else
if not foundItem then
error("Invalid Selection Update -- " .. text)
end
if scrollBarPosition + dropDownItemCount > itemCount + 1 then
scrollBarPosition = itemCount - dropDownItemCount + 1
end
dropDownMenu.Text = text
end
end
local function scrollDown()
if scrollBarPosition + dropDownItemCount <= itemCount then
scrollBarPosition += 1
updateScroll()
return true
end
return false
end
local function scrollUp()
if scrollBarPosition > 1 then
scrollBarPosition -= 1
updateScroll()
return true
end
return false
end
if useScrollButtons then
--Make some scroll buttons
scrollUpButton = New "ImageButton" {
Name = "ScrollUpButton",
BackgroundTransparency = 1,
Image = "rbxasset://textures/ui/scrollbuttonUp.png",
Size = UDim2.new(0, 17, 0, 17),
Position = UDim2.new(
1,
-11,
(1 * 0.8) / ((dropDownItemCount + 1) * 0.8),
0
),
}
scrollUpButton.MouseButton1Click:connect(function()
scrollMouseCount += 1
end)
scrollUpButton.MouseLeave:connect(function()
scrollMouseCount += 1
end)
scrollUpButton.MouseButton1Down:connect(function()
scrollMouseCount += 1
scrollUp()
local val = scrollMouseCount
wait(0.5)
while val == scrollMouseCount do
if scrollUp() == false then
break
end
wait(0.1)
end
end)
scrollUpButton.Parent = droppedDownMenu
scrollDownButton = New "ImageButton" {
Name = "ScrollDownButton",
BackgroundTransparency = 1,
Image = "rbxasset://textures/ui/scrollbuttonDown.png",
Size = UDim2.new(0, 17, 0, 17),
Position = UDim2.new(1, -11, 1, -11),
Parent = droppedDownMenu,
}
scrollDownButton.MouseButton1Click:connect(function()
scrollMouseCount += 1
end)
scrollDownButton.MouseLeave:connect(function()
scrollMouseCount += 1
end)
scrollDownButton.MouseButton1Down:connect(function()
scrollMouseCount += 1
scrollDown()
local val = scrollMouseCount
wait(0.5)
while val == scrollMouseCount do
if scrollDown() == false then
break
end
wait(0.1)
end
end)
New "ImageLabel" {
Name = "ScrollBar",
Image = "rbxasset://textures/ui/scrollbar.png",
BackgroundTransparency = 1,
Size = UDim2.new(
0,
18,
(dropDownItemCount * 0.8) / ((dropDownItemCount + 1) * 0.8),
-17 - 11 - 4
),
Position = UDim2.new(
1,
-11,
(1 * 0.8) / ((dropDownItemCount + 1) * 0.8),
17 + 2
),
Parent = droppedDownMenu,
}
end
for _, item in ipairs(items) do
-- needed to maintain local scope for items in event listeners below
local button = choiceButton:Clone()
if forRoblox then
button.RobloxLocked = true
end
button.Text = item
button.Parent = droppedDownMenu
button.MouseButton1Click:connect(function()
--Remove Highlight
button.TextColor3 = Color3.new(1, 1, 1)
button.BackgroundTransparency = 1
updateSelection(item)
onSelect(item)
toggleVisibility()
end)
button.MouseEnter:connect(function()
--Add Highlight
button.TextColor3 = Color3.new(0, 0, 0)
button.BackgroundTransparency = 0
end)
button.MouseLeave:connect(function()
--Remove Highlight
button.TextColor3 = Color3.new(1, 1, 1)
button.BackgroundTransparency = 1
end)
end
--This does the initial layout of the buttons
updateScroll()
frame.AncestryChanged:connect(function(_, parent)
if parent == nil then
areaSoak.Parent = nil
else
areaSoak.Parent = getScreenGuiAncestor(frame)
end
end)
dropDownMenu.MouseButton1Click:connect(toggleVisibility)
areaSoak.MouseButton1Click:connect(toggleVisibility)
return frame, updateSelection
end
function RbxGui.CreatePropertyDropDownMenu(instance, property, enum)
local items = enum:GetEnumItems()
local names = {}
local nameToItem = {}
for i, obj in ipairs(items) do
names[i] = obj.Name
nameToItem[obj.Name] = obj
end
local frame
local updateSelection
frame, updateSelection = RbxGui.CreateDropDownMenu(names, function(text)
instance[property] = nameToItem[text]
end)
ScopedConnect(frame, instance, "Changed", function(prop)
if prop == property then
updateSelection(instance[property].Name)
end
end, function()
updateSelection(instance[property].Name)
end)
return frame
end
function RbxGui.GetFontHeight(font, fontSize)
if font == nil or fontSize == nil then
error "Font and FontSize must be non-nil"
end
if font == Enum.Font.Legacy then
if fontSize == Enum.FontSize.Size8 then
return 12
elseif fontSize == Enum.FontSize.Size9 then
return 14
elseif fontSize == Enum.FontSize.Size10 then
return 15
elseif fontSize == Enum.FontSize.Size11 then
return 17
elseif fontSize == Enum.FontSize.Size12 then
return 18
elseif fontSize == Enum.FontSize.Size14 then
return 21
elseif fontSize == Enum.FontSize.Size18 then
return 27
elseif fontSize == Enum.FontSize.Size24 then
return 36
elseif fontSize == Enum.FontSize.Size36 then
return 54
elseif fontSize == Enum.FontSize.Size48 then
return 72
else
error "Unknown FontSize"
end
elseif font == Enum.Font.Arial or font == Enum.Font.ArialBold then
if fontSize == Enum.FontSize.Size8 then
return 8
elseif fontSize == Enum.FontSize.Size9 then
return 9
elseif fontSize == Enum.FontSize.Size10 then
return 10
elseif fontSize == Enum.FontSize.Size11 then
return 11
elseif fontSize == Enum.FontSize.Size12 then
return 12
elseif fontSize == Enum.FontSize.Size14 then
return 14
elseif fontSize == Enum.FontSize.Size18 then
return 18
elseif fontSize == Enum.FontSize.Size24 then
return 24
elseif fontSize == Enum.FontSize.Size36 then
return 36
elseif fontSize == Enum.FontSize.Size48 then
return 48
else
error "Unknown FontSize"
end
else
error("Unknown Font " .. font)
end
end
local function layoutGuiObjectsHelper(frame: Frame, guiObjects, settingsTable)
local totalPixels = frame.AbsoluteSize.Y
local pixelsRemaining = frame.AbsoluteSize.Y
for _, ch in ipairs(guiObjects) do
if ch:IsA "TextLabel" or ch:IsA "TextButton" then
local child = ch :: TextLabel & TextButton -- luau moment
local isLabel = child:IsA "TextLabel"
if isLabel then
pixelsRemaining = pixelsRemaining
- settingsTable.TextLabelPositionPadY
else
pixelsRemaining = pixelsRemaining
- settingsTable.TextButtonPositionPadY
end
child.Position = UDim2.new(
child.Position.X.Scale,
child.Position.X.Offset,
0,
totalPixels - pixelsRemaining
)
child.Size = UDim2.new(
child.Size.X.Scale,
child.Size.X.Offset,
0,
pixelsRemaining
)
if
child.TextFits
and (child.TextBounds.Y :: number) < pixelsRemaining
then
child.Visible = true
if isLabel then
child.Size = UDim2.new(
child.Size.X.Scale,
child.Size.X.Offset,
0,
child.TextBounds.Y + settingsTable.TextLabelSizePadY
)
else
child.Size = UDim2.new(
child.Size.X.Scale,
child.Size.X.Offset,
0,
child.TextBounds.Y + settingsTable.TextButtonSizePadY
)
end
while not child.TextFits do
child.Size = UDim2.new(
child.Size.X.Scale,
child.Size.X.Offset,
0,
child.AbsoluteSize.Y + 1
)
end
pixelsRemaining -= child.AbsoluteSize.Y
if isLabel then
pixelsRemaining = pixelsRemaining
- settingsTable.TextLabelPositionPadY
else
pixelsRemaining = pixelsRemaining
- settingsTable.TextButtonPositionPadY
end
else
child.Visible = false
pixelsRemaining = -1
end
else
local child = ch :: GuiObject
-- GuiObject
child.Position = UDim2.new(
child.Position.X.Scale,
child.Position.X.Offset,
0,
totalPixels - pixelsRemaining
)
pixelsRemaining -= child.AbsoluteSize.Y
child.Visible = (pixelsRemaining >= 0)
end
end
end
function RbxGui.LayoutGuiObjects(frame, guiObjects, settingsTable)
if not frame:IsA "GuiObject" then
error "Frame must be a GuiObject"
end
for _, child in ipairs(guiObjects) do
if not child:IsA "GuiObject" then
error "All elements that are layed out must be of type GuiObject"
end
end
if not settingsTable then
settingsTable = {}
end
if not settingsTable.TextLabelSizePadY then
settingsTable.TextLabelSizePadY = 0
end
if not settingsTable.TextLabelPositionPadY then
settingsTable.TextLabelPositionPadY = 0
end
if not settingsTable.TextButtonSizePadY then
settingsTable.TextButtonSizePadY = 12
end
if not settingsTable.TextButtonPositionPadY then
settingsTable.TextButtonPositionPadY = 2
end
--Wrapper frame takes care of styled objects
local wrapperFrame = Instance.new "Frame"
wrapperFrame.Name = "WrapperFrame"
wrapperFrame.BackgroundTransparency = 1
wrapperFrame.Size = UDim2.new(1, 0, 1, 0)
wrapperFrame.Parent = frame
for _, child in ipairs(guiObjects) do
child.Parent = wrapperFrame
end
local function recalculate()
RunService.Heartbeat:wait()
layoutGuiObjectsHelper(wrapperFrame, guiObjects, settingsTable)
end
frame.Changed:connect(function(prop)
if prop == "AbsoluteSize" then
--Wait a heartbeat for it to sync in
recalculate()
end
end)
frame.AncestryChanged:connect(recalculate)
layoutGuiObjectsHelper(wrapperFrame, guiObjects, settingsTable)
end
function RbxGui.CreateSlider(steps: number, width: number, position)
local sliderGui = New "Frame" {
Size = UDim2.new(1, 0, 1, 0),
BackgroundTransparency = 1,
Name = "SliderGui",
}
local sliderSteps = New "IntValue" {
Name = "SliderSteps",
Value = steps,
Parent = sliderGui,
}
local areaSoak = New "TextButton" {
Name = "AreaSoak",
Text = "",
BackgroundTransparency = 1,
Active = false,
Size = UDim2.new(1, 0, 1, 0),
Visible = false,
ZIndex = 4,
}
sliderGui.AncestryChanged:connect(function(_, parent)
if parent == nil then
areaSoak.Parent = nil
else
areaSoak.Parent = getScreenGuiAncestor(sliderGui)
end
end)
local sliderPosition = New "IntValue" {
Name = "SliderPosition",
Value = 1,
Parent = sliderGui,
}
local bar = New "TextButton" {
Text = "",
AutoButtonColor = false,
Name = "Bar",
BackgroundColor3 = Color3.new(0, 0, 0),
Size = type(width) == "number" and UDim2.new(0, width, 0, 5)
or UDim2.new(0, 200, 0, 5),
BorderColor3 = Colour3(95, 95, 95),
ZIndex = 2,
Parent = sliderGui,
}
if
position.X
and position.X.Scale
and position.X.Offset
and position.Y
and position.Y.Scale
and position.Y.Offset
then
bar.Position = position
end
local slider = New "ImageButton" {
Name = "Slider",
BackgroundTransparency = 1,
Image = "rbxasset://textures/ui/Slider.png",
Position = UDim2.new(0, 0, 0.5, -10),
Size = UDim2.new(0, 20, 0, 20),
ZIndex = 3,
Parent = bar,
}
areaSoak.MouseLeave:connect(function()
if areaSoak.Visible then
cancelSlide(areaSoak)
end
end)
areaSoak.MouseButton1Up:connect(function()
if areaSoak.Visible then
cancelSlide(areaSoak)
end
end)
slider.MouseButton1Down:connect(function()
areaSoak.Visible = true
if areaSoakMouseMoveCon then
areaSoakMouseMoveCon:disconnect()
end
areaSoakMouseMoveCon = areaSoak.MouseMoved:connect(function(x, _)
setSliderPos(x, slider, sliderPosition, bar, steps)
end)
end)
slider.MouseButton1Up:connect(function()
cancelSlide(areaSoak)
end)
sliderPosition.Changed:connect(function(_)
sliderPosition.Value =
math.min(steps, math.max(1, sliderPosition.Value))
local relativePosX = (sliderPosition.Value - 1) / (steps - 1)
slider.Position = UDim2.new(
relativePosX,
-slider.AbsoluteSize.X / 2,
slider.Position.Y.Scale,
slider.Position.Y.Offset
)
end)
bar.MouseButton1Down:connect(function(x, _)
setSliderPos(x, slider, sliderPosition, bar, steps)
end)
return sliderGui, sliderPosition, sliderSteps
end
function RbxGui.CreateTrueScrollingFrame()
local lowY: number?
local highY: number?
local dragCon: RBXScriptConnection?
local upCon: RBXScriptConnection?
local internalChange = false
local descendantsChangeConMap = {}
local scrollingFrame = New "Frame" {
Name = "ScrollingFrame",
Active = true,
Size = UDim2.new(1, 0, 1, 0),
ClipsDescendants = true,
}
local controlFrame = New "Frame" {
Name = "ControlFrame",
BackgroundTransparency = 1,
Size = UDim2.new(0, 18, 1, 0),
Position = UDim2.new(1, -20, 0, 0),
Parent = scrollingFrame,
}
local scrollBottom = New "BoolValue" {
Value = false,
Name = "ScrollBottom",
Parent = controlFrame,
}
local scrollUpValue = New "BoolValue" {
Value = false,
Name = "scrollUp",
Parent = controlFrame,
}
local scrollUpButton = New "TextButton" {
Name = "ScrollUpButton",
Text = "",
AutoButtonColor = false,
BackgroundColor3 = Color3.new(0, 0, 0),
BorderColor3 = Color3.new(1, 1, 1),
BackgroundTransparency = 0.5,
Size = UDim2.new(0, 18, 0, 18),
ZIndex = 2,
Parent = controlFrame,
}
for i = 1, 6 do
New "Frame" {
BorderColor3 = Color3.new(1, 1, 1),
Name = "tri" .. i,
ZIndex = 3,
BackgroundTransparency = 0.5,
Size = UDim2.new(0, 12 - ((i - 1) * 2), 0, 0),
Position = UDim2.new(0, 3 + (i - 1), 0.5, 2 - (i - 1)),
Parent = scrollUpButton,
}
end
scrollUpButton.MouseEnter:connect(function()
scrollUpButton.BackgroundTransparency = 0.1
local upChildren = scrollUpButton:GetChildren()
for i = 1, #upChildren do
upChildren[i].BackgroundTransparency = 0.1
end
end)
scrollUpButton.MouseLeave:connect(function()
scrollUpButton.BackgroundTransparency = 0.5
local upChildren = scrollUpButton:GetChildren()
for i = 1, #upChildren do
upChildren[i].BackgroundTransparency = 0.5
end
end)
local scrollDownButton = scrollUpButton:Clone()
scrollDownButton.Name = "ScrollDownButton"
scrollDownButton.Position = UDim2.new(0, 0, 1, -18)
local downChildren = scrollDownButton:GetChildren()
for i = 1, #downChildren do
downChildren[i].Position = UDim2.new(0, 3 + (i - 1), 0.5, -2 + (i - 1))
end
scrollDownButton.MouseEnter:connect(function()
scrollDownButton.BackgroundTransparency = 0.1
downChildren = scrollDownButton:GetChildren()
for i = 1, #downChildren do
downChildren[i].BackgroundTransparency = 0.1
end
end)
scrollDownButton.MouseLeave:connect(function()
scrollDownButton.BackgroundTransparency = 0.5
downChildren = scrollDownButton:GetChildren()
for i = 1, #downChildren do
downChildren[i].BackgroundTransparency = 0.5
end
end)
scrollDownButton.Parent = controlFrame
local scrollTrack = New "Frame" {
Name = "ScrollTrack",
BackgroundTransparency = 1,
Size = UDim2.new(0, 18, 1, -38),
Position = UDim2.new(0, 0, 0, 19),
Parent = controlFrame,
}
local scrollbar = New "TextButton" {
BackgroundColor3 = Color3.new(0, 0, 0),
BorderColor3 = Color3.new(1, 1, 1),
BackgroundTransparency = 0.5,
AutoButtonColor = false,
Text = "",
Active = true,
Name = "ScrollBar",
ZIndex = 2,
Size = UDim2.new(0, 18, 0.1, 0),
Position = UDim2.new(0, 0, 0, 0),
Parent = scrollTrack,
}
local function nub()
return New "Frame" {
Name = "ScrollNub",
BorderColor3 = Color3.new(1, 1, 1),
Size = UDim2.new(0, 10, 0, 0),
ZIndex = 2,
BackgroundTransparency = 0.5,
}
end
local scrollNub = Hydrate(nub()) {
Position = UDim2.new(0.5, -5, 0.5, 0),
Parent = scrollbar,
}
local newNub = Hydrate(nub()) {
Position = UDim2.new(0.5, -5, 0.5, -2),
Parent = scrollbar,
}
local lastNub = Hydrate(nub()) {
Position = UDim2.new(0.5, -5, 0.5, 2),
Parent = scrollbar,
}
scrollbar.MouseEnter:connect(function()
scrollbar.BackgroundTransparency = 0.1
scrollNub.BackgroundTransparency = 0.1
newNub.BackgroundTransparency = 0.1
lastNub.BackgroundTransparency = 0.1
end)
scrollbar.MouseLeave:connect(function()
scrollbar.BackgroundTransparency = 0.5
scrollNub.BackgroundTransparency = 0.5
newNub.BackgroundTransparency = 0.5
lastNub.BackgroundTransparency = 0.5
end)
local mouseDrag = New "ImageButton" {
Active = false,
Size = UDim2.new(1.5, 0, 1.5, 0),
AutoButtonColor = false,
BackgroundTransparency = 1,
Name = "mouseDrag",
Position = UDim2.new(-0.25, 0, -0.25, 0),
ZIndex = 10,
}
local function positionScrollBar(_, y, offset)
local oldPos = scrollbar.Position
if y < scrollTrack.AbsolutePosition.y then
scrollbar.Position = UDim2.new(
scrollbar.Position.X.Scale,
scrollbar.Position.X.Offset,
0,
0
)
return (oldPos ~= scrollbar.Position)
end
local relativeSize = scrollbar.AbsoluteSize.Y
/ scrollTrack.AbsoluteSize.Y
if
y > (scrollTrack.AbsolutePosition.y + scrollTrack.AbsoluteSize.y)
then
scrollbar.Position = UDim2.new(
scrollbar.Position.X.Scale,
scrollbar.Position.X.Offset,
1 - relativeSize,
0
)
return (oldPos ~= scrollbar.Position)
end
local newScaleYPos = (y - scrollTrack.AbsolutePosition.y - offset)
/ scrollTrack.AbsoluteSize.y
if newScaleYPos + relativeSize > 1 then
newScaleYPos = 1 - relativeSize
scrollBottom.Value = true
scrollUpValue.Value = false
elseif newScaleYPos <= 0 then
newScaleYPos = 0
scrollUpValue.Value = true
scrollBottom.Value = false
else
scrollUpValue.Value = false
scrollBottom.Value = false
end
scrollbar.Position = UDim2.new(
scrollbar.Position.X.Scale,
scrollbar.Position.X.Offset,
newScaleYPos,
0
)
return (oldPos ~= scrollbar.Position)
end
local function drillDownSetHighLow(instance: GuiObject)
if
not instance
or not instance:IsA "GuiObject"
or instance == controlFrame
or instance:IsDescendantOf(controlFrame)
or not instance.Visible
then
return
elseif (lowY and lowY > instance.AbsolutePosition.Y) or not lowY then
lowY = instance.AbsolutePosition.Y
end
if
(
highY
and highY
< (instance.AbsolutePosition.Y + instance.AbsoluteSize.Y)
) or not highY
then
highY = instance.AbsolutePosition.Y + instance.AbsoluteSize.Y
end
local children = instance:GetChildren()
for i = 1, #children do
drillDownSetHighLow(children[i] :: GuiObject)
end
end
local function resetHighLow()
local firstChildren = scrollingFrame:GetChildren()
for i = 1, #firstChildren do
drillDownSetHighLow(firstChildren[i]) -- y no type annotation here, luau?
end
end
local function recalculate()
internalChange = true
local percentFrame = 0
if scrollbar.Position.Y.Scale > 0 then
if scrollbar.Visible then
percentFrame = scrollbar.Position.Y.Scale
/ (
(scrollTrack.AbsoluteSize.Y - scrollbar.AbsoluteSize.Y)
/ scrollTrack.AbsoluteSize.Y
)
else
percentFrame = 0
end
end
if percentFrame > 0.99 then
percentFrame = 1
end
local hiddenYAmount = (scrollingFrame.AbsoluteSize.Y - (highY - lowY))
* percentFrame
local guiChildren = scrollingFrame:GetChildren()
for i = 1, #guiChildren do
if guiChildren[i] ~= controlFrame then
guiChildren[i].Position = UDim2.new(
guiChildren[i].Position.X.Scale,
guiChildren[i].Position.X.Offset,
0,
math.ceil(guiChildren[i].AbsolutePosition.Y)
- math.ceil(lowY)
+ hiddenYAmount
)
end
end
lowY = nil
highY = nil
resetHighLow()
internalChange = false
end
local function setSliderSizeAndPosition()
if not highY or not lowY then
return
end
local totalYSpan = math.abs(highY - lowY)
if totalYSpan == 0 then
scrollbar.Visible = false
scrollDownButton.Visible = false
scrollUpButton.Visible = false
if dragCon then
dragCon:disconnect()
dragCon = nil
end
if upCon then
upCon:disconnect()
upCon = nil
end
return
end
local percentShown = scrollingFrame.AbsoluteSize.Y / totalYSpan
if percentShown >= 1 then
scrollbar.Visible = false
scrollDownButton.Visible = false
scrollUpButton.Visible = false
recalculate()
else
scrollbar.Visible = true
scrollDownButton.Visible = true
scrollUpButton.Visible = true
scrollbar.Size = UDim2.new(
scrollbar.Size.X.Scale,
scrollbar.Size.X.Offset,
percentShown,
0
)
end
local percentPosition = (scrollingFrame.AbsolutePosition.Y - lowY)
/ totalYSpan
scrollbar.Position = UDim2.new(
scrollbar.Position.X.Scale,
scrollbar.Position.X.Offset,
percentPosition,
-scrollbar.AbsoluteSize.X / 2
)
if scrollbar.AbsolutePosition.y < scrollTrack.AbsolutePosition.y then
scrollbar.Position = UDim2.new(
scrollbar.Position.X.Scale,
scrollbar.Position.X.Offset,
0,
0
)
end
if
(scrollbar.AbsolutePosition.y + scrollbar.AbsoluteSize.Y)
> (scrollTrack.AbsolutePosition.y + scrollTrack.AbsoluteSize.y)
then
local relativeSize = scrollbar.AbsoluteSize.Y
/ scrollTrack.AbsoluteSize.Y
scrollbar.Position = UDim2.new(
scrollbar.Position.X.Scale,
scrollbar.Position.X.Offset,
1 - relativeSize,
0
)
end
end
local buttonScrollAmountPixels = 7
local reentrancyGuardScrollUp = false
local function doScrollUp()
if reentrancyGuardScrollUp then
return
end
reentrancyGuardScrollUp = true
if
positionScrollBar(
0,
scrollbar.AbsolutePosition.Y - buttonScrollAmountPixels,
0
)
then
recalculate()
end
reentrancyGuardScrollUp = false
end
local reentrancyGuardScrollDown = false
local function doScrollDown()
if reentrancyGuardScrollDown then
return
end
reentrancyGuardScrollDown = true
if
positionScrollBar(
0,
scrollbar.AbsolutePosition.Y + buttonScrollAmountPixels,
0
)
then
recalculate()
end
reentrancyGuardScrollDown = false
end
local scrollStamp
local function scrollUp()
if scrollUpButton.Active then
scrollStamp = tick()
local current = scrollStamp
upCon = mouseDrag.MouseButton1Up:connect(function()
scrollStamp = tick()
mouseDrag.Parent = nil
if upCon then
-- what's upcon
-- nothing much, you?
upCon:disconnect()
end
end)
mouseDrag.Parent = getScreenGuiAncestor(scrollbar)
doScrollUp()
wait(0.2)
local t = tick()
while scrollStamp == current do
doScrollUp()
if not scrollUpButton.Active then
break
elseif tick() - t > 5 then
wait()
elseif tick() - t > 2 then
wait(0.06)
else
wait(0.1)
end
end
end
end
local function scrollDown(mouseYPos)
if scrollDownButton.Active then
scrollStamp = tick()
local current = scrollStamp
local downCon
downCon = mouseDrag.MouseButton1Up:connect(function()
scrollStamp = tick()
mouseDrag.Parent = nil
downCon:disconnect()
end)
mouseDrag.Parent = getScreenGuiAncestor(scrollbar)
doScrollDown()
wait(0.2)
local t = tick()
local w = 0.1
while scrollStamp == current do
doScrollDown()
if
mouseYPos
and mouseYPos
< (scrollbar.AbsolutePosition.y + scrollbar.AbsoluteSize.x)
then
break
end
if not scrollDownButton.Active then
break
end
if tick() - t > 5 then
w = 0
elseif tick() - t > 2 then
w = 0.06
end
wait(w)
end
end
end
scrollbar.MouseButton1Down:connect(function(_, y)
if scrollbar.Active then
local mouseOffset = y - scrollbar.AbsolutePosition.y
if dragCon then
dragCon:disconnect()
dragCon = nil
end
if upCon then
upCon:disconnect()
upCon = nil
end
local reentrancyGuardMouseScroll = false
dragCon = mouseDrag.MouseMoved:connect(function(x2, y2)
if reentrancyGuardMouseScroll then
return
end
reentrancyGuardMouseScroll = true
if positionScrollBar(x2, y2, mouseOffset) then
recalculate()
end
reentrancyGuardMouseScroll = false
end)
upCon = mouseDrag.MouseButton1Up:connect(function()
mouseDrag.Parent = nil
dragCon:disconnect()
dragCon = nil
upCon:disconnect()
end)
mouseDrag.Parent = getScreenGuiAncestor(scrollbar)
end
end)
scrollMouseCount = 0
scrollUpButton.MouseButton1Down:connect(function()
scrollUp()
end)
scrollDownButton.MouseButton1Down:connect(function()
scrollDown()
end)
local function scrollTick()
scrollStamp = tick()
end
scrollUpButton.MouseButton1Up:connect(scrollTick)
scrollDownButton.MouseButton1Up:connect(scrollTick)
scrollbar.MouseButton1Up:connect(scrollTick)
-- local function heightCheck(instance)
-- if
-- (
-- highY
-- and (instance.AbsolutePosition.Y + instance.AbsoluteSize.Y)
-- > highY
-- ) or not highY
-- then
-- highY = instance.AbsolutePosition.Y + instance.AbsoluteSize.Y
-- end
-- setSliderSizeAndPosition()
-- end
local function highLowRecheck()
local oldLowY = lowY
local oldHighY = highY
lowY = nil
highY = nil
resetHighLow()
if (lowY ~= oldLowY) or (highY ~= oldHighY) then
setSliderSizeAndPosition()
end
end
local function descendantChanged(this, prop)
if
not internalChange
and this.Visible
and (prop == "Size" or prop == "Position")
then
RunService.Heartbeat:wait()
highLowRecheck()
end
end
scrollingFrame.DescendantAdded:connect(function(instance)
if not instance:IsA "GuiObject" then
return
elseif instance.Visible then
RunService.Heartbeat:wait() -- wait a heartbeat for sizes to reconfig
highLowRecheck()
end
descendantsChangeConMap[instance] = instance.Changed:connect(
function(prop)
descendantChanged(instance, prop)
end
)
end)
scrollingFrame.DescendantRemoving:connect(function(instance)
if not instance:IsA "GuiObject" then
return
elseif descendantsChangeConMap[instance] then
descendantsChangeConMap[instance]:disconnect()
descendantsChangeConMap[instance] = nil
end
RunService.Heartbeat:wait() -- wait a heartbeat for sizes to reconfig
highLowRecheck()
end)
scrollingFrame.Changed:connect(function(prop)
if prop == "AbsoluteSize" and not (highY and lowY) then
highLowRecheck()
setSliderSizeAndPosition()
end
end)
return scrollingFrame, controlFrame
end
function RbxGui.CreateScrollingFrame(orderList: { GuiObject }?, scrollStyle)
local frame = New "Frame" {
Name = "ScrollingFrame",
BackgroundTransparency = 1,
Size = UDim2.new(1, 0, 1, 0),
}
local scrollUpButton = New "ImageButton" {
Name = "ScrollUpButton",
BackgroundTransparency = 1,
Image = "rbxasset://textures/ui/scrollbuttonUp.png",
Size = UDim2.new(0, 17, 0, 17),
}
local scrollDownButton = New "ImageButton" {
Name = "ScrollDownButton",
BackgroundTransparency = 1,
Image = "rbxasset://textures/ui/scrollbuttonDown.png",
Size = UDim2.new(0, 17, 0, 17),
}
local scrollbar = New "ImageButton" {
Name = "ScrollBar",
Image = "rbxasset://textures/ui/scrollbar.png",
BackgroundTransparency = 1,
Size = UDim2.new(0, 18, 0, 150),
}
local scrollStamp = 0
local scrollDrag = New "ImageButton" {
Image = path "asset?id=61367186",
Size = UDim2.new(1, 0, 0, 16),
BackgroundTransparency = 1,
Name = "ScrollDrag",
Active = true,
Parent = scrollbar,
}
local mouseDrag = New "ImageButton" {
Active = false,
Size = UDim2.new(1.5, 0, 1.5, 0),
AutoButtonColor = false,
BackgroundTransparency = 1,
Name = "mouseDrag",
Position = UDim2.new(-0.25, 0, -0.25, 0),
ZIndex = 10,
}
local style = "simple"
if scrollStyle and tostring(scrollStyle) then
style = scrollStyle
end
local scrollPosition = 1
local rowSize = 0
local howManyDisplayed = 0
local function layoutGridScrollBar()
howManyDisplayed = 0
local guiObjects = {}
if orderList then
for _, child in ipairs(orderList) do
if child.Parent == frame then
table.insert(guiObjects, child)
end
end
else
local children = frame:GetChildren()
if children then
for _, child in ipairs(children) do
if child:IsA "GuiObject" then
table.insert(guiObjects, child)
end
end
end
end
if #guiObjects == 0 then
scrollUpButton.Active = false
scrollDownButton.Active = false
scrollDrag.Active = false
scrollPosition = 1
return
end
if scrollPosition > #guiObjects then
scrollPosition = #guiObjects
end
if scrollPosition < 1 then
scrollPosition = 1
end
local totalPixelsY = frame.AbsoluteSize.Y
local pixelsRemainingY = frame.AbsoluteSize.Y
local totalPixelsX = frame.AbsoluteSize.X
local xCounter = 0
local rowSizeCounter = 0
local setRowSize = true
local pixelsBelowScrollbar = 0
local pos = #guiObjects
local currentRowY = 0
pos = scrollPosition
--count up from current scroll position to fill out grid
while pos <= #guiObjects and pixelsBelowScrollbar < totalPixelsY do
xCounter += guiObjects[pos].AbsoluteSize.X
--previous pos was the end of a row
if xCounter >= totalPixelsX then
pixelsBelowScrollbar += currentRowY
currentRowY = 0
xCounter = guiObjects[pos].AbsoluteSize.X
end
if guiObjects[pos].AbsoluteSize.Y > currentRowY then
currentRowY = guiObjects[pos].AbsoluteSize.Y
end
pos += 1
end
--Count wherever current row left off
pixelsBelowScrollbar += currentRowY
currentRowY = 0
pos = scrollPosition - 1
xCounter = 0
--objects with varying X,Y dimensions can rarely cause minor errors
--rechecking every new scrollPosition is necessary to avoid 100% of errors
--count backwards from current scrollPosition to see if we can add more rows
while pixelsBelowScrollbar + currentRowY < totalPixelsY and pos >= 1 do
xCounter += guiObjects[pos].AbsoluteSize.X
rowSizeCounter += 1
if xCounter >= totalPixelsX then
rowSize = rowSizeCounter - 1
rowSizeCounter = 0
xCounter = guiObjects[pos].AbsoluteSize.X
if pixelsBelowScrollbar + currentRowY <= totalPixelsY then
--It fits, so back up our scroll position
pixelsBelowScrollbar += currentRowY
if scrollPosition <= rowSize then
scrollPosition = 1
break
else
scrollPosition -= rowSize
end
currentRowY = 0
else
break
end
end
if guiObjects[pos].AbsoluteSize.Y > currentRowY then
currentRowY = guiObjects[pos].AbsoluteSize.Y
end
pos -= 1
end
--Do check last time if pos = 0
if
(pos == 0) and (pixelsBelowScrollbar + currentRowY <= totalPixelsY)
then
scrollPosition = 1
end
xCounter = 0
--pos = scrollPosition
rowSizeCounter = 0
setRowSize = true
local lastChildSize = 0
local xOffset = 0
local yOffset = 0
if guiObjects[1] then
yOffset = math.ceil(
math.floor(
math.fmod(totalPixelsY, guiObjects[1].AbsoluteSize.X)
) / 2
)
xOffset = math.ceil(
math.floor(
math.fmod(totalPixelsX, guiObjects[1].AbsoluteSize.Y)
) / 2
)
end
for i, child in ipairs(guiObjects) do
if i < scrollPosition then
--print("Hiding " .. child.Name)
child.Visible = false
else
if pixelsRemainingY < 0 then
--print("Out of Space " .. child.Name)
child.Visible = false
else
--print("Laying out " .. child.Name)
--GuiObject
if setRowSize then
rowSizeCounter += 1
end
if xCounter + child.AbsoluteSize.X >= totalPixelsX then
if setRowSize then
rowSize = rowSizeCounter - 1
setRowSize = false
end
xCounter = 0
pixelsRemainingY = pixelsRemainingY
- child.AbsoluteSize.Y
end
child.Position = UDim2.new(
child.Position.X.Scale,
xCounter + xOffset,
0,
totalPixelsY - pixelsRemainingY + yOffset
)
xCounter += child.AbsoluteSize.X
child.Visible = (
(pixelsRemainingY - child.AbsoluteSize.Y) >= 0
)
if child.Visible then
howManyDisplayed += 1
end
lastChildSize = child.AbsoluteSize
end
end
end
scrollUpButton.Active = (scrollPosition > 1)
if lastChildSize == 0 then
scrollDownButton.Active = false
else
scrollDownButton.Active = ((pixelsRemainingY - lastChildSize.Y) < 0)
end
scrollDrag.Active = #guiObjects > howManyDisplayed
scrollDrag.Visible = scrollDrag.Active
end
local function layoutSimpleScrollBar()
local guiObjects = {}
howManyDisplayed = 0
if orderList then
for _, child in ipairs(orderList) do
if child.Parent == frame then
table.insert(guiObjects, child)
end
end
else
local children = frame:GetChildren()
if children then
for _, child in ipairs(children) do
if child:IsA "GuiObject" then
table.insert(guiObjects, child)
end
end
end
end
if #guiObjects == 0 then
scrollUpButton.Active = false
scrollDownButton.Active = false
scrollDrag.Active = false
scrollPosition = 1
return
end
if scrollPosition > #guiObjects then
scrollPosition = #guiObjects
end
local totalPixels = frame.AbsoluteSize.Y
local pixelsRemaining = frame.AbsoluteSize.Y
local pixelsBelowScrollbar = 0
local pos = #guiObjects
while pixelsBelowScrollbar < totalPixels and pos >= 1 do
if pos >= scrollPosition then
pixelsBelowScrollbar = pixelsBelowScrollbar
+ guiObjects[pos].AbsoluteSize.Y
else
if
pixelsBelowScrollbar + guiObjects[pos].AbsoluteSize.Y
<= totalPixels
then
--It fits, so back up our scroll position
pixelsBelowScrollbar = pixelsBelowScrollbar
+ guiObjects[pos].AbsoluteSize.Y
if scrollPosition <= 1 then
scrollPosition = 1
break
else
--local ("Backing up ScrollPosition from -- " ..scrollPosition)
scrollPosition -= 1
end
else
break
end
end
pos -= 1
end
pos = scrollPosition
for i, child in ipairs(guiObjects) do
if i < scrollPosition then
--print("Hiding " .. child.Name)
child.Visible = false
else
if pixelsRemaining < 0 then
--print("Out of Space " .. child.Name)
child.Visible = false
else
--print("Laying out " .. child.Name)
--GuiObject
child.Position = UDim2.new(
child.Position.X.Scale,
child.Position.X.Offset,
0,
totalPixels - pixelsRemaining
)
pixelsRemaining -= child.AbsoluteSize.Y
if pixelsRemaining >= 0 then
child.Visible = true
howManyDisplayed += 1
else
child.Visible = false
end
end
end
end
scrollUpButton.Active = (scrollPosition > 1)
scrollDownButton.Active = (pixelsRemaining < 0)
scrollDrag.Active = #guiObjects > howManyDisplayed
scrollDrag.Visible = scrollDrag.Active
end
local function moveDragger()
local guiObjects = 0
local children = frame:GetChildren()
if children then
for _, child in ipairs(children) do
if child:IsA "GuiObject" then
guiObjects += 1
end
end
end
if not scrollDrag.Parent then
return
end
local dragSizeY = scrollDrag.Parent.AbsoluteSize.y
* (1 / (guiObjects - howManyDisplayed + 1))
if dragSizeY < 16 then
dragSizeY = 16
end
scrollDrag.Size = UDim2.new(
scrollDrag.Size.X.Scale,
scrollDrag.Size.X.Offset,
scrollDrag.Size.Y.Scale,
dragSizeY
)
local relativeYPos = (scrollPosition - 1)
/ (guiObjects - howManyDisplayed)
if relativeYPos > 1 then
relativeYPos = 1
elseif relativeYPos < 0 then
relativeYPos = 0
end
local absYPos = 0
if relativeYPos ~= 0 then
absYPos = (relativeYPos * scrollbar.AbsoluteSize.y)
- (relativeYPos * scrollDrag.AbsoluteSize.y)
end
scrollDrag.Position = UDim2.new(
scrollDrag.Position.X.Scale,
scrollDrag.Position.X.Offset,
scrollDrag.Position.Y.Scale,
absYPos
)
end
local reentrancyGuard = false
local function recalculate()
if reentrancyGuard then
return
end
reentrancyGuard = true
RunService.Heartbeat:wait()
local ok, err
if style == "grid" then
ok, err = pcall(function()
layoutGridScrollBar()
end)
elseif style == "simple" then
ok, err = pcall(function()
layoutSimpleScrollBar()
end)
end
if not ok then
print(err)
end
moveDragger()
reentrancyGuard = false
end
local function doScrollUp()
scrollPosition -= rowSize
if scrollPosition < 1 then
scrollPosition = 1
end
recalculate()
end
local function doScrollDown()
scrollPosition += rowSize
recalculate()
end
local function scrollUp(mouseYPos)
if scrollUpButton.Active then
scrollStamp = tick()
local current = scrollStamp
local upCon
upCon = mouseDrag.MouseButton1Up:connect(function()
scrollStamp = tick()
mouseDrag.Parent = nil
upCon:disconnect()
end)
mouseDrag.Parent = getScreenGuiAncestor(scrollbar)
doScrollUp()
wait(0.2)
local t = tick()
local w = 0.1
while scrollStamp == current do
doScrollUp()
if mouseYPos and mouseYPos > scrollDrag.AbsolutePosition.y then
break
end
if not scrollUpButton.Active then
break
end
if tick() - t > 5 then
w = 0
elseif tick() - t > 2 then
w = 0.06
end
wait(w)
end
end
end
local function scrollDown(mouseYPos)
if scrollDownButton.Active then
scrollStamp = tick()
local current = scrollStamp
local downCon
downCon = mouseDrag.MouseButton1Up:connect(function()
scrollStamp = tick()
mouseDrag.Parent = nil
downCon:disconnect()
end)
mouseDrag.Parent = getScreenGuiAncestor(scrollbar)
doScrollDown()
wait(0.2)
local t = tick()
local w = 0.1
while scrollStamp == current do
doScrollDown()
if
mouseYPos
and mouseYPos
< (scrollDrag.AbsolutePosition.y + scrollDrag.AbsoluteSize.x)
then
break
end
if not scrollDownButton.Active then
break
end
if tick() - t > 5 then
w = 0
elseif tick() - t > 2 then
w = 0.06
end
wait(w)
end
end
end
-- local y = 0
scrollDrag.MouseButton1Down:connect(function(_, y: number)
if scrollDrag.Active then
scrollStamp = tick()
local mouseOffset = y - scrollDrag.AbsolutePosition.y
local dragCon
local upCon
dragCon = mouseDrag.MouseMoved:connect(function(_, y2: number)
local barAbsPos = scrollbar.AbsolutePosition.y
local barAbsSize = scrollbar.AbsoluteSize.y
local dragAbsSize = scrollDrag.AbsoluteSize.y
local barAbsOne = barAbsPos + barAbsSize - dragAbsSize
y2 -= mouseOffset
y2 = y2 < barAbsPos and barAbsPos
or y2 > barAbsOne and barAbsOne
or y2
y2 -= barAbsPos
local guiObjects = 0
local children = frame:GetChildren()
if children then
for _, child in ipairs(children) do
if child:IsA "GuiObject" then
guiObjects += 1
end
end
end
local doublePercent = y2 / (barAbsSize - dragAbsSize)
local rowDiff = rowSize
local totalScrollCount = guiObjects - (howManyDisplayed - 1)
local newScrollPosition = math.floor(
(doublePercent * totalScrollCount) + 0.5
) + rowDiff
if newScrollPosition < scrollPosition then
rowDiff = -rowDiff
end
if newScrollPosition < 1 then
newScrollPosition = 1
end
scrollPosition = newScrollPosition
recalculate()
end)
upCon = mouseDrag.MouseButton1Up:connect(function()
scrollStamp = tick()
mouseDrag.Parent = nil
dragCon:disconnect()
dragCon = nil
upCon:disconnect()
end)
mouseDrag.Parent = getScreenGuiAncestor(scrollbar)
end
end)
scrollMouseCount = 0
scrollUpButton.MouseButton1Down:connect(function()
scrollUp()
end)
scrollUpButton.MouseButton1Up:connect(function()
scrollStamp = tick()
end)
scrollDownButton.MouseButton1Up:connect(function()
scrollStamp = tick()
end)
scrollDownButton.MouseButton1Down:connect(function()
scrollDown()
end)
scrollbar.MouseButton1Up:connect(function()
scrollStamp = tick()
end)
scrollbar.MouseButton1Down:connect(function(_, y)
if y > (scrollDrag.AbsoluteSize.y + scrollDrag.AbsolutePosition.y) then
scrollDown(y)
elseif y < scrollDrag.AbsolutePosition.y then
scrollUp(y)
end
end)
frame.ChildAdded:connect(function()
recalculate()
end)
frame.ChildRemoved:connect(function()
recalculate()
end)
frame.Changed:connect(function(prop)
if prop == "AbsoluteSize" then
--Wait a heartbeat for it to sync in
recalculate()
end
end)
frame.AncestryChanged:connect(function()
recalculate()
end)
return frame, scrollUpButton, scrollDownButton, recalculate, scrollbar
end
local function binaryGrow(
min: number,
max: number,
fits: (number) -> boolean
): number
if min > max then
return min
end
local biggestLegal = min
while min <= max do
local mid = min + math.floor((max - min) / 2)
if fits(mid) and (biggestLegal == nil or biggestLegal < mid) then
biggestLegal = mid
-- Try growing
min = mid + 1
else
-- Doesn't fit, shrink
max = mid - 1
end
end
return biggestLegal
end
local function binaryShrink(
min: number,
max: number,
fits: (number) -> boolean
): number
if min > max then
return min
end
local smallestLegal = max
while min <= max do
local mid = min + math.floor((max - min) / 2)
if fits(mid) and (smallestLegal == nil or smallestLegal > mid) then
smallestLegal = mid
-- It fits, shrink
max = mid - 1
else
-- Doesn't fit, grow
min = mid + 1
end
end
return smallestLegal
end
local function hasGuiOwner(instance: Instance)
local obj: Instance? = instance
while obj do
if obj:IsA "ScreenGui" or obj:IsA "BillboardGui" then
return true
end
obj = obj.Parent
end
return false
end
function RbxGui.AutoTruncateTextObject(textLabel: TextLabel)
local text = textLabel.Text
local fullLabel = Hydrate(textLabel:Clone()) {
Name = "Full" .. textLabel.Name,
BorderSizePixel = 0,
BackgroundTransparency = 0,
Text = text,
TextXAlignment = Enum.TextXAlignment.Center,
Position = UDim2.new(0, -3, 0, 0),
Size = UDim2.new(0, 100, 1, 0),
Visible = false,
Parent = textLabel,
}
local shortText
local mouseEnterConnection: RBXScriptConnection?
local mouseLeaveConnection: RBXScriptConnection?
local function checkForResize()
if not hasGuiOwner(textLabel) then
return
end
textLabel.Text = text
if textLabel.TextFits then
--Tear down the rollover if it is active
if mouseEnterConnection then
mouseEnterConnection:disconnect()
mouseEnterConnection = nil
end
if mouseLeaveConnection then
mouseLeaveConnection:disconnect()
mouseLeaveConnection = nil
end
else
local len = string.len(text)
textLabel.Text = text .. "~"
--Shrink the text
local textSize = binaryGrow(0, len, function(pos)
textLabel.Text = pos == 0 and "~"
or string.sub(text, 1, pos) .. "~"
return textLabel.TextFits
end)
shortText = string.sub(text, 1, textSize) .. "~"
textLabel.Text = shortText
--Make sure the fullLabel fits
if not fullLabel.TextFits then
--Already too small, grow it really bit to start
fullLabel.Size = UDim2.new(0, 10000, 1, 0)
end
--Okay, now try to binary shrink it back down
local fullLabelSize = binaryShrink(
textLabel.AbsoluteSize.X,
fullLabel.AbsoluteSize.X,
function(size)
fullLabel.Size = UDim2.new(0, size, 1, 0)
return fullLabel.TextFits
end
)
fullLabel.Size = UDim2.new(0, fullLabelSize + 6, 1, 0)
--Now setup the rollover effects, if they are currently off
if mouseEnterConnection == nil then
mouseEnterConnection = textLabel.MouseEnter:connect(function()
fullLabel.ZIndex = textLabel.ZIndex + 1
fullLabel.Visible = true
--textLabel.Text = ""
end)
end
if mouseLeaveConnection == nil then
mouseLeaveConnection = textLabel.MouseLeave:connect(function()
fullLabel.Visible = false
--textLabel.Text = shortText
end)
end
end
end
textLabel.AncestryChanged:connect(checkForResize)
textLabel.Changed:connect(function(prop)
if prop == "AbsoluteSize" then
checkForResize()
end
end)
checkForResize()
local function changeText(newText)
text = newText
fullLabel.Text = text
checkForResize()
end
return textLabel, changeText
end
local function TransitionTutorialPages(
fromPage: GuiObject?,
toPage: GuiObject?,
transitionFrame: Frame,
currentPageValue: ObjectValue
)
if fromPage then
fromPage.Visible = false
if transitionFrame.Visible == false then
transitionFrame.Size = fromPage.Size
transitionFrame.Position = fromPage.Position
end
else
if transitionFrame.Visible == false then
transitionFrame.Size = UDim2.new(0, 50, 0, 50)
transitionFrame.Position = UDim2.new(0.5, -25, 0.5, -25)
end
end
transitionFrame.Visible = true
currentPageValue.Value = nil
local newSize, newPosition
if toPage then
--Make it visible so it resizes
toPage.Visible = true
newSize = toPage.Size
newPosition = toPage.Position
toPage.Visible = false
else
newSize = UDim2.new(0, 50, 0, 50)
newPosition = UDim2.new(0.5, -25, 0.5, -25)
end
transitionFrame:TweenSizeAndPosition(
newSize,
newPosition,
Enum.EasingDirection.InOut,
Enum.EasingStyle.Quad,
0.3,
true,
function(state)
if state == Enum.TweenStatus.Completed then
transitionFrame.Visible = false
if toPage then
toPage.Visible = true
currentPageValue.Value = toPage
end
end
end
)
end
function RbxGui.CreateTutorial(name, tutorialKey, createButtons: boolean)
local frame = New "Frame" {
Name = "Tutorial-" .. name,
BackgroundTransparency = 1,
Size = UDim2.new(0.6, 0, 0.6, 0),
Position = UDim2.new(0.2, 0, 0.2, 0),
New "BoolValue" {
Name = "Buttons",
Value = createButtons,
},
}
local transitionFrame = New "Frame" {
Name = "TransitionFrame",
Style = Enum.FrameStyle.RobloxRound,
Size = UDim2.new(0.6, 0, 0.6, 0),
Position = UDim2.new(0.2, 0, 0.2, 0),
Visible = false,
Parent = frame,
}
local currentPageValue = New "ObjectValue" {
Name = "CurrentTutorialPage",
Value = nil,
Parent = frame,
}
local pages = New "Frame" {
Name = "Pages",
BackgroundTransparency = 1,
Size = UDim2.new(1, 0, 1, 0),
Parent = frame,
}
local function getVisiblePageAndHideOthers()
local visiblePage
for _, child in ipairs(pages:GetChildren() or {}) do
if child.Visible then
if visiblePage then
child.Visible = false
else
visiblePage = child
end
end
end
return visiblePage
end
local function showTutorial(alwaysShow)
if
alwaysShow
or UserSettings().GameSettings:GetTutorialState(tutorialKey)
== false
then
print("Showing tutorial-", tutorialKey)
local currentTutorialPage = getVisiblePageAndHideOthers()
local firstPage = pages:FindFirstChild "TutorialPage1"
if firstPage then
TransitionTutorialPages(
currentTutorialPage,
firstPage,
transitionFrame,
currentPageValue
)
else
error "Could not find TutorialPage1"
end
end
end
local function dismissTutorial()
local currentTutorialPage = getVisiblePageAndHideOthers()
if currentTutorialPage then
TransitionTutorialPages(
currentTutorialPage,
nil,
transitionFrame,
currentPageValue
)
end
UserSettings().GameSettings:SetTutorialState(tutorialKey, true)
end
local function gotoPage(pageNum)
local page = pages:FindFirstChild("TutorialPage" .. pageNum)
local currentTutorialPage = getVisiblePageAndHideOthers()
TransitionTutorialPages(
currentTutorialPage,
page,
transitionFrame,
currentPageValue
)
end
return frame, showTutorial, dismissTutorial, gotoPage
end
local function CreateBasicTutorialPage(
name: string,
handleResize: (number, number) -> (),
skipTutorial: () -> (),
giveDoneButton: boolean? -- idk
)
local frame = New "Frame" {
Name = "TutorialPage",
Style = Enum.FrameStyle.RobloxRound,
Size = UDim2.new(0.6, 0, 0.6, 0),
Position = UDim2.new(0.2, 0, 0.2, 0),
Visible = false,
New "TextLabel" {
Name = "Header",
Text = name,
BackgroundTransparency = 1,
FontSize = Enum.FontSize.Size24,
Font = Enum.Font.ArialBold,
TextColor3 = Color3.new(1, 1, 1),
TextXAlignment = Enum.TextXAlignment.Center,
TextWrapped = true,
Size = UDim2.new(1, -55, 0, 22),
Position = UDim2.new(0, 0, 0, 0),
},
New "TextButton" {
Name = "NextButton",
Text = "Next",
TextColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.Arial,
FontSize = Enum.FontSize.Size18,
Style = Enum.ButtonStyle.RobloxButtonDefault,
Size = UDim2.new(0, 80, 0, 32),
Position = UDim2.new(0.5, 5, 1, -32),
Active = false,
Visible = false,
},
New "TextButton" {
Name = "PrevButton",
Text = "Previous",
TextColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.Arial,
FontSize = Enum.FontSize.Size18,
Style = Enum.ButtonStyle.RobloxButton,
Size = UDim2.new(0, 80, 0, 32),
Position = UDim2.new(0.5, -85, 1, -32),
Active = false,
Visible = false,
},
}
local skipButton = New "ImageButton" {
Name = "SkipButton",
AutoButtonColor = false,
BackgroundTransparency = 1,
Image = "rbxasset://textures/ui/closeButton.png",
Size = UDim2.new(0, 25, 0, 25),
Position = UDim2.new(1, -25, 0, 0),
}
skipButton.MouseButton1Click:connect(function()
skipTutorial()
end)
skipButton.MouseEnter:connect(function()
skipButton.Image = "rbxasset://textures/ui/closeButton_dn.png"
end)
skipButton.MouseLeave:connect(function()
skipButton.Image = "rbxasset://textures/ui/closeButton.png"
end)
skipButton.Parent = frame
if giveDoneButton then
local doneButton = New "TextButton" {
Name = "DoneButton",
Style = Enum.ButtonStyle.RobloxButtonDefault,
Text = "Done",
TextColor3 = Color3.new(1, 1, 1),
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size18,
Size = UDim2.new(0, 100, 0, 50),
Position = UDim2.new(0.5, -50, 1, -50),
}
if skipTutorial then
doneButton.MouseButton1Click:connect(function()
skipTutorial()
end)
end
doneButton.Parent = frame
end
local innerFrame = New "Frame" {
Name = "ContentFrame",
BackgroundTransparency = 1,
Position = UDim2.new(0, 0, 0, 25),
Parent = frame,
}
innerFrame.Size = giveDoneButton and UDim2.new(1, 0, 1, -75)
or UDim2.new(1, 0, 1, -22)
local parentConnection: RBXScriptConnection?
local function basicHandleResize()
if frame.Visible and frame.Parent then
local maxSize = math.min(
frame.Parent.AbsoluteSize.X,
frame.Parent.AbsoluteSize.Y
)
handleResize(200, maxSize)
end
end
frame.Changed:connect(function(prop)
if prop == "Parent" then
if parentConnection then
parentConnection:disconnect()
parentConnection = nil
end
if frame.Parent and frame.Parent:IsA "GuiObject" then
parentConnection = frame.Parent.Changed:connect(
function(parentProp)
if parentProp == "AbsoluteSize" then
RunService.Heartbeat:wait()
basicHandleResize()
end
end
)
basicHandleResize()
end
end
if prop == "Visible" then
basicHandleResize()
end
end)
return frame, innerFrame
end
function RbxGui.CreateTextTutorialPage(name, text, skipTutorial)
local frame
local contentFrame
local textLabel = New "TextLabel" {
BackgroundTransparency = 1,
TextColor3 = Color3.new(1, 1, 1),
Text = text,
TextWrapped = true,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Center,
Font = Enum.Font.Arial,
FontSize = Enum.FontSize.Size14,
Size = UDim2.new(1, 0, 1, 0),
}
local function handleResize(minSize, maxSize)
local size = binaryShrink(minSize, maxSize, function(newSize)
frame.Size = UDim2.new(0, newSize, 0, newSize)
return textLabel.TextFits
end)
frame.Size = UDim2.new(0, size, 0, size)
frame.Position = UDim2.new(0.5, -size / 2, 0.5, -size / 2)
end
frame, contentFrame =
CreateBasicTutorialPage(name, handleResize, skipTutorial)
textLabel.Parent = contentFrame
return frame
end
function RbxGui.CreateImageTutorialPage(
name,
imageAsset,
x: number,
y: number,
skipTutorial: () -> (),
giveDoneButton
)
local frame
local contentFrame
-- local imageLabel = Instance.new "ImageLabel"
-- imageLabel.BackgroundTransparency = 1
-- imageLabel.Image = imageAsset
-- imageLabel.Size = UDim2.new(0, x, 0, y)
-- imageLabel.Position = UDim2.new(0.5, -x / 2, 0.5, -y / 2)
local imageLabel = New "ImageLabel" {
BackgroundTransparency = 1,
Image = imageAsset,
Size = UDim2.new(0, x, 0, y),
Position = UDim2.new(0.5, -x / 2, 0.5, -y / 2),
}
local function handleResize(minSize, maxSize)
local size = binaryShrink(minSize, maxSize, function(newSize)
return newSize >= x and newSize >= y
end)
if size >= x and size >= y then
imageLabel.Size = UDim2.new(0, x, 0, y)
imageLabel.Position = UDim2.new(0.5, -x / 2, 0.5, -y / 2)
else
if x > y then
--X is limiter, so
imageLabel.Size = UDim2.new(1, 0, y / x, 0)
imageLabel.Position = UDim2.new(0, 0, 0.5 - (y / x) / 2, 0)
else
--Y is limiter
imageLabel.Size = UDim2.new(x / y, 0, 1, 0)
imageLabel.Position = UDim2.new(0.5 - (x / y) / 2, 0, 0, 0)
end
end
size += 50
frame.Size = UDim2.new(0, size, 0, size)
frame.Position = UDim2.new(0.5, -size / 2, 0.5, -size / 2)
end
frame, contentFrame = CreateBasicTutorialPage(
name,
handleResize,
skipTutorial,
giveDoneButton
)
imageLabel.Parent = contentFrame
return frame
end
type TutorialPage = GuiObject & {
NextButton: TextButton,
PrevButton: TextButton,
}
function RbxGui.AddTutorialPage(
tutorial: {
TransitionFrame: Frame,
CurrentTutorialPage: ObjectValue,
Buttons: BoolValue,
Pages: Frame,
},
tutorialPage: TutorialPage
)
local transitionFrame = tutorial.TransitionFrame
local currentPageValue = tutorial.CurrentTutorialPage
if not tutorial.Buttons.Value then
tutorialPage.NextButton.Parent = nil
tutorialPage.PrevButton.Parent = nil
end
local children = tutorial.Pages:GetChildren() :: { TutorialPage }
if children and #children > 0 then
tutorialPage.Name = "TutorialPage" .. (#children + 1)
local previousPage: TutorialPage = children[#children]
if not previousPage:IsA "GuiObject" then
error "All elements under Pages must be GuiObjects"
end
if tutorial.Buttons.Value then
if previousPage.NextButton.Active then
error "NextButton already Active on previousPage, please only add pages with RbxGui.AddTutorialPage function"
end
previousPage.NextButton.MouseButton1Click:connect(function()
TransitionTutorialPages(
previousPage,
tutorialPage,
transitionFrame,
currentPageValue
)
end)
previousPage.NextButton.Active = true
previousPage.NextButton.Visible = true
if tutorialPage.PrevButton.Active then
error "PrevButton already Active on tutorialPage, please only add pages with RbxGui.AddTutorialPage function"
end
tutorialPage.PrevButton.MouseButton1Click:connect(function()
TransitionTutorialPages(
tutorialPage,
previousPage,
transitionFrame,
currentPageValue
)
end)
tutorialPage.PrevButton.Active = true
tutorialPage.PrevButton.Visible = true
end
else
-- First child
tutorialPage.Name = "TutorialPage1"
end
tutorialPage.Parent = tutorial.Pages
end
function RbxGui.CreateSetPanel(
userIdsForSets,
objectSelected,
dialogClosed,
size,
position,
showAdminCategories,
useAssetVersionId
)
if not userIdsForSets then
error "CreateSetPanel: userIdsForSets (first arg) is nil, should be a table of number ids"
end
if
type(userIdsForSets) ~= "table"
and type(userIdsForSets) ~= "userdata"
then
error(
`CreateSetPanel: userIdsForSets (first arg) is of type {type(
userIdsForSets
)}, should be of type table or userdata`
)
end
if not objectSelected then
error "CreateSetPanel: objectSelected (second arg) is nil, should be a callback function!"
end
if type(objectSelected) ~= "function" then
error(
`CreateSetPanel: objectSelected (second arg) is of type {type(
objectSelected
)}, should be of type function!`
)
end
if dialogClosed and type(dialogClosed) ~= "function" then
error(
`CreateSetPanel: dialogClosed (third arg) is of type {type(
dialogClosed
)}, should be of type function!`
)
end
if showAdminCategories == nil then -- by default, don't show beta sets
showAdminCategories = false
end
local arrayPosition = 1
local insertButtons = {}
local insertButtonCons: { RBXScriptConnection } = {}
local contents
local setGui
-- used for water selections
local waterForceDirection = "NegX"
local waterForce = "None"
local waterGui, waterTypeChangedEvent
local Data = {}
Data.CurrentCategory = nil
Data.Category = {}
local SetCache = {}
local userCategoryButtons
local buttonWidth = 64
local buttonHeight = buttonWidth
local SmallThumbnailUrl
local LargeThumbnailUrl
local BaseUrl = string.lower(ContentProvider.BaseUrl)
local ThumbUrl = `{BaseUrl}Game/Tools/ThumbnailAsset.ashx?fmt=png&wd=`
if useAssetVersionId then
LargeThumbnailUrl = `{ThumbUrl}420&ht=420&assetversionid=`
SmallThumbnailUrl = `{ThumbUrl}75&ht=75&assetversionid=`
else
LargeThumbnailUrl = `{ThumbUrl}420&ht=420&aid=`
SmallThumbnailUrl = `{ThumbUrl}75&ht=75&aid=`
end
local function drillDownSetZIndex(parent, index)
local children = parent:GetChildren()
for i = 1, #children do
if children[i]:IsA "GuiObject" then
children[i].ZIndex = index
end
drillDownSetZIndex(children[i], index)
end
end
-- for terrain stamping
local currTerrainDropDownFrame
local terrainShapes = {
"Block",
"Vertical Ramp",
"Corner Wedge",
"Inverse Corner Wedge",
"Horizontal Ramp",
"Auto-Wedge",
}
local terrainShapeMap = {}
for i = 1, #terrainShapes do
terrainShapeMap[terrainShapes[i]] = i - 1
end
terrainShapeMap[terrainShapes[#terrainShapes]] = 6
local function createWaterGui()
local waterForceDirections = { "NegX", "X", "NegY", "Y", "NegZ", "Z" }
local waterForces = { "None", "Small", "Medium", "Strong", "Max" }
local waterFrame = New "Frame" {
Name = "WaterFrame",
Style = Enum.FrameStyle.RobloxSquare,
Size = UDim2.new(0, 150, 0, 110),
Visible = false,
}
local waterForceLabel = New "TextLabel" {
Name = "WaterForceLabel",
BackgroundTransparency = 1,
Size = UDim2.new(1, 0, 0, 12),
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size12,
TextColor3 = Color3.new(1, 1, 1),
TextXAlignment = Enum.TextXAlignment.Left,
Text = "Water Force",
Parent = waterFrame,
}
local waterForceDirLabel = Hydrate(waterForceLabel:Clone()) {
Name = "WaterForceDirectionLabel",
Text = "Water Force Direction",
Position = UDim2.new(0, 0, 0, 50),
Parent = waterFrame,
}
waterTypeChangedEvent = New "BindableEvent" {
Name = "WaterTypeChangedEvent",
Parent = waterFrame,
}
local function waterForceDirectionSelected(newForceDirection)
waterForceDirection = newForceDirection
waterTypeChangedEvent:Fire { waterForce, waterForceDirection }
end
local function waterForceSelected(newForce)
waterForce = newForce
waterTypeChangedEvent:Fire { waterForce, waterForceDirection }
end
local waterForceDirectionDropDown, forceWaterDirectionSelection =
RbxGui.CreateDropDownMenu(
waterForceDirections,
waterForceDirectionSelected
)
waterForceDirectionDropDown.Size = UDim2.new(1, 0, 0, 25)
waterForceDirectionDropDown.Position = UDim2.new(0, 0, 1, 3)
forceWaterDirectionSelection "NegX"
waterForceDirectionDropDown.Parent = waterForceDirLabel
local waterForceDropDown, forceWaterForceSelection =
RbxGui.CreateDropDownMenu(waterForces, waterForceSelected)
forceWaterForceSelection "None"
waterForceDropDown.Size = UDim2.new(1, 0, 0, 25)
waterForceDropDown.Position = UDim2.new(0, 0, 1, 3)
waterForceDropDown.Parent = waterForceLabel
return waterFrame, waterTypeChangedEvent
end
-- Helper Function that contructs gui elements
local function createSetGui()
setGui = New "ScreenGui" {
Name = "SetGui",
}
local setsLists, controlFrame = RbxGui.CreateTrueScrollingFrame()
drillDownSetZIndex(controlFrame, 7)
local setPanel = New "Frame" {
Name = "SetPanel",
Active = true,
BackgroundTransparency = 1,
Style = Enum.FrameStyle.RobloxRound,
ZIndex = 6,
New "Frame" {
Name = "ItemPreview",
BackgroundTransparency = 1,
Position = UDim2.new(0.8, 5, 0.085, 0),
Size = UDim2.new(0.21, 0, 0.9, 0),
ZIndex = 6,
New "Frame" {
Name = "TextPanel",
BackgroundTransparency = 1,
Position = UDim2.new(0, 0, 0.45, 0),
Size = UDim2.new(1, 0, 0.55, 0),
ZIndex = 6,
New "TextLabel" {
Name = "RolloverText",
BackgroundTransparency = 1,
Size = UDim2.new(1, 0, 0, 48),
ZIndex = 6,
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size24,
Text = "",
TextColor3 = Color3.new(1, 1, 1),
TextWrapped = true,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
},
},
New "ImageLabel" {
Name = "LargePreview",
BackgroundTransparency = 1,
Image = "",
Size = UDim2.new(1, 0, 0, 170),
ZIndex = 6,
},
},
New "Frame" {
Name = "Sets",
BackgroundTransparency = 1,
Position = UDim2.new(0, 0, 0, 5),
Size = UDim2.new(0.23, 0, 1, -5),
ZIndex = 6,
New "Frame" {
Name = "Line",
BackgroundColor3 = Color3.new(1, 1, 1),
BackgroundTransparency = 0.7,
BorderSizePixel = 0,
Position = UDim2.new(1, -3, 0.06, 0),
Size = UDim2.new(0, 3, 0.9, 0),
ZIndex = 6,
},
Hydrate(setsLists) {
Size = UDim2.new(1, -6, 0.94, 0),
Position = UDim2.new(0, 0, 0.06, 0),
BackgroundTransparency = 1,
Name = "SetsLists",
ZIndex = 6,
},
New "TextLabel" {
Name = "SetsHeader",
BackgroundTransparency = 1,
Size = UDim2.new(0, 47, 0, 24),
ZIndex = 6,
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size24,
Text = "Sets",
TextColor3 = Color3.new(1, 1, 1),
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
},
},
New "TextButton" {
Name = "CancelButton",
Position = UDim2.new(1, -32, 0, -2),
Size = UDim2.new(0, 34, 0, 34),
Style = Enum.ButtonStyle.RobloxButtonDefault,
ZIndex = 6,
Text = "",
Modal = true,
New "ImageLabel" {
Name = "CancelImage",
BackgroundTransparency = 1,
Image = path "asset?id=54135717",
Position = UDim2.new(0, -2, 0, -2),
Size = UDim2.new(0, 16, 0, 16),
ZIndex = 6,
},
},
}
if position then
setPanel.Position = position
else
setPanel.Position = UDim2.new(0.2, 29, 0.1, 24)
end
if size then
setPanel.Size = size
else
setPanel.Size = UDim2.new(0.6, -58, 0.64, 0)
end
setPanel.Parent = setGui
return setGui
end
local function createSetButton(text)
return New "TextButton" {
AutoButtonColor = false,
BackgroundTransparency = 1,
BackgroundColor3 = Color3.new(1, 1, 1),
BorderSizePixel = 0,
Size = UDim2.new(1, -5, 0, 18),
ZIndex = 6,
Visible = false,
Font = Enum.Font.Arial,
FontSize = Enum.FontSize.Size18,
TextColor3 = Color3.new(1, 1, 1),
TextXAlignment = Enum.TextXAlignment.Left,
Text = text or "",
}
end
local function buildSetButton(name, setId, _, _, _)
return Hydrate(createSetButton(name)) {
Text = name,
Name = "SetButton",
Visible = true,
New "IntValue" {
Name = "SetId",
Value = setId,
},
New "StringValue" {
Name = "SetName",
Value = name,
},
}
end
local function processCategory(sets)
local setButtons = {}
local numSkipped = 0
for i = 1, #sets do
if not showAdminCategories and sets[i].Name == "Beta" then
numSkipped += 1
else
setButtons[i - numSkipped] = buildSetButton(
sets[i].Name,
sets[i].CategoryId,
sets[i].ImageAssetId,
i - numSkipped,
#sets
)
end
end
return setButtons
end
local function handleResize()
RunService.Heartbeat:wait() -- neccessary to insure heartbeat happened
local itemPreview = setGui.SetPanel.ItemPreview
itemPreview.LargePreview.Size =
UDim2.new(1, 0, 0, itemPreview.AbsoluteSize.X)
itemPreview.LargePreview.Position =
UDim2.new(0.5, -itemPreview.LargePreview.AbsoluteSize.X / 2, 0, 0)
itemPreview.TextPanel.Position =
UDim2.new(0, 0, 0, itemPreview.LargePreview.AbsoluteSize.Y)
itemPreview.TextPanel.Size = UDim2.new(
1,
0,
0,
itemPreview.AbsoluteSize.Y - itemPreview.LargePreview.AbsoluteSize.Y
)
end
local function buttonImage()
return New "ImageLabel" {
Image = "",
BackgroundTransparency = 1,
}
end
local function makeInsertAssetButton()
return New "Frame" {
Name = "InsertAssetButtonExample",
Position = UDim2.new(0, 128, 0, 64),
Size = UDim2.new(0, 64, 0, 64),
BackgroundTransparency = 1,
ZIndex = 6,
Visible = false,
New "IntValue" {
Name = "AssetId",
Value = 0,
},
New "StringValue" {
Name = "AssetName",
Value = "",
},
New "TextButton" {
Name = "Button",
Text = "",
Style = Enum.ButtonStyle.RobloxButton,
Position = UDim2.new(0.025, 0, 0.025, 0),
Size = UDim2.new(0.95, 0, 0.95, 0),
ZIndex = 6,
Hydrate(buttonImage()) {
Name = "ButtonImage",
Position = UDim2.new(0, -7, 0, -7),
Size = UDim2.new(1, 14, 1, 14),
ZIndex = 7,
},
},
Hydrate(buttonImage()) {
Name = "ConfigIcon",
Visible = false,
Position = UDim2.new(1, -23, 1, -24),
Size = UDim2.new(0, 16, 0, 16),
ZIndex = 6,
},
}
end
local function showLargePreview(insertButton)
if insertButton:FindFirstChild "AssetId" then
delay(0, function()
ContentProvider:Preload(
LargeThumbnailUrl .. tostring(insertButton.AssetId.Value)
)
setGui.SetPanel.ItemPreview.LargePreview.Image = LargeThumbnailUrl
.. tostring(insertButton.AssetId.Value)
end)
end
if insertButton:FindFirstChild "AssetName" then
setGui.SetPanel.ItemPreview.TextPanel.RolloverText.Text =
insertButton.AssetName.Value
end
end
local function selectTerrainShape(shape)
if currTerrainDropDownFrame then
objectSelected(
tostring(currTerrainDropDownFrame.AssetName.Value),
tonumber(currTerrainDropDownFrame.AssetId.Value),
shape
)
end
end
local function createTerrainTypeButton(name: string, parent: Frame)
local dropDownTextButton = New "TextButton" {
Name = name .. "Button",
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size14,
BorderSizePixel = 0,
TextColor3 = Color3.new(1, 1, 1),
Text = name,
TextXAlignment = Enum.TextXAlignment.Left,
BackgroundTransparency = 1,
ZIndex = parent.ZIndex + 1,
Size = UDim2.new(0, parent.Size.X.Offset - 2, 0, 16),
Position = UDim2.new(0, 1, 0, 0),
}
dropDownTextButton.MouseEnter:connect(function()
dropDownTextButton.BackgroundTransparency = 0
dropDownTextButton.TextColor3 = Color3.new(0, 0, 0)
end)
dropDownTextButton.MouseLeave:connect(function()
dropDownTextButton.BackgroundTransparency = 1
dropDownTextButton.TextColor3 = Color3.new(1, 1, 1)
end)
dropDownTextButton.MouseButton1Click:connect(function()
dropDownTextButton.BackgroundTransparency = 1
dropDownTextButton.TextColor3 = Color3.new(1, 1, 1)
if
dropDownTextButton.Parent
and dropDownTextButton.Parent:IsA "GuiObject"
then
dropDownTextButton.Parent.Visible = false
end
selectTerrainShape(terrainShapeMap[dropDownTextButton.Text])
end)
return dropDownTextButton
end
local function createTerrainDropDownMenu(zIndex: number)
local dropDown = New "Frame" {
Name = "TerrainDropDown",
BackgroundColor3 = Color3.new(0, 0, 0),
BorderColor3 = Color3.new(1, 0, 0),
Size = UDim2.new(0, 200, 0, 0),
Visible = false,
ZIndex = zIndex,
Parent = setGui,
}
for i = 1, #terrainShapes do
local shapeButton =
createTerrainTypeButton(terrainShapes[i], dropDown)
shapeButton.Position =
UDim2.new(0, 1, 0, (i - 1) * shapeButton.Size.Y.Offset)
shapeButton.Parent = dropDown
dropDown.Size = UDim2.new(
0,
200,
0,
dropDown.Size.Y.Offset + shapeButton.Size.Y.Offset
)
end
dropDown.MouseLeave:connect(function()
dropDown.Visible = false
end)
end
local function createDropDownMenuButton(parent: Frame)
local dropDownButton = New "ImageButton" {
Name = "DropDownButton",
Image = path "asset?id=67581509",
BackgroundTransparency = 1,
Size = UDim2.new(0, 16, 0, 16),
Position = UDim2.new(1, -24, 0, 6),
ZIndex = parent.ZIndex + 2,
Parent = parent,
}
if not setGui:FindFirstChild "TerrainDropDown" then
createTerrainDropDownMenu(8)
end
dropDownButton.MouseButton1Click:connect(function()
setGui.TerrainDropDown.Visible = true
setGui.TerrainDropDown.Position = UDim2.new(
0,
parent.AbsolutePosition.X,
0,
parent.AbsolutePosition.Y
)
currTerrainDropDownFrame = parent
end)
end
local function buildInsertButton()
local insertButton = Hydrate(makeInsertAssetButton()) {
Name = "InsertAssetButton",
Visible = true,
}
if
Data.Category[Data.CurrentCategory].SetName == "High Scalability"
then
createDropDownMenuButton(insertButton)
end
local lastEnter
local mouseEnterCon = insertButton.MouseEnter:connect(function()
lastEnter = insertButton
delay(0.1, function()
if lastEnter == insertButton then
showLargePreview(insertButton)
end
end)
end)
return insertButton, mouseEnterCon
end
local function realignButtonGrid(columns)
local x = 0
local y = 0
for i = 1, #insertButtons do
insertButtons[i].Position =
UDim2.new(0, buttonWidth * x, 0, buttonHeight * y)
x += 1
if x >= columns then
x = 0
y += 1
end
end
end
local function setInsertButtonImageBehavior(
insertFrame,
visible,
name,
assetId
)
if visible then
insertFrame.AssetName.Value = name
insertFrame.AssetId.Value = assetId
local newImageUrl = SmallThumbnailUrl .. assetId
if newImageUrl ~= insertFrame.Button.ButtonImage.Image then
delay(0, function()
ContentProvider:Preload(SmallThumbnailUrl .. assetId)
insertFrame.Button.ButtonImage.Image = SmallThumbnailUrl
.. assetId
end)
end
table.insert(
insertButtonCons,
insertFrame.Button.MouseButton1Click:connect(function()
-- special case for water, show water selection gui
local isWaterSelected = (name == "Water")
and (
Data.Category[Data.CurrentCategory].SetName
== "High Scalability"
)
waterGui.Visible = isWaterSelected
if isWaterSelected then
objectSelected(name, tonumber(assetId), nil)
else
objectSelected(name, tonumber(assetId))
end
end)
)
insertFrame.Visible = true
else
insertFrame.Visible = false
end
end
local function loadSectionOfItems(setGui, rows: number, columns: number)
local pageSize = rows * columns
if arrayPosition > #contents then
return
end
local origArrayPos = arrayPosition
for _ = 1, pageSize + 1 do
if arrayPosition >= #contents + 1 then
break
end
local buttonCon
insertButtons[arrayPosition], buttonCon = buildInsertButton()
table.insert(insertButtonCons, buttonCon)
insertButtons[arrayPosition].Parent = setGui.SetPanel.ItemsFrame
arrayPosition += 1
end
realignButtonGrid(columns)
-- local indexCopy = origArrayPos
for index = origArrayPos, arrayPosition do
if insertButtons[index] then
if contents[index] then
-- we don't want water to have a drop down button
if contents[index].Name == "Water" then
if
Data.Category[Data.CurrentCategory].SetName
== "High Scalability"
then
insertButtons[index]
:FindFirstChild("DropDownButton", true)
:Destroy()
end
end
local assetId
if useAssetVersionId then
assetId = contents[index].AssetVersionId
else
assetId = contents[index].AssetId
end
setInsertButtonImageBehavior(
insertButtons[index],
true,
contents[index].Name,
assetId
)
else
break
end
else
break
end
-- indexCopy = index
end
end
local function setSetIndex()
Data.Category[Data.CurrentCategory].Index = 0
local rows = 7
local columns =
math.floor(setGui.SetPanel.ItemsFrame.AbsoluteSize.X / buttonWidth)
contents = Data.Category[Data.CurrentCategory].Contents
if contents then
-- remove our buttons and their connections
for i = 1, #insertButtons do
insertButtons[i]:remove()
end
for i = 1, #insertButtonCons do
if insertButtonCons[i] then
insertButtonCons[i]:disconnect()
end
end
insertButtonCons = {}
insertButtons = {}
arrayPosition = 1
loadSectionOfItems(setGui, rows, columns)
end
end
local function selectSet(button, setName, setId, _)
if button and Data.Category[Data.CurrentCategory] ~= nil then
if button ~= Data.Category[Data.CurrentCategory].Button then
Data.Category[Data.CurrentCategory].Button = button
if SetCache[setId] == nil then
SetCache[setId] = InsertService:GetCollection(setId)
end
Data.Category[Data.CurrentCategory].Contents = SetCache[setId]
Data.Category[Data.CurrentCategory].SetName = setName
Data.Category[Data.CurrentCategory].SetId = setId
end
setSetIndex()
end
end
local function selectCategoryPage(buttons, _)
if buttons ~= Data.CurrentCategory then
if Data.CurrentCategory then
for _, button in pairs(Data.CurrentCategory) do
button.Visible = false
end
end
Data.CurrentCategory = buttons
if Data.Category[Data.CurrentCategory] == nil then
Data.Category[Data.CurrentCategory] = {}
if #buttons > 0 then
selectSet(
buttons[1],
buttons[1].SetName.Value,
buttons[1].SetId.Value,
0
)
end
else
Data.Category[Data.CurrentCategory].Button = nil
selectSet(
Data.Category[Data.CurrentCategory].ButtonFrame,
Data.Category[Data.CurrentCategory].SetName,
Data.Category[Data.CurrentCategory].SetId,
Data.Category[Data.CurrentCategory].Index
)
end
end
end
local function selectCategory(category)
selectCategoryPage(category, 0)
end
local function resetAllSetButtonSelection()
local setButtons = setGui.SetPanel.Sets.SetsLists:GetChildren()
for _, setButton in ipairs(setButtons) do
if setButton:IsA "TextButton" then
setButton.Selected = false
setButton.BackgroundTransparency = 1
setButton.TextColor3 = Color3.new(1, 1, 1)
setButton.BackgroundColor3 = Color3.new(1, 1, 1)
end
end
end
local function populateSetsFrame()
local currRow = 0
for i = 1, #userCategoryButtons do
local button = userCategoryButtons[i]
button.Visible = true
button.Position = UDim2.new(0, 5, 0, currRow * button.Size.Y.Offset)
button.Parent = setGui.SetPanel.Sets.SetsLists
if i == 1 then -- we will have this selected by default, so show it
button.Selected = true
button.BackgroundColor3 = Color3.new(0, 204 / 255, 0)
button.TextColor3 = Color3.new(0, 0, 0)
button.BackgroundTransparency = 0
end
button.MouseEnter:connect(function()
if not button.Selected then
button.BackgroundTransparency = 0
button.TextColor3 = Color3.new(0, 0, 0)
end
end)
button.MouseLeave:connect(function()
if not button.Selected then
button.BackgroundTransparency = 1
button.TextColor3 = Color3.new(1, 1, 1)
end
end)
button.MouseButton1Click:connect(function()
resetAllSetButtonSelection()
button.Selected = not button.Selected
button.BackgroundColor3 = Color3.new(0, 204 / 255, 0)
button.TextColor3 = Color3.new(0, 0, 0)
button.BackgroundTransparency = 0
selectSet(
button,
button.Text,
userCategoryButtons[i].SetId.Value,
0
)
end)
currRow += 1
end
local buttons = setGui.SetPanel.Sets.SetsLists:GetChildren()
-- set first category as loaded for default
if buttons then
for i = 1, #buttons do
if buttons[i]:IsA "TextButton" then
selectSet(
buttons[i],
buttons[i].Text,
userCategoryButtons[i].SetId.Value,
0
)
selectCategory(userCategoryButtons)
break
end
end
end
end
setGui = createSetGui()
waterGui, waterTypeChangedEvent = createWaterGui()
waterGui.Position = UDim2.new(0, 55, 0, 0)
waterGui.Parent = setGui
setGui.Changed:connect(
function(prop) -- this resizes the preview image to always be the right size
if prop == "AbsoluteSize" then
handleResize()
setSetIndex()
end
end
)
local scrollFrame, controlFrame = RbxGui.CreateTrueScrollingFrame()
Hydrate(scrollFrame) {
Size = UDim2.new(0.54, 0, 0.85, 0),
Position = UDim2.new(0.24, 0, 0.085, 0),
Name = "ItemsFrame",
ZIndex = 6,
Parent = setGui.SetPanel,
BackgroundTransparency = 1,
}
drillDownSetZIndex(controlFrame, 7)
controlFrame.Parent = setGui.SetPanel
controlFrame.Position = UDim2.new(0.76, 5, 0, 0)
local rows =
math.floor(setGui.SetPanel.ItemsFrame.AbsoluteSize.Y / buttonHeight)
local columns =
math.floor(setGui.SetPanel.ItemsFrame.AbsoluteSize.X / buttonWidth)
local debounce = false
controlFrame.ScrollBottom.Changed:connect(function(_)
if controlFrame.ScrollBottom.Value == true then
if debounce then
return
end
debounce = true
loadSectionOfItems(setGui, rows, columns)
debounce = false
end
end)
local userData = {}
for id = 1, #userIdsForSets do
local newUserData = InsertService:GetUserSets(userIdsForSets[id])
if newUserData and #newUserData > 2 then
-- start at #3 to skip over My Decals and My Models for each account
for category = 3, #newUserData do
if newUserData[category].Name == "High Scalability" then -- we want high scalability parts to show first
table.insert(userData, 1, newUserData[category])
else
table.insert(userData, newUserData[category])
end
end
end
end
if userData then
userCategoryButtons = processCategory(userData)
end
populateSetsFrame()
--[[local insertPanelCloseCon = ]]
setGui.SetPanel.CancelButton.MouseButton1Click:connect(function()
setGui.SetPanel.Visible = false
if dialogClosed then
dialogClosed()
end
end)
local function setVisibilityFunction(visible)
if visible then
setGui.SetPanel.Visible = true
else
setGui.SetPanel.Visible = false
end
end
local function getVisibilityFunction()
if setGui then
if setGui:FindFirstChild "SetPanel" then
return setGui.SetPanel.Visible
end
end
return false
end
return setGui,
setVisibilityFunction,
getVisibilityFunction,
waterTypeChangedEvent
end
-- We all know enums are just numbers in a trench coat
local cm = Enum.CellMaterial
local EnumMaterialNames = {
[cm.Grass] = "Grass",
[cm.Sand] = "Sand",
[cm.Empty] = "Erase",
[cm.Brick] = "Brick",
[cm.Granite] = "Granite",
[cm.Asphalt] = "Asphalt",
[cm.Iron] = "Iron",
[cm.Aluminum] = "Aluminum",
[cm.Gold] = "Gold",
[cm.WoodPlank] = "Plank",
[cm.WoodLog] = "Log",
[cm.Gravel] = "Gravel",
[cm.CinderBlock] = "Cinder Block",
[cm.MossyStone] = "Stone Wall",
[cm.Cement] = "Concrete",
[cm.RedPlastic] = "Plastic (red)",
[cm.BluePlastic] = "Plastic (blue)",
[cm.Water] = "Water",
}
local MaterialNames = {
"Grass",
"Sand",
"Erase",
"Brick",
"Granite",
"Asphalt",
"Iron",
"Aluminum",
"Gold",
"Plank",
"Log",
"Gravel",
"Cinder Block",
"Stone Wall",
"Concrete",
"Plastic (red)",
"Plastic (blue)",
"Water",
}
local StringChoices = {}
for k, v in pairs(EnumMaterialNames) do
StringChoices[v] = k
end
function RbxGui.CreateTerrainMaterialSelector(size, position)
local terrainMaterialSelectionChanged = Instance.new "BindableEvent"
terrainMaterialSelectionChanged.Name = "TerrainMaterialSelectionChanged"
local selectedButton
local frame = Instance.new "Frame"
frame.Name = "TerrainMaterialSelector"
frame.Size = size or UDim2.new(0, 245, 0, 230)
if position then
frame.Position = position
end
frame.BorderSizePixel = 0
frame.BackgroundColor3 = Color3.new(0, 0, 0)
frame.Active = true
terrainMaterialSelectionChanged.Parent = frame
local materialToImageMap = {}
local currentMaterial: number = 1
local function updateMaterialChoice(choice)
currentMaterial = (StringChoices[choice] :: unknown) :: number
terrainMaterialSelectionChanged:Fire(currentMaterial)
end
for _, v in pairs(MaterialNames) do
local materials = {
Grass = 56563112,
Sand = 62356652,
Brick = 65961537,
Granite = 67532153,
Asphalt = 67532038,
Iron = 67532093,
Aluminum = 67531995,
Gold = 67532118,
["Plastic (red)"] = 67531848,
["Plastic (blue)"] = 67531924,
Plank = 67532015,
Log = 67532051,
Gravel = 67532206,
["Cinder Block"] = 67532103,
["Stone Wall"] = 67531804,
Concrete = 67532059,
Water = 81407474,
}
local toAdd = materials[v]
if not toAdd then
toAdd = 66887593
end
materialToImageMap[v] = {
Regular = path "asset?id=" .. toAdd,
}
end
local scrollFrame, scrollUp, scrollDown, recalculateScroll =
RbxGui.CreateScrollingFrame(nil, "grid")
scrollFrame.Size = UDim2.new(0.85, 0, 1, 0)
scrollFrame.Position = UDim2.new(0, 0, 0, 0)
scrollFrame.Parent = frame
scrollUp.Parent = frame
scrollUp.Visible = true
scrollUp.Position = UDim2.new(1, -19, 0, 0)
scrollDown.Parent = frame
scrollDown.Visible = true
scrollDown.Position = UDim2.new(1, -19, 1, -17)
local function goToNewMaterial(buttonWrap, materialName)
updateMaterialChoice(materialName)
buttonWrap.BackgroundTransparency = 0
selectedButton.BackgroundTransparency = 1
selectedButton = buttonWrap
end
local function createMaterialButton(name)
local buttonWrap = New "TextButton" {
Text = "",
Size = UDim2.new(0, 32, 0, 32),
BackgroundColor3 = Color3.new(1, 1, 1),
BorderSizePixel = 0,
BackgroundTransparency = 1,
AutoButtonColor = false,
Name = tostring(name),
New "NumberValue" {
Name = "EnumType",
Value = 0,
},
}
local imageButton = New "ImageButton" {
AutoButtonColor = false,
BackgroundTransparency = 1,
Size = UDim2.new(0, 30, 0, 30),
Position = UDim2.new(0, 1, 0, 1),
Name = tostring(name),
Parent = buttonWrap,
Image = materialToImageMap[name].Regular,
}
imageButton.MouseEnter:connect(function()
buttonWrap.BackgroundTransparency = 0
end)
imageButton.MouseLeave:connect(function()
if selectedButton ~= buttonWrap then
buttonWrap.BackgroundTransparency = 1
end
end)
imageButton.MouseButton1Click:connect(function()
if selectedButton ~= buttonWrap then
goToNewMaterial(buttonWrap, tostring(name))
end
end)
return buttonWrap
end
for i = 1, #MaterialNames do
local imageButton = createMaterialButton(MaterialNames[i])
if MaterialNames[i] == "Grass" then -- always start with grass as the default
selectedButton = imageButton
imageButton.BackgroundTransparency = 0
end
imageButton.Parent = scrollFrame
end
local function forceTerrainMaterialSelection(newMaterialType)
if not newMaterialType or currentMaterial == newMaterialType then
return
end
local matName = EnumMaterialNames[newMaterialType]
or MaterialNames[newMaterialType]
local buttons = scrollFrame:GetChildren()
for i = 1, #buttons do
if
(
buttons[i].Name == "Plastic (blue)"
and matName == "Plastic (blue)"
)
or (buttons[i].Name == "Plastic (red)" and matName == "Plastic (red)")
or string.find(buttons[i].Name, matName)
then
goToNewMaterial(buttons[i], matName)
return
end
end
end
frame.Changed:connect(function(prop)
if prop == "AbsoluteSize" then
recalculateScroll()
end
end)
recalculateScroll()
return frame, terrainMaterialSelectionChanged, forceTerrainMaterialSelection
end
function RbxGui.CreateLoadingFrame(name, size, position)
ContentProvider:Preload(path "asset?id=35238053")
local loadingFrame = New "Frame" {
Name = "LoadingFrame",
Style = Enum.FrameStyle.RobloxRound,
New "TextLabel" {
Name = "loadingName",
BackgroundTransparency = 1,
Size = UDim2.new(1, 0, 0, 18),
Position = UDim2.new(0, 0, 0, 2),
Font = Enum.Font.Arial,
Text = name,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeTransparency = 1,
FontSize = Enum.FontSize.Size18,
},
}
loadingFrame.Size = size or UDim2.new(0, 300, 0, 160)
loadingFrame.Position = position or UDim2.new(0.5, -150, 0.5, -80)
local loadingBar = New "Frame" {
Name = "LoadingBar",
BackgroundColor3 = Color3.new(0, 0, 0),
BorderColor3 = Colour3(79, 79, 79),
Position = UDim2.new(0, 0, 0, 41),
Size = UDim2.new(1, 0, 0, 30),
Parent = loadingFrame,
}
local loadingGreenBar = New "ImageLabel" {
Name = "LoadingGreenBar",
Image = path "asset?id=35238053",
Position = UDim2.new(0, 0, 0, 0),
Size = UDim2.new(0, 0, 1, 0),
Visible = false,
Parent = loadingBar,
}
local loadingPercent = New "TextLabel" {
Name = "LoadingPercent",
BackgroundTransparency = 1,
Position = UDim2.new(0, 0, 1, 0),
Size = UDim2.new(1, 0, 0, 14),
Font = Enum.Font.Arial,
Text = "0%",
FontSize = Enum.FontSize.Size14,
TextColor3 = Color3.new(1, 1, 1),
Parent = loadingBar,
}
local cancelButton = New "TextButton" {
Name = "CancelButton",
Position = UDim2.new(0.5, -60, 1, -40),
Size = UDim2.new(0, 120, 0, 40),
Font = Enum.Font.Arial,
FontSize = Enum.FontSize.Size18,
TextColor3 = Color3.new(1, 1, 1),
Text = "Cancel",
Style = Enum.ButtonStyle.RobloxButton,
Parent = loadingFrame,
}
local cancelButtonClicked = New "BindableEvent" {
Name = "CancelButtonClicked",
Parent = cancelButton,
}
cancelButton.MouseButton1Click:connect(function()
cancelButtonClicked:Fire()
end)
local function updateLoadingGuiPercent(
percent: number, -- thats not a percent bruh
tweenAction,
tweenLength
)
if percent and type(percent) ~= "number" then
error(
`updateLoadingGuiPercent expects number as argument, got {type(
percent
)} instead`
)
end
local newSize
if percent < 0 then
newSize = UDim2.new(0, 0, 1, 0)
elseif percent > 1 then
newSize = UDim2.new(1, 0, 1, 0)
else
newSize = UDim2.new(percent, 0, 1, 0)
end
if tweenAction then
if not tweenLength then
error "updateLoadingGuiPercent is set to tween new percentage, but got no tween time length! Please pass this in as third argument"
end
if newSize.X.Scale > 0 then
loadingGreenBar.Visible = true
loadingGreenBar:TweenSize(
newSize,
Enum.EasingDirection.Out,
Enum.EasingStyle.Quad,
tweenLength,
true
)
else
loadingGreenBar:TweenSize(
newSize,
Enum.EasingDirection.Out,
Enum.EasingStyle.Quad,
tweenLength,
true,
function()
if newSize.X.Scale < 0 then
loadingGreenBar.Visible = false
end
end
)
end
else
loadingGreenBar.Size = newSize
loadingGreenBar.Visible = (newSize.X.Scale > 0)
end
end
loadingGreenBar.Changed:connect(function(prop)
if prop == "Size" then
loadingPercent.Text =
`{math.ceil(loadingGreenBar.Size.X.Scale * 100)}%`
end
end)
return loadingFrame, updateLoadingGuiPercent, cancelButtonClicked
end
function RbxGui.CreatePluginFrame(
name: string,
size,
position,
scrollable,
parent
)
local function createMenuButton(
size,
position,
text,
fontsize,
name,
parent
)
local button = New "TextButton" {
AutoButtonColor = false,
Name = name,
BackgroundTransparency = 1,
Position = position,
Size = size,
Font = Enum.Font.ArialBold,
FontSize = fontsize,
Text = text,
TextColor3 = Color3.new(1, 1, 1),
BorderSizePixel = 0,
BackgroundColor3 = Colour3(20, 20, 20),
}
button.MouseEnter:connect(function()
if button.Selected then
return
end
button.BackgroundTransparency = 0
end)
button.MouseLeave:connect(function()
if button.Selected then
return
end
button.BackgroundTransparency = 1
end)
button.Parent = parent
return button
end
local function separatingLineC()
return New "Frame" {
Name = "SeparatingLine",
BackgroundColor3 = Colour3(115, 115, 115),
BorderSizePixel = 0,
Size = UDim2.new(0, 1, 0, 14),
}
end
local dragBar = New "ImageButton" {
Name = `{name}DragBar`,
BackgroundColor3 = Colour3(39, 39, 39),
BorderColor3 = Color3.new(0, 0, 0),
Active = true,
Draggable = true,
-- plugin name label
New "TextLabel" {
Name = "BarNameLabel",
Text = ` {name}`,
TextColor3 = Color3.new(1, 1, 1),
TextStrokeTransparency = 0,
Size = UDim2.new(1, 0, 1, 0),
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size18,
TextXAlignment = Enum.TextXAlignment.Left,
BackgroundTransparency = 1,
},
Hydrate(separatingLineC()) {
Position = UDim2.new(1, -18, 0.5, -7),
},
Hydrate(separatingLineC()) {
Position = UDim2.new(1, -35, 0.5, -7),
},
}
if size then
dragBar.Size = UDim2.new(size.X.Scale, size.X.Offset, 0, 20)
+ UDim2.new(0, 20, 0, 0)
else
dragBar.Size = UDim2.new(0, 183, 0, 20)
end
if position then
dragBar.Position = position
end
--dragBar.Visible = false
dragBar.MouseEnter:connect(function()
dragBar.BackgroundColor3 = Colour3(49, 49, 49)
end)
dragBar.MouseLeave:connect(function()
dragBar.BackgroundColor3 = Colour3(39, 39, 39)
end)
dragBar.Parent = parent
-- close button
local closeButton = createMenuButton(
UDim2.new(0, 15, 0, 17),
UDim2.new(1, -16, 0.5, -8),
"X",
Enum.FontSize.Size14,
"CloseButton",
dragBar
)
local closeEvent = New "BindableEvent" {
Name = "CloseEvent",
Parent = closeButton,
}
closeButton.MouseButton1Click:connect(function()
closeEvent:Fire()
closeButton.BackgroundTransparency = 1
end)
-- help button
local helpButton = createMenuButton(
UDim2.new(0, 15, 0, 17),
UDim2.new(1, -51, 0.5, -8),
"?",
Enum.FontSize.Size14,
"HelpButton",
dragBar
)
local helpFrame = New "Frame" {
Name = "HelpFrame",
BackgroundColor3 = Color3.new(0, 0, 0),
Size = UDim2.new(0, 300, 0, 552),
Position = UDim2.new(1, 5, 0, 0),
Active = true,
BorderSizePixel = 0,
Visible = false,
Parent = dragBar,
}
helpButton.MouseButton1Click:connect(function()
helpFrame.Visible = not helpFrame.Visible
if helpFrame.Visible then
helpButton.Selected = true
helpButton.BackgroundTransparency = 0
local screenGui = getScreenGuiAncestor(helpFrame)
if screenGui then
if
helpFrame.AbsolutePosition.X + helpFrame.AbsoluteSize.X
> screenGui.AbsoluteSize.X
then --position on left hand side
helpFrame.Position =
UDim2.new(0, -5 - helpFrame.AbsoluteSize.X, 0, 0)
else -- position on right hand side
helpFrame.Position = UDim2.new(1, 5, 0, 0)
end
else
helpFrame.Position = UDim2.new(1, 5, 0, 0)
end
else
helpButton.Selected = false
helpButton.BackgroundTransparency = 1
end
end)
local minimizeButton = createMenuButton(
UDim2.new(0, 16, 0, 17),
UDim2.new(1, -34, 0.5, -8),
"-",
Enum.FontSize.Size14,
"MinimizeButton",
dragBar
)
minimizeButton.TextYAlignment = Enum.TextYAlignment.Top
local minimizeFrame = New "Frame" {
Name = "MinimizeFrame",
BackgroundColor3 = Colour3(73, 73, 73),
BorderColor3 = Color3.new(0, 0, 0),
Position = UDim2.new(0, 0, 1, 0),
Visible = false,
Parent = dragBar,
}
if size then
minimizeFrame.Size = UDim2.new(size.X.Scale, size.X.Offset, 0, 50)
+ UDim2.new(0, 20, 0, 0)
else
minimizeFrame.Size = UDim2.new(0, 183, 0, 50)
end
minimizeFrame.Parent = dragBar
local minimizeBigButton = New "TextButton" {
Position = UDim2.new(0.5, -50, 0.5, -20),
Size = UDim2.new(0, 100, 0, 40),
Style = Enum.ButtonStyle.RobloxButton,
Font = Enum.Font.ArialBold,
FontSize = Enum.FontSize.Size18,
TextColor3 = Color3.new(1, 1, 1),
Text = "Show",
Parent = minimizeFrame,
}
local widgetContainer = New "Frame" {
Name = "WidgetContainer",
BackgroundTransparency = 1,
Position = UDim2.new(0, 0, 1, 0),
BorderColor3 = Color3.new(0, 0, 0),
}
if not scrollable then
widgetContainer.BackgroundTransparency = 0
widgetContainer.BackgroundColor3 = Colour3(72, 72, 72)
end
widgetContainer.Parent = dragBar
if size then
widgetContainer.Size = scrollable and size
or UDim2.new(0, dragBar.AbsoluteSize.X, size.Y.Scale, size.Y.Offset)
else
widgetContainer.Size = scrollable and UDim2.new(0, 163, 0, 400)
or UDim2.new(0, dragBar.AbsoluteSize.X, 0, 400)
end
if position then
widgetContainer.Position = position + UDim2.new(0, 0, 0, 20)
end
local frame, control, verticalDragger
if scrollable then
--frame for widgets
frame, control = RbxGui.CreateTrueScrollingFrame()
Hydrate(frame) {
Size = UDim2.new(1, 0, 1, 0),
BackgroundColor3 = Colour3(72, 72, 72),
BorderColor3 = Color3.new(0, 0, 0),
Active = true,
Parent = widgetContainer,
}
Hydrate(control) {
BackgroundColor3 = Colour3(72, 72, 72),
BorderSizePixel = 0,
BackgroundTransparency = 0,
Position = UDim2.new(1, -21, 1, 1),
New "Frame" {
Name = "FakeLine",
BackgroundColor3 = Color3.new(0, 0, 0),
BorderSizePixel = 0,
Size = UDim2.new(0, 1, 1, 1),
Position = UDim2.new(1, 0, 0, 0),
},
}
control.Size = size and UDim2.new(0, 21, size.Y.Scale, size.Y.Offset)
or UDim2.new(0, 21, 0, 400)
control:FindFirstChild("ScrollDownButton").Position =
UDim2.new(0, 0, 1, -20)
control.Parent = dragBar
local function scrubFrame()
return New "Frame" {
Name = "ScrubFrame",
BackgroundColor3 = Color3.new(1, 1, 1),
BorderSizePixel = 0,
Size = UDim2.new(0, 10, 0, 1),
ZIndex = 5,
}
end
verticalDragger = New "TextButton" {
ZIndex = 2,
AutoButtonColor = false,
Name = "VerticalDragger",
BackgroundColor3 = Colour3(50, 50, 50),
BorderColor3 = Color3.new(0, 0, 0),
Size = UDim2.new(1, 20, 0, 20),
Position = UDim2.new(0, 0, 1, 0),
Active = true,
Text = "",
Parent = widgetContainer,
Hydrate(scrubFrame()) {
Position = UDim2.new(0.5, -5, 0.5, -2),
},
Hydrate(scrubFrame()) {
Position = UDim2.new(0.5, -5, 0.5, 0),
},
Hydrate(scrubFrame()) {
Position = UDim2.new(0.5, -5, 0.5, 2),
},
}
local areaSoak = New "TextButton" {
Name = "AreaSoak",
Size = UDim2.new(1, 0, 1, 0),
BackgroundTransparency = 1,
BorderSizePixel = 0,
Text = "",
ZIndex = 10,
Visible = false,
Active = true,
Parent = getScreenGuiAncestor(parent),
}
local draggingVertical = false
local startYPos
verticalDragger.MouseEnter:connect(function()
verticalDragger.BackgroundColor3 = Colour3(60, 60, 60)
end)
verticalDragger.MouseLeave:connect(function()
verticalDragger.BackgroundColor3 = Colour3(50, 50, 50)
end)
verticalDragger.MouseButton1Down:connect(function(_, y)
draggingVertical = true
areaSoak.Visible = true
startYPos = y
end)
areaSoak.MouseButton1Up:connect(function()
draggingVertical = false
areaSoak.Visible = false
end)
areaSoak.MouseMoved:connect(function(_, y: number)
if not draggingVertical then
return
end
local yDelta = y - startYPos
if not control.ScrollDownButton.Visible and yDelta > 0 then
return
end
if (widgetContainer.Size.Y.Offset + yDelta) < 150 then
widgetContainer.Size = UDim2.new(
widgetContainer.Size.X.Scale,
widgetContainer.Size.X.Offset,
widgetContainer.Size.Y.Scale,
150
)
control.Size = UDim2.new(0, 21, 0, 150)
return
end
startYPos = y
if widgetContainer.Size.Y.Offset + yDelta >= 0 then
widgetContainer.Size = UDim2.new(
widgetContainer.Size.X.Scale,
widgetContainer.Size.X.Offset,
widgetContainer.Size.Y.Scale,
widgetContainer.Size.Y.Offset + yDelta
)
control.Size =
UDim2.new(0, 21, 0, control.Size.Y.Offset + yDelta)
end
end)
end
local function switchMinimize()
minimizeFrame.Visible = not minimizeFrame.Visible
if scrollable then
frame.Visible = not frame.Visible
verticalDragger.Visible = not verticalDragger.Visible
control.Visible = not control.Visible
else
widgetContainer.Visible = not widgetContainer.Visible
end
minimizeButton.Text = minimizeFrame.Visible and "+" or "-"
end
minimizeBigButton.MouseButton1Click:connect(function()
switchMinimize()
end)
minimizeButton.MouseButton1Click:connect(function()
switchMinimize()
end)
if scrollable then
return dragBar, frame, helpFrame, closeEvent
end
return dragBar, widgetContainer, helpFrame, closeEvent
end
function RbxGui.Help(funcNameOrFunc: string | (any) -> any)
-- input argument can be a string or a function. Should return a description (of arguments and expected side effects)
if
funcNameOrFunc == "CreatePropertyDropDownMenu"
or funcNameOrFunc == RbxGui.CreatePropertyDropDownMenu
then
return [[Function CreatePropertyDropDownMenu.
Arguments: (instance, propertyName, enumType).
Side effect: returns a container with a drop-down-box that is linked to the 'property' field of 'instance' which is of type 'enumType']]
elseif
funcNameOrFunc == "CreateDropDownMenu"
or funcNameOrFunc == RbxGui.CreateDropDownMenu
then
return [[Function CreateDropDownMenu.
Arguments: (items, onItemSelected).
Side effect: Returns 2 results, a container to the gui object and a 'updateSelection' function for external updating. The container is a drop-down-box created around a list of items]]
elseif
funcNameOrFunc == "CreateMessageDialog"
or funcNameOrFunc == RbxGui.CreateMessageDialog
then
return [[Function CreateMessageDialog.
Arguments: (title, message, buttons).
Side effect: Returns a gui object of a message box with 'title' and 'message' as passed in. 'buttons' input is an array of Tables contains a 'Text' and 'Function' field for the text/callback of each button]]
elseif
funcNameOrFunc == "CreateStyledMessageDialog"
or funcNameOrFunc == RbxGui.CreateStyledMessageDialog
then
return [[Function CreateStyledMessageDialog.
Arguments: (title, message, style, buttons).
Side effect: Returns a gui object of a message box with 'title' and 'message' as passed in. 'buttons' input is an array of Tables contains a 'Text' and 'Function' field for the text/callback of each button, 'style' is a string, either Error, Notify or Confirm]]
elseif
funcNameOrFunc == "GetFontHeight"
or funcNameOrFunc == RbxGui.GetFontHeight
then
return [[Function GetFontHeight.
Arguments: (font, fontSize).
Side effect: returns the size in pixels of the given font + fontSize]]
elseif
funcNameOrFunc == "CreateScrollingFrame"
or funcNameOrFunc == RbxGui.CreateScrollingFrame
then
return [[Function CreateScrollingFrame.
Arguments: (orderList, style)
Side effect: returns 4 objects, (scrollFrame, scrollUpButton, scrollDownButton, recalculateFunction). 'scrollFrame' can be filled with GuiObjects. It will lay them out and allow scrollUpButton/scrollDownButton to interact with them. Orderlist is optional (and specifies the order to layout the children. Without orderlist, it uses the children order. style is also optional, and allows for a 'grid' styling if style is passed 'grid' as a string. recalculateFunction can be called when a relayout is needed (when orderList changes)]]
elseif
funcNameOrFunc == "CreateTrueScrollingFrame"
or funcNameOrFunc == RbxGui.CreateTrueScrollingFrame
then
return [[Function CreateTrueScrollingFrame.
Arguments: (nil)
Side effect: returns 2 objects, (scrollFrame, controlFrame). 'scrollFrame' can be filled with GuiObjects, and they will be clipped if not inside the frame's bounds. controlFrame has children scrollup and scrolldown, as well as a slider. controlFrame can be parented to any guiobject and it will readjust itself to fit.]]
elseif
funcNameOrFunc == "AutoTruncateTextObject"
or funcNameOrFunc == RbxGui.AutoTruncateTextObject
then
return [[Function AutoTruncateTextObject.
Arguments: (textLabel)
Side effect: returns 2 objects, (textLabel, changeText). The 'textLabel' input is modified to automatically truncate text (with ellipsis), if it gets too small to fit. 'changeText' is a function that can be used to change the text, it takes 1 string as an argument]]
elseif
funcNameOrFunc == "CreateSlider"
or funcNameOrFunc == RbxGui.CreateSlider
then
return [[Function CreateSlider.
Arguments: (steps, width, position)
Side effect: returns 2 objects, (sliderGui, sliderPosition). The 'steps' argument specifies how many different positions the slider can hold along the bar. 'width' specifies in pixels how wide the bar should be (modifiable afterwards if desired). 'position' argument should be a UDim2 for slider positioning. 'sliderPosition' is an IntValue whose current .Value specifies the specific step the slider is currently on.]]
elseif
funcNameOrFunc == "CreateLoadingFrame"
or funcNameOrFunc == RbxGui.CreateLoadingFrame
then
return [[Function CreateLoadingFrame.
Arguments: (name, size, position)
Side effect: Creates a gui that can be manipulated to show progress for a particular action. Name appears above the loading bar, and size and position are udim2 values (both size and position are optional arguments). Returns 3 arguments, the first being the gui created. The second being updateLoadingGuiPercent, which is a bindable function. This function takes one argument (two optionally), which should be a number between 0 and 1, representing the percentage the loading gui should be at. The second argument to this function is a boolean value that if set to true will tween the current percentage value to the new percentage value, therefore our third argument is how long this tween should take. Our third returned argument is a BindableEvent, that when fired means that someone clicked the cancel button on the dialog.]]
elseif
funcNameOrFunc == "CreateTerrainMaterialSelector"
or funcNameOrFunc == RbxGui.CreateTerrainMaterialSelector
then
return [[Function CreateTerrainMaterialSelector.
Arguments: (size, position)
Side effect: Size and position are UDim2 values that specifies the selector's size and position. Both size and position are optional arguments. This method returns 3 objects (terrainSelectorGui, terrainSelected, forceTerrainSelection). terrainSelectorGui is just the gui object that we generate with this function, parent it as you like. TerrainSelected is a BindableEvent that is fired whenever a new terrain type is selected in the gui. ForceTerrainSelection is a function that takes an argument of Enum.CellMaterial and will force the gui to show that material as currently selected.]]
end
return "No help available for this function"
end
return RbxGui