0% found this document useful (0 votes)
9 views

Dex Final Version - Lua

Uploaded by

tdmasonplay
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views

Dex Final Version - Lua

Uploaded by

tdmasonplay
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 226

-- https://github.

com/LorekeeperZinnia/Dex

--[[
New Dex
Final Version
Developed by Moon
Modified for Infinite Yield

Dex is a debugging suite designed to help the user debug games and find any
potential vulnerabilities.

This is the final version of this script.


You are encouraged to edit, fork, do whatever with this. I pretty much won't
be updating it anymore.
Though I would appreciate it if you kept the credits in the script if you
enjoy this hard work.

If you want more info, you can join the server: https://discord.io/zinnia
Note that very limited to no support will be provided.
]]

local nodes = {}
local selection
local clonerefs = cloneref or function(...) return ... end

local EmbeddedModules = {
Explorer = function()
--[[
Explorer App Module

The main explorer interface


]]

-- Common Locals
local Main,Lib,Apps,Settings -- Main Containers
local Explorer, Properties, ScriptViewer, Notebook -- Major Apps
local API,RMD,env,service,plr,create,createSimple -- Main Locals

local function initDeps(data)


Main = data.Main
Lib = data.Lib
Apps = data.Apps
Settings = data.Settings

API = data.API
RMD = data.RMD
env = data.env
service = data.service
plr = data.plr
create = data.create
createSimple = data.createSimple
end

local function initAfterMain()


Explorer = Apps.Explorer
Properties = Apps.Properties
ScriptViewer = Apps.ScriptViewer
Notebook = Apps.Notebook
end
local function main()
local Explorer = {}
local tree,listEntries,explorerOrders,searchResults,specResults = {},{},{},
{},{}
local expanded
local
entryTemplate,treeFrame,toolBar,descendantAddedCon,descendantRemovingCon,itemChange
dCon
local ffa = game.FindFirstAncestorWhichIsA
local getDescendants = game.GetDescendants
local getTextSize = service.TextService.GetTextSize
local updateDebounce,refreshDebounce = false,false
local nilNode = {Obj = Instance.new("Folder")}
local idCounter = 0
local scrollV,scrollH,clipboard
local renameBox,renamingNode,searchFunc
local sortingEnabled,autoUpdateSearch
local table,math = table,math
local nilMap,nilCons = {},{}
local connectSignal = game.DescendantAdded.Connect
local addObject,removeObject,moveObject = nil,nil,nil

addObject = function(root)
if nodes[root] then return end

local isNil = false


local rootParObj = ffa(root,"Instance")
local par = nodes[rootParObj]

-- Nil Handling
if not par then
if nilMap[root] then
nilCons[root] = nilCons[root] or {
connectSignal(root.ChildAdded,addObject),
connectSignal(root.AncestryChanged,moveObject),
}
par = nilNode
isNil = true
else
return
end
elseif nilMap[rootParObj] or par == nilNode then
nilMap[root] = true
nilCons[root] = nilCons[root] or {
connectSignal(root.ChildAdded,addObject),
connectSignal(root.AncestryChanged,moveObject),
}
isNil = true
end

local newNode = {Obj = root, Parent = par}


nodes[root] = newNode

-- Automatic sorting if expanded


if sortingEnabled and expanded[par] and par.Sorted then
local left,right = 1,#par
local floor = math.floor
local sorter = Explorer.NodeSorter
local pos = (right == 0 and 1)

if not pos then


while true do
if left >= right then
if sorter(newNode,par[left]) then
pos = left
else
pos = left+1
end
break
end

local mid = floor((left+right)/2)


if sorter(newNode,par[mid]) then
right = mid-1
else
left = mid+1
end
end
end

table.insert(par,pos,newNode)
else
par[#par+1] = newNode
par.Sorted = nil
end

local insts = getDescendants(root)


for i = 1,#insts do
local obj = insts[i]
if nodes[obj] then continue end -- Deferred

local par = nodes[ffa(obj,"Instance")]


if not par then continue end
local newNode = {Obj = obj, Parent = par}
nodes[obj] = newNode
par[#par+1] = newNode

-- Nil Handling
if isNil then
nilMap[obj] = true
nilCons[obj] = nilCons[obj] or {
connectSignal(obj.ChildAdded,addObject),
connectSignal(obj.AncestryChanged,moveObject),
}
end
end

if searchFunc and autoUpdateSearch then


searchFunc({newNode})
end

if not updateDebounce and Explorer.IsNodeVisible(par) then


if expanded[par] then
Explorer.PerformUpdate()
elseif not refreshDebounce then
Explorer.PerformRefresh()
end
end
end

removeObject = function(root)
local node = nodes[root]
if not node then return end

-- Nil Handling
if nilMap[node.Obj] then
moveObject(node.Obj)
return
end

local par = node.Parent


if par then
par.HasDel = true
end

local function recur(root)


for i = 1,#root do
local node = root[i]
if not node.Del then
nodes[node.Obj] = nil
if #node > 0 then recur(node) end
end
end
end
recur(node)
node.Del = true
nodes[root] = nil

if par and not updateDebounce and Explorer.IsNodeVisible(par) then


if expanded[par] then
Explorer.PerformUpdate()
elseif not refreshDebounce then
Explorer.PerformRefresh()
end
end
end

moveObject = function(obj)
local node = nodes[obj]
if not node then return end

local oldPar = node.Parent


local newPar = nodes[ffa(obj,"Instance")]
if oldPar == newPar then return end

-- Nil Handling
if not newPar then
if nilMap[obj] then
newPar = nilNode
else
return
end
elseif nilMap[newPar.Obj] or newPar == nilNode then
nilMap[obj] = true
nilCons[obj] = nilCons[obj] or {
connectSignal(obj.ChildAdded,addObject),
connectSignal(obj.AncestryChanged,moveObject),
}
end

if oldPar then
local parPos = table.find(oldPar,node)
if parPos then table.remove(oldPar,parPos) end
end

node.Id = nil
node.Parent = newPar

if sortingEnabled and expanded[newPar] and newPar.Sorted then


local left,right = 1,#newPar
local floor = math.floor
local sorter = Explorer.NodeSorter
local pos = (right == 0 and 1)

if not pos then


while true do
if left >= right then
if sorter(node,newPar[left]) then
pos = left
else
pos = left+1
end
break
end

local mid = floor((left+right)/2)


if sorter(node,newPar[mid]) then
right = mid-1
else
left = mid+1
end
end
end

table.insert(newPar,pos,node)
else
newPar[#newPar+1] = node
newPar.Sorted = nil
end

if searchFunc and searchResults[node] then


local currentNode = node.Parent
while currentNode and (not searchResults[currentNode] or
expanded[currentNode] == 0) do
expanded[currentNode] = true
searchResults[currentNode] = true
currentNode = currentNode.Parent
end
end

if not updateDebounce and (Explorer.IsNodeVisible(newPar) or


Explorer.IsNodeVisible(oldPar)) then
if expanded[newPar] or expanded[oldPar] then
Explorer.PerformUpdate()
elseif not refreshDebounce then
Explorer.PerformRefresh()
end
end
end

Explorer.ViewWidth = 0
Explorer.Index = 0
Explorer.EntryIndent = 20
Explorer.FreeWidth = 32
Explorer.GuiElems = {}

Explorer.InitRenameBox = function()
renameBox = create({{1,"TextBox",
{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Bo
rderColor3=Color3.new(0.062745101749897,0.51764708757401,1),BorderMode=2,ClearTextO
nFocus=false,Font=3,Name="RenameBox",PlaceholderColor3=Color3.new(0.69803923368454,
0.69803923368454,0.69803923368454),Position=UDim2.new(0,26,0,2),Size=UDim2.new(0,20
0,0,16),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=0,Visible=f
alse,ZIndex=2}}})

renameBox.Parent = Explorer.Window.GuiElems.Content.List

renameBox.FocusLost:Connect(function()
if not renamingNode then return end

pcall(function() renamingNode.Obj.Name = renameBox.Text end)


renamingNode = nil
Explorer.Refresh()
end)

renameBox.Focused:Connect(function()
renameBox.SelectionStart = 1
renameBox.CursorPosition = #renameBox.Text + 1
end)
end

Explorer.SetRenamingNode = function(node)
renamingNode = node
renameBox.Text = tostring(node.Obj)
renameBox:CaptureFocus()
Explorer.Refresh()
end

Explorer.SetSortingEnabled = function(val)
sortingEnabled = val
Settings.Explorer.Sorting = val
end

Explorer.UpdateView = function()
local maxNodes = math.ceil(treeFrame.AbsoluteSize.Y / 20)
local maxX = treeFrame.AbsoluteSize.X
local totalWidth = Explorer.ViewWidth + Explorer.FreeWidth

scrollV.VisibleSpace = maxNodes
scrollV.TotalSpace = #tree + 1
scrollH.VisibleSpace = maxX
scrollH.TotalSpace = totalWidth

scrollV.Gui.Visible = #tree + 1 > maxNodes


scrollH.Gui.Visible = totalWidth > maxX

local oldSize = treeFrame.Size


treeFrame.Size = UDim2.new(1,(scrollV.Gui.Visible and -16 or 0),1,
(scrollH.Gui.Visible and -39 or -23))
if oldSize ~= treeFrame.Size then
Explorer.UpdateView()
else
scrollV:Update()
scrollH:Update()

renameBox.Size = UDim2.new(0,maxX-100,0,16)

if scrollV.Gui.Visible and scrollH.Gui.Visible then


scrollV.Gui.Size = UDim2.new(0,16,1,-39)
scrollH.Gui.Size = UDim2.new(1,-16,0,16)
Explorer.Window.GuiElems.Content.ScrollCorner.Visible =
true
else
scrollV.Gui.Size = UDim2.new(0,16,1,-23)
scrollH.Gui.Size = UDim2.new(1,0,0,16)
Explorer.Window.GuiElems.Content.ScrollCorner.Visible =
false
end

Explorer.Index = scrollV.Index
end
end

Explorer.NodeSorter = function(a,b)
if a.Del or b.Del then return false end -- Ghost node

local aClass = a.Class


local bClass = b.Class
if not aClass then aClass = a.Obj.ClassName a.Class = aClass end
if not bClass then bClass = b.Obj.ClassName b.Class = bClass end

local aOrder = explorerOrders[aClass]


local bOrder = explorerOrders[bClass]
if not aOrder then aOrder = RMD.Classes[aClass] and
tonumber(RMD.Classes[aClass].ExplorerOrder) or 9999 explorerOrders[aClass] = aOrder
end
if not bOrder then bOrder = RMD.Classes[bClass] and
tonumber(RMD.Classes[bClass].ExplorerOrder) or 9999 explorerOrders[bClass] = bOrder
end

if aOrder ~= bOrder then


return aOrder < bOrder
else
local aName,bName = tostring(a.Obj),tostring(b.Obj)
if aName ~= bName then
return aName < bName
elseif aClass ~= bClass then
return aClass < bClass
else
local aId = a.Id if not aId then aId = idCounter idCounter
= (idCounter+0.001)%999999999 a.Id = aId end
local bId = b.Id if not bId then bId = idCounter idCounter
= (idCounter+0.001)%999999999 b.Id = bId end
return aId < bId
end
end
end

Explorer.Update = function()
table.clear(tree)
local maxNameWidth,maxDepth,count = 0,1,1
local nameCache = {}
local font = Enum.Font.SourceSans
local size = Vector2.new(math.huge,20)
local useNameWidth = Settings.Explorer.UseNameWidth
local tSort = table.sort
local sortFunc = Explorer.NodeSorter
local isSearching = (expanded == Explorer.SearchExpanded)
local textServ = service.TextService

local function recur(root,depth)


if depth > maxDepth then maxDepth = depth end
depth = depth + 1
if sortingEnabled and not root.Sorted then
tSort(root,sortFunc)
root.Sorted = true
end
for i = 1,#root do
local n = root[i]

if (isSearching and not searchResults[n]) or n.Del then


continue end

if useNameWidth then
local nameWidth = n.NameWidth
if not nameWidth then
local objName = tostring(n.Obj)
nameWidth = nameCache[objName]
if not nameWidth then
nameWidth =
getTextSize(textServ,objName,14,font,size).X
nameCache[objName] = nameWidth
end
n.NameWidth = nameWidth
end
if nameWidth > maxNameWidth then
maxNameWidth = nameWidth
end
end

tree[count] = n
count = count + 1
if expanded[n] and #n > 0 then
recur(n,depth)
end
end
end

recur(nodes[game],1)

-- Nil Instances
if env.getnilinstances then
if not (isSearching and not searchResults[nilNode]) then
tree[count] = nilNode
count = count + 1
if expanded[nilNode] then
recur(nilNode,2)
end
end
end

Explorer.MaxNameWidth = maxNameWidth
Explorer.MaxDepth = maxDepth
Explorer.ViewWidth = useNameWidth and Explorer.EntryIndent*maxDepth +
maxNameWidth + 26 or Explorer.EntryIndent*maxDepth + 226
Explorer.UpdateView()
end

Explorer.StartDrag = function(offX,offY)
if Explorer.Dragging then return end
Explorer.Dragging = true

local dragTree = treeFrame:Clone()


dragTree:ClearAllChildren()

for i,v in pairs(listEntries) do


local node = tree[i + Explorer.Index]
if node and selection.Map[node] then
local clone = v:Clone()
clone.Active = false
clone.Indent.Expand.Visible = false
clone.Parent = dragTree
end
end

local newGui = Instance.new("ScreenGui")


newGui.DisplayOrder = Main.DisplayOrders.Menu
dragTree.Parent = newGui
Lib.ShowGui(newGui)

local dragOutline = create({


{1,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="DragSelect",Size
=UDim2.new(1,0,1,0),}},
{2,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BorderSizePixel=0,Name="Line",Parent={1},Size=U
Dim2.new(1,0,0,1),ZIndex=2,}},
{3,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BorderSizePixel=0,Name="Line",Parent={1},Positi
on=UDim2.new(0,0,1,-1),Size=UDim2.new(1,0,0,1),ZIndex=2,}},
{4,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BorderSizePixel=0,Name="Line",Parent={1},Size=U
Dim2.new(0,1,1,0),ZIndex=2,}},
{5,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BorderSizePixel=0,Name="Line",Parent={1},Positi
on=UDim2.new(1,-1,0,0),Size=UDim2.new(0,1,1,0),ZIndex=2,}},
})
dragOutline.Parent = treeFrame

local mouse = Main.Mouse or service.Players.LocalPlayer:GetMouse()


local function move()
local posX = mouse.X - offX
local posY = mouse.Y - offY
dragTree.Position = UDim2.new(0,posX,0,posY)

for i = 1,#listEntries do
local entry = listEntries[i]
if Lib.CheckMouseInGui(entry) then
dragOutline.Position =
UDim2.new(0,entry.Indent.Position.X.Offset-scrollH.Index,0,entry.Position.Y.Offset)
dragOutline.Size = UDim2.new(0,entry.Size.X.Offset-
entry.Indent.Position.X.Offset,0,20)
dragOutline.Visible = true
return
end
end
dragOutline.Visible = false
end
move()

local input = service.UserInputService


local mouseEvent,releaseEvent

mouseEvent = input.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
move()
end
end)

releaseEvent = input.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
newGui:Destroy()
dragOutline:Destroy()
Explorer.Dragging = false

for i = 1,#listEntries do
if Lib.CheckMouseInGui(listEntries[i]) then
local node = tree[i + Explorer.Index]
if node then
if selection.Map[node] then return end
local newPar = node.Obj
local sList = selection.List
for i = 1,#sList do
local n = sList[i]
pcall(function() n.Obj.Parent =
newPar end)
end
Explorer.ViewNode(sList[1])
end
break
end
end
end
end)
end

Explorer.NewListEntry = function(index)
local newEntry = entryTemplate:Clone()
newEntry.Position = UDim2.new(0,0,0,20*(index-1))

local isRenaming = false

newEntry.InputBegan:Connect(function(input)
local node = tree[index + Explorer.Index]
if not node or selection.Map[node] or input.UserInputType ~=
Enum.UserInputType.MouseMovement then return end

newEntry.Indent.BackgroundColor3 = Settings.Theme.Button
newEntry.Indent.BorderSizePixel = 0
newEntry.Indent.BackgroundTransparency = 0
end)

newEntry.InputEnded:Connect(function(input)
local node = tree[index + Explorer.Index]
if not node or selection.Map[node] or input.UserInputType ~=
Enum.UserInputType.MouseMovement then return end

newEntry.Indent.BackgroundTransparency = 1
end)

newEntry.MouseButton1Down:Connect(function()

end)

newEntry.MouseButton1Up:Connect(function()

end)

newEntry.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 then
local releaseEvent,mouseEvent

local mouse = Main.Mouse or plr:GetMouse()


local startX = mouse.X
local startY = mouse.Y

local listOffsetX = startX - treeFrame.AbsolutePosition.X


local listOffsetY = startY - treeFrame.AbsolutePosition.Y

releaseEvent =
clonerefs(game:GetService("UserInputService")).InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseButton1 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
end
end)

mouseEvent =
clonerefs(game:GetService("UserInputService")).InputChanged:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
local deltaX = mouse.X - startX
local deltaY = mouse.Y - startY
local dist = math.sqrt(deltaX^2 + deltaY^2)
if dist > 5 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
isRenaming = false

Explorer.StartDrag(listOffsetX,listOffsetY)
end
end
end)
end
end)

newEntry.MouseButton2Down:Connect(function()

end)

newEntry.Indent.Expand.InputBegan:Connect(function(input)
local node = tree[index + Explorer.Index]
if not node or input.UserInputType ~=
Enum.UserInputType.MouseMovement then return end

Explorer.MiscIcons:DisplayByKey(newEntry.Indent.Expand.Icon,
expanded[node] and "Collapse_Over" or "Expand_Over")
end)

newEntry.Indent.Expand.InputEnded:Connect(function(input)
local node = tree[index + Explorer.Index]
if not node or input.UserInputType ~=
Enum.UserInputType.MouseMovement then return end

Explorer.MiscIcons:DisplayByKey(newEntry.Indent.Expand.Icon,
expanded[node] and "Collapse" or "Expand")
end)

newEntry.Indent.Expand.MouseButton1Down:Connect(function()
local node = tree[index + Explorer.Index]
if not node or #node == 0 then return end

expanded[node] = not expanded[node]


Explorer.Update()
Explorer.Refresh()
end)

newEntry.Parent = treeFrame
return newEntry
end

Explorer.Refresh = function()
local maxNodes = math.max(math.ceil((treeFrame.AbsoluteSize.Y) / 20),0)

local renameNodeVisible = false


local isa = game.IsA

for i = 1,maxNodes do
local entry = listEntries[i]
if not listEntries[i] then entry = Explorer.NewListEntry(i)
listEntries[i] = entry Explorer.ClickSystem:Add(entry) end

local node = tree[i + Explorer.Index]


if node then
local obj = node.Obj
local depth = Explorer.EntryIndent*Explorer.NodeDepth(node)

entry.Visible = true
entry.Position = UDim2.new(0,-
scrollH.Index,0,entry.Position.Y.Offset)
entry.Size = UDim2.new(0,Explorer.ViewWidth,0,20)
entry.Indent.EntryName.Text = tostring(node.Obj)
entry.Indent.Position = UDim2.new(0,depth,0,0)
entry.Indent.Size = UDim2.new(1,-depth,1,0)

entry.Indent.EntryName.TextTruncate =
(Settings.Explorer.UseNameWidth and Enum.TextTruncate.None or
Enum.TextTruncate.AtEnd)

if (isa(obj,"LocalScript") or isa(obj,"Script")) and


obj.Disabled then
Explorer.MiscIcons:DisplayByKey(entry.Indent.Icon,
isa(obj,"LocalScript") and "LocalScript_Disabled" or "Script_Disabled")
else
local rmdEntry = RMD.Classes[obj.ClassName]
Explorer.ClassIcons:Display(entry.Indent.Icon,
rmdEntry and rmdEntry.ExplorerImageIndex or 0)
end

if selection.Map[node] then
entry.Indent.BackgroundColor3 =
Settings.Theme.ListSelection
entry.Indent.BorderSizePixel = 0
entry.Indent.BackgroundTransparency = 0
else
if Lib.CheckMouseInGui(entry) then
entry.Indent.BackgroundColor3 =
Settings.Theme.Button
else
entry.Indent.BackgroundTransparency = 1
end
end

if node == renamingNode then


renameNodeVisible = true
renameBox.Position = UDim2.new(0,depth+25-
scrollH.Index,0,entry.Position.Y.Offset+2)
renameBox.Visible = true
end

if #node > 0 and expanded[node] ~= 0 then


if Lib.CheckMouseInGui(entry.Indent.Expand) then

Explorer.MiscIcons:DisplayByKey(entry.Indent.Expand.Icon, expanded[node] and


"Collapse_Over" or "Expand_Over")
else

Explorer.MiscIcons:DisplayByKey(entry.Indent.Expand.Icon, expanded[node] and


"Collapse" or "Expand")
end
entry.Indent.Expand.Visible = true
else
entry.Indent.Expand.Visible = false
end
else
entry.Visible = false
end
end

if not renameNodeVisible then


renameBox.Visible = false
end

for i = maxNodes+1, #listEntries do


Explorer.ClickSystem:Remove(listEntries[i])
listEntries[i]:Destroy()
listEntries[i] = nil
end
end

Explorer.PerformUpdate = function(instant)
updateDebounce = true
Lib.FastWait(not instant and 0.1)
if not updateDebounce then return end
updateDebounce = false
if not Explorer.Window:IsVisible() then return end
Explorer.Update()
Explorer.Refresh()
end

Explorer.ForceUpdate = function(norefresh)
updateDebounce = false
Explorer.Update()
if not norefresh then Explorer.Refresh() end
end

Explorer.PerformRefresh = function()
refreshDebounce = true
Lib.FastWait(0.1)
refreshDebounce = false
if updateDebounce or not Explorer.Window:IsVisible() then return end
Explorer.Refresh()
end

Explorer.IsNodeVisible = function(node)
if not node then return end

local curNode = node.Parent


while curNode do
if not expanded[curNode] then return false end
curNode = curNode.Parent
end
return true
end

Explorer.NodeDepth = function(node)
local depth = 0

if node == nilNode then


return 1
end
local curNode = node.Parent
while curNode do
if curNode == nilNode then depth = depth + 1 end
curNode = curNode.Parent
depth = depth + 1
end
return depth
end

Explorer.SetupConnections = function()
if descendantAddedCon then descendantAddedCon:Disconnect() end
if descendantRemovingCon then descendantRemovingCon:Disconnect() end
if itemChangedCon then itemChangedCon:Disconnect() end

if Main.Elevated then
descendantAddedCon = game.DescendantAdded:Connect(addObject)
descendantRemovingCon =
game.DescendantRemoving:Connect(removeObject)
else
descendantAddedCon = game.DescendantAdded:Connect(function(obj)
pcall(addObject,obj) end)
descendantRemovingCon =
game.DescendantRemoving:Connect(function(obj) pcall(removeObject,obj) end)
end

if Settings.Explorer.UseNameWidth then
itemChangedCon = game.ItemChanged:Connect(function(obj,prop)
if prop == "Parent" and nodes[obj] then
moveObject(obj)
elseif prop == "Name" and nodes[obj] then
nodes[obj].NameWidth = nil
end
end)
else
itemChangedCon = game.ItemChanged:Connect(function(obj,prop)
if prop == "Parent" and nodes[obj] then
moveObject(obj)
end
end)
end
end

Explorer.ViewNode = function(node)
if not node then return end

Explorer.MakeNodeVisible(node)
Explorer.ForceUpdate(true)
local visibleSpace = scrollV.VisibleSpace

for i,v in next,tree do


if v == node then
local relative = i - 1
if Explorer.Index > relative then
scrollV.Index = relative
elseif Explorer.Index + visibleSpace - 1 <= relative then
scrollV.Index = relative - visibleSpace + 2
end
end
end

scrollV:Update() Explorer.Index = scrollV.Index


Explorer.Refresh()
end

Explorer.ViewObj = function(obj)
Explorer.ViewNode(nodes[obj])
end

Explorer.MakeNodeVisible = function(node,expandRoot)
if not node then return end

local hasExpanded = false

if expandRoot and not expanded[node] then


expanded[node] = true
hasExpanded = true
end

local currentNode = node.Parent


while currentNode do
hasExpanded = true
expanded[currentNode] = true
currentNode = currentNode.Parent
end

if hasExpanded and not updateDebounce then


coroutine.wrap(Explorer.PerformUpdate)(true)
end
end

Explorer.ShowRightClick = function()
local context = Explorer.RightClickContext
context:Clear()

local sList = selection.List


local sMap = selection.Map
local emptyClipboard = #clipboard == 0
local presentClasses = {}
local apiClasses = API.Classes

for i = 1, #sList do
local node = sList[i]
local class = node.Class
if not class then class = node.Obj.ClassName node.Class = class
end
local curClass = apiClasses[class]
while curClass and not presentClasses[curClass.Name] do
presentClasses[curClass.Name] = true
curClass = curClass.Superclass
end
end

context:AddRegistered("CUT")
context:AddRegistered("COPY")
context:AddRegistered("PASTE", emptyClipboard)
context:AddRegistered("DUPLICATE")
context:AddRegistered("DELETE")
context:AddRegistered("RENAME", #sList ~= 1)

context:AddDivider()
context:AddRegistered("GROUP")
context:AddRegistered("UNGROUP")
context:AddRegistered("SELECT_CHILDREN")
context:AddRegistered("JUMP_TO_PARENT")
context:AddRegistered("EXPAND_ALL")
context:AddRegistered("COLLAPSE_ALL")

context:AddDivider()
if expanded == Explorer.SearchExpanded then
context:AddRegistered("CLEAR_SEARCH_AND_JUMP_TO") end
if env.setclipboard then context:AddRegistered("COPY_PATH") end
context:AddRegistered("INSERT_OBJECT")
context:AddRegistered("SAVE_INST")
context:AddRegistered("CALL_FUNCTION")
context:AddRegistered("VIEW_CONNECTIONS")
context:AddRegistered("GET_REFERENCES")
context:AddRegistered("VIEW_API")

context:QueueDivider()

if presentClasses["BasePart"] or presentClasses["Model"] then


context:AddRegistered("TELEPORT_TO")
context:AddRegistered("VIEW_OBJECT")
end

if presentClasses["TouchTransmitter"] then
context:AddRegistered("FIRE_TOUCHTRANSMITTER", firetouchinterest == nil) end
if presentClasses["ClickDetector"] then
context:AddRegistered("FIRE_CLICKDETECTOR", fireclickdetector == nil) end
if presentClasses["ProximityPrompt"] then
context:AddRegistered("FIRE_PROXIMITYPROMPT", fireproximityprompt == nil) end
if presentClasses["Player"] then
context:AddRegistered("SELECT_CHARACTER") end
if presentClasses["Players"] then
context:AddRegistered("SELECT_LOCAL_PLAYER") end
if presentClasses["LuaSourceContainer"] then
context:AddRegistered("VIEW_SCRIPT") end

if sMap[nilNode] then
context:AddRegistered("REFRESH_NIL")
context:AddRegistered("HIDE_NIL")
end

Explorer.LastRightClickX, Explorer.LastRightClickY = Main.Mouse.X,


Main.Mouse.Y
context:Show()
end

Explorer.InitRightClick = function()
local context = Lib.ContextMenu.new()

context:Register("CUT",{Name = "Cut", IconMap = Explorer.MiscIcons,


Icon = "Cut", DisabledIcon = "Cut_Disabled", Shortcut = "Ctrl+Z", OnClick =
function()
local destroy,clone = game.Destroy,game.Clone
local sList,newClipboard = selection.List,{}
local count = 1
for i = 1,#sList do
local inst = sList[i].Obj
local s,cloned = pcall(clone,inst)
if s and cloned then
newClipboard[count] = cloned
count = count + 1
end
pcall(destroy,inst)
end
clipboard = newClipboard
selection:Clear()
end})

context:Register("COPY",{Name = "Copy", IconMap = Explorer.MiscIcons,


Icon = "Copy", DisabledIcon = "Copy_Disabled", Shortcut = "Ctrl+C", OnClick =
function()
local clone = game.Clone
local sList,newClipboard = selection.List,{}
local count = 1
for i = 1,#sList do
local inst = sList[i].Obj
local s,cloned = pcall(clone,inst)
if s and cloned then
newClipboard[count] = cloned
count = count + 1
end
end
clipboard = newClipboard
end})

context:Register("PASTE",{Name = "Paste Into", IconMap =


Explorer.MiscIcons, Icon = "Paste", DisabledIcon = "Paste_Disabled", Shortcut =
"Ctrl+Shift+V", OnClick = function()
local sList = selection.List
local newSelection = {}
local count = 1
for i = 1,#sList do
local node = sList[i]
local inst = node.Obj
Explorer.MakeNodeVisible(node,true)
for c = 1,#clipboard do
local cloned = clipboard[c]:Clone()
if cloned then
cloned.Parent = inst
local clonedNode = nodes[cloned]
if clonedNode then newSelection[count] =
clonedNode count = count + 1 end
end
end
end
selection:SetTable(newSelection)

if #newSelection > 0 then


Explorer.ViewNode(newSelection[1])
end
end})
context:Register("DUPLICATE",{Name = "Duplicate", IconMap =
Explorer.MiscIcons, Icon = "Copy", DisabledIcon = "Copy_Disabled", Shortcut =
"Ctrl+D", OnClick = function()
local clone = game.Clone
local sList = selection.List
local newSelection = {}
local count = 1
for i = 1,#sList do
local node = sList[i]
local inst = node.Obj
local instPar = node.Parent and node.Parent.Obj
Explorer.MakeNodeVisible(node)
local s,cloned = pcall(clone,inst)
if s and cloned then
cloned.Parent = instPar
local clonedNode = nodes[cloned]
if clonedNode then newSelection[count] = clonedNode
count = count + 1 end
end
end

selection:SetTable(newSelection)
if #newSelection > 0 then
Explorer.ViewNode(newSelection[1])
end
end})

context:Register("DELETE",{Name = "Delete", IconMap =


Explorer.MiscIcons, Icon = "Delete", DisabledIcon = "Delete_Disabled", Shortcut =
"Del", OnClick = function()
local destroy = game.Destroy
local sList = selection.List
for i = 1,#sList do
pcall(destroy,sList[i].Obj)
end
selection:Clear()
end})

context:Register("RENAME",{Name = "Rename", IconMap =


Explorer.MiscIcons, Icon = "Rename", DisabledIcon = "Rename_Disabled", Shortcut =
"F2", OnClick = function()
local sList = selection.List
if sList[1] then
Explorer.SetRenamingNode(sList[1])
end
end})

context:Register("GROUP",{Name = "Group", IconMap = Explorer.MiscIcons,


Icon = "Group", DisabledIcon = "Group_Disabled", Shortcut = "Ctrl+G", OnClick =
function()
local sList = selection.List
if #sList == 0 then return end

local model = Instance.new("Model",sList[#sList].Obj.Parent)


for i = 1,#sList do
pcall(function() sList[i].Obj.Parent = model end)
end

if nodes[model] then
selection:Set(nodes[model])
Explorer.ViewNode(nodes[model])
end
end})

context:Register("UNGROUP",{Name = "Ungroup", IconMap =


Explorer.MiscIcons, Icon = "Ungroup", DisabledIcon = "Ungroup_Disabled", Shortcut =
"Ctrl+U", OnClick = function()
local newSelection = {}
local count = 1
local isa = game.IsA

local function ungroup(node)


local par = node.Parent.Obj
local ch = {}
local chCount = 1

for i = 1,#node do
local n = node[i]
newSelection[count] = n
ch[chCount] = n
count = count + 1
chCount = chCount + 1
end

for i = 1,#ch do
pcall(function() ch[i].Obj.Parent = par end)
end

node.Obj:Destroy()
end

for i,v in next,selection.List do


if isa(v.Obj,"Model") then
ungroup(v)
end
end

selection:SetTable(newSelection)
if #newSelection > 0 then
Explorer.ViewNode(newSelection[1])
end
end})

context:Register("SELECT_CHILDREN",{Name = "Select Children", IconMap =


Explorer.MiscIcons, Icon = "SelectChildren", DisabledIcon =
"SelectChildren_Disabled", OnClick = function()
local newSelection = {}
local count = 1
local sList = selection.List

for i = 1,#sList do
local node = sList[i]
for ind = 1,#node do
local cNode = node[ind]
if ind == 1 then Explorer.MakeNodeVisible(cNode) end

newSelection[count] = cNode
count = count + 1
end
end

selection:SetTable(newSelection)
if #newSelection > 0 then
Explorer.ViewNode(newSelection[1])
else
Explorer.Refresh()
end
end})

context:Register("JUMP_TO_PARENT",{Name = "Jump to Parent", IconMap =


Explorer.MiscIcons, Icon = "JumpToParent", OnClick = function()
local newSelection = {}
local count = 1
local sList = selection.List

for i = 1,#sList do
local node = sList[i]
if node.Parent then
newSelection[count] = node.Parent
count = count + 1
end
end

selection:SetTable(newSelection)
if #newSelection > 0 then
Explorer.ViewNode(newSelection[1])
else
Explorer.Refresh()
end
end})

context:Register("TELEPORT_TO",{Name = "Teleport To", IconMap =


Explorer.MiscIcons, Icon = "TeleportTo", OnClick = function()
local sList = selection.List
local isa = game.IsA

local hrp = plr.Character and


plr.Character:FindFirstChild("HumanoidRootPart")
if not hrp then return end

for i = 1,#sList do
local node = sList[i]

if isa(node.Obj,"BasePart") then
hrp.CFrame = node.Obj.CFrame +
Settings.Explorer.TeleportToOffset
break
elseif isa(node.Obj,"Model") then
if node.Obj.PrimaryPart then
hrp.CFrame = node.Obj.PrimaryPart.CFrame +
Settings.Explorer.TeleportToOffset
break
else
local part =
node.Obj:FindFirstChildWhichIsA("BasePart",true)
if part and nodes[part] then
hrp.CFrame = nodes[part].Obj.CFrame +
Settings.Explorer.TeleportToOffset
end
end
end
end
end})

context:Register("EXPAND_ALL",{Name = "Expand All", OnClick =


function()
local sList = selection.List

local function expand(node)


expanded[node] = true
for i = 1,#node do
if #node[i] > 0 then
expand(node[i])
end
end
end

for i = 1,#sList do
expand(sList[i])
end

Explorer.ForceUpdate()
end})

context:Register("COLLAPSE_ALL",{Name = "Collapse All", OnClick =


function()
local sList = selection.List

local function expand(node)


expanded[node] = nil
for i = 1,#node do
if #node[i] > 0 then
expand(node[i])
end
end
end

for i = 1,#sList do
expand(sList[i])
end

Explorer.ForceUpdate()
end})

context:Register("CLEAR_SEARCH_AND_JUMP_TO",{Name = "Clear Search and


Jump to", OnClick = function()
local newSelection = {}
local count = 1
local sList = selection.List

for i = 1,#sList do
newSelection[count] = sList[i]
count = count + 1
end
selection:SetTable(newSelection)
Explorer.ClearSearch()
if #newSelection > 0 then
Explorer.ViewNode(newSelection[1])
end
end})

local clth = function(str)


if str:sub(1, 28) == "game:GetService(\"Workspace\")" then str =
str:gsub("game:GetService%(\"Workspace\"%)", "workspace", 1) end
if str:sub(1, 27 + #plr.Name) ==
"game:GetService(\"Players\")." .. plr.Name then str = str:gsub("game:GetService%
(\"Players\"%)." .. plr.Name, "game:GetService(\"Players\").LocalPlayer", 1) end
return str
end

context:Register("COPY_PATH",{Name = "Copy Path", OnClick = function()


local sList = selection.List
if #sList == 1 then

env.setclipboard(clth(Explorer.GetInstancePath(sList[1].Obj)))
elseif #sList > 1 then
local resList = {"{"}
local count = 2
for i = 1,#sList do
local path = "\
t"..clth(Explorer.GetInstancePath(sList[i].Obj))..","
if #path > 0 then
resList[count] = path
count = count+1
end
end
resList[count] = "}"
env.setclipboard(table.concat(resList,"\n"))
end
end})

context:Register("INSERT_OBJECT",{Name = "Insert Object", IconMap =


Explorer.MiscIcons, Icon = "InsertObject", OnClick = function()
local mouse = Main.Mouse
local x,y = Explorer.LastRightClickX or mouse.X,
Explorer.LastRightClickY or mouse.Y
Explorer.InsertObjectContext:Show(x,y)
end})

context:Register("CALL_FUNCTION",{Name = "Call Function", IconMap =


Explorer.ClassIcons, Icon = 66, OnClick = function()

end})

context:Register("GET_REFERENCES",{Name = "Get Lua References", IconMap


= Explorer.ClassIcons, Icon = 34, OnClick = function()

end})

context:Register("SAVE_INST",{Name = "Save to File", IconMap =


Explorer.MiscIcons, Icon = "Save", OnClick = function()

end})
context:Register("VIEW_CONNECTIONS",{Name = "View Connections", OnClick
= function()

end})

context:Register("VIEW_API",{Name = "View API Page", IconMap =


Explorer.MiscIcons, Icon = "Reference", OnClick = function()

end})

context:Register("VIEW_OBJECT",{Name = "View Object (Right click to


reset)", IconMap = Explorer.ClassIcons, Icon = 5, OnClick = function()
local sList = selection.List
local isa = game.IsA

for i = 1,#sList do
local node = sList[i]

if isa(node.Obj,"BasePart") or isa(node.Obj,"Model") then


workspace.CurrentCamera.CameraSubject = node.Obj
break
end
end
end, OnRightClick = function()
workspace.CurrentCamera.CameraSubject = plr.Character
end})

context:Register("FIRE_TOUCHTRANSMITTER",{Name = "Fire
TouchTransmitter", IconMap = Explorer.ClassIcons, Icon = 37, OnClick = function()
local hrp = plr.Character and
plr.Character:FindFirstChild("HumanoidRootPart")
if not hrp then return end
for _, v in ipairs(selection.List) do if v.Obj and
v.Obj:IsA("TouchTransmitter") then firetouchinterest(hrp, v.Obj.Parent, 0) end end
end})

context:Register("FIRE_CLICKDETECTOR",{Name = "Fire ClickDetector",


IconMap = Explorer.ClassIcons, Icon = 41, OnClick = function()
local hrp = plr.Character and
plr.Character:FindFirstChild("HumanoidRootPart")
if not hrp then return end
for _, v in ipairs(selection.List) do if v.Obj and
v.Obj:IsA("ClickDetector") then fireclickdetector(v.Obj) end end
end})

context:Register("FIRE_PROXIMITYPROMPT",{Name = "Fire ProximityPrompt",


IconMap = Explorer.ClassIcons, Icon = 124, OnClick = function()
local hrp = plr.Character and
plr.Character:FindFirstChild("HumanoidRootPart")
if not hrp then return end
for _, v in ipairs(selection.List) do if v.Obj and
v.Obj:IsA("ProximityPrompt") then fireproximityprompt(v.Obj) end end
end})

context:Register("VIEW_SCRIPT",{Name = "View Script", IconMap =


Explorer.MiscIcons, Icon = "ViewScript", OnClick = function()
local scr = selection.List[1] and selection.List[1].Obj
if scr then ScriptViewer.ViewScript(scr) end
end})

context:Register("SELECT_CHARACTER",{Name = "Select Character", IconMap


= Explorer.ClassIcons, Icon = 9, OnClick = function()
local newSelection = {}
local count = 1
local sList = selection.List
local isa = game.IsA

for i = 1,#sList do
local node = sList[i]
if isa(node.Obj,"Player") and nodes[node.Obj.Character]
then
newSelection[count] = nodes[node.Obj.Character]
count = count + 1
end
end

selection:SetTable(newSelection)
if #newSelection > 0 then
Explorer.ViewNode(newSelection[1])
else
Explorer.Refresh()
end
end})

context:Register("SELECT_LOCAL_PLAYER",{Name = "Select Local Player",


IconMap = Explorer.ClassIcons, Icon = 9, OnClick = function()
pcall(function() if nodes[plr] then selection:Set(nodes[plr])
Explorer.ViewNode(nodes[plr]) end end)
end})

context:Register("REFRESH_NIL",{Name = "Refresh Nil Instances", OnClick


= function()
Explorer.RefreshNilInstances()
end})

context:Register("HIDE_NIL",{Name = "Hide Nil Instances", OnClick =


function()
Explorer.HideNilInstances()
end})

Explorer.RightClickContext = context
end

Explorer.HideNilInstances = function()
table.clear(nilMap)

local disconnectCon =
Instance.new("Folder").ChildAdded:Connect(function() end).Disconnect
for i,v in next,nilCons do
disconnectCon(v[1])
disconnectCon(v[2])
end
table.clear(nilCons)

for i = 1,#nilNode do
coroutine.wrap(removeObject)(nilNode[i].Obj)
end
Explorer.Update()
Explorer.Refresh()
end

Explorer.RefreshNilInstances = function()
if not env.getnilinstances then return end

local nilInsts = env.getnilinstances()


local game = game
local getDescs = game.GetDescendants
--local newNilMap = {}
--local newNilRoots = {}
--local nilRoots = Explorer.NilRoots
--local connect = game.DescendantAdded.Connect
--local disconnect
--if not nilRoots then nilRoots = {} Explorer.NilRoots = nilRoots end

for i = 1,#nilInsts do
local obj = nilInsts[i]
if obj ~= game then
nilMap[obj] = true
--newNilRoots[obj] = true

local descs = getDescs(obj)


for j = 1,#descs do
nilMap[descs[j]] = true
end
end
end

-- Remove unmapped nil nodes


--[[for i = 1,#nilNode do
local node = nilNode[i]
if not newNilMap[node.Obj] then
nilMap[node.Obj] = nil
coroutine.wrap(removeObject)(node)
end
end]]

--nilMap = newNilMap

for i = 1,#nilInsts do
local obj = nilInsts[i]
local node = nodes[obj]
if not node then coroutine.wrap(addObject)(obj) end
end

--[[
-- Remove old root connections
for obj in next,nilRoots do
if not newNilRoots[obj] then
if not disconnect then disconnect = obj[1].Disconnect end
disconnect(obj[1])
disconnect(obj[2])
end
end

for obj in next,newNilRoots do


if not nilRoots[obj] then
nilRoots[obj] = {
connect(obj.DescendantAdded,addObject),
connect(obj.DescendantRemoving,removeObject)
}
end
end]]

--nilMap = newNilMap
--Explorer.NilRoots = newNilRoots

Explorer.Update()
Explorer.Refresh()
end

Explorer.GetInstancePath = function(obj)
local ffc = game.FindFirstChild
local getCh = game.GetChildren
local path = ""
local curObj = obj
local ts = tostring
local match = string.match
local gsub = string.gsub
local tableFind = table.find
local useGetCh = Settings.Explorer.CopyPathUseGetChildren
local formatLuaString = Lib.FormatLuaString

while curObj do
if curObj == game then
path = "game"..path
break
end

local className = curObj.ClassName


local curName = ts(curObj)
local indexName
if match(curName,"^[%a_][%w_]*$") then
indexName = "."..curName
else
local cleanName = formatLuaString(curName)
indexName = '["'..cleanName..'"]'
end

local parObj = curObj.Parent


if parObj then
local fc = ffc(parObj,curName)
if useGetCh and fc and fc ~= curObj then
local parCh = getCh(parObj)
local fcInd = tableFind(parCh,curObj)
indexName = ":GetChildren()["..fcInd.."]"
elseif parObj == game and API.Classes[className] and
API.Classes[className].Tags.Service then
indexName = ':GetService("'..className..'")'
end
elseif parObj == nil then
local getnil = "local getNil = function(name, class) for _,
v in next, getnilinstances() do if v.ClassName == class and v.Name == name then
return v end end end"
local gotnil = "\n\ngetNil(\"%s\", \"%s\")"
indexName = getnil .. gotnil:format(curObj.Name, className)
end

path = indexName..path
curObj = parObj
end

return path
end

Explorer.InitInsertObject = function()
local context = Lib.ContextMenu.new()
context.SearchEnabled = true
context.MaxHeight = 400
context:ApplyTheme({
ContentColor = Settings.Theme.Main2,
OutlineColor = Settings.Theme.Outline1,
DividerColor = Settings.Theme.Outline1,
TextColor = Settings.Theme.Text,
HighlightColor = Settings.Theme.ButtonHover
})

local classes = {}
for i,class in next,API.Classes do
local tags = class.Tags
if not tags.NotCreatable and not tags.Service then
local rmdEntry = RMD.Classes[class.Name]
classes[#classes+1] = {class,rmdEntry and
rmdEntry.ClassCategory or "Uncategorized"}
end
end
table.sort(classes,function(a,b)
if a[2] ~= b[2] then
return a[2] < b[2]
else
return a[1].Name < b[1].Name
end
end)

local function onClick(className)


local sList = selection.List
local instNew = Instance.new
for i = 1,#sList do
local node = sList[i]
local obj = node.Obj
Explorer.MakeNodeVisible(node,true)
pcall(instNew,className,obj)
end
end

local lastCategory = ""


for i = 1,#classes do
local class = classes[i][1]
local rmdEntry = RMD.Classes[class.Name]
local iconInd = rmdEntry and
tonumber(rmdEntry.ExplorerImageIndex) or 0
local category = classes[i][2]

if lastCategory ~= category then


context:AddDivider(category)
lastCategory = category
end
context:Add({Name = class.Name, IconMap = Explorer.ClassIcons,
Icon = iconInd, OnClick = onClick})
end

Explorer.InsertObjectContext = context
end

--[[
Headers, Setups, Predicate, ObjectDefs
]]
Explorer.SearchFilters = { -- TODO: Use data table (so we can disable some if
funcs don't exist)
Comparison = {
["isa"] = function(argString)
local lower = string.lower
local find = string.find
local classQuery = string.split(argString)[1]
if not classQuery then return end
classQuery = lower(classQuery)

local className
for class,_ in pairs(API.Classes) do
local cName = lower(class)
if cName == classQuery then
className = class
break
elseif find(cName,classQuery,1,true) then
className = class
end
end
if not className then return end

return {
Headers = {"local isa = game.IsA"},
Predicate = "isa(obj,'"..className.."')"
}
end,
["remotes"] = function(argString)
return {
Headers = {"local isa = game.IsA"},
Predicate = "isa(obj,'RemoteEvent') or
isa(obj,'RemoteFunction')"
}
end,
["bindables"] = function(argString)
return {
Headers = {"local isa = game.IsA"},
Predicate = "isa(obj,'BindableEvent') or
isa(obj,'BindableFunction')"
}
end,
["rad"] = function(argString)
local num = tonumber(argString)
if not num then return end

if not service.Players.LocalPlayer.Character or not


service.Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart") or not
service.Players.LocalPlayer.Character.HumanoidRootPart:IsA("BasePart") then return
end

return {
Headers = {"local isa = game.IsA", "local hrp =
service.Players.LocalPlayer.Character.HumanoidRootPart"},
Setups = {"local hrpPos = hrp.Position"},
ObjectDefs = {"local isBasePart =
isa(obj,'BasePart')"},
Predicate = "(isBasePart and (obj.Position-
hrpPos).Magnitude <= "..num..")"
}
end,
},
Specific = {
["players"] = function()
return function() return service.Players:GetPlayers() end
end,
["loadedmodules"] = function()
return env.getloadedmodules
end,
},
Default = function(argString,caseSensitive)
local cleanString = argString:gsub("\"","\\\""):gsub("\n","\\n")
if caseSensitive then
return {
Headers = {"local find = string.find"},
ObjectDefs = {"local objName = tostring(obj)"},
Predicate = "find(objName,\"" .. cleanString ..
"\",1,true)"
}
else
return {
Headers = {"local lower = string.lower","local find =
string.find","local tostring = tostring"},
ObjectDefs = {"local lowerName =
lower(tostring(obj))"},
Predicate = "find(lowerName,\"" ..
cleanString:lower() .. "\",1,true)"
}
end
end,
SpecificDefault = function(n)
return {
Headers = {},
ObjectDefs = {"local isSpec"..n.." = specResults["..n.."]
[node]"},
Predicate = "isSpec"..n
}
end,
}

Explorer.BuildSearchFunc = function(query)
local specFilterList,specMap = {},{}
local finalPredicate = ""
local rep = string.rep
local formatQuery = query:gsub("\\."," "):gsub('".-"',function(str)
return rep(" ",#str) end)
local headers = {}
local objectDefs = {}
local setups = {}
local find = string.find
local sub = string.sub
local lower = string.lower
local match = string.match
local ops = {
["("] = "(",
[")"] = ")",
["||"] = " or ",
["&&"] = " and "
}
local filterCount = 0
local compFilters = Explorer.SearchFilters.Comparison
local specFilters = Explorer.SearchFilters.Specific
local init = 1
local lastOp = nil

local function processFilter(dat)


if dat.Headers then
local t = dat.Headers
for i = 1,#t do
headers[t[i]] = true
end
end

if dat.ObjectDefs then
local t = dat.ObjectDefs
for i = 1,#t do
objectDefs[t[i]] = true
end
end

if dat.Setups then
local t = dat.Setups
for i = 1,#t do
setups[t[i]] = true
end
end

finalPredicate = finalPredicate..dat.Predicate
end

local found = {}
local foundData = {}
local find = string.find
local sub = string.sub

local function findAll(str,pattern)


local count = #found+1
local init = 1
local sz = #pattern
local x,y,extra = find(str,pattern,init,true)
while x do
found[count] = x
foundData[x] = {sz,pattern}

count = count+1
init = y+1
x,y,extra = find(str,pattern,init,true)
end
end
local start = tick()
findAll(formatQuery,'&&')
findAll(formatQuery,"||")
findAll(formatQuery,"(")
findAll(formatQuery,")")
table.sort(found)
table.insert(found,#formatQuery+1)

local function inQuotes(str)


local len = #str
if sub(str,1,1) == '"' and sub(str,len,len) == '"' then
return sub(str,2,len-1)
end
end

for i = 1,#found do
local nextInd = found[i]
local nextData = foundData[nextInd] or {1}
local op = ops[nextData[2]]
local term = sub(query,init,nextInd-1)
term = match(term,"^%s*(.-)%s*$") or "" -- Trim

if #term > 0 then


if sub(term,1,1) == "!" then
term = sub(term,2)
finalPredicate = finalPredicate.."not "
end

local qTerm = inQuotes(term)


if qTerm then

processFilter(Explorer.SearchFilters.Default(qTerm,true))
else
local x,y = find(term,"%S+")
if x then
local first = sub(term,x,y)
local specifier = sub(first,1,1) == "/" and
lower(sub(first,2))
local compFunc = specifier and
compFilters[specifier]
local specFunc = specifier and
specFilters[specifier]

if compFunc then
local argStr = sub(term,y+2)
local ret = compFunc(inQuotes(argStr) or
argStr)
if ret then
processFilter(ret)
else
finalPredicate =
finalPredicate.."false"
end
elseif specFunc then
local argStr = sub(term,y+2)
local ret = specFunc(inQuotes(argStr) or
argStr)
if ret then
if not specMap[term] then

specFilterList[#specFilterList + 1] = ret
specMap[term] =
#specFilterList
end

processFilter(Explorer.SearchFilters.SpecificDefault(specMap[term]))
else
finalPredicate =
finalPredicate.."false"
end
else

processFilter(Explorer.SearchFilters.Default(term))
end
end
end
end

if op then
finalPredicate = finalPredicate..op
if op == "(" and (#term > 0 or lastOp == ")") then --
Handle bracket glitch
return
else
lastOp = op
end
end
init = nextInd+nextData[1]
end

local finalSetups = ""


local finalHeaders = ""
local finalObjectDefs = ""

for setup,_ in next,setups do finalSetups = finalSetups..setup.."\n"


end
for header,_ in next,headers do finalHeaders = finalHeaders..header.."\
n" end
for oDef,_ in next,objectDefs do finalObjectDefs =
finalObjectDefs..oDef.."\n" end

local template = [==[


local searchResults = searchResults
local nodes = nodes
local expandTable = Explorer.SearchExpanded
local specResults = specResults
local service = service

%s
local function search(root)
%s

local expandedpar = false


for i = 1,#root do
local node = root[i]
local obj = node.Obj

%s

if %s then
expandTable[node] = 0
searchResults[node] = true
if not expandedpar then
local parnode = node.Parent
while parnode and (not searchResults[parnode] or
expandTable[parnode] == 0) do
expandTable[parnode] = true
searchResults[parnode] = true
parnode = parnode.Parent
end
expandedpar = true
end
end

if #node > 0 then search(node) end


end
end
return search]==]

local funcStr =
template:format(finalHeaders,finalSetups,finalObjectDefs,finalPredicate)
local s,func = pcall(loadstring,funcStr)
if not s or not func then return nil,specFilterList end

local env = setmetatable({["searchResults"] = searchResults, ["nodes"]


= nodes, ["Explorer"] = Explorer, ["specResults"] = specResults,
["service"] = service},{__index = getfenv()})
setfenv(func,env)

return func(),specFilterList
end

Explorer.DoSearch = function(query)
table.clear(Explorer.SearchExpanded)
table.clear(searchResults)
expanded = (#query == 0 and Explorer.Expanded or
Explorer.SearchExpanded)
searchFunc = nil

if #query > 0 then


local expandTable = Explorer.SearchExpanded
local specFilters

local lower = string.lower


local find = string.find
local tostring = tostring

local lowerQuery = lower(query)

local function defaultSearch(root)


local expandedpar = false
for i = 1,#root do
local node = root[i]
local obj = node.Obj

if find(lower(tostring(obj)),lowerQuery,1,true) then
expandTable[node] = 0
searchResults[node] = true
if not expandedpar then
local parnode = node.Parent
while parnode and (not
searchResults[parnode] or expandTable[parnode] == 0) do
expanded[parnode] = true
searchResults[parnode] = true
parnode = parnode.Parent
end
expandedpar = true
end
end

if #node > 0 then defaultSearch(node) end


end
end

if Main.Elevated then
local start = tick()
searchFunc,specFilters = Explorer.BuildSearchFunc(query)
--print("BUILD SEARCH",tick()-start)
else
searchFunc = defaultSearch
end

if specFilters then
table.clear(specResults)
for i = 1,#specFilters do -- Specific search filers that
returns list of matches
local resMap = {}
specResults[i] = resMap
local objs = specFilters[i]()
for c = 1,#objs do
local node = nodes[objs[c]]
if node then
resMap[node] = true
end
end
end
end

if searchFunc then
local start = tick()
searchFunc(nodes[game])
searchFunc(nilNode)
--warn(tick()-start)
end
end

Explorer.ForceUpdate()
end

Explorer.ClearSearch = function()
Explorer.GuiElems.SearchBar.Text = ""
expanded = Explorer.Expanded
searchFunc = nil
end

Explorer.InitSearch = function()
local searchBox = Explorer.GuiElems.ToolBar.SearchFrame.SearchBox
Explorer.GuiElems.SearchBar = searchBox

Lib.ViewportTextBox.convert(searchBox)

searchBox.FocusLost:Connect(function()
Explorer.DoSearch(searchBox.Text)
end)
end

Explorer.InitEntryTemplate = function()
entryTemplate = create({
{1,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0,0,0),BackgroundTransparency=1,
BorderColor3=Color3.new(0,0,0),Font=3,Name="Entry",Position=UDim2.new(0,1,0,1),Size
=UDim2.new(0,250,0,20),Text="",TextSize=14,}},
{2,"Frame",
{BackgroundColor3=Color3.new(0.04313725605607,0.35294118523598,0.68627452850342),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.33725491166115,0.49019610881805,0.
73725491762161),BorderSizePixel=0,Name="Indent",Parent={1},Position=UDim2.new(0,20,
0,0),Size=UDim2.new(1,-20,1,0),}},
{3,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="EntryName
",Parent={2},Position=UDim2.new(0,26,0,0),Size=UDim2.new(1,-
26,1,0),Text="Workspace",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.
86274516582489),TextSize=14,TextXAlignment=0,}},
{4,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ClipsDescendants=true,
Font=3,Name="Expand",Parent={2},Position=UDim2.new(0,-
20,0,0),Size=UDim2.new(0,20,0,20),Text="",TextSize=14,}},
{5,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
5642383285",ImageRectOffset=Vector2.new(144,16),ImageRectSize=Vector2.new(16,16),Na
me="Icon",Parent={4},Position=UDim2.new(0,2,0,2),ScaleType=4,Size=UDim2.new(0,16,0,
16),}},
{6,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxasset://
textures/
ClassImages.png",ImageRectOffset=Vector2.new(304,0),ImageRectSize=Vector2.new(16,16
),Name="Icon",Parent={2},Position=UDim2.new(0,4,0,2),ScaleType=4,Size=UDim2.new(0,1
6,0,16),}},
})

local sys = Lib.ClickSystem.new()


sys.AllowedButtons = {1,2}
sys.OnDown:Connect(function(item,combo,button)
local ind = table.find(listEntries,item)
if not ind then return end
local node = tree[ind + Explorer.Index]
if not node then return end

local entry = listEntries[ind]

if button == 1 then
if combo == 2 then
if node.Obj:IsA("LuaSourceContainer") then
ScriptViewer.ViewScript(node.Obj)
elseif #node > 0 and expanded[node] ~= 0 then
expanded[node] = not expanded[node]
Explorer.Update()
end
end

if Properties.SelectObject(node.Obj) then
sys.IsRenaming = false
return
end

sys.IsRenaming = selection.Map[node]

if Lib.IsShiftDown() then
if not selection.Piviot then return end

local fromIndex = table.find(tree,selection.Piviot)


local toIndex = table.find(tree,node)
if not fromIndex or not toIndex then return end
fromIndex,toIndex =
math.min(fromIndex,toIndex),math.max(fromIndex,toIndex)

local sList = selection.List


for i = #sList,1,-1 do
local elem = sList[i]
if selection.ShiftSet[elem] then
selection.Map[elem] = nil
table.remove(sList,i)
end
end
selection.ShiftSet = {}
for i = fromIndex,toIndex do
local elem = tree[i]
if not selection.Map[elem] then
selection.ShiftSet[elem] = true
selection.Map[elem] = true
sList[#sList+1] = elem
end
end
selection.Changed:Fire()
elseif Lib.IsCtrlDown() then
selection.ShiftSet = {}
if selection.Map[node] then selection:Remove(node)
else selection:Add(node) end
selection.Piviot = node
sys.IsRenaming = false
elseif not selection.Map[node] then
selection.ShiftSet = {}
selection:Set(node)
selection.Piviot = node
end
elseif button == 2 then
if Properties.SelectObject(node.Obj) then
return
end

if not Lib.IsCtrlDown() and not selection.Map[node] then


selection.ShiftSet = {}
selection:Set(node)
selection.Piviot = node
Explorer.Refresh()
end
end

Explorer.Refresh()
end)

sys.OnRelease:Connect(function(item,combo,button)
local ind = table.find(listEntries,item)
if not ind then return end
local node = tree[ind + Explorer.Index]
if not node then return end

if button == 1 then
if selection.Map[node] and not Lib.IsShiftDown() and not
Lib.IsCtrlDown() then
selection.ShiftSet = {}
selection:Set(node)
selection.Piviot = node
Explorer.Refresh()
end

local id = sys.ClickId
Lib.FastWait(sys.ComboTime)
if combo == 1 and id == sys.ClickId and sys.IsRenaming and
selection.Map[node] then
Explorer.SetRenamingNode(node)
end
elseif button == 2 then
Explorer.ShowRightClick()
end
end)
Explorer.ClickSystem = sys
end

Explorer.InitDelCleaner = function()
coroutine.wrap(function()
local fw = Lib.FastWait
while true do
local processed = false
local c = 0
for _,node in next,nodes do
if node.HasDel then
local delInd
for i = 1,#node do
if node[i].Del then
delInd = i
break
end
end
if delInd then
for i = delInd+1,#node do
local cn = node[i]
if not cn.Del then
node[delInd] = cn
delInd = delInd+1
end
end
for i = delInd,#node do
node[i] = nil
end
end
node.HasDel = false
processed = true
fw()
end
c = c + 1
if c > 10000 then
c = 0
fw()
end
end
if processed and not refreshDebounce then
Explorer.PerformRefresh() end
fw(0.5)
end
end)()
end

Explorer.UpdateSelectionVisuals = function()
local holder = Explorer.SelectionVisualsHolder
local isa = game.IsA
local clone = game.Clone
if not holder then
holder = Instance.new("ScreenGui")
holder.Name = "ExplorerSelections"
holder.DisplayOrder = Main.DisplayOrders.Core
Lib.ShowGui(holder)
Explorer.SelectionVisualsHolder = holder
Explorer.SelectionVisualCons = {}

local guiTemplate = create({


{1,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Size=UDim2.new(0,100,0
,100),}},
{2,"Frame",
{BackgroundColor3=Color3.new(0.04313725605607,0.35294118523598,0.68627452850342),Bo
rderSizePixel=0,Parent={1},Position=UDim2.new(0,-1,0,-
1),Size=UDim2.new(1,2,0,1),}},
{3,"Frame",
{BackgroundColor3=Color3.new(0.04313725605607,0.35294118523598,0.68627452850342),Bo
rderSizePixel=0,Parent={1},Position=UDim2.new(0,-1,1,0),Size=UDim2.new(1,2,0,1),}},
{4,"Frame",
{BackgroundColor3=Color3.new(0.04313725605607,0.35294118523598,0.68627452850342),Bo
rderSizePixel=0,Parent={1},Position=UDim2.new(0,-1,0,0),Size=UDim2.new(0,1,1,0),}},
{5,"Frame",
{BackgroundColor3=Color3.new(0.04313725605607,0.35294118523598,0.68627452850342),Bo
rderSizePixel=0,Parent={1},Position=UDim2.new(1,0,0,0),Size=UDim2.new(0,1,1,0),}},
})
Explorer.SelectionVisualGui = guiTemplate

local boxTemplate = Instance.new("SelectionBox")


boxTemplate.LineThickness = 0.03
boxTemplate.Color3 = Color3.fromRGB(0, 170, 255)
Explorer.SelectionVisualBox = boxTemplate
end
holder:ClearAllChildren()

-- Updates theme
for i,v in pairs(Explorer.SelectionVisualGui:GetChildren()) do
v.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
end

local attachCons = Explorer.SelectionVisualCons


for i = 1,#attachCons do
attachCons[i].Destroy()
end
table.clear(attachCons)

local partEnabled = Settings.Explorer.PartSelectionBox


local guiEnabled = Settings.Explorer.GuiSelectionBox
if not partEnabled and not guiEnabled then return end

local svg = Explorer.SelectionVisualGui


local svb = Explorer.SelectionVisualBox
local attachTo = Lib.AttachTo
local sList = selection.List
local count = 1
local boxCount = 0
local workspaceNode = nodes[workspace]
for i = 1,#sList do
if boxCount > 1000 then break end
local node = sList[i]
local obj = node.Obj

if node ~= workspaceNode then


if isa(obj,"GuiObject") and guiEnabled then
local newVisual = clone(svg)
attachCons[count] = attachTo(newVisual,{Target = obj,
Resize = true})
count = count + 1
newVisual.Parent = holder
boxCount = boxCount + 1
elseif isa(obj,"PVInstance") and partEnabled then
local newBox = clone(svb)
newBox.Adornee = obj
newBox.Parent = holder
boxCount = boxCount + 1
end
end
end
end

Explorer.Init = function()
Explorer.ClassIcons =
Lib.IconMap.newLinear("rbxasset://textures/ClassImages.png",16,16)
Explorer.MiscIcons = Main.MiscIcons

clipboard = {}

selection = Lib.Set.new()
selection.ShiftSet = {}
selection.Changed:Connect(Properties.ShowExplorerProps)
Explorer.Selection = selection
Explorer.InitRightClick()
Explorer.InitInsertObject()
Explorer.SetSortingEnabled(Settings.Explorer.Sorting)
Explorer.Expanded = setmetatable({},{__mode = "k"})
Explorer.SearchExpanded = setmetatable({},{__mode = "k"})
expanded = Explorer.Expanded

nilNode.Obj.Name = "Nil Instances"


nilNode.Locked = true

local explorerItems = create({


{1,"Folder",{Name="ExplorerItems",}},
{2,"Frame",
{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),Bo
rderSizePixel=0,Name="ToolBar",Parent={1},Size=UDim2.new(1,0,0,22),}},
{3,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.1176470592618,0.1176470592618,0.1176470592618),BorderSizePi
xel=0,Name="SearchFrame",Parent={2},Position=UDim2.new(0,3,0,1),Size=UDim2.new(1,-
6,0,18),}},
{4,"TextBox",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ClearTextOnFocus=false
,Font=3,Name="SearchBox",Parent={3},PlaceholderColor3=Color3.new(0.39215689897537,0
.39215689897537,0.39215689897537),PlaceholderText="Search
workspace",Position=UDim2.new(0,4,0,0),Size=UDim2.new(1,-
24,0,18),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=0,}},
{5,"UICorner",{CornerRadius=UDim.new(0,2),Parent={3},}},
{6,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.1254902034997
9,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Reset",
Parent={3},Position=UDim2.new(1,-
17,0,1),Size=UDim2.new(0,16,0,16),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,
}},
{7,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
5034718129",ImageColor3=Color3.new(0.39215686917305,0.39215686917305,0.392156869173
05),Parent={6},Size=UDim2.new(0,16,0,16),}},
{8,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.1254902034997
9,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Refresh
",Parent={2},Position=UDim2.new(1,-
20,0,1),Size=UDim2.new(0,18,0,18),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,
Visible=false,}},
{9,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
5642310344",Parent={8},Position=UDim2.new(0,3,0,3),Size=UDim2.new(0,12,0,12),}},
{10,"Frame",
{BackgroundColor3=Color3.new(0.15686275064945,0.15686275064945,0.15686275064945),Bo
rderSizePixel=0,Name="ScrollCorner",Parent={1},Position=UDim2.new(1,-16,1,-
16),Size=UDim2.new(0,16,0,16),Visible=false,}},
{11,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ClipsDescendants=true,
Name="List",Parent={1},Position=UDim2.new(0,0,0,23),Size=UDim2.new(1,0,1,-23),}},
})

toolBar = explorerItems.ToolBar
treeFrame = explorerItems.List
Explorer.GuiElems.ToolBar = toolBar
Explorer.GuiElems.TreeFrame = treeFrame

scrollV = Lib.ScrollBar.new()
scrollV.WheelIncrement = 3
scrollV.Gui.Position = UDim2.new(1,-16,0,23)
scrollV:SetScrollFrame(treeFrame)
scrollV.Scrolled:Connect(function()
Explorer.Index = scrollV.Index
Explorer.Refresh()
end)

scrollH = Lib.ScrollBar.new(true)
scrollH.Increment = 5
scrollH.WheelIncrement = Explorer.EntryIndent
scrollH.Gui.Position = UDim2.new(0,0,1,-16)
scrollH.Scrolled:Connect(function()
Explorer.Refresh()
end)

local window = Lib.Window.new()


Explorer.Window = window
window:SetTitle("Explorer")
window.GuiElems.Line.Position = UDim2.new(0,0,0,22)

Explorer.InitEntryTemplate()
toolBar.Parent = window.GuiElems.Content
treeFrame.Parent = window.GuiElems.Content
explorerItems.ScrollCorner.Parent = window.GuiElems.Content
scrollV.Gui.Parent = window.GuiElems.Content
scrollH.Gui.Parent = window.GuiElems.Content

-- Init stuff that requires the window


Explorer.InitRenameBox()
Explorer.InitSearch()
Explorer.InitDelCleaner()
selection.Changed:Connect(Explorer.UpdateSelectionVisuals)

-- Window events

window.GuiElems.Main:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
if Explorer.Active then
Explorer.UpdateView()
Explorer.Refresh()
end
end)
window.OnActivate:Connect(function()
Explorer.Active = true
Explorer.UpdateView()
Explorer.Update()
Explorer.Refresh()
end)
window.OnRestore:Connect(function()
Explorer.Active = true
Explorer.UpdateView()
Explorer.Update()
Explorer.Refresh()
end)
window.OnDeactivate:Connect(function() Explorer.Active = false end)
window.OnMinimize:Connect(function() Explorer.Active = false end)

-- Settings
autoUpdateSearch = Settings.Explorer.AutoUpdateSearch

-- Fill in nodes
nodes[game] = {Obj = game}
expanded[nodes[game]] = true

-- Nil Instances
if env.getnilinstances then
nodes[nilNode.Obj] = nilNode
end

Explorer.SetupConnections()

local insts = getDescendants(game)


if Main.Elevated then
for i = 1,#insts do
local obj = insts[i]
local par = nodes[ffa(obj,"Instance")]
if not par then continue end
local newNode = {
Obj = obj,
Parent = par,
}
nodes[obj] = newNode
par[#par+1] = newNode
end
else
for i = 1,#insts do
local obj = insts[i]
local s,parObj = pcall(ffa,obj,"Instance")
local par = nodes[parObj]
if not par then continue end
local newNode = {
Obj = obj,
Parent = par,
}
nodes[obj] = newNode
par[#par+1] = newNode
end
end
end

return Explorer
end

return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main}


end,
Properties = function()
--[[
Properties App Module

The main properties interface


]]
-- Common Locals
local Main,Lib,Apps,Settings -- Main Containers
local Explorer, Properties, ScriptViewer, Notebook -- Major Apps
local API,RMD,env,service,plr,create,createSimple -- Main Locals

local function initDeps(data)


Main = data.Main
Lib = data.Lib
Apps = data.Apps
Settings = data.Settings

API = data.API
RMD = data.RMD
env = data.env
service = data.service
plr = data.plr
create = data.create
createSimple = data.createSimple
end

local function initAfterMain()


Explorer = Apps.Explorer
Properties = Apps.Properties
ScriptViewer = Apps.ScriptViewer
Notebook = Apps.Notebook
end

local function main()


local Properties = {}

local window, toolBar, propsFrame


local scrollV, scrollH
local categoryOrder
local props,viewList,expanded,indexableProps,propEntries,autoUpdateObjs = {},
{},{},{},{},{}
local inputBox,inputTextBox,inputProp
local checkboxes,propCons = {},{}
local table,string = table,string
local getPropChangedSignal = game.GetPropertyChangedSignal
local getAttributeChangedSignal = game.GetAttributeChangedSignal
local isa = game.IsA
local getAttribute = game.GetAttribute
local setAttribute = game.SetAttribute

Properties.GuiElems = {}
Properties.Index = 0
Properties.ViewWidth = 0
Properties.MinInputWidth = 100
Properties.EntryIndent = 16
Properties.EntryOffset = 4
Properties.NameWidthCache = {}
Properties.SubPropCache = {}
Properties.ClassLists = {}
Properties.SearchText = ""

Properties.AddAttributeProp = {Category = "Attributes", Class = "", Name =


"", SpecialRow = "AddAttribute", Tags = {}}
Properties.SoundPreviewProp = {Category = "Data", ValueType = {Name =
"SoundPlayer"}, Class = "Sound", Name = "Preview", Tags = {}}
Properties.IgnoreProps = {
["DataModel"] = {
["PrivateServerId"] = true,
["PrivateServerOwnerId"] = true,
["VIPServerId"] = true,
["VIPServerOwnerId"] = true
}
}

Properties.ExpandableTypes = {
["Vector2"] = true,
["Vector3"] = true,
["UDim"] = true,
["UDim2"] = true,
["CFrame"] = true,
["Rect"] = true,
["PhysicalProperties"] = true,
["Ray"] = true,
["NumberRange"] = true,
["Faces"] = true,
["Axes"] = true,
}

Properties.ExpandableProps = {
["Sound.SoundId"] = true
}

Properties.CollapsedCategories = {
["Surface Inputs"] = true,
["Surface"] = true
}

Properties.ConflictSubProps = {
["Vector2"] = {"X","Y"},
["Vector3"] = {"X","Y","Z"},
["UDim"] = {"Scale","Offset"},
["UDim2"] = {"X","X.Scale","X.Offset","Y","Y.Scale","Y.Offset"},
["CFrame"] = {"Position","Position.X","Position.Y","Position.Z",
"RightVector","RightVector.X","RightVector.Y","RightVector.Z",
"UpVector","UpVector.X","UpVector.Y","UpVector.Z",
"LookVector","LookVector.X","LookVector.Y","LookVector.Z"},
["Rect"] = {"Min.X","Min.Y","Max.X","Max.Y"},
["PhysicalProperties"] =
{"Density","Elasticity","ElasticityWeight","Friction","FrictionWeight"},
["Ray"] =
{"Origin","Origin.X","Origin.Y","Origin.Z","Direction","Direction.X","Direction.Y",
"Direction.Z"},
["NumberRange"] = {"Min","Max"},
["Faces"] = {"Back","Bottom","Front","Left","Right","Top"},
["Axes"] = {"X","Y","Z"}
}

Properties.ConflictIgnore = {
["BasePart"] = {
["ResizableFaces"] = true
}
}
Properties.RoundableTypes = {
["float"] = true,
["double"] = true,
["Color3"] = true,
["UDim"] = true,
["UDim2"] = true,
["Vector2"] = true,
["Vector3"] = true,
["NumberRange"] = true,
["Rect"] = true,
["NumberSequence"] = true,
["ColorSequence"] = true,
["Ray"] = true,
["CFrame"] = true
}

Properties.TypeNameConvert = {
["number"] = "double",
["boolean"] = "bool"
}

Properties.ToNumberTypes = {
["int"] = true,
["int64"] = true,
["float"] = true,
["double"] = true
}

Properties.DefaultPropValue = {
string = "",
bool = false,
double = 0,
UDim = UDim.new(0,0),
UDim2 = UDim2.new(0,0,0,0),
BrickColor = BrickColor.new("Medium stone grey"),
Color3 = Color3.new(1,1,1),
Vector2 = Vector2.new(0,0),
Vector3 = Vector3.new(0,0,0),
NumberSequence = NumberSequence.new(1),
ColorSequence = ColorSequence.new(Color3.new(1,1,1)),
NumberRange = NumberRange.new(0),
Rect = Rect.new(0,0,0,0)
}

Properties.AllowedAttributeTypes =
{"string","boolean","number","UDim","UDim2","BrickColor","Color3","Vector2","Vector
3","NumberSequence","ColorSequence","NumberRange","Rect"}

Properties.StringToValue = function(prop,str)
local typeData = prop.ValueType
local typeName = typeData.Name

if typeName == "string" or typeName == "Content" then


return str
elseif Properties.ToNumberTypes[typeName] then
return tonumber(str)
elseif typeName == "Vector2" then
local vals = str:split(",")
local x,y = tonumber(vals[1]),tonumber(vals[2])
if x and y and #vals >= 2 then return Vector2.new(x,y) end
elseif typeName == "Vector3" then
local vals = str:split(",")
local x,y,z =
tonumber(vals[1]),tonumber(vals[2]),tonumber(vals[3])
if x and y and z and #vals >= 3 then return Vector3.new(x,y,z)
end
elseif typeName == "UDim" then
local vals = str:split(",")
local scale,offset = tonumber(vals[1]),tonumber(vals[2])
if scale and offset and #vals >= 2 then return
UDim.new(scale,offset) end
elseif typeName == "UDim2" then
local vals = str:gsub("[{}]",""):split(",")
local xScale,xOffset,yScale,yOffset =
tonumber(vals[1]),tonumber(vals[2]),tonumber(vals[3]),tonumber(vals[4])
if xScale and xOffset and yScale and yOffset and #vals >= 4 then
return UDim2.new(xScale,xOffset,yScale,yOffset) end
elseif typeName == "CFrame" then
local vals = str:split(",")
local s,result = pcall(CFrame.new,unpack(vals))
if s and #vals >= 12 then return result end
elseif typeName == "Rect" then
local vals = str:split(",")
local s,result = pcall(Rect.new,unpack(vals))
if s and #vals >= 4 then return result end
elseif typeName == "Ray" then
local vals = str:gsub("[{}]",""):split(",")
local s,origin = pcall(Vector3.new,unpack(vals,1,3))
local s2,direction = pcall(Vector3.new,unpack(vals,4,6))
if s and s2 and #vals >= 6 then return Ray.new(origin,direction)
end
elseif typeName == "NumberRange" then
local vals = str:split(",")
local s,result = pcall(NumberRange.new,unpack(vals))
if s and #vals >= 1 then return result end
elseif typeName == "Color3" then
local vals = str:gsub("[{}]",""):split(",")
local s,result = pcall(Color3.fromRGB,unpack(vals))
if s and #vals >= 3 then return result end
end

return nil
end

Properties.ValueToString = function(prop,val)
local typeData = prop.ValueType
local typeName = typeData.Name

if typeName == "Color3" then


return Lib.ColorToBytes(val)
elseif typeName == "NumberRange" then
return val.Min..", "..val.Max
end

return tostring(val)
end

Properties.GetIndexableProps = function(obj,classData)
if not Main.Elevated then
if not pcall(function() return obj.ClassName end) then return nil
end
end

local ignoreProps = Properties.IgnoreProps[classData.Name] or {}

local result = {}
local count = 1
local props = classData.Properties
for i = 1,#props do
local prop = props[i]
if not ignoreProps[prop.Name] then
local s = pcall(function() return obj[prop.Name] end)
if s then
result[count] = prop
count = count + 1
end
end
end

return result
end

Properties.FindFirstObjWhichIsA = function(class)
local classList = Properties.ClassLists[class] or {}
if classList and #classList > 0 then
return classList[1]
end

return nil
end

Properties.ComputeConflicts = function(p)
local maxConflictCheck = Settings.Properties.MaxConflictCheck
local sList = Explorer.Selection.List
local classLists = Properties.ClassLists
local stringSplit = string.split
local t_clear = table.clear
local conflictIgnore = Properties.ConflictIgnore
local conflictMap = {}
local propList = p and {p} or props

if p then
local gName = p.Class.."."..p.Name
autoUpdateObjs[gName] = nil
local subProps = Properties.ConflictSubProps[p.ValueType.Name] or
{}
for i = 1,#subProps do
autoUpdateObjs[gName.."."..subProps[i]] = nil
end
else
table.clear(autoUpdateObjs)
end

if #sList > 0 then


for i = 1,#propList do
local prop = propList[i]
local propName,propClass = prop.Name,prop.Class
local typeData = prop.RootType or prop.ValueType
local typeName = typeData.Name
local attributeName = prop.AttributeName
local gName = propClass.."."..propName

local checked = 0
local subProps = Properties.ConflictSubProps[typeName] or
{}
local subPropCount = #subProps
local toCheck = subPropCount + 1
local conflictsFound = 0
local indexNames = {}
local ignored = conflictIgnore[propClass] and
conflictIgnore[propClass][propName]
local truthyCheck = (typeName == "PhysicalProperties")
local isAttribute = prop.IsAttribute
local isMultiType = prop.MultiType

t_clear(conflictMap)

if not isMultiType then


local firstVal,firstObj,firstSet
local classList = classLists[prop.Class] or {}
for c = 1,#classList do
local obj = classList[c]
if not firstSet then
if isAttribute then
firstVal =
getAttribute(obj,attributeName)
if firstVal ~= nil then
firstObj = obj
firstSet = true
end
else
firstVal = obj[propName]
firstObj = obj
firstSet = true
end
if ignored then break end
else
local propVal,skip
if isAttribute then
propVal =
getAttribute(obj,attributeName)
if propVal == nil then skip = true
end
else
propVal = obj[propName]
end

if not skip then


if not conflictMap[1] then
if truthyCheck then
if (firstVal and true or
false) ~= (propVal and true or false) then
conflictMap[1] =
true
conflictsFound =
conflictsFound + 1
end
elseif firstVal ~= propVal
then
conflictMap[1] = true
conflictsFound =
conflictsFound + 1
end
end

if subPropCount > 0 then


for sPropInd = 1,subPropCount
do
local indexes =
indexNames[sPropInd]
if not indexes then
indexes = stringSplit(subProps[sPropInd],".") indexNames[sPropInd] = indexes end

local firstValSub =
firstVal
local propValSub =
propVal

for j = 1,#indexes do
if not firstValSub
or not propValSub then break end -- PhysicalProperties
local indexName =
indexes[j]
firstValSub =
firstValSub[indexName]
propValSub =
propValSub[indexName]
end

local mapInd = sPropInd


+ 1
if not
conflictMap[mapInd] and firstValSub ~= propValSub then

conflictMap[mapInd] = true
conflictsFound =
conflictsFound + 1
end
end
end

if conflictsFound == toCheck then


break end
end
end

checked = checked + 1
if checked == maxConflictCheck then break end
end

if not conflictMap[1] then autoUpdateObjs[gName] =


firstObj end
for sPropInd = 1,subPropCount do
if not conflictMap[sPropInd+1] then
autoUpdateObjs[gName.."."..subProps[sPropInd]] = firstObj
end
end
end
end
end

if p then
Properties.Refresh()
end
end

-- Fetches the properties to be displayed based on the explorer selection


Settings.Properties.ShowAttributes = true -- im making it true anyway since
its useful by default and people complain
Properties.ShowExplorerProps = function()
local maxConflictCheck = Settings.Properties.MaxConflictCheck
local sList = Explorer.Selection.List
local foundClasses = {}
local propCount = 1
local elevated = Main.Elevated
local showDeprecated,showHidden =
Settings.Properties.ShowDeprecated,Settings.Properties.ShowHidden
local Classes = API.Classes
local classLists = {}
local lower = string.lower
local RMDCustomOrders = RMD.PropertyOrders
local getAttributes = game.GetAttributes
local maxAttrs = Settings.Properties.MaxAttributes
local showingAttrs = Settings.Properties.ShowAttributes
local foundAttrs = {}
local attrCount = 0
local typeof = typeof
local typeNameConvert = Properties.TypeNameConvert

table.clear(props)

for i = 1,#sList do
local node = sList[i]
local obj = node.Obj
local class = node.Class
if not class then class = obj.ClassName node.Class = class end

local apiClass = Classes[class]


while apiClass do
local APIClassName = apiClass.Name
if not foundClasses[APIClassName] then
local apiProps = indexableProps[APIClassName]
if not apiProps then apiProps =
Properties.GetIndexableProps(obj,apiClass) indexableProps[APIClassName] = apiProps
end

for i = 1,#apiProps do
local prop = apiProps[i]
local tags = prop.Tags
if (not tags.Deprecated or showDeprecated) and
(not tags.Hidden or showHidden) then
props[propCount] = prop
propCount = propCount + 1
end
end
foundClasses[APIClassName] = true
end

local classList = classLists[APIClassName]


if not classList then classList = {}
classLists[APIClassName] = classList end
classList[#classList+1] = obj

apiClass = apiClass.Superclass
end

if showingAttrs and attrCount < maxAttrs then


local attrs = getAttributes(obj)
for name,val in pairs(attrs) do
local typ = typeof(val)
if not foundAttrs[name] then
local category = (typ == "Instance" and
"Class") or (typ == "EnumItem" and "Enum") or "Other"
local valType = {Name = typeNameConvert[typ] or
typ, Category = category}
local attrProp = {IsAttribute = true, Name =
"ATTR_"..name, AttributeName = name, DisplayName = name, Class = "Instance",
ValueType = valType, Category = "Attributes", Tags = {}}
props[propCount] = attrProp
propCount = propCount + 1
attrCount = attrCount + 1
foundAttrs[name] = {typ,attrProp}
if attrCount == maxAttrs then break end
elseif foundAttrs[name][1] ~= typ then
foundAttrs[name][2].MultiType = true
foundAttrs[name][2].Tags.ReadOnly = true
foundAttrs[name][2].ValueType = {Name =
"string"}
end
end
end
end

table.sort(props,function(a,b)
if a.Category ~= b.Category then
return (categoryOrder[a.Category] or 9999) <
(categoryOrder[b.Category] or 9999)
else
local aOrder = (RMDCustomOrders[a.Class] and
RMDCustomOrders[a.Class][a.Name]) or 9999999
local bOrder = (RMDCustomOrders[b.Class] and
RMDCustomOrders[b.Class][b.Name]) or 9999999
if aOrder ~= bOrder then
return aOrder < bOrder
else
return lower(a.Name) < lower(b.Name)
end
end
end)

-- Find conflicts and get auto-update instances


Properties.ClassLists = classLists
Properties.ComputeConflicts()
--warn("CONFLICT",tick()-start)
if #props > 0 then
props[#props+1] = Properties.AddAttributeProp
end

Properties.Update()
Properties.Refresh()
end

Properties.UpdateView = function()
local maxEntries = math.ceil(propsFrame.AbsoluteSize.Y / 23)
local maxX = propsFrame.AbsoluteSize.X
local totalWidth = Properties.ViewWidth + Properties.MinInputWidth

scrollV.VisibleSpace = maxEntries
scrollV.TotalSpace = #viewList + 1
scrollH.VisibleSpace = maxX
scrollH.TotalSpace = totalWidth

scrollV.Gui.Visible = #viewList + 1 > maxEntries


scrollH.Gui.Visible = Settings.Properties.ScaleType == 0 and totalWidth
> maxX

local oldSize = propsFrame.Size


propsFrame.Size = UDim2.new(1,(scrollV.Gui.Visible and -16 or 0),1,
(scrollH.Gui.Visible and -39 or -23))
if oldSize ~= propsFrame.Size then
Properties.UpdateView()
else
scrollV:Update()
scrollH:Update()

if scrollV.Gui.Visible and scrollH.Gui.Visible then


scrollV.Gui.Size = UDim2.new(0,16,1,-39)
scrollH.Gui.Size = UDim2.new(1,-16,0,16)
Properties.Window.GuiElems.Content.ScrollCorner.Visible =
true
else
scrollV.Gui.Size = UDim2.new(0,16,1,-23)
scrollH.Gui.Size = UDim2.new(1,0,0,16)
Properties.Window.GuiElems.Content.ScrollCorner.Visible =
false
end

Properties.Index = scrollV.Index
end
end

Properties.MakeSubProp = function(prop,subName,valueType,displayName)
local subProp = {}
for i,v in pairs(prop) do
subProp[i] = v
end
subProp.RootType = subProp.RootType or subProp.ValueType
subProp.ValueType = valueType
subProp.SubName = subProp.SubName and (subProp.SubName..subName) or
subName
subProp.DisplayName = displayName
return subProp
end

Properties.GetExpandedProps = function(prop) -- TODO: Optimize using table


local result = {}
local typeData = prop.ValueType
local typeName = typeData.Name
local makeSubProp = Properties.MakeSubProp

if typeName == "Vector2" then


result[1] = makeSubProp(prop,".X",{Name = "float"})
result[2] = makeSubProp(prop,".Y",{Name = "float"})
elseif typeName == "Vector3" then
result[1] = makeSubProp(prop,".X",{Name = "float"})
result[2] = makeSubProp(prop,".Y",{Name = "float"})
result[3] = makeSubProp(prop,".Z",{Name = "float"})
elseif typeName == "CFrame" then
result[1] = makeSubProp(prop,".Position",{Name = "Vector3"})
result[2] = makeSubProp(prop,".RightVector",{Name = "Vector3"})
result[3] = makeSubProp(prop,".UpVector",{Name = "Vector3"})
result[4] = makeSubProp(prop,".LookVector",{Name = "Vector3"})
elseif typeName == "UDim" then
result[1] = makeSubProp(prop,".Scale",{Name = "float"})
result[2] = makeSubProp(prop,".Offset",{Name = "int"})
elseif typeName == "UDim2" then
result[1] = makeSubProp(prop,".X",{Name = "UDim"})
result[2] = makeSubProp(prop,".Y",{Name = "UDim"})
elseif typeName == "Rect" then
result[1] = makeSubProp(prop,".Min.X",{Name = "float"},"X0")
result[2] = makeSubProp(prop,".Min.Y",{Name = "float"},"Y0")
result[3] = makeSubProp(prop,".Max.X",{Name = "float"},"X1")
result[4] = makeSubProp(prop,".Max.Y",{Name = "float"},"Y1")
elseif typeName == "PhysicalProperties" then
result[1] = makeSubProp(prop,".Density",{Name = "float"})
result[2] = makeSubProp(prop,".Elasticity",{Name = "float"})
result[3] = makeSubProp(prop,".ElasticityWeight",{Name =
"float"})
result[4] = makeSubProp(prop,".Friction",{Name = "float"})
result[5] = makeSubProp(prop,".FrictionWeight",{Name = "float"})
elseif typeName == "Ray" then
result[1] = makeSubProp(prop,".Origin",{Name = "Vector3"})
result[2] = makeSubProp(prop,".Direction",{Name = "Vector3"})
elseif typeName == "NumberRange" then
result[1] = makeSubProp(prop,".Min",{Name = "float"})
result[2] = makeSubProp(prop,".Max",{Name = "float"})
elseif typeName == "Faces" then
result[1] = makeSubProp(prop,".Back",{Name = "bool"})
result[2] = makeSubProp(prop,".Bottom",{Name = "bool"})
result[3] = makeSubProp(prop,".Front",{Name = "bool"})
result[4] = makeSubProp(prop,".Left",{Name = "bool"})
result[5] = makeSubProp(prop,".Right",{Name = "bool"})
result[6] = makeSubProp(prop,".Top",{Name = "bool"})
elseif typeName == "Axes" then
result[1] = makeSubProp(prop,".X",{Name = "bool"})
result[2] = makeSubProp(prop,".Y",{Name = "bool"})
result[3] = makeSubProp(prop,".Z",{Name = "bool"})
end
if prop.Name == "SoundId" and prop.Class == "Sound" then
result[1] = Properties.SoundPreviewProp
end

return result
end

Properties.Update = function()
table.clear(viewList)

local nameWidthCache = Properties.NameWidthCache


local lastCategory
local count = 1
local maxWidth,maxDepth = 0,1

local textServ = service.TextService


local getTextSize = textServ.GetTextSize
local font = Enum.Font.SourceSans
local size = Vector2.new(math.huge,20)
local stringSplit = string.split
local entryIndent = Properties.EntryIndent
local isFirstScaleType = Settings.Properties.ScaleType == 0
local find,lower = string.find,string.lower
local searchText = (#Properties.SearchText > 0 and
lower(Properties.SearchText))

local function recur(props,depth)


for i = 1,#props do
local prop = props[i]
local propName = prop.Name
local subName = prop.SubName
local category = prop.Category

local visible
if searchText and depth == 1 then
if find(lower(propName),searchText,1,true) then
visible = true
end
else
visible = true
end

if visible and lastCategory ~= category then


viewList[count] = {CategoryName = category}
count = count + 1
lastCategory = category
end

if (expanded["CAT_"..category] and visible) or


prop.SpecialRow then
if depth > 1 then prop.Depth = depth if depth >
maxDepth then maxDepth = depth end end

if isFirstScaleType then
local nameArr = subName and
stringSplit(subName,".")
local displayName = prop.DisplayName or
(nameArr and nameArr[#nameArr]) or propName
local nameWidth = nameWidthCache[displayName]
if not nameWidth then nameWidth =
getTextSize(textServ,displayName,14,font,size).X nameWidthCache[displayName] =
nameWidth end

local totalWidth = nameWidth +


entryIndent*depth
if totalWidth > maxWidth then
maxWidth = totalWidth
end
end

viewList[count] = prop
count = count + 1

local fullName = prop.Class.."."..prop.Name..


(prop.SubName or "")
if expanded[fullName] then
local nextDepth = depth+1
local expandedProps =
Properties.GetExpandedProps(prop)
if #expandedProps > 0 then
recur(expandedProps,nextDepth)
end
end
end
end
end
recur(props,1)

inputProp = nil
Properties.ViewWidth = maxWidth + 9 + Properties.EntryOffset
Properties.UpdateView()
end

Properties.NewPropEntry = function(index)
local newEntry = Properties.EntryTemplate:Clone()
local nameFrame = newEntry.NameFrame
local valueFrame = newEntry.ValueFrame
local newCheckbox = Lib.Checkbox.new(1)
newCheckbox.Gui.Position = UDim2.new(0,3,0,3)
newCheckbox.Gui.Parent = valueFrame
newCheckbox.OnInput:Connect(function()
local prop = viewList[index + Properties.Index]
if not prop then return end

if prop.ValueType.Name == "PhysicalProperties" then


Properties.SetProp(prop,newCheckbox.Toggled and true or
nil)
else
Properties.SetProp(prop,newCheckbox.Toggled)
end
end)
checkboxes[index] = newCheckbox

local iconFrame = Main.MiscIcons:GetLabel()


iconFrame.Position = UDim2.new(0,2,0,3)
iconFrame.Parent = newEntry.ValueFrame.RightButton
newEntry.Position = UDim2.new(0,0,0,23*(index-1))

nameFrame.Expand.InputBegan:Connect(function(input)
local prop = viewList[index + Properties.Index]
if not prop or input.UserInputType ~=
Enum.UserInputType.MouseMovement then return end

local fullName = (prop.CategoryName and


"CAT_"..prop.CategoryName) or prop.Class.."."..prop.Name..(prop.SubName or "")

Main.MiscIcons:DisplayByKey(newEntry.NameFrame.Expand.Icon,
expanded[fullName] and "Collapse_Over" or "Expand_Over")
end)

nameFrame.Expand.InputEnded:Connect(function(input)
local prop = viewList[index + Properties.Index]
if not prop or input.UserInputType ~=
Enum.UserInputType.MouseMovement then return end

local fullName = (prop.CategoryName and


"CAT_"..prop.CategoryName) or prop.Class.."."..prop.Name..(prop.SubName or "")

Main.MiscIcons:DisplayByKey(newEntry.NameFrame.Expand.Icon,
expanded[fullName] and "Collapse" or "Expand")
end)

nameFrame.Expand.MouseButton1Down:Connect(function()
local prop = viewList[index + Properties.Index]
if not prop then return end

local fullName = (prop.CategoryName and


"CAT_"..prop.CategoryName) or prop.Class.."."..prop.Name..(prop.SubName or "")
if not prop.CategoryName and not
Properties.ExpandableTypes[prop.ValueType and prop.ValueType.Name] and not
Properties.ExpandableProps[fullName] then return end

expanded[fullName] = not expanded[fullName]


Properties.Update()
Properties.Refresh()
end)

nameFrame.PropName.InputBegan:Connect(function(input)
local prop = viewList[index + Properties.Index]
if not prop then return end
if input.UserInputType == Enum.UserInputType.MouseMovement and
not nameFrame.PropName.TextFits then
local fullNameFrame = Properties.FullNameFrame
local nameArr = string.split(prop.Class.."."..prop.Name..
(prop.SubName or ""),".")
local dispName = prop.DisplayName or nameArr[#nameArr]
local sizeX =
service.TextService:GetTextSize(dispName,14,Enum.Font.SourceSans,Vector2.new(math.h
uge,20)).X

fullNameFrame.TextLabel.Text = dispName
--fullNameFrame.Position =
UDim2.new(0,Properties.EntryIndent*(prop.Depth or 1) +
Properties.EntryOffset,0,23*(index-1))
fullNameFrame.Size = UDim2.new(0,sizeX + 4,0,22)
fullNameFrame.Visible = true
Properties.FullNameFrameIndex = index
Properties.FullNameFrameAttach.SetData(fullNameFrame,
{Target = nameFrame})
Properties.FullNameFrameAttach.Enable()
end
end)

nameFrame.PropName.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and
Properties.FullNameFrameIndex == index then
Properties.FullNameFrame.Visible = false
Properties.FullNameFrameAttach.Disable()
end
end)

valueFrame.ValueBox.MouseButton1Down:Connect(function()
local prop = viewList[index + Properties.Index]
if not prop then return end

Properties.SetInputProp(prop,index)
end)

valueFrame.ColorButton.MouseButton1Down:Connect(function()
local prop = viewList[index + Properties.Index]
if not prop then return end

Properties.SetInputProp(prop,index,"color")
end)

valueFrame.RightButton.MouseButton1Click:Connect(function()
local prop = viewList[index + Properties.Index]
if not prop then return end

local fullName = prop.Class.."."..prop.Name..(prop.SubName or "")


local inputFullName = inputProp and
(inputProp.Class.."."..inputProp.Name..(inputProp.SubName or ""))

if fullName == inputFullName and inputProp.ValueType.Category ==


"Class" then
inputProp = nil
Properties.SetProp(prop,nil)
else
Properties.SetInputProp(prop,index,"right")
end
end)

nameFrame.ToggleAttributes.MouseButton1Click:Connect(function()
Settings.Properties.ShowAttributes = not
Settings.Properties.ShowAttributes
Properties.ShowExplorerProps()
end)

newEntry.RowButton.MouseButton1Click:Connect(function()
Properties.DisplayAddAttributeWindow()
end)

newEntry.EditAttributeButton.MouseButton1Down:Connect(function()
local prop = viewList[index + Properties.Index]
if not prop then return end

Properties.DisplayAttributeContext(prop)
end)

valueFrame.SoundPreview.ControlButton.MouseButton1Click:Connect(function()
if Properties.PreviewSound and Properties.PreviewSound.Playing
then
Properties.SetSoundPreview(false)
else
local soundObj = Properties.FindFirstObjWhichIsA("Sound")
if soundObj then Properties.SetSoundPreview(soundObj) end
end
end)

valueFrame.SoundPreview.InputBegan:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then
return end

local releaseEvent,mouseEvent
releaseEvent =
service.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1
then return end
releaseEvent:Disconnect()
mouseEvent:Disconnect()
end)

local timeLine = newEntry.ValueFrame.SoundPreview.TimeLine


local soundObj = Properties.FindFirstObjWhichIsA("Sound")
if soundObj then Properties.SetSoundPreview(soundObj,true) end

local function update(input)


local sound = Properties.PreviewSound
if not sound or sound.TimeLength == 0 then return end

local mouseX = input.Position.X


local timeLineSize = timeLine.AbsoluteSize
local relaX = mouseX - timeLine.AbsolutePosition.X

if timeLineSize.X <= 1 then return end


if relaX < 0 then relaX = 0 elseif relaX >= timeLineSize.X
then relaX = timeLineSize.X-1 end

local perc = (relaX/(timeLineSize.X-1))


sound.TimePosition = perc*sound.TimeLength
timeLine.Slider.Position = UDim2.new(perc,-4,0,-8)
end
update(input)

mouseEvent =
service.UserInputService.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
then
update(input)
end
end)
end)
newEntry.Parent = propsFrame

return {
Gui = newEntry,
GuiElems = {
NameFrame = nameFrame,
ValueFrame = valueFrame,
PropName = nameFrame.PropName,
ValueBox = valueFrame.ValueBox,
Expand = nameFrame.Expand,
ColorButton = valueFrame.ColorButton,
ColorPreview = valueFrame.ColorButton.ColorPreview,
Gradient = valueFrame.ColorButton.ColorPreview.UIGradient,
EnumArrow = valueFrame.EnumArrow,
Checkbox = valueFrame.Checkbox,
RightButton = valueFrame.RightButton,
RightButtonIcon = iconFrame,
RowButton = newEntry.RowButton,
EditAttributeButton = newEntry.EditAttributeButton,
ToggleAttributes = nameFrame.ToggleAttributes,
SoundPreview = valueFrame.SoundPreview,
SoundPreviewSlider =
valueFrame.SoundPreview.TimeLine.Slider
}
}
end

Properties.GetSoundPreviewEntry = function()
for i = 1,#viewList do
if viewList[i] == Properties.SoundPreviewProp then
return propEntries[i - Properties.Index]
end
end
end

Properties.SetSoundPreview = function(soundObj,noplay)
local sound = Properties.PreviewSound
if not sound then
sound = Instance.new("Sound")
sound.Name = "Preview"
sound.Paused:Connect(function()
local entry = Properties.GetSoundPreviewEntry()
if entry then
Main.MiscIcons:DisplayByKey(entry.GuiElems.SoundPreview.ControlButton.Icon, "Play")
end
end)
sound.Resumed:Connect(function() Properties.Refresh() end)
sound.Ended:Connect(function()
local entry = Properties.GetSoundPreviewEntry()
if entry then entry.GuiElems.SoundPreviewSlider.Position =
UDim2.new(0,-4,0,-8) end
Properties.Refresh()
end)
sound.Parent = window.Gui
Properties.PreviewSound = sound
end

if not soundObj then


sound:Pause()
else
local newId = sound.SoundId ~= soundObj.SoundId
sound.SoundId = soundObj.SoundId
sound.PlaybackSpeed = soundObj.PlaybackSpeed
sound.Volume = soundObj.Volume
if newId then sound.TimePosition = 0 end
if not noplay then sound:Resume() end

coroutine.wrap(function()
local previewTime = tick()
Properties.SoundPreviewTime = previewTime
while previewTime == Properties.SoundPreviewTime and
sound.Playing do
local entry = Properties.GetSoundPreviewEntry()
if entry then
local tl = sound.TimeLength
local perc = sound.TimePosition/(tl == 0 and 1
or tl)
entry.GuiElems.SoundPreviewSlider.Position =
UDim2.new(perc,-4,0,-8)
end
Lib.FastWait()
end
end)()
Properties.Refresh()
end
end

Properties.DisplayAttributeContext = function(prop)
local context = Properties.AttributeContext
if not context then
context = Lib.ContextMenu.new()
context.Iconless = true
context.Width = 80
end
context:Clear()

context:Add({Name = "Edit", OnClick = function()


Properties.DisplayAddAttributeWindow(prop)
end})
context:Add({Name = "Delete", OnClick = function()
Properties.SetProp(prop,nil,true)
Properties.ShowExplorerProps()
end})

context:Show()
end

Properties.DisplayAddAttributeWindow = function(editAttr)
local win = Properties.AddAttributeWindow
if not win then
win = Lib.Window.new()
win.Alignable = false
win.Resizable = false
win:SetTitle("Add Attribute")
win:SetSize(200,130)

local saveButton = Lib.Button.new()


local nameLabel = Lib.Label.new()
nameLabel.Text = "Name"
nameLabel.Position = UDim2.new(0,30,0,10)
nameLabel.Size = UDim2.new(0,40,0,20)
win:Add(nameLabel)

local nameBox = Lib.ViewportTextBox.new()


nameBox.Position = UDim2.new(0,75,0,10)
nameBox.Size = UDim2.new(0,120,0,20)
win:Add(nameBox,"NameBox")

nameBox.TextBox:GetPropertyChangedSignal("Text"):Connect(function()
saveButton:SetDisabled(#nameBox:GetText() == 0)
end)

local typeLabel = Lib.Label.new()


typeLabel.Text = "Type"
typeLabel.Position = UDim2.new(0,30,0,40)
typeLabel.Size = UDim2.new(0,40,0,20)
win:Add(typeLabel)

local typeChooser = Lib.DropDown.new()


typeChooser.CanBeEmpty = false
typeChooser.Position = UDim2.new(0,75,0,40)
typeChooser.Size = UDim2.new(0,120,0,20)
typeChooser:SetOptions(Properties.AllowedAttributeTypes)
win:Add(typeChooser,"TypeChooser")

local errorLabel = Lib.Label.new()


errorLabel.Text = ""
errorLabel.Position = UDim2.new(0,5,1,-45)
errorLabel.Size = UDim2.new(1,-10,0,20)
errorLabel.TextColor3 = Settings.Theme.Important
win.ErrorLabel = errorLabel
win:Add(errorLabel,"Error")

local cancelButton = Lib.Button.new()


cancelButton.Text = "Cancel"
cancelButton.Position = UDim2.new(1,-97,1,-25)
cancelButton.Size = UDim2.new(0,92,0,20)
cancelButton.OnClick:Connect(function()
win:Close()
end)
win:Add(cancelButton)

saveButton.Text = "Save"
saveButton.Position = UDim2.new(0,5,1,-25)
saveButton.Size = UDim2.new(0,92,0,20)
saveButton.OnClick:Connect(function()
local name = nameBox:GetText()
if #name > 100 then
errorLabel.Text = "Error: Name over 100 chars"
return
elseif name:sub(1,3) == "RBX" then
errorLabel.Text = "Error: Name begins with 'RBX'"
return
end

local typ = typeChooser.Selected


local valType = {Name = Properties.TypeNameConvert[typ] or
typ, Category = "DataType"}
local attrProp = {IsAttribute = true, Name = "ATTR_"..name,
AttributeName = name, DisplayName = name, Class = "Instance", ValueType = valType,
Category = "Attributes", Tags = {}}

Settings.Properties.ShowAttributes = true

Properties.SetProp(attrProp,Properties.DefaultPropValue[valType.Name],true,Properti
es.EditingAttribute)
Properties.ShowExplorerProps()
win:Close()
end)
win:Add(saveButton,"SaveButton")

Properties.AddAttributeWindow = win
end

Properties.EditingAttribute = editAttr
win:SetTitle(editAttr and "Edit Attribute "..editAttr.AttributeName or
"Add Attribute")
win.Elements.Error.Text = ""
win.Elements.NameBox:SetText("")
win.Elements.SaveButton:SetDisabled(true)
win.Elements.TypeChooser:SetSelected(1)
win:Show()
end

Properties.IsTextEditable = function(prop)
local typeData = prop.ValueType
local typeName = typeData.Name

return typeName ~= "bool" and typeData.Category ~= "Enum" and


typeData.Category ~= "Class" and typeName ~= "BrickColor"
end

Properties.DisplayEnumDropdown = function(entryIndex)
local context = Properties.EnumContext
if not context then
context = Lib.ContextMenu.new()
context.Iconless = true
context.MaxHeight = 200
context.ReverseYOffset = 22
Properties.EnumDropdown = context
end

if not inputProp or inputProp.ValueType.Category ~= "Enum" then return


end
local prop = inputProp

local entry = propEntries[entryIndex]


local valueFrame = entry.GuiElems.ValueFrame

local enum = Enum[prop.ValueType.Name]


if not enum then return end

local sorted = {}
for name,enum in next,enum:GetEnumItems() do
sorted[#sorted+1] = enum
end
table.sort(sorted,function(a,b) return a.Name < b.Name end)

context:Clear()

local function onClick(name)


if prop ~= inputProp then return end

local enumItem = enum[name]


inputProp = nil
Properties.SetProp(prop,enumItem)
end

for i = 1,#sorted do
local enumItem = sorted[i]
context:Add({Name = enumItem.Name, OnClick = onClick})
end

context.Width = valueFrame.AbsoluteSize.X
context:Show(valueFrame.AbsolutePosition.X,
valueFrame.AbsolutePosition.Y + 22)
end

Properties.DisplayBrickColorEditor = function(prop,entryIndex,col)
local editor = Properties.BrickColorEditor
if not editor then
editor = Lib.BrickColorPicker.new()
editor.Gui.DisplayOrder = Main.DisplayOrders.Menu
editor.ReverseYOffset = 22

editor.OnSelect:Connect(function(col)
if not editor.CurrentProp or
editor.CurrentProp.ValueType.Name ~= "BrickColor" then return end

if editor.CurrentProp == inputProp then inputProp = nil end


Properties.SetProp(editor.CurrentProp,BrickColor.new(col))
end)

editor.OnMoreColors:Connect(function() -- TODO: Special Case


BasePart.BrickColor to BasePart.Color
editor:Close()
local colProp
for i,v in pairs(API.Classes.BasePart.Properties) do
if v.Name == "Color" then
colProp = v
break
end
end

Properties.DisplayColorEditor(colProp,editor.SavedColor.Color)
end)

Properties.BrickColorEditor = editor
end

local entry = propEntries[entryIndex]


local valueFrame = entry.GuiElems.ValueFrame
editor.CurrentProp = prop
editor.SavedColor = col
if prop and prop.Class == "BasePart" and prop.Name == "BrickColor" then
editor:SetMoreColorsVisible(true)
else
editor:SetMoreColorsVisible(false)
end
editor:Show(valueFrame.AbsolutePosition.X,
valueFrame.AbsolutePosition.Y + 22)
end

Properties.DisplayColorEditor = function(prop,col)
local editor = Properties.ColorEditor
if not editor then
editor = Lib.ColorPicker.new()

editor.OnSelect:Connect(function(col)
if not editor.CurrentProp then return end
local typeName = editor.CurrentProp.ValueType.Name
if typeName ~= "Color3" and typeName ~= "BrickColor" then
return end

local colVal = (typeName == "Color3" and col or


BrickColor.new(col))

if editor.CurrentProp == inputProp then inputProp = nil end


Properties.SetProp(editor.CurrentProp,colVal)
end)

Properties.ColorEditor = editor
end

editor.CurrentProp = prop
if col then
editor:SetColor(col)
else
local firstVal = Properties.GetFirstPropVal(prop)
if firstVal then editor:SetColor(firstVal) end
end
editor:Show()
end

Properties.DisplayNumberSequenceEditor = function(prop,seq)
local editor = Properties.NumberSequenceEditor
if not editor then
editor = Lib.NumberSequenceEditor.new()

editor.OnSelect:Connect(function(val)
if not editor.CurrentProp or
editor.CurrentProp.ValueType.Name ~= "NumberSequence" then return end

if editor.CurrentProp == inputProp then inputProp = nil end


Properties.SetProp(editor.CurrentProp,val)
end)

Properties.NumberSequenceEditor = editor
end

editor.CurrentProp = prop
if seq then
editor:SetSequence(seq)
else
local firstVal = Properties.GetFirstPropVal(prop)
if firstVal then editor:SetSequence(firstVal) end
end
editor:Show()
end

Properties.DisplayColorSequenceEditor = function(prop,seq)
local editor = Properties.ColorSequenceEditor
if not editor then
editor = Lib.ColorSequenceEditor.new()

editor.OnSelect:Connect(function(val)
if not editor.CurrentProp or
editor.CurrentProp.ValueType.Name ~= "ColorSequence" then return end

if editor.CurrentProp == inputProp then inputProp = nil end


Properties.SetProp(editor.CurrentProp,val)
end)

Properties.ColorSequenceEditor = editor
end

editor.CurrentProp = prop
if seq then
editor:SetSequence(seq)
else
local firstVal = Properties.GetFirstPropVal(prop)
if firstVal then editor:SetSequence(firstVal) end
end
editor:Show()
end

Properties.GetFirstPropVal = function(prop)
local first = Properties.FindFirstObjWhichIsA(prop.Class)
if first then
return Properties.GetPropVal(prop,first)
end
end

Properties.GetPropVal = function(prop,obj)
if prop.MultiType then return "<Multiple Types>" end
if not obj then return end

local propVal
if prop.IsAttribute then
propVal = getAttribute(obj,prop.AttributeName)
if propVal == nil then return nil end

local typ = typeof(propVal)


local currentType = Properties.TypeNameConvert[typ] or typ
if prop.RootType then
if prop.RootType.Name ~= currentType then
return nil
end
elseif prop.ValueType.Name ~= currentType then
return nil
end
else
propVal = obj[prop.Name]
end
if prop.SubName then
local indexes = string.split(prop.SubName,".")
for i = 1,#indexes do
local indexName = indexes[i]
if #indexName > 0 and propVal then
propVal = propVal[indexName]
end
end
end

return propVal
end

Properties.SelectObject = function(obj)
if inputProp and inputProp.ValueType.Category == "Class" then
local prop = inputProp
inputProp = nil

if isa(obj,prop.ValueType.Name) then
Properties.SetProp(prop,obj)
else
Properties.Refresh()
end

return true
end

return false
end

Properties.DisplayProp = function(prop,entryIndex)
local propName = prop.Name
local typeData = prop.ValueType
local typeName = typeData.Name
local tags = prop.Tags
local gName = prop.Class.."."..prop.Name..(prop.SubName or "")
local propObj = autoUpdateObjs[gName]
local entryData = propEntries[entryIndex]
local UDim2 = UDim2

local guiElems = entryData.GuiElems


local valueFrame = guiElems.ValueFrame
local valueBox = guiElems.ValueBox
local colorButton = guiElems.ColorButton
local colorPreview = guiElems.ColorPreview
local gradient = guiElems.Gradient
local enumArrow = guiElems.EnumArrow
local checkbox = guiElems.Checkbox
local rightButton = guiElems.RightButton
local soundPreview = guiElems.SoundPreview

local propVal = Properties.GetPropVal(prop,propObj)


local inputFullName = inputProp and
(inputProp.Class.."."..inputProp.Name..(inputProp.SubName or ""))
local offset = 4
local endOffset = 6

-- Offsetting the ValueBox for ValueType specific buttons


if (typeName == "Color3" or typeName == "BrickColor" or typeName ==
"ColorSequence") then
colorButton.Visible = true
enumArrow.Visible = false
if propVal then
gradient.Color = (typeName == "Color3" and
ColorSequence.new(propVal)) or (typeName == "BrickColor" and
ColorSequence.new(propVal.Color)) or propVal
else
gradient.Color = ColorSequence.new(Color3.new(1,1,1))
end
colorPreview.BorderColor3 = (typeName == "ColorSequence" and
Color3.new(1,1,1) or Color3.new(0,0,0))
offset = 22
endOffset = 24 + (typeName == "ColorSequence" and 20 or 0)
elseif typeData.Category == "Enum" then
colorButton.Visible = false
enumArrow.Visible = not prop.Tags.ReadOnly
endOffset = 22
elseif (gName == inputFullName and typeData.Category == "Class") or
typeName == "NumberSequence" then
colorButton.Visible = false
enumArrow.Visible = false
endOffset = 26
else
colorButton.Visible = false
enumArrow.Visible = false
end

valueBox.Position = UDim2.new(0,offset,0,0)
valueBox.Size = UDim2.new(1,-endOffset,1,0)

-- Right button
if inputFullName == gName and typeData.Category == "Class" then
Main.MiscIcons:DisplayByKey(guiElems.RightButtonIcon, "Delete")
guiElems.RightButtonIcon.Visible = true
rightButton.Text = ""
rightButton.Visible = true
elseif typeName == "NumberSequence" or typeName == "ColorSequence" then
guiElems.RightButtonIcon.Visible = false
rightButton.Text = "..."
rightButton.Visible = true
else
rightButton.Visible = false
end

-- Displays the correct ValueBox for the ValueType, and sets it to the
prop value
if typeName == "bool" or typeName == "PhysicalProperties" then
valueBox.Visible = false
checkbox.Visible = true
soundPreview.Visible = false
checkboxes[entryIndex].Disabled = tags.ReadOnly
if typeName == "PhysicalProperties" and autoUpdateObjs[gName]
then
checkboxes[entryIndex]:SetState(propVal and true or false)
else
checkboxes[entryIndex]:SetState(propVal)
end
elseif typeName == "SoundPlayer" then
valueBox.Visible = false
checkbox.Visible = false
soundPreview.Visible = true
local playing = Properties.PreviewSound and
Properties.PreviewSound.Playing
Main.MiscIcons:DisplayByKey(soundPreview.ControlButton.Icon,
playing and "Pause" or "Play")
else
valueBox.Visible = true
checkbox.Visible = false
soundPreview.Visible = false

if propVal ~= nil then


if typeName == "Color3" then
valueBox.Text = "["..Lib.ColorToBytes(propVal).."]"
elseif typeData.Category == "Enum" then
valueBox.Text = propVal.Name
elseif Properties.RoundableTypes[typeName] and
Settings.Properties.NumberRounding then
local rawStr = Properties.ValueToString(prop,propVal)
valueBox.Text = rawStr:gsub("-?%d+%.
%d+",function(num)
return
tostring(tonumber(("%."..Settings.Properties.NumberRounding.."f"):format(num)))
end)
else
valueBox.Text =
Properties.ValueToString(prop,propVal)
end
else
valueBox.Text = ""
end

valueBox.TextColor3 = tags.ReadOnly and


Settings.Theme.PlaceholderText or Settings.Theme.Text
end
end

Properties.Refresh = function()
local maxEntries = math.max(math.ceil((propsFrame.AbsoluteSize.Y) /
23),0)
local maxX = propsFrame.AbsoluteSize.X
local valueWidth = math.max(Properties.MinInputWidth,maxX-
Properties.ViewWidth)
local inputPropVisible = false
local isa = game.IsA
local UDim2 = UDim2
local stringSplit = string.split
local scaleType = Settings.Properties.ScaleType

-- Clear connections
for i = 1,#propCons do
propCons[i]:Disconnect()
end
table.clear(propCons)

-- Hide full name viewer


Properties.FullNameFrame.Visible = false
Properties.FullNameFrameAttach.Disable()

for i = 1,maxEntries do
local entryData = propEntries[i]
if not propEntries[i] then entryData = Properties.NewPropEntry(i)
propEntries[i] = entryData end

local entry = entryData.Gui


local guiElems = entryData.GuiElems
local nameFrame = guiElems.NameFrame
local propNameLabel = guiElems.PropName
local valueFrame = guiElems.ValueFrame
local expand = guiElems.Expand
local valueBox = guiElems.ValueBox
local propNameBox = guiElems.PropName
local rightButton = guiElems.RightButton
local editAttributeButton = guiElems.EditAttributeButton
local toggleAttributes = guiElems.ToggleAttributes

local prop = viewList[i + Properties.Index]


if prop then
local entryXOffset = (scaleType == 0 and scrollH.Index or
0)
entry.Visible = true
entry.Position = UDim2.new(0,-
entryXOffset,0,entry.Position.Y.Offset)
entry.Size = UDim2.new(scaleType == 0 and 0 or 1, scaleType
== 0 and Properties.ViewWidth + valueWidth or 0,0,22)

if prop.SpecialRow then
if prop.SpecialRow == "AddAttribute" then
nameFrame.Visible = false
valueFrame.Visible = false
guiElems.RowButton.Visible = true
end
else
-- Revert special row stuff
nameFrame.Visible = true
guiElems.RowButton.Visible = false

local depth = Properties.EntryIndent*(prop.Depth or


1)
local leftOffset = depth + Properties.EntryOffset
nameFrame.Position = UDim2.new(0,leftOffset,0,0)
propNameLabel.Size = UDim2.new(1,-2 - (scaleType == 0
and 0 or 6),1,0)

local gName = (prop.CategoryName and


"CAT_"..prop.CategoryName) or prop.Class.."."..prop.Name..(prop.SubName or "")

if prop.CategoryName then
entry.BackgroundColor3 = Settings.Theme.Main1
valueFrame.Visible = false

propNameBox.Text = prop.CategoryName
propNameBox.Font = Enum.Font.SourceSansBold
expand.Visible = true
propNameBox.TextColor3 = Settings.Theme.Text
nameFrame.BackgroundTransparency = 1
nameFrame.Size = UDim2.new(1,0,1,0)
editAttributeButton.Visible = false

local showingAttrs =
Settings.Properties.ShowAttributes
toggleAttributes.Position = UDim2.new(1,-85-
leftOffset,0,0)
toggleAttributes.Text = (showingAttrs and
"[Setting: ON]" or "[Setting: OFF]")
toggleAttributes.TextColor3 =
Settings.Theme.Text
toggleAttributes.Visible = (prop.CategoryName
== "Attributes")
else
local propName = prop.Name
local typeData = prop.ValueType
local typeName = typeData.Name
local tags = prop.Tags
local propObj = autoUpdateObjs[gName]

local attributeOffset = (prop.IsAttribute and


20 or 0)
editAttributeButton.Visible = (prop.IsAttribute
and not prop.RootType)
toggleAttributes.Visible = false

-- Moving around the frames


if scaleType == 0 then
nameFrame.Size =
UDim2.new(0,Properties.ViewWidth - leftOffset - 1,1,0)
valueFrame.Position =
UDim2.new(0,Properties.ViewWidth,0,0)
valueFrame.Size = UDim2.new(0,valueWidth
- attributeOffset,1,0)
else
nameFrame.Size = UDim2.new(0.5,-
leftOffset - 1,1,0)
valueFrame.Position =
UDim2.new(0.5,0,0,0)
valueFrame.Size = UDim2.new(0.5,-
attributeOffset,1,0)
end

local nameArr = stringSplit(gName,".")


propNameBox.Text = prop.DisplayName or
nameArr[#nameArr]
propNameBox.Font = Enum.Font.SourceSans
entry.BackgroundColor3 = Settings.Theme.Main2
valueFrame.Visible = true

expand.Visible = typeData.Category ==
"DataType" and Properties.ExpandableTypes[typeName] or
Properties.ExpandableProps[gName]
propNameBox.TextColor3 = tags.ReadOnly and
Settings.Theme.PlaceholderText or Settings.Theme.Text
-- Display property value
Properties.DisplayProp(prop,i)
if propObj then
if prop.IsAttribute then
propCons[#propCons+1] =
getAttributeChangedSignal(propObj,prop.AttributeName):Connect(function()

Properties.DisplayProp(prop,i)
end)
else
propCons[#propCons+1] =
getPropChangedSignal(propObj,propName):Connect(function()

Properties.DisplayProp(prop,i)
end)
end
end

-- Position and resize Input Box


local beforeVisible = valueBox.Visible
local inputFullName = inputProp and
(inputProp.Class.."."..inputProp.Name..(inputProp.SubName or ""))
if gName == inputFullName then
nameFrame.BackgroundColor3 =
Settings.Theme.ListSelection
nameFrame.BackgroundTransparency = 0
if typeData.Category == "Class" or
typeData.Category == "Enum" or typeName == "BrickColor" then
valueFrame.BackgroundColor3 =
Settings.Theme.TextBox
valueFrame.BackgroundTransparency =
0
valueBox.Visible = true
else
inputPropVisible = true
local scale = (scaleType == 0 and 0
or 0.5)
local offset = (scaleType == 0 and
Properties.ViewWidth-scrollH.Index or 0)
local endOffset = 0

if typeName == "Color3" or typeName


== "ColorSequence" then
offset = offset + 22
end

if typeName == "NumberSequence" or
typeName == "ColorSequence" then
endOffset = 20
end

inputBox.Position =
UDim2.new(scale,offset,0,entry.Position.Y.Offset)
inputBox.Size = UDim2.new(1-scale,-
offset-endOffset-attributeOffset,0,22)
inputBox.Visible = true
valueBox.Visible = false
end
else
nameFrame.BackgroundColor3 =
Settings.Theme.Main1
nameFrame.BackgroundTransparency = 1
valueFrame.BackgroundColor3 =
Settings.Theme.Main1
valueFrame.BackgroundTransparency = 1
valueBox.Visible = beforeVisible
end
end

-- Expand
if prop.CategoryName or
Properties.ExpandableTypes[prop.ValueType and prop.ValueType.Name] or
Properties.ExpandableProps[gName] then
if Lib.CheckMouseInGui(expand) then
Main.MiscIcons:DisplayByKey(expand.Icon,
expanded[gName] and "Collapse_Over" or "Expand_Over")
else
Main.MiscIcons:DisplayByKey(expand.Icon,
expanded[gName] and "Collapse" or "Expand")
end
expand.Visible = true
else
expand.Visible = false
end
end
entry.Visible = true
else
entry.Visible = false
end
end

if not inputPropVisible then


inputBox.Visible = false
end

for i = maxEntries+1,#propEntries do
propEntries[i].Gui:Destroy()
propEntries[i] = nil
checkboxes[i] = nil
end
end

Properties.SetProp = function(prop,val,noupdate,prevAttribute)
local sList = Explorer.Selection.List
local propName = prop.Name
local subName = prop.SubName
local propClass = prop.Class
local typeData = prop.ValueType
local typeName = typeData.Name
local attributeName = prop.AttributeName
local rootTypeData = prop.RootType
local rootTypeName = rootTypeData and rootTypeData.Name
local fullName = prop.Class.."."..prop.Name..(prop.SubName or "")
local Vector3 = Vector3

for i = 1,#sList do
local node = sList[i]
local obj = node.Obj

if isa(obj,propClass) then
pcall(function()
local setVal = val
local root
if prop.IsAttribute then
root = getAttribute(obj,attributeName)
else
root = obj[propName]
end

if prevAttribute then
if prevAttribute.ValueType.Name == typeName
then
setVal =
getAttribute(obj,prevAttribute.AttributeName) or setVal
end

setAttribute(obj,prevAttribute.AttributeName,nil)
end

if rootTypeName then
if rootTypeName == "Vector2" then
setVal = Vector2.new((subName == ".X" and
setVal) or root.X, (subName == ".Y" and setVal) or root.Y)
elseif rootTypeName == "Vector3" then
setVal = Vector3.new((subName == ".X" and
setVal) or root.X, (subName == ".Y" and setVal) or root.Y, (subName == ".Z" and
setVal) or root.Z)
elseif rootTypeName == "UDim" then
setVal = UDim.new((subName == ".Scale"
and setVal) or root.Scale, (subName == ".Offset" and setVal) or root.Offset)
elseif rootTypeName == "UDim2" then
local rootX,rootY = root.X,root.Y
local X_UDim = (subName == ".X" and
setVal) or UDim.new((subName == ".X.Scale" and setVal) or rootX.Scale, (subName ==
".X.Offset" and setVal) or rootX.Offset)
local Y_UDim = (subName == ".Y" and
setVal) or UDim.new((subName == ".Y.Scale" and setVal) or rootY.Scale, (subName ==
".Y.Offset" and setVal) or rootY.Offset)
setVal = UDim2.new(X_UDim,Y_UDim)
elseif rootTypeName == "CFrame" then
local rootPos,rootRight,rootUp,rootLook =
root.Position,root.RightVector,root.UpVector,root.LookVector
local pos = (subName == ".Position" and
setVal) or Vector3.new((subName == ".Position.X" and setVal) or rootPos.X, (subName
== ".Position.Y" and setVal) or rootPos.Y, (subName == ".Position.Z" and setVal) or
rootPos.Z)
local rightV = (subName == ".RightVector"
and setVal) or Vector3.new((subName == ".RightVector.X" and setVal) or rootRight.X,
(subName == ".RightVector.Y" and setVal) or rootRight.Y, (subName ==
".RightVector.Z" and setVal) or rootRight.Z)
local upV = (subName == ".UpVector" and
setVal) or Vector3.new((subName == ".UpVector.X" and setVal) or rootUp.X, (subName
== ".UpVector.Y" and setVal) or rootUp.Y, (subName == ".UpVector.Z" and setVal) or
rootUp.Z)
local lookV = (subName == ".LookVector"
and setVal) or Vector3.new((subName == ".LookVector.X" and setVal) or rootLook.X,
(subName == ".RightVector.Y" and setVal) or rootLook.Y, (subName ==
".RightVector.Z" and setVal) or rootLook.Z)
setVal =
CFrame.fromMatrix(pos,rightV,upV,-lookV)
elseif rootTypeName == "Rect" then
local rootMin,rootMax = root.Min,root.Max
local min = Vector2.new((subName ==
".Min.X" and setVal) or rootMin.X, (subName == ".Min.Y" and setVal) or rootMin.Y)
local max = Vector2.new((subName ==
".Max.X" and setVal) or rootMax.X, (subName == ".Max.Y" and setVal) or rootMax.Y)
setVal = Rect.new(min,max)
elseif rootTypeName == "PhysicalProperties"
then
local rootProps =
PhysicalProperties.new(obj.Material)
local density = (subName == ".Density"
and setVal) or (root and root.Density) or rootProps.Density
local friction = (subName == ".Friction"
and setVal) or (root and root.Friction) or rootProps.Friction
local elasticity = (subName ==
".Elasticity" and setVal) or (root and root.Elasticity) or rootProps.Elasticity
local frictionWeight = (subName ==
".FrictionWeight" and setVal) or (root and root.FrictionWeight) or
rootProps.FrictionWeight
local elasticityWeight = (subName ==
".ElasticityWeight" and setVal) or (root and root.ElasticityWeight) or
rootProps.ElasticityWeight
setVal =
PhysicalProperties.new(density,friction,elasticity,frictionWeight,elasticityWeight)
elseif rootTypeName == "Ray" then
local rootOrigin,rootDirection =
root.Origin,root.Direction
local origin = (subName == ".Origin" and
setVal) or Vector3.new((subName == ".Origin.X" and setVal) or rootOrigin.X,
(subName == ".Origin.Y" and setVal) or rootOrigin.Y, (subName == ".Origin.Z" and
setVal) or rootOrigin.Z)
local direction = (subName ==
".Direction" and setVal) or Vector3.new((subName == ".Direction.X" and setVal) or
rootDirection.X, (subName == ".Direction.Y" and setVal) or rootDirection.Y,
(subName == ".Direction.Z" and setVal) or rootDirection.Z)
setVal = Ray.new(origin,direction)
elseif rootTypeName == "Faces" then
local faces = {}
local faceList =
{"Back","Bottom","Front","Left","Right","Top"}
for _,face in pairs(faceList) do
local val
if subName == "."..face then
val = setVal
else
val = root[face]
end
if val then faces[#faces+1] =
Enum.NormalId[face] end
end
setVal = Faces.new(unpack(faces))
elseif rootTypeName == "Axes" then
local axes = {}
local axesList = {"X","Y","Z"}
for _,axe in pairs(axesList) do
local val
if subName == "."..axe then
val = setVal
else
val = root[axe]
end
if val then axes[#axes+1] =
Enum.Axis[axe] end
end
setVal = Axes.new(unpack(axes))
elseif rootTypeName == "NumberRange" then
setVal = NumberRange.new(subName ==
".Min" and setVal or root.Min, subName == ".Max" and setVal or root.Max)
end
end

if typeName == "PhysicalProperties" and setVal then


setVal = root or
PhysicalProperties.new(obj.Material)
end

if prop.IsAttribute then
setAttribute(obj,attributeName,setVal)
else
obj[propName] = setVal
end
end)
end
end

if not noupdate then


Properties.ComputeConflicts(prop)
end
end

Properties.InitInputBox = function()
inputBox = create({
{1,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderSizePixel=0,Name="InputBox",Size=UDim2.new(0,200,0,22),Visible=false,ZIndex=2,}
},
{2,"TextBox",
{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.062745101749897,0.51764708757401,1
),BorderSizePixel=0,ClearTextOnFocus=false,Font=3,Parent={1},PlaceholderColor3=Colo
r3.new(0.69803923368454,0.69803923368454,0.69803923368454),Position=UDim2.new(0,3,0
,0),Size=UDim2.new(1,-
6,1,0),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=0,ZIndex=2,}
},
})
inputTextBox = inputBox.TextBox
inputBox.BackgroundColor3 = Settings.Theme.TextBox
inputBox.Parent = Properties.Window.GuiElems.Content.List

inputTextBox.FocusLost:Connect(function()
if not inputProp then return end

local prop = inputProp


inputProp = nil
local val = Properties.StringToValue(prop,inputTextBox.Text)
if val then Properties.SetProp(prop,val) else
Properties.Refresh() end
end)

inputTextBox.Focused:Connect(function()
inputTextBox.SelectionStart = 1
inputTextBox.CursorPosition = #inputTextBox.Text + 1
end)

Lib.ViewportTextBox.convert(inputTextBox)
end

Properties.SetInputProp = function(prop,entryIndex,special)
local typeData = prop.ValueType
local typeName = typeData.Name
local fullName = prop.Class.."."..prop.Name..(prop.SubName or "")
local propObj = autoUpdateObjs[fullName]
local propVal = Properties.GetPropVal(prop,propObj)

if prop.Tags.ReadOnly then return end

inputProp = prop
if special then
if special == "color" then
if typeName == "Color3" then
inputTextBox.Text = propVal and
Properties.ValueToString(prop,propVal) or ""
Properties.DisplayColorEditor(prop,propVal)
elseif typeName == "BrickColor" then

Properties.DisplayBrickColorEditor(prop,entryIndex,propVal)
elseif typeName == "ColorSequence" then
inputTextBox.Text = propVal and
Properties.ValueToString(prop,propVal) or ""
Properties.DisplayColorSequenceEditor(prop,propVal)
end
elseif special == "right" then
if typeName == "NumberSequence" then
inputTextBox.Text = propVal and
Properties.ValueToString(prop,propVal) or ""
Properties.DisplayNumberSequenceEditor(prop,propVal)
elseif typeName == "ColorSequence" then
inputTextBox.Text = propVal and
Properties.ValueToString(prop,propVal) or ""
Properties.DisplayColorSequenceEditor(prop,propVal)
end
end
else
if Properties.IsTextEditable(prop) then
inputTextBox.Text = propVal and
Properties.ValueToString(prop,propVal) or ""
inputTextBox:CaptureFocus()
elseif typeData.Category == "Enum" then
Properties.DisplayEnumDropdown(entryIndex)
elseif typeName == "BrickColor" then
Properties.DisplayBrickColorEditor(prop,entryIndex,propVal)
end
end
Properties.Refresh()
end

Properties.InitSearch = function()
local searchBox = Properties.GuiElems.ToolBar.SearchFrame.SearchBox

Lib.ViewportTextBox.convert(searchBox)

searchBox:GetPropertyChangedSignal("Text"):Connect(function()
Properties.SearchText = searchBox.Text
Properties.Update()
Properties.Refresh()
end)
end

Properties.InitEntryStuff = function()
Properties.EntryTemplate = create({
{1,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.17647059261799,0.1764705926179
9,0.17647059261799),BorderColor3=Color3.new(0.1294117718935,0.1294117718935,0.12941
17718935),Font=3,Name="Entry",Position=UDim2.new(0,1,0,1),Size=UDim2.new(0,250,0,22
),Text="",TextSize=14,}},
{2,"Frame",
{BackgroundColor3=Color3.new(0.04313725605607,0.35294118523598,0.68627452850342),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.33725491166115,0.49019610881805,0.
73725491762161),BorderSizePixel=0,Name="NameFrame",Parent={1},Position=UDim2.new(0,
20,0,0),Size=UDim2.new(1,-40,1,0),}},
{3,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="PropName"
,Parent={2},Position=UDim2.new(0,2,0,0),Size=UDim2.new(1,-
2,1,0),Text="Anchored",TextColor3=Color3.new(1,1,1),TextSize=14,TextTransparency=0.
10000000149012,TextTruncate=1,TextXAlignment=0,}},
{4,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ClipsDescendants=true,
Font=3,Name="Expand",Parent={2},Position=UDim2.new(0,-
20,0,1),Size=UDim2.new(0,20,0,20),Text="",TextSize=14,Visible=false,}},
{5,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
5642383285",ImageRectOffset=Vector2.new(144,16),ImageRectSize=Vector2.new(16,16),Na
me="Icon",Parent={4},Position=UDim2.new(0,2,0,2),ScaleType=4,Size=UDim2.new(0,16,0,
16),}},
{6,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Font
=4,Name="ToggleAttributes",Parent={2},Position=UDim2.new(1,-
85,0,0),Size=UDim2.new(0,85,0,22),Text="[SETTING:
OFF]",TextColor3=Color3.new(1,1,1),TextSize=14,TextTransparency=0.10000000149012,Vi
sible=false,}},
{7,"Frame",
{BackgroundColor3=Color3.new(0.04313725605607,0.35294118523598,0.68627452850342),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.33725491166115,0.49019607901573,0.
73725491762161),BorderSizePixel=0,Name="ValueFrame",Parent={1},Position=UDim2.new(1
,-100,0,0),Size=UDim2.new(0,80,1,0),}},
{8,"Frame",
{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),Bo
rderColor3=Color3.new(0.33725491166115,0.49019610881805,0.73725491762161),BorderSiz
ePixel=0,Name="Line",Parent={7},Position=UDim2.new(0,-
1,0,0),Size=UDim2.new(0,1,1,0),}},
{9,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Font
=3,Name="ColorButton",Parent={7},Size=UDim2.new(0,20,0,22),Text="",TextColor3=Color
3.new(1,1,1),TextSize=14,Visible=false,}},
{10,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BorderColor3=Color3.new(0,0,0),Name="ColorPrevi
ew",Parent={9},Position=UDim2.new(0,5,0,6),Size=UDim2.new(0,10,0,10),}},
{11,"UIGradient",{Parent={10},}},
{12,"Frame",
{BackgroundTransparency=1,Name="EnumArrow",Parent={7},Position=UDim2.new(1,-
16,0,3),Size=UDim2.new(0,16,0,16),Visible=false,}},
{13,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={12},Position=UDim2.new(0,8,0,9),Size=UDim2.new(0,1,0,1),}},
{14,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={12},Position=UDim2.new(0,7,0,8),Size=UDim2.new(0,3,0,1),}},
{15,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={12},Position=UDim2.new(0,6,0,7),Size=UDim2.new(0,5,0,1),}},
{16,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="ValueBox"
,Parent={7},Position=UDim2.new(0,4,0,0),Size=UDim2.new(1,-
8,1,0),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,TextTransparency=0.10000000
149012,TextTruncate=1,TextXAlignment=0,}},
{17,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Font
=3,Name="RightButton",Parent={7},Position=UDim2.new(1,-
20,0,0),Size=UDim2.new(0,20,0,22),Text="...",TextColor3=Color3.new(1,1,1),TextSize=
14,Visible=false,}},
{18,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Font
=3,Name="SettingsButton",Parent={7},Position=UDim2.new(1,-
20,0,0),Size=UDim2.new(0,20,0,22),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,
Visible=false,}},
{19,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="SoundPreview",Pa
rent={7},Size=UDim2.new(1,0,1,0),Visible=false,}},
{20,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Font
=3,Name="ControlButton",Parent={19},Size=UDim2.new(0,20,0,22),Text="",TextColor3=Co
lor3.new(1,1,1),TextSize=14,}},
{21,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
5642383285",ImageRectOffset=Vector2.new(144,16),ImageRectSize=Vector2.new(16,16),Na
me="Icon",Parent={20},Position=UDim2.new(0,2,0,3),ScaleType=4,Size=UDim2.new(0,16,0
,16),}},
{22,"Frame",
{BackgroundColor3=Color3.new(0.3137255012989,0.3137255012989,0.3137255012989),Borde
rSizePixel=0,Name="TimeLine",Parent={19},Position=UDim2.new(0,26,0.5,-
1),Size=UDim2.new(1,-34,0,2),}},
{23,"Frame",
{BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,0.2352941185236),Borde
rColor3=Color3.new(0.1294117718935,0.1294117718935,0.1294117718935),Name="Slider",P
arent={22},Position=UDim2.new(0,-4,0,-8),Size=UDim2.new(0,8,0,18),}},
{24,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Font
=3,Name="EditAttributeButton",Parent={1},Position=UDim2.new(1,-
20,0,0),Size=UDim2.new(0,20,0,22),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,
}},
{25,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
5034718180",ImageTransparency=0.20000000298023,Name="Icon",Parent={24},Position=UDi
m2.new(0,2,0,3),Size=UDim2.new(0,16,0,16),}},
{26,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,
0.2352941185236),BorderSizePixel=0,Font=3,Name="RowButton",Parent={1},Size=UDim2.ne
w(1,0,1,0),Text="Add
Attribute",TextColor3=Color3.new(1,1,1),TextSize=14,TextTransparency=0.100000001490
12,Visible=false,}},
})

local fullNameFrame = Lib.Frame.new()


local label = Lib.Label.new()
label.Parent = fullNameFrame.Gui
label.Position = UDim2.new(0,2,0,0)
label.Size = UDim2.new(1,-4,1,0)
fullNameFrame.Visible = false
fullNameFrame.Parent = window.Gui

Properties.FullNameFrame = fullNameFrame
Properties.FullNameFrameAttach = Lib.AttachTo(fullNameFrame)
end

Properties.Init = function() -- TODO: MAKE BETTER


local guiItems = create({
{1,"Folder",{Name="Items",}},
{2,"Frame",
{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),Bo
rderSizePixel=0,Name="ToolBar",Parent={1},Size=UDim2.new(1,0,0,22),}},
{3,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.1176470592618,0.1176470592618,0.1176470592618),BorderSizePi
xel=0,Name="SearchFrame",Parent={2},Position=UDim2.new(0,3,0,1),Size=UDim2.new(1,-
6,0,18),}},
{4,"TextBox",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ClearTextOnFocus=false
,Font=3,Name="SearchBox",Parent={3},PlaceholderColor3=Color3.new(0.39215689897537,0
.39215689897537,0.39215689897537),PlaceholderText="Search
properties",Position=UDim2.new(0,4,0,0),Size=UDim2.new(1,-
24,0,18),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=0,}},
{5,"UICorner",{CornerRadius=UDim.new(0,2),Parent={3},}},
{6,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.1254902034997
9,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Reset",
Parent={3},Position=UDim2.new(1,-
17,0,1),Size=UDim2.new(0,16,0,16),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,
}},
{7,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
5034718129",ImageColor3=Color3.new(0.39215686917305,0.39215686917305,0.392156869173
05),Parent={6},Size=UDim2.new(0,16,0,16),}},
{8,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.1254902034997
9,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Refresh
",Parent={2},Position=UDim2.new(1,-
20,0,1),Size=UDim2.new(0,18,0,18),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,
Visible=false,}},
{9,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
5642310344",Parent={8},Position=UDim2.new(0,3,0,3),Size=UDim2.new(0,12,0,12),}},
{10,"Frame",
{BackgroundColor3=Color3.new(0.15686275064945,0.15686275064945,0.15686275064945),Bo
rderSizePixel=0,Name="ScrollCorner",Parent={1},Position=UDim2.new(1,-16,1,-
16),Size=UDim2.new(0,16,0,16),Visible=false,}},
{11,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ClipsDescendants=true,
Name="List",Parent={1},Position=UDim2.new(0,0,0,23),Size=UDim2.new(1,0,1,-23),}},
})

-- Vars
categoryOrder = API.CategoryOrder
for category,_ in next,categoryOrder do
if not Properties.CollapsedCategories[category] then
expanded["CAT_"..category] = true
end
end
expanded["Sound.SoundId"] = true

-- Init window
window = Lib.Window.new()
Properties.Window = window
window:SetTitle("Properties")

toolBar = guiItems.ToolBar
propsFrame = guiItems.List

Properties.GuiElems.ToolBar = toolBar
Properties.GuiElems.PropsFrame = propsFrame

Properties.InitEntryStuff()

-- Window events

window.GuiElems.Main:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
if Properties.Window:IsContentVisible() then
Properties.UpdateView()
Properties.Refresh()
end
end)
window.OnActivate:Connect(function()
Properties.UpdateView()
Properties.Update()
Properties.Refresh()
end)
window.OnRestore:Connect(function()
Properties.UpdateView()
Properties.Update()
Properties.Refresh()
end)

-- Init scrollbars
scrollV = Lib.ScrollBar.new()
scrollV.WheelIncrement = 3
scrollV.Gui.Position = UDim2.new(1,-16,0,23)
scrollV:SetScrollFrame(propsFrame)
scrollV.Scrolled:Connect(function()
Properties.Index = scrollV.Index
Properties.Refresh()
end)

scrollH = Lib.ScrollBar.new(true)
scrollH.Increment = 5
scrollH.WheelIncrement = 20
scrollH.Gui.Position = UDim2.new(0,0,1,-16)
scrollH.Scrolled:Connect(function()
Properties.Refresh()
end)

-- Setup Gui
window.GuiElems.Line.Position = UDim2.new(0,0,0,22)
toolBar.Parent = window.GuiElems.Content
propsFrame.Parent = window.GuiElems.Content
guiItems.ScrollCorner.Parent = window.GuiElems.Content
scrollV.Gui.Parent = window.GuiElems.Content
scrollH.Gui.Parent = window.GuiElems.Content
Properties.InitInputBox()
Properties.InitSearch()
end

return Properties
end

return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main}


end,
ScriptViewer = function()
--[[
Script Viewer App Module

A script viewer that is basically a notepad


]]

-- Common Locals
local Main,Lib,Apps,Settings -- Main Containers
local Explorer, Properties, ScriptViewer, Notebook -- Major Apps
local API,RMD,env,service,plr,create,createSimple -- Main Locals

local function initDeps(data)


Main = data.Main
Lib = data.Lib
Apps = data.Apps
Settings = data.Settings

API = data.API
RMD = data.RMD
env = data.env
service = data.service
plr = data.plr
create = data.create
createSimple = data.createSimple
end

local function initAfterMain()


Explorer = Apps.Explorer
Properties = Apps.Properties
ScriptViewer = Apps.ScriptViewer
Notebook = Apps.Notebook
end

local function main()


local ScriptViewer = {}
local window, codeFrame
local PreviousScr = nil

ScriptViewer.ViewScript = function(scr)
local success, source = pcall(env.decompile or function() end, scr)
if not success or not source then source, PreviousScr = "-- DEX -
Source failed to decompile", nil else PreviousScr = scr end
codeFrame:SetText(source)
window:Show()
end

ScriptViewer.Init = function()
window = Lib.Window.new()
window:SetTitle("Script Viewer")
window:Resize(500,400)
ScriptViewer.Window = window

codeFrame = Lib.CodeFrame.new()
codeFrame.Frame.Position = UDim2.new(0,0,0,20)
codeFrame.Frame.Size = UDim2.new(1,0,1,-20)
codeFrame.Frame.Parent = window.GuiElems.Content

-- TODO: REMOVE AND MAKE BETTER


local copy = Instance.new("TextButton",window.GuiElems.Content)
copy.BackgroundTransparency = 1
copy.Size = UDim2.new(0.5,0,0,20)
copy.Text = "Copy to Clipboard"
copy.TextColor3 = Color3.new(1,1,1)

copy.MouseButton1Click:Connect(function()
local source = codeFrame:GetText()
setclipboard(source)
end)

local save = Instance.new("TextButton",window.GuiElems.Content)


save.BackgroundTransparency = 1
save.Position = UDim2.new(0.35,0,0,0)
save.Size = UDim2.new(0.3,0,0,20)
save.Text = "Save to File"
save.TextColor3 = Color3.new(1,1,1)

save.MouseButton1Click:Connect(function()
local source = codeFrame:GetText()
local filename =
"Place_"..game.PlaceId.."_Script_"..os.time()..".txt"

writefile(filename,source)
if movefileas then -- TODO: USE ENV
movefileas(filename,".txt")
end
end)

local dumpbtn = Instance.new("TextButton",window.GuiElems.Content)


dumpbtn.BackgroundTransparency = 1
dumpbtn.Position = UDim2.new(0.7,0,0,0)
dumpbtn.Size = UDim2.new(0.3,0,0,20)
dumpbtn.Text = "Dump Functions"
dumpbtn.TextColor3 = Color3.new(1,1,1)

dumpbtn.MouseButton1Click:Connect(function()
if PreviousScr ~= nil then
pcall(function()
-- thanks King.Kevin#6025 you'll obviously be credited (no
discord tag since that can easily be impersonated)
local getgc = getgc or get_gc_objects
local getupvalues = (debug and debug.getupvalues) or
getupvalues or getupvals
local getconstants = (debug and debug.getconstants) or
getconstants or getconsts
local getinfo = (debug and (debug.getinfo or debug.info)) or
getinfo
local original = ("\n-- // Function Dumper made by King.Kevin\
n-- // Script Path: %s\n\n--[["):format(PreviousScr:GetFullName())
local dump = original
local functions, function_count, data_base = {}, 0, {}
function functions:add_to_dump(str, indentation, new_line)
local new_line = new_line or true
dump = dump .. ("%s%s%s"):format(string.rep(" ",
indentation), tostring(str), new_line and "\n" or "")
end
function functions:get_function_name(func)
local n = getinfo(func).name
return n ~= "" and n or "Unknown Name"
end
function functions:dump_table(input, indent, index)
local indent = indent < 0 and 0 or indent
functions:add_to_dump(("%s [%s]
%s"):format(tostring(index), tostring(typeof(input)), tostring(input)), indent - 1)
local count = 0
for index, value in pairs(input) do
count = count + 1
if type(value) == "function" then
functions:add_to_dump(("%d [function] =
%s"):format(count, functions:get_function_name(value)), indent)
elseif type(value) == "table" then
if not data_base[value] then
data_base[value] = true
functions:add_to_dump(("%d
[table]:"):format(count), indent)
functions:dump_table(value, indent + 1, index)
else
functions:add_to_dump(("%d [table] (Recursive
table detected)"):format(count), indent)
end
else
functions:add_to_dump(("%d [%s] =
%s"):format(count, tostring(typeof(value)), tostring(value)), indent)
end
end
end
function functions:dump_function(input, indent)
functions:add_to_dump(("\nFunction Dump:
%s"):format(functions:get_function_name(input)), indent)
functions:add_to_dump(("\nFunction Upvalues:
%s"):format(functions:get_function_name(input)), indent)
for index, upvalue in pairs(getupvalues(input)) do
if type(upvalue) == "function" then
functions:add_to_dump(("%d [function] =
%s"):format(index, functions:get_function_name(upvalue)), indent + 1)
elseif type(upvalue) == "table" then
if not data_base[upvalue] then
data_base[upvalue] = true
functions:add_to_dump(("%d
[table]:"):format(index), indent + 1)
functions:dump_table(upvalue, indent + 2,
index)
else
functions:add_to_dump(("%d [table] (Recursive
table detected)"):format(index), indent + 1)
end
else
functions:add_to_dump(("%d [%s] =
%s"):format(index, tostring(typeof(upvalue)), tostring(upvalue)), indent + 1)
end
end
functions:add_to_dump(("\nFunction Constants:
%s"):format(functions:get_function_name(input)), indent)
for index, constant in pairs(getconstants(input)) do
if type(constant) == "function" then
functions:add_to_dump(("%d [function] =
%s"):format(index, functions:get_function_name(constant)), indent + 1)
elseif type(constant) == "table" then
if not data_base[constant] then
data_base[constant] = true
functions:add_to_dump(("%d
[table]:"):format(index), indent + 1)
functions:dump_table(constant, indent + 2,
index)
else
functions:add_to_dump(("%d [table] (Recursive
table detected)"):format(index), indent + 1)
end
else
functions:add_to_dump(("%d [%s] =
%s"):format(index, tostring(typeof(constant)), tostring(constant)), indent + 1)
end
end
end
for _, _function in pairs(getgc()) do
if typeof(_function) == "function" and
getfenv(_function).script and getfenv(_function).script == PreviousScr then
functions:dump_function(_function, 0)
functions:add_to_dump("\n" .. ("="):rep(100), 0, false)
end
end
local source = codeFrame:GetText()
if dump ~= original then source = source .. dump .. "]]" end
codeFrame:SetText(source)
end)
end
end)
end
return ScriptViewer
end

return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main}


end,
Lib = function()
--[[
Lib Module

Container for functions and classes


]]

-- Common Locals
local Main,Lib,Apps,Settings -- Main Containers
local Explorer, Properties, ScriptViewer, Notebook -- Major Apps
local API,RMD,env,service,plr,create,createSimple -- Main Locals

local function initDeps(data)


Main = data.Main
Lib = data.Lib
Apps = data.Apps
Settings = data.Settings

API = data.API
RMD = data.RMD
env = data.env
service = data.service
plr = data.plr
create = data.create
createSimple = data.createSimple
end

local function initAfterMain()


Explorer = Apps.Explorer
Properties = Apps.Properties
ScriptViewer = Apps.ScriptViewer
Notebook = Apps.Notebook
end

local function main()


local Lib = {}

local renderStepped = service.RunService.RenderStepped


local signalWait = renderStepped.wait
local PH = newproxy() -- Placeholder, must be replaced in constructor
local SIGNAL = newproxy()

-- Usually for classes that work with a Roblox Object


local function initObj(props,mt)
local type = type
local function copy(t)
local res = {}
for i,v in pairs(t) do
if v == SIGNAL then
res[i] = Lib.Signal.new()
elseif type(v) == "table" then
res[i] = copy(v)
else
res[i] = v
end
end
return res
end

local newObj = copy(props)


return setmetatable(newObj,mt)
end

local function getGuiMT(props,funcs)


return {__index = function(self,ind) if not props[ind] then return
funcs[ind] or self.Gui[ind] end end,
__newindex = function(self,ind,val) if not props[ind] then
self.Gui[ind] = val else rawset(self,ind,val) end end}
end

-- Functions

Lib.FormatLuaString = (function()
local string = string
local gsub = string.gsub
local format = string.format
local char = string.char
local cleanTable = {['"'] = '\\"', ['\\'] = '\\\\'}
for i = 0,31 do
cleanTable[char(i)] = "\\"..format("%03d",i)
end
for i = 127,255 do
cleanTable[char(i)] = "\\"..format("%03d",i)
end

return function(str)
return gsub(str,"[\"\\\0-\31\127-\255]",cleanTable)
end
end)()

Lib.CheckMouseInGui = function(gui)
if gui == nil then return false end
local mouse = Main.Mouse
local guiPosition = gui.AbsolutePosition
local guiSize = gui.AbsoluteSize

return mouse.X >= guiPosition.X and mouse.X < guiPosition.X + guiSize.X


and mouse.Y >= guiPosition.Y and mouse.Y < guiPosition.Y + guiSize.Y
end

Lib.IsShiftDown = function()
return service.UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or
service.UserInputService:IsKeyDown(Enum.KeyCode.RightShift)
end

Lib.IsCtrlDown = function()
return service.UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or
service.UserInputService:IsKeyDown(Enum.KeyCode.RightControl)
end

Lib.CreateArrow = function(size,num,dir)
local max = num
local arrowFrame = createSimple("Frame",{
BackgroundTransparency = 1,
Name = "Arrow",
Size = UDim2.new(0,size,0,size)
})
if dir == "up" then
for i = 1,num do
local newLine = createSimple("Frame",{
BackgroundColor3 =
Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)-(i-
1),0,math.floor(size/2)+i-math.floor(max/2)-1),
Size = UDim2.new(0,i+(i-1),0,1),
Parent = arrowFrame
})
end
return arrowFrame
elseif dir == "down" then
for i = 1,num do
local newLine = createSimple("Frame",{
BackgroundColor3 =
Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)-(i-
1),0,math.floor(size/2)-i+math.floor(max/2)+1),
Size = UDim2.new(0,i+(i-1),0,1),
Parent = arrowFrame
})
end
return arrowFrame
elseif dir == "left" then
for i = 1,num do
local newLine = createSimple("Frame",{
BackgroundColor3 =
Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)+i-
math.floor(max/2)-1,0,math.floor(size/2)-(i-1)),
Size = UDim2.new(0,1,0,i+(i-1)),
Parent = arrowFrame
})
end
return arrowFrame
elseif dir == "right" then
for i = 1,num do
local newLine = createSimple("Frame",{
BackgroundColor3 =
Color3.new(220/255,220/255,220/255),
BorderSizePixel = 0,
Position = UDim2.new(0,math.floor(size/2)-
i+math.floor(max/2)+1,0,math.floor(size/2)-(i-1)),
Size = UDim2.new(0,1,0,i+(i-1)),
Parent = arrowFrame
})
end
return arrowFrame
end
error("r u ok")
end

Lib.ParseXML = (function()
local func = function()
-- Only exists to parse RMD
-- from https://github.com/jonathanpoelen/xmlparser

local string, print, pairs = string, print, pairs

-- http://lua-users.org/wiki/StringTrim
local trim = function(s)
local from = s:match"^%s*()"
return from > #s and "" or s:match(".*%S", from)
end

local gtchar = string.byte('>', 1)


local slashchar = string.byte('/', 1)
local D = string.byte('D', 1)
local E = string.byte('E', 1)

function parse(s, evalEntities)


-- remove comments
s = s:gsub('<!%-%-(.-)%-%->', '')

local entities, tentities = {}

if evalEntities then
local pos = s:find('<[_%w]')
if pos then
s:sub(1, pos):gsub('<!ENTITY%s+([_%w]+)%s+(.)
(.-)%2', function(name, q, entity)
entities[#entities+1] = {name=name,
value=entity}
end)
tentities = createEntityTable(entities)
s = replaceEntities(s:sub(pos), tentities)
end
end

local t, l = {}, {}

local addtext = function(txt)


txt = txt:match'^%s*(.*%S)' or ''
if #txt ~= 0 then
t[#t+1] = {text=txt}
end
end

s:gsub('<([?!/]?)([-:_%w]+)%s*(/?>?)([^<]*)',
function(type, name, closed, txt)
-- open
if #type == 0 then
local a = {}
if #closed == 0 then
local len = 0
for all,aname,_,value,starttxt in
string.gmatch(txt, "(.-([-_%w]+)%s*=%s*(.)(.-)%3%s*(/?>?))") do
len = len + #all
a[aname] = value
if #starttxt ~= 0 then
txt = txt:sub(len+1)
closed = starttxt
break
end
end
end
t[#t+1] = {tag=name, attrs=a, children={}}

if closed:byte(1) ~= slashchar then


l[#l+1] = t
t = t[#t].children
end

addtext(txt)
-- close
elseif '/' == type then
t = l[#l]
l[#l] = nil

addtext(txt)
-- ENTITY
elseif '!' == type then
if E == name:byte(1) then
txt:gsub('([_%w]+)%s+(.)(.-)%2',
function(name, q, entity)
entities[#entities+1] = {name=name,
value=entity}
end, 1)
end
-- elseif '?' == type then
-- print('? ' .. name .. ' // ' .. attrs ..
'$$')
-- elseif '-' == type then
-- print('comment ' .. name .. ' // ' ..
attrs .. '$$')
-- else
-- print('o ' .. #p .. ' // ' .. name ..
' // ' .. attrs .. '$$')
end
end)

return {children=t, entities=entities, tentities=tentities}


end

function parseText(txt)
return parse(txt)
end

function defaultEntityTable()
return { quot='"', apos='\'', lt='<', gt='>', amp='&',
tab='\t', nbsp=' ', }
end

function replaceEntities(s, entities)


return s:gsub('&([^;]+);', entities)
end

function createEntityTable(docEntities, resultEntities)


entities = resultEntities or defaultEntityTable()
for _,e in pairs(docEntities) do
e.value = replaceEntities(e.value, entities)
entities[e.name] = e.value
end
return entities
end

return parseText
end
local newEnv = setmetatable({},{__index = getfenv()})
setfenv(func,newEnv)
return func()
end)()

Lib.FastWait = function(s)
if not s then return signalWait(renderStepped) end
local start = tick()
while tick() - start < s do signalWait(renderStepped) end
end

Lib.ButtonAnim = function(button,data)
local holding = false
local disabled = false
local mode = data and data.Mode or 1
local control = {}

if mode == 2 then
local lerpTo = data.LerpTo or Color3.new(0,0,0)
local delta = data.LerpDelta or 0.2
control.StartColor = data.StartColor or button.BackgroundColor3
control.PressColor = data.PressColor or
control.StartColor:lerp(lerpTo,delta)
control.HoverColor = data.HoverColor or
control.StartColor:lerp(control.PressColor,0.6)
control.OutlineColor = data.OutlineColor
end

button.InputBegan:Connect(function(input)
if disabled then return end
if input.UserInputType == Enum.UserInputType.MouseMovement and
not holding then
if mode == 1 then
button.BackgroundTransparency = 0.4
elseif mode == 2 then
button.BackgroundColor3 = control.HoverColor
end
elseif input.UserInputType == Enum.UserInputType.MouseButton1
then
holding = true
if mode == 1 then
button.BackgroundTransparency = 0
elseif mode == 2 then
button.BackgroundColor3 = control.PressColor
if control.OutlineColor then button.BorderColor3 =
control.PressColor end
end
end
end)
button.InputEnded:Connect(function(input)
if disabled then return end
if input.UserInputType == Enum.UserInputType.MouseMovement and
not holding then
if mode == 1 then
button.BackgroundTransparency = 1
elseif mode == 2 then
button.BackgroundColor3 = control.StartColor
end
elseif input.UserInputType == Enum.UserInputType.MouseButton1
then
holding = false
if mode == 1 then
button.BackgroundTransparency =
Lib.CheckMouseInGui(button) and 0.4 or 1
elseif mode == 2 then
button.BackgroundColor3 = Lib.CheckMouseInGui(button)
and control.HoverColor or control.StartColor
if control.OutlineColor then button.BorderColor3 =
control.OutlineColor end
end
end
end)

control.Disable = function()
disabled = true
holding = false

if mode == 1 then
button.BackgroundTransparency = 1
elseif mode == 2 then
button.BackgroundColor3 = control.StartColor
end
end

control.Enable = function()
disabled = false
end

return control
end

Lib.FindAndRemove = function(t,item)
local pos = table.find(t,item)
if pos then table.remove(t,pos) end
end

Lib.AttachTo = function(obj,data)
local target,posOffX,posOffY,sizeOffX,sizeOffY,resize,con
local disabled = false

local function update()


if not obj or not target then return end

local targetPos = target.AbsolutePosition


local targetSize = target.AbsoluteSize
obj.Position = UDim2.new(0,targetPos.X + posOffX,0,targetPos.Y +
posOffY)
if resize then obj.Size = UDim2.new(0,targetSize.X +
sizeOffX,0,targetSize.Y + sizeOffY) end
end

local function setup(o,data)


obj = o
data = data or {}
target = data.Target
posOffX = data.PosOffX or 0
posOffY = data.PosOffY or 0
sizeOffX = data.SizeOffX or 0
sizeOffY = data.SizeOffY or 0
resize = data.Resize or false

if con then con:Disconnect() con = nil end


if target then
con = target.Changed:Connect(function(prop)
if not disabled and prop == "AbsolutePosition" or
prop == "AbsoluteSize" then
update()
end
end)
end

update()
end
setup(obj,data)

return {
SetData = function(obj,data)
setup(obj,data)
end,
Enable = function()
disabled = false
update()
end,
Disable = function()
disabled = true
end,
Destroy = function()
con:Disconnect()
con = nil
end,
}
end

Lib.ProtectedGuis = {}

Lib.ShowGui = function(gui)
if env.protectgui then
env.protectgui(gui)
end
gui.Parent = Main.GuiHolder
end

Lib.ColorToBytes = function(col)
local round = math.round
return string.format("%d, %d,
%d",round(col.r*255),round(col.g*255),round(col.b*255))
end

Lib.ReadFile = function(filename)
if not env.readfile then return end

local s,contents = pcall(env.readfile,filename)


if s and contents then return contents end
end

Lib.DeferFunc = function(f,...)
signalWait(renderStepped)
return f(...)
end

Lib.LoadCustomAsset = function(filepath)
if not env.getcustomasset or not env.isfile or not env.isfile(filepath)
then return end

return env.getcustomasset(filepath)
end

Lib.FetchCustomAsset = function(url,filepath)
if not env.writefile then return end

local s,data = pcall(game.HttpGet,game,url)


if not s then return end

env.writefile(filepath,data)
return Lib.LoadCustomAsset(filepath)
end

-- Classes

Lib.Signal = (function()
local funcs = {}

local disconnect = function(con)


local pos = table.find(con.Signal.Connections,con)
if pos then table.remove(con.Signal.Connections,pos) end
end

funcs.Connect = function(self,func)
if type(func) ~= "function" then error("Attempt to connect a non-
function") end
local con = {
Signal = self,
Func = func,
Disconnect = disconnect
}
self.Connections[#self.Connections+1] = con
return con
end

funcs.Fire = function(self,...)
for i,v in next,self.Connections do
xpcall(coroutine.wrap(v.Func),function(e) warn(e.."\
n"..debug.traceback()) end,...)
end
end
local mt = {
__index = funcs,
__tostring = function(self)
return "Signal: " .. tostring(#self.Connections) .. "
Connections"
end
}

local function new()


local obj = {}
obj.Connections = {}

return setmetatable(obj,mt)
end

return {new = new}


end)()

Lib.Set = (function()
local funcs = {}

funcs.Add = function(self,obj)
if self.Map[obj] then return end

local list = self.List


list[#list+1] = obj
self.Map[obj] = true
self.Changed:Fire()
end

funcs.AddTable = function(self,t)
local changed
local list,map = self.List,self.Map
for i = 1,#t do
local elem = t[i]
if not map[elem] then
list[#list+1] = elem
map[elem] = true
changed = true
end
end
if changed then self.Changed:Fire() end
end

funcs.Remove = function(self,obj)
if not self.Map[obj] then return end

local list = self.List


local pos = table.find(list,obj)
if pos then table.remove(list,pos) end
self.Map[obj] = nil
self.Changed:Fire()
end

funcs.RemoveTable = function(self,t)
local changed
local list,map = self.List,self.Map
local removeSet = {}
for i = 1,#t do
local elem = t[i]
map[elem] = nil
removeSet[elem] = true
end

for i = #list,1,-1 do
local elem = list[i]
if removeSet[elem] then
table.remove(list,i)
changed = true
end
end
if changed then self.Changed:Fire() end
end

funcs.Set = function(self,obj)
if #self.List == 1 and self.List[1] == obj then return end

self.List = {obj}
self.Map = {[obj] = true}
self.Changed:Fire()
end

funcs.SetTable = function(self,t)
local newList,newMap = {},{}
self.List,self.Map = newList,newMap
table.move(t,1,#t,1,newList)
for i = 1,#t do
newMap[t[i]] = true
end
self.Changed:Fire()
end

funcs.Clear = function(self)
if #self.List == 0 then return end
self.List = {}
self.Map = {}
self.Changed:Fire()
end

local mt = {__index = funcs}

local function new()


local obj = setmetatable({
List = {},
Map = {},
Changed = Lib.Signal.new()
},mt)

return obj
end

return {new = new}


end)()

Lib.IconMap = (function()
local funcs = {}
funcs.GetLabel = function(self)
local label = Instance.new("ImageLabel")
self:SetupLabel(label)
return label
end

funcs.SetupLabel = function(self,obj)
obj.BackgroundTransparency = 1
obj.ImageRectOffset = Vector2.new(0,0)
obj.ImageRectSize = Vector2.new(self.IconSizeX,self.IconSizeY)
obj.ScaleType = Enum.ScaleType.Crop
obj.Size = UDim2.new(0,self.IconSizeX,0,self.IconSizeY)
end

funcs.Display = function(self,obj,index)
obj.Image = self.MapId
if not self.NumX then
obj.ImageRectOffset = Vector2.new(self.IconSizeX*index, 0)
else
obj.ImageRectOffset = Vector2.new(self.IconSizeX*(index %
self.NumX), self.IconSizeY*math.floor(index / self.NumX))
end
end

funcs.DisplayByKey = function(self,obj,key)
if self.IndexDict[key] then
self:Display(obj,self.IndexDict[key])
end
end

funcs.SetDict = function(self,dict)
self.IndexDict = dict
end

local mt = {}
mt.__index = funcs

local function new(mapId,mapSizeX,mapSizeY,iconSizeX,iconSizeY)


local obj = setmetatable({
MapId = mapId,
MapSizeX = mapSizeX,
MapSizeY = mapSizeY,
IconSizeX = iconSizeX,
IconSizeY = iconSizeY,
NumX = mapSizeX/iconSizeX,
IndexDict = {}
},mt)
return obj
end

local function newLinear(mapId,iconSizeX,iconSizeY)


local obj = setmetatable({
MapId = mapId,
IconSizeX = iconSizeX,
IconSizeY = iconSizeY,
IndexDict = {}
},mt)
return obj
end
return {new = new, newLinear = newLinear}
end)()

Lib.ScrollBar = (function()
local funcs = {}
local user = service.UserInputService
local mouse = plr:GetMouse()
local checkMouseInGui = Lib.CheckMouseInGui
local createArrow = Lib.CreateArrow

local function drawThumb(self)


local total = self.TotalSpace
local visible = self.VisibleSpace
local index = self.Index
local scrollThumb = self.GuiElems.ScrollThumb
local scrollThumbFrame = self.GuiElems.ScrollThumbFrame

if not (self:CanScrollUp() or self:CanScrollDown()) then


scrollThumb.Visible = false
else
scrollThumb.Visible = true
end

if self.Horizontal then
scrollThumb.Size = UDim2.new(visible/total,0,1,0)
if scrollThumb.AbsoluteSize.X < 16 then
scrollThumb.Size = UDim2.new(0,16,1,0)
end
local fs = scrollThumbFrame.AbsoluteSize.X
local bs = scrollThumb.AbsoluteSize.X
scrollThumb.Position =
UDim2.new(self:GetScrollPercent()*(fs-bs)/fs,0,0,0)
else
scrollThumb.Size = UDim2.new(1,0,visible/total,0)
if scrollThumb.AbsoluteSize.Y < 16 then
scrollThumb.Size = UDim2.new(1,0,0,16)
end
local fs = scrollThumbFrame.AbsoluteSize.Y
local bs = scrollThumb.AbsoluteSize.Y
scrollThumb.Position =
UDim2.new(0,0,self:GetScrollPercent()*(fs-bs)/fs,0)
end
end

local function createFrame(self)


local newFrame = createSimple("Frame",
{Style=0,Active=true,AnchorPoint=Vector2.new(0,0),BackgroundColor3=Color3.new(0.352
94118523598,0.35294118523598,0.35294118523598),BackgroundTransparency=0,BorderColor
3=Color3.new(0.10588236153126,0.16470588743687,0.20784315466881),BorderSizePixel=0,
ClipsDescendants=false,Draggable=false,Position=UDim2.new(1,-
16,0,0),Rotation=0,Selectable=false,Size=UDim2.new(0,16,1,0),SizeConstraint=0,Visib
le=true,ZIndex=1,Name="ScrollBar",})
local button1 = nil
local button2 = nil

if self.Horizontal then
newFrame.Size = UDim2.new(1,0,0,16)
button1 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Left",
Size = UDim2.new(0,16,0,16),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(16,4,"left").Parent = button1
button2 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Right",
Position = UDim2.new(1,-16,0,0),
Size = UDim2.new(0,16,0,16),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(16,4,"right").Parent = button2
else
newFrame.Size = UDim2.new(0,16,1,0)
button1 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Up",
Size = UDim2.new(0,16,0,16),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(16,4,"up").Parent = button1
button2 = createSimple("ImageButton",{
Parent = newFrame,
Name = "Down",
Position = UDim2.new(0,0,1,-16),
Size = UDim2.new(0,16,0,16),
BackgroundTransparency = 1,
BorderSizePixel = 0,
AutoButtonColor = false
})
createArrow(16,4,"down").Parent = button2
end

local scrollThumbFrame = createSimple("Frame",{


BackgroundTransparency = 1,
Parent = newFrame
})
if self.Horizontal then
scrollThumbFrame.Position = UDim2.new(0,16,0,0)
scrollThumbFrame.Size = UDim2.new(1,-32,1,0)
else
scrollThumbFrame.Position = UDim2.new(0,0,0,16)
scrollThumbFrame.Size = UDim2.new(1,0,1,-32)
end

local scrollThumb = createSimple("Frame",{


BackgroundColor3 = Color3.new(120/255,120/255,120/255),
BorderSizePixel = 0,
Parent = scrollThumbFrame
})
local markerFrame = createSimple("Frame",{
BackgroundTransparency = 1,
Name = "Markers",
Size = UDim2.new(1,0,1,0),
Parent = scrollThumbFrame
})

local buttonPress = false


local thumbPress = false
local thumbFramePress = false

--local thumbColor = Color3.new(120/255,120/255,120/255)


--local thumbSelectColor = Color3.new(140/255,140/255,140/255)
button1.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
and not buttonPress and self:CanScrollUp() then button1.BackgroundTransparency =
0.8 end
if input.UserInputType ~= Enum.UserInputType.MouseButton1
or not self:CanScrollUp() then return end
buttonPress = true
button1.BackgroundTransparency = 0.5
if self:CanScrollUp() then self:ScrollUp()
self.Scrolled:Fire() end
local buttonTick = tick()
local releaseEvent
releaseEvent = user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
if checkMouseInGui(button1) and self:CanScrollUp()
then button1.BackgroundTransparency = 0.8 else button1.BackgroundTransparency = 1
end
buttonPress = false
end)
while buttonPress do
if tick() - buttonTick >= 0.3 and self:CanScrollUp()
then
self:ScrollUp()
self.Scrolled:Fire()
end
wait()
end
end)
button1.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
and not buttonPress then button1.BackgroundTransparency = 1 end
end)
button2.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
and not buttonPress and self:CanScrollDown() then button2.BackgroundTransparency =
0.8 end
if input.UserInputType ~= Enum.UserInputType.MouseButton1
or not self:CanScrollDown() then return end
buttonPress = true
button2.BackgroundTransparency = 0.5
if self:CanScrollDown() then self:ScrollDown()
self.Scrolled:Fire() end
local buttonTick = tick()
local releaseEvent
releaseEvent = user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
if checkMouseInGui(button2) and self:CanScrollDown()
then button2.BackgroundTransparency = 0.8 else button2.BackgroundTransparency = 1
end
buttonPress = false
end)
while buttonPress do
if tick() - buttonTick >= 0.3 and
self:CanScrollDown() then
self:ScrollDown()
self.Scrolled:Fire()
end
wait()
end
end)
button2.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
and not buttonPress then button2.BackgroundTransparency = 1 end
end)

scrollThumb.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
and not thumbPress then scrollThumb.BackgroundTransparency = 0.2
scrollThumb.BackgroundColor3 = self.ThumbSelectColor end
if input.UserInputType ~= Enum.UserInputType.MouseButton1
then return end

local dir = self.Horizontal and "X" or "Y"


local lastThumbPos = nil

buttonPress = false
thumbFramePress = false
thumbPress = true
scrollThumb.BackgroundTransparency = 0
local mouseOffset = mouse[dir] -
scrollThumb.AbsolutePosition[dir]
local mouseStart = mouse[dir]
local releaseEvent
local mouseEvent
releaseEvent = user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
if mouseEvent then mouseEvent:Disconnect() end
if checkMouseInGui(scrollThumb) then
scrollThumb.BackgroundTransparency = 0.2 else scrollThumb.BackgroundTransparency =
0 scrollThumb.BackgroundColor3 = self.ThumbColor end
thumbPress = false
end)
self:Update()

mouseEvent = user.InputChanged:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement and thumbPress and releaseEvent.Connected then
local thumbFrameSize =
scrollThumbFrame.AbsoluteSize[dir]-scrollThumb.AbsoluteSize[dir]
local pos = mouse[dir] -
scrollThumbFrame.AbsolutePosition[dir] - mouseOffset
if pos > thumbFrameSize then
pos = thumbFrameSize
elseif pos < 0 then
pos = 0
end
if lastThumbPos ~= pos then
lastThumbPos = pos

self:ScrollTo(math.floor(0.5+pos/thumbFrameSize*(self.TotalSpace-
self.VisibleSpace)))
end
wait()
end
end)
end)
scrollThumb.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
and not thumbPress then scrollThumb.BackgroundTransparency = 0
scrollThumb.BackgroundColor3 = self.ThumbColor end
end)
scrollThumbFrame.InputBegan:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1
or checkMouseInGui(scrollThumb) then return end

local dir = self.Horizontal and "X" or "Y"


local scrollDir = 0
if mouse[dir] >= scrollThumb.AbsolutePosition[dir] +
scrollThumb.AbsoluteSize[dir] then
scrollDir = 1
end

local function doTick()


local scrollSize = self.VisibleSpace - 1
if scrollDir == 0 and mouse[dir] <
scrollThumb.AbsolutePosition[dir] then
self:ScrollTo(self.Index - scrollSize)
elseif scrollDir == 1 and mouse[dir] >=
scrollThumb.AbsolutePosition[dir] + scrollThumb.AbsoluteSize[dir] then
self:ScrollTo(self.Index + scrollSize)
end
end

thumbPress = false
thumbFramePress = true
doTick()
local thumbFrameTick = tick()
local releaseEvent
releaseEvent = user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
thumbFramePress = false
end)
while thumbFramePress do
if tick() - thumbFrameTick >= 0.3 and
checkMouseInGui(scrollThumbFrame) then
doTick()
end
wait()
end
end)

newFrame.MouseWheelForward:Connect(function()
self:ScrollTo(self.Index - self.WheelIncrement)
end)

newFrame.MouseWheelBackward:Connect(function()
self:ScrollTo(self.Index + self.WheelIncrement)
end)

self.GuiElems.ScrollThumb = scrollThumb
self.GuiElems.ScrollThumbFrame = scrollThumbFrame
self.GuiElems.Button1 = button1
self.GuiElems.Button2 = button2
self.GuiElems.MarkerFrame = markerFrame

return newFrame
end

funcs.Update = function(self,nocallback)
local total = self.TotalSpace
local visible = self.VisibleSpace
local index = self.Index
local button1 = self.GuiElems.Button1
local button2 = self.GuiElems.Button2

self.Index = math.clamp(self.Index,0,math.max(0,total-visible))

if self.LastTotalSpace ~= self.TotalSpace then


self.LastTotalSpace = self.TotalSpace
self:UpdateMarkers()
end

if self:CanScrollUp() then
for i,v in pairs(button1.Arrow:GetChildren()) do
v.BackgroundTransparency = 0
end
else
button1.BackgroundTransparency = 1
for i,v in pairs(button1.Arrow:GetChildren()) do
v.BackgroundTransparency = 0.5
end
end
if self:CanScrollDown() then
for i,v in pairs(button2.Arrow:GetChildren()) do
v.BackgroundTransparency = 0
end
else
button2.BackgroundTransparency = 1
for i,v in pairs(button2.Arrow:GetChildren()) do
v.BackgroundTransparency = 0.5
end
end

drawThumb(self)
end
funcs.UpdateMarkers = function(self)
local markerFrame = self.GuiElems.MarkerFrame
markerFrame:ClearAllChildren()

for i,v in pairs(self.Markers) do


if i < self.TotalSpace then
createSimple("Frame",{
BackgroundTransparency = 0,
BackgroundColor3 = v,
BorderSizePixel = 0,
Position = self.Horizontal and
UDim2.new(i/self.TotalSpace,0,1,-6) or UDim2.new(1,-6,i/self.TotalSpace,0),
Size = self.Horizontal and UDim2.new(0,1,0,6)
or UDim2.new(0,6,0,1),
Name = "Marker"..tostring(i),
Parent = markerFrame
})
end
end
end

funcs.AddMarker = function(self,ind,color)
self.Markers[ind] = color or Color3.new(0,0,0)
end
funcs.ScrollTo = function(self,ind,nocallback)
self.Index = ind
self:Update()
if not nocallback then
self.Scrolled:Fire()
end
end
funcs.ScrollUp = function(self)
self.Index = self.Index - self.Increment
self:Update()
end
funcs.ScrollDown = function(self)
self.Index = self.Index + self.Increment
self:Update()
end
funcs.CanScrollUp = function(self)
return self.Index > 0
end
funcs.CanScrollDown = function(self)
return self.Index + self.VisibleSpace < self.TotalSpace
end
funcs.GetScrollPercent = function(self)
return self.Index/(self.TotalSpace-self.VisibleSpace)
end
funcs.SetScrollPercent = function(self,perc)
self.Index = math.floor(perc*(self.TotalSpace-self.VisibleSpace))
self:Update()
end

funcs.Texture = function(self,data)
self.ThumbColor = data.ThumbColor or Color3.new(0,0,0)
self.ThumbSelectColor = data.ThumbSelectColor or
Color3.new(0,0,0)
self.GuiElems.ScrollThumb.BackgroundColor3 = data.ThumbColor or
Color3.new(0,0,0)
self.Gui.BackgroundColor3 = data.FrameColor or Color3.new(0,0,0)
self.GuiElems.Button1.BackgroundColor3 = data.ButtonColor or
Color3.new(0,0,0)
self.GuiElems.Button2.BackgroundColor3 = data.ButtonColor or
Color3.new(0,0,0)
for i,v in pairs(self.GuiElems.Button1.Arrow:GetChildren()) do
v.BackgroundColor3 = data.ArrowColor or Color3.new(0,0,0)
end
for i,v in pairs(self.GuiElems.Button2.Arrow:GetChildren()) do
v.BackgroundColor3 = data.ArrowColor or Color3.new(0,0,0)
end
end

funcs.SetScrollFrame = function(self,frame)
if self.ScrollUpEvent then self.ScrollUpEvent:Disconnect()
self.ScrollUpEvent = nil end
if self.ScrollDownEvent then self.ScrollDownEvent:Disconnect()
self.ScrollDownEvent = nil end
self.ScrollUpEvent = frame.MouseWheelForward:Connect(function()
self:ScrollTo(self.Index - self.WheelIncrement) end)
self.ScrollDownEvent =
frame.MouseWheelBackward:Connect(function() self:ScrollTo(self.Index +
self.WheelIncrement) end)
end

local mt = {}
mt.__index = funcs

local function new(hor)


local obj = setmetatable({
Index = 0,
VisibleSpace = 0,
TotalSpace = 0,
Increment = 1,
WheelIncrement = 1,
Markers = {},
GuiElems = {},
Horizontal = hor,
LastTotalSpace = 0,
Scrolled = Lib.Signal.new()
},mt)
obj.Gui = createFrame(obj)
obj:Texture({
ThumbColor = Color3.fromRGB(60,60,60),
ThumbSelectColor = Color3.fromRGB(75,75,75),
ArrowColor = Color3.new(1,1,1),
FrameColor = Color3.fromRGB(40,40,40),
ButtonColor = Color3.fromRGB(75,75,75)
})
return obj
end

return {new = new}


end)()

Lib.Window = (function()
local funcs = {}
local static = {MinWidth = 200, FreeWidth = 200}
local mouse = plr:GetMouse()
local sidesGui,alignIndicator
local visibleWindows = {}
local leftSide = {Width = 300, Windows = {}, ResizeCons = {}, Hidden =
true}
local rightSide = {Width = 300, Windows = {}, ResizeCons = {}, Hidden =
true}

local displayOrderStart
local sideDisplayOrder
local sideTweenInfo =
TweenInfo.new(0.3,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
local tweens = {}
local isA = game.IsA

local theme = {
MainColor1 = Color3.fromRGB(52,52,52),
MainColor2 = Color3.fromRGB(45,45,45),
Button = Color3.fromRGB(60,60,60)
}

local function stopTweens()


for i = 1,#tweens do
tweens[i]:Cancel()
end
tweens = {}
end

local function resizeHook(self,resizer,dir)


local guiMain = self.GuiElems.Main
resizer.InputBegan:Connect(function(input)
if not self.Dragging and not self.Resizing and
self.Resizable and self.ResizableInternal then
local isH = dir:find("[WE]") and true
local isV = dir:find("[NS]") and true
local signX = dir:find("W",1,true) and -1 or 1
local signY = dir:find("N",1,true) and -1 or 1

if self.Minimized and isV then return end

if input.UserInputType ==
Enum.UserInputType.MouseMovement then
resizer.BackgroundTransparency = 0.5
elseif input.UserInputType ==
Enum.UserInputType.MouseButton1 then
local releaseEvent,mouseEvent

local offX = mouse.X -


resizer.AbsolutePosition.X
local offY = mouse.Y -
resizer.AbsolutePosition.Y

self.Resizing = resizer
resizer.BackgroundTransparency = 1

releaseEvent =
service.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseButton1 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
self.Resizing = false
resizer.BackgroundTransparency = 1
end
end)

mouseEvent =
service.UserInputService.InputChanged:Connect(function(input)
if self.Resizable and
self.ResizableInternal and input.UserInputType == Enum.UserInputType.MouseMovement
then
self:StopTweens()
local deltaX = input.Position.X -
resizer.AbsolutePosition.X - offX
local deltaY = input.Position.Y -
resizer.AbsolutePosition.Y - offY

if guiMain.AbsoluteSize.X +
deltaX*signX < self.MinX then deltaX = signX*(self.MinX - guiMain.AbsoluteSize.X)
end
if guiMain.AbsoluteSize.Y +
deltaY*signY < self.MinY then deltaY = signY*(self.MinY - guiMain.AbsoluteSize.Y)
end
if signY < 0 and
guiMain.AbsolutePosition.Y + deltaY < 0 then deltaY = -guiMain.AbsolutePosition.Y
end

guiMain.Position = guiMain.Position
+ UDim2.new(0,(signX < 0 and deltaX or 0),0,(signY < 0 and deltaY or 0))
self.SizeX = self.SizeX + (isH and
deltaX*signX or 0)
self.SizeY = self.SizeY + (isV and
deltaY*signY or 0)
guiMain.Size =
UDim2.new(0,self.SizeX,0,self.Minimized and 20 or self.SizeY)

--if isH then self.SizeX =


guiMain.AbsoluteSize.X end
--if isV then self.SizeY =
guiMain.AbsoluteSize.Y end
end
end)
end
end
end)

resizer.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
and self.Resizing ~= resizer then
resizer.BackgroundTransparency = 1
end
end)
end

local updateWindows

local function moveToTop(window)


local found = table.find(visibleWindows,window)
if found then
table.remove(visibleWindows,found)
table.insert(visibleWindows,1,window)
updateWindows()
end
end

local function sideHasRoom(side,neededSize)


local maxY = sidesGui.AbsoluteSize.Y - (math.max(0,#side.Windows
- 1) * 4)
local inc = 0
for i,v in pairs(side.Windows) do
inc = inc + (v.MinY or 100)
if inc > maxY - neededSize then return false end
end

return true
end

local function getSideInsertPos(side,curY)


local pos = #side.Windows + 1
local range = {0,sidesGui.AbsoluteSize.Y}

for i,v in pairs(side.Windows) do


local midPos = v.PosY + v.SizeY/2
if curY <= midPos then
pos = i
range[2] = midPos
break
else
range[1] = midPos
end
end

return pos,range
end

local function focusInput(self,obj)


if isA(obj,"GuiButton") then
obj.MouseButton1Down:Connect(function()
moveToTop(self)
end)
elseif isA(obj,"TextBox") then
obj.Focused:Connect(function()
moveToTop(self)
end)
end
end

local createGui = function(self)


local gui = create({
{1,"ScreenGui",{Name="Window",}},
{2,"Frame",
{Active=true,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSize
Pixel=0,Name="Main",Parent={1},Position=UDim2.new(0.40000000596046,0,0.400000005960
46,0),Size=UDim2.new(0,300,0,300),}},
{3,"Frame",
{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Bo
rderSizePixel=0,Name="Content",Parent={2},Position=UDim2.new(0,0,0,20),Size=UDim2.n
ew(1,0,1,-20),ClipsDescendants=true}},
{4,"Frame",
{BackgroundColor3=Color3.fromRGB(33,33,33),BorderSizePixel=0,Name="Line",Parent={3}
,Size=UDim2.new(1,0,0,1),}},
{5,"Frame",
{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),Bo
rderSizePixel=0,Name="TopBar",Parent={2},Size=UDim2.new(1,0,0,20),}},
{6,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={5},Position=UDim2.new(0,5,0,0),Size=UDim2.new(1,-
10,0,20),Text="Window",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=0,}}
,
{7,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.1254902034997
9,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Close",
Parent={5},Position=UDim2.new(1,-
18,0,2),Size=UDim2.new(0,16,0,16),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,
}},
{8,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
5054663650",Parent={7},Position=UDim2.new(0,3,0,3),Size=UDim2.new(0,10,0,10),}},
{9,"UICorner",{CornerRadius=UDim.new(0,4),Parent={7},}},
{10,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.1254902034997
9,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Minimiz
e",Parent={5},Position=UDim2.new(1,-
36,0,2),Size=UDim2.new(0,16,0,16),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,
}},
{11,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
5034768003",Parent={10},Position=UDim2.new(0,3,0,3),Size=UDim2.new(0,10,0,10),}},
{12,"UICorner",{CornerRadius=UDim.new(0,4),Parent={10},}},
{13,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Imag
e="rbxassetid://1427967925",Name="Outlines",Parent={2},Position=UDim2.new(0,-5,0,-
5),ScaleType=1,Size=UDim2.new(1,10,1,10),SliceCenter=Rect.new(6,6,25,25),TileSize=U
Dim2.new(0,20,0,20),}},
{14,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="ResizeControls",
Parent={2},Position=UDim2.new(0,-5,0,-5),Size=UDim2.new(1,10,1,10),}},
{15,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.2745098173618
3,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="North",
Parent={14},Position=UDim2.new(0,5,0,0),Size=UDim2.new(1,-
10,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{16,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.2745098173618
3,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="South",
Parent={14},Position=UDim2.new(0,5,1,-5),Size=UDim2.new(1,-
10,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{17,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.2745098173618
3,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="NorthEa
st",Parent={14},Position=UDim2.new(1,-
5,0,0),Size=UDim2.new(0,5,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{18,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.2745098173618
3,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="East",P
arent={14},Position=UDim2.new(1,-5,0,5),Size=UDim2.new(0,5,1,-
10),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{19,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.2745098173618
3,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="West",P
arent={14},Position=UDim2.new(0,0,0,5),Size=UDim2.new(0,5,1,-
10),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{20,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.2745098173618
3,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="SouthEa
st",Parent={14},Position=UDim2.new(1,-5,1,-
5),Size=UDim2.new(0,5,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{21,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.2745098173618
3,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="NorthWe
st",Parent={14},Size=UDim2.new(0,5,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSi
ze=14,}},
{22,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.2745098173618
3,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="SouthWe
st",Parent={14},Position=UDim2.new(0,0,1,-
5),Size=UDim2.new(0,5,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
})

local guiMain = gui.Main


local guiTopBar = guiMain.TopBar
local guiResizeControls = guiMain.ResizeControls

self.GuiElems.Main = guiMain
self.GuiElems.TopBar = guiMain.TopBar
self.GuiElems.Content = guiMain.Content
self.GuiElems.Line = guiMain.Content.Line
self.GuiElems.Outlines = guiMain.Outlines
self.GuiElems.Title = guiTopBar.Title
self.GuiElems.Close = guiTopBar.Close
self.GuiElems.Minimize = guiTopBar.Minimize
self.GuiElems.ResizeControls = guiResizeControls
self.ContentPane = guiMain.Content

guiTopBar.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
and self.Draggable then
local releaseEvent,mouseEvent

local maxX = sidesGui.AbsoluteSize.X


local initX = guiMain.AbsolutePosition.X
local initY = guiMain.AbsolutePosition.Y
local offX = mouse.X - initX
local offY = mouse.Y - initY

local alignInsertPos,alignInsertSide

guiDragging = true

releaseEvent =
clonerefs(game:GetService("UserInputService")).InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseButton1 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
guiDragging = false
alignIndicator.Parent = nil
if alignInsertSide then
local targetSide = (alignInsertSide
== "left" and leftSide) or (alignInsertSide == "right" and rightSide)

self:AlignTo(targetSide,alignInsertPos)
end
end
end)

mouseEvent =
clonerefs(game:GetService("UserInputService")).InputChanged:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement and self.Draggable and not self.Closed then
if self.Aligned then
if leftSide.Resizing or
rightSide.Resizing then return end
local posX,posY = input.Position.X-
offX,input.Position.Y-offY
local delta = math.sqrt((posX-
initX)^2 + (posY-initY)^2)
if delta >= 5 then
self:SetAligned(false)
end
else
local inputX,inputY =
input.Position.X,input.Position.Y
local posX,posY = inputX-
offX,inputY-offY
if posY < 0 then posY = 0 end
guiMain.Position =
UDim2.new(0,posX,0,posY)

if self.Resizable and
self.Alignable then
if inputX < 25 then
if
sideHasRoom(leftSide,self.MinY or 100) then
local
insertPos,range = getSideInsertPos(leftSide,inputY)

alignIndicator.Indicator.Position = UDim2.new(0,-15,0,range[1])

alignIndicator.Indicator.Size = UDim2.new(0,40,0,range[2]-range[1])

Lib.ShowGui(alignIndicator)
alignInsertPos =
insertPos
alignInsertSide =
"left"
return
end
elseif inputX >= maxX - 25
then
if
sideHasRoom(rightSide,self.MinY or 100) then
local
insertPos,range = getSideInsertPos(rightSide,inputY)
alignIndicator.Indicator.Position = UDim2.new(0,maxX-25,0,range[1])

alignIndicator.Indicator.Size = UDim2.new(0,40,0,range[2]-range[1])

Lib.ShowGui(alignIndicator)
alignInsertPos =
insertPos
alignInsertSide =
"right"
return
end
end
end
alignIndicator.Parent = nil
alignInsertPos = nil
alignInsertSide = nil
end
end
end)
end
end)

guiTopBar.Close.MouseButton1Click:Connect(function()
if self.Closed then return end
self:Close()
end)

guiTopBar.Minimize.MouseButton1Click:Connect(function()
if self.Closed then return end
if self.Aligned then
self:SetAligned(false)
else
self:SetMinimized()
end
end)

guiTopBar.Minimize.MouseButton2Click:Connect(function()
if self.Closed then return end
if not self.Aligned then
self:SetMinimized(nil,2)
guiTopBar.Minimize.BackgroundTransparency = 1
end
end)

guiMain.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
and not self.Aligned and not self.Closed then
moveToTop(self)
end
end)

guiMain:GetPropertyChangedSignal("AbsolutePosition"):Connect(function()
local absPos = guiMain.AbsolutePosition
self.PosX = absPos.X
self.PosY = absPos.Y
end)
resizeHook(self,guiResizeControls.North,"N")
resizeHook(self,guiResizeControls.NorthEast,"NE")
resizeHook(self,guiResizeControls.East,"E")
resizeHook(self,guiResizeControls.SouthEast,"SE")
resizeHook(self,guiResizeControls.South,"S")
resizeHook(self,guiResizeControls.SouthWest,"SW")
resizeHook(self,guiResizeControls.West,"W")
resizeHook(self,guiResizeControls.NorthWest,"NW")

guiMain.Size = UDim2.new(0,self.SizeX,0,self.SizeY)

gui.DescendantAdded:Connect(function(obj) focusInput(self,obj)
end)
local descs = gui:GetDescendants()
for i = 1,#descs do
focusInput(self,descs[i])
end

self.MinimizeAnim = Lib.ButtonAnim(guiTopBar.Minimize)
self.CloseAnim = Lib.ButtonAnim(guiTopBar.Close)

return gui
end

local function updateSideFrames(noTween)


stopTweens()
leftSide.Frame.Size = UDim2.new(0,leftSide.Width,1,0)
rightSide.Frame.Size = UDim2.new(0,rightSide.Width,1,0)
leftSide.Frame.Resizer.Position = UDim2.new(0,leftSide.Width,0,0)
rightSide.Frame.Resizer.Position = UDim2.new(0,-5,0,0)

--leftSide.Frame.Visible = (#leftSide.Windows > 0)


--rightSide.Frame.Visible = (#rightSide.Windows > 0)

--[[if #leftSide.Windows > 0 and leftSide.Frame.Position ==


UDim2.new(0,-leftSide.Width-5,0,0) then

leftSide.Frame:TweenPosition(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.Easin
gStyle.Quad,0.3,true)
elseif #leftSide.Windows == 0 and leftSide.Frame.Position ==
UDim2.new(0,0,0,0) then
leftSide.Frame:TweenPosition(UDim2.new(0,-leftSide.Width-
5,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)
end
local rightTweenPos = (#rightSide.Windows == 0 and
UDim2.new(1,5,0,0) or UDim2.new(1,-rightSide.Width,0,0))

rightSide.Frame:TweenPosition(rightTweenPos,Enum.EasingDirection.Out,Enum.EasingSty
le.Quad,0.3,true)]]
local leftHidden = #leftSide.Windows == 0 or leftSide.Hidden
local rightHidden = #rightSide.Windows == 0 or rightSide.Hidden
local leftPos = (leftHidden and UDim2.new(0,-leftSide.Width-
10,0,0) or UDim2.new(0,0,0,0))
local rightPos = (rightHidden and UDim2.new(1,10,0,0) or
UDim2.new(1,-rightSide.Width,0,0))

sidesGui.LeftToggle.Text = leftHidden and ">" or "<"


sidesGui.RightToggle.Text = rightHidden and "<" or ">"

if not noTween then


local function insertTween(...)
local tween = service.TweenService:Create(...)
tweens[#tweens+1] = tween
tween:Play()
end
insertTween(leftSide.Frame,sideTweenInfo,{Position =
leftPos})
insertTween(rightSide.Frame,sideTweenInfo,{Position =
rightPos})
insertTween(sidesGui.LeftToggle,sideTweenInfo,{Position =
UDim2.new(0,#leftSide.Windows == 0 and -16 or 0,0,-36)})
insertTween(sidesGui.RightToggle,sideTweenInfo,{Position =
UDim2.new(1,#rightSide.Windows == 0 and 0 or -16,0,-36)})
else
leftSide.Frame.Position = leftPos
rightSide.Frame.Position = rightPos
sidesGui.LeftToggle.Position =
UDim2.new(0,#leftSide.Windows == 0 and -16 or 0,0,-36)
sidesGui.RightToggle.Position =
UDim2.new(1,#rightSide.Windows == 0 and 0 or -16,0,-36)
end
end

local function getSideFramePos(side)


local leftHidden = #leftSide.Windows == 0 or leftSide.Hidden
local rightHidden = #rightSide.Windows == 0 or rightSide.Hidden
if side == leftSide then
return (leftHidden and UDim2.new(0,-leftSide.Width-10,0,0)
or UDim2.new(0,0,0,0))
else
return (rightHidden and UDim2.new(1,10,0,0) or
UDim2.new(1,-rightSide.Width,0,0))
end
end

local function sideResized(side)


local currentPos = 0
local sideFramePos = getSideFramePos(side)
for i,v in pairs(side.Windows) do
v.SizeX = side.Width
v.GuiElems.Main.Size = UDim2.new(0,side.Width,0,v.SizeY)
v.GuiElems.Main.Position =
UDim2.new(sideFramePos.X.Scale,sideFramePos.X.Offset,0,currentPos)
currentPos = currentPos + v.SizeY+4
end
end

local function sideResizerHook(resizer,dir,side,pos)


local mouse = Main.Mouse
local windows = side.Windows

resizer.InputBegan:Connect(function(input)
if not side.Resizing then
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
resizer.BackgroundColor3 = theme.MainColor2
elseif input.UserInputType ==
Enum.UserInputType.MouseButton1 then
local releaseEvent,mouseEvent

local offX = mouse.X -


resizer.AbsolutePosition.X
local offY = mouse.Y -
resizer.AbsolutePosition.Y

side.Resizing = resizer
resizer.BackgroundColor3 = theme.MainColor2

releaseEvent =
service.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseButton1 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
side.Resizing = false
resizer.BackgroundColor3 =
theme.Button
end
end)

mouseEvent =
service.UserInputService.InputChanged:Connect(function(input)
if not resizer.Parent then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
side.Resizing = false
return
end
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
if dir == "V" then
local delta =
input.Position.Y - resizer.AbsolutePosition.Y - offY

if delta > 0 then


local neededSize = delta
for i = pos+1,#windows
do
local window =
windows[i]
local newSize =
math.max(window.SizeY-neededSize,(window.MinY or 100))
neededSize =
neededSize - (window.SizeY - newSize)
window.SizeY =
newSize
end
windows[pos].SizeY =
windows[pos].SizeY + math.max(0,delta-neededSize)
else
local neededSize = -
delta
for i = pos,1,-1 do
local window =
windows[i]
local newSize =
math.max(window.SizeY-neededSize,(window.MinY or 100))
neededSize =
neededSize - (window.SizeY - newSize)
window.SizeY =
newSize
end
windows[pos+1].SizeY =
windows[pos+1].SizeY + math.max(0,-delta-neededSize)
end

updateSideFrames()
sideResized(side)
elseif dir == "H" then
local maxWidth =
math.max(300,sidesGui.AbsoluteSize.X-static.FreeWidth)
local otherSide = (side ==
leftSide and rightSide or leftSide)
local delta =
input.Position.X - resizer.AbsolutePosition.X - offX
delta = (side == leftSide and
delta or -delta)

local proposedSize =
math.max(static.MinWidth,side.Width + delta)
if proposedSize +
otherSide.Width <= maxWidth then
side.Width =
proposedSize
else
local newOtherSize =
maxWidth - proposedSize
if newOtherSize >=
static.MinWidth then
side.Width =
proposedSize
otherSide.Width =
newOtherSize
else
side.Width =
maxWidth - static.MinWidth
otherSide.Width =
static.MinWidth
end
end

updateSideFrames(true)
sideResized(side)
sideResized(otherSide)
end
end
end)
end
end
end)

resizer.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
and side.Resizing ~= resizer then
resizer.BackgroundColor3 = theme.Button
end
end)
end

local function renderSide(side,noTween) -- TODO: Use existing resizers


local currentPos = 0
local sideFramePos = getSideFramePos(side)
local template = side.WindowResizer:Clone()
for i,v in pairs(side.ResizeCons) do v:Disconnect() end
for i,v in pairs(side.Frame:GetChildren()) do if v.Name ==
"WindowResizer" then v:Destroy() end end
side.ResizeCons = {}
side.Resizing = nil

for i,v in pairs(side.Windows) do


v.SidePos = i
local isEnd = i == #side.Windows
local size = UDim2.new(0,side.Width,0,v.SizeY)
local pos =
UDim2.new(sideFramePos.X.Scale,sideFramePos.X.Offset,0,currentPos)
Lib.ShowGui(v.Gui)
--
v.GuiElems.Main:TweenSizeAndPosition(size,pos,Enum.EasingDirection.Out,Enum.EasingS
tyle.Quad,0.3,true)
if noTween then
v.GuiElems.Main.Size = size
v.GuiElems.Main.Position = pos
else
local tween =
service.TweenService:Create(v.GuiElems.Main,sideTweenInfo,{Size = size, Position =
pos})
tweens[#tweens+1] = tween
tween:Play()
end
currentPos = currentPos + v.SizeY+4

if not isEnd then


local newTemplate = template:Clone()
newTemplate.Position = UDim2.new(1,-
side.Width,0,currentPos-4)
side.ResizeCons[#side.ResizeCons+1] =
v.Gui.Main:GetPropertyChangedSignal("Size"):Connect(function()
newTemplate.Position = UDim2.new(1,-
side.Width,0, v.GuiElems.Main.Position.Y.Offset + v.GuiElems.Main.Size.Y.Offset)
end)
side.ResizeCons[#side.ResizeCons+1] =
v.Gui.Main:GetPropertyChangedSignal("Position"):Connect(function()
newTemplate.Position = UDim2.new(1,-
side.Width,0, v.GuiElems.Main.Position.Y.Offset + v.GuiElems.Main.Size.Y.Offset)
end)
sideResizerHook(newTemplate,"V",side,i)
newTemplate.Parent = side.Frame
end
end

--side.Frame.Back.Position = UDim2.new(0,0,0,0)
--side.Frame.Back.Size = UDim2.new(0,side.Width,1,0)
end
local function updateSide(side,noTween)
local oldHeight = 0
local currentPos = 0
local neededSize = 0
local windows = side.Windows
local height = sidesGui.AbsoluteSize.Y - (math.max(0,#windows -
1) * 4)

for i,v in pairs(windows) do oldHeight = oldHeight + v.SizeY end


for i,v in pairs(windows) do
if i == #windows then
v.SizeY = height-currentPos
neededSize = math.max(0,(v.MinY or 100)-v.SizeY)
else
v.SizeY =
math.max(math.floor(v.SizeY/oldHeight*height),v.MinY or 100)
end
currentPos = currentPos + v.SizeY
end

if neededSize > 0 then


for i = #windows-1,1,-1 do
local window = windows[i]
local newSize = math.max(window.SizeY-neededSize,
(window.MinY or 100))
neededSize = neededSize - (window.SizeY - newSize)
window.SizeY = newSize
end
local lastWindow = windows[#windows]
lastWindow.SizeY = (lastWindow.MinY or 100)-neededSize
end
renderSide(side,noTween)
end

updateWindows = function(noTween)
updateSideFrames(noTween)
updateSide(leftSide,noTween)
updateSide(rightSide,noTween)
local count = 0
for i = #visibleWindows,1,-1 do
visibleWindows[i].Gui.DisplayOrder = displayOrderStart +
count
Lib.ShowGui(visibleWindows[i].Gui)
count = count + 1
end

--[[local leftTweenPos = (#leftSide.Windows == 0 and


UDim2.new(0,-leftSide.Width-5,0,0) or UDim2.new(0,0,0,0))

leftSide.Frame:TweenPosition(leftTweenPos,Enum.EasingDirection.Out,Enum.EasingStyle
.Quad,0.3,true)
local rightTweenPos = (#rightSide.Windows == 0 and
UDim2.new(1,5,0,0) or UDim2.new(1,-rightSide.Width,0,0))

rightSide.Frame:TweenPosition(rightTweenPos,Enum.EasingDirection.Out,Enum.EasingSty
le.Quad,0.3,true)]]
end

funcs.SetMinimized = function(self,set,mode)
local oldVal = self.Minimized
local newVal
if set == nil then newVal = not self.Minimized else newVal = set
end
self.Minimized = newVal
if not mode then mode = 1 end

local resizeControls = self.GuiElems.ResizeControls


local minimizeControls =
{"North","NorthEast","NorthWest","South","SouthEast","SouthWest"}
for i = 1,#minimizeControls do
local control =
resizeControls:FindFirstChild(minimizeControls[i])
if control then control.Visible = not newVal end
end

if mode == 1 or mode == 2 then


self:StopTweens()
if mode == 1 then

self.GuiElems.Main:TweenSize(UDim2.new(0,self.SizeX,0,newVal and 20 or
self.SizeY),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.25,true)
else
local maxY = sidesGui.AbsoluteSize.Y
local newPos = UDim2.new(0,self.PosX,0,newVal and
math.min(maxY-20,self.PosY + self.SizeY - 20) or math.max(0,self.PosY - self.SizeY
+ 20))

self.GuiElems.Main:TweenPosition(newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Q
uart,0.25,true)

self.GuiElems.Main:TweenSize(UDim2.new(0,self.SizeX,0,newVal and 20 or
self.SizeY),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.25,true)
end
self.GuiElems.Minimize.ImageLabel.Image = newVal and
"rbxassetid://5060023708" or "rbxassetid://5034768003"
end

if oldVal ~= newVal then


if newVal then
self.OnMinimize:Fire()
else
self.OnRestore:Fire()
end
end
end

funcs.Resize = function(self,sizeX,sizeY)
self.SizeX = sizeX or self.SizeX
self.SizeY = sizeY or self.SizeY
self.GuiElems.Main.Size = UDim2.new(0,self.SizeX,0,self.SizeY)
end

funcs.SetSize = funcs.Resize
funcs.SetTitle = function(self,title)
self.GuiElems.Title.Text = title
end

funcs.SetResizable = function(self,val)
self.Resizable = val
self.GuiElems.ResizeControls.Visible = self.Resizable and
self.ResizableInternal
end

funcs.SetResizableInternal = function(self,val)
self.ResizableInternal = val
self.GuiElems.ResizeControls.Visible = self.Resizable and
self.ResizableInternal
end

funcs.SetAligned = function(self,val)
self.Aligned = val
self:SetResizableInternal(not val)
self.GuiElems.Main.Active = not val
self.GuiElems.Main.Outlines.Visible = not val
if not val then
for i,v in pairs(leftSide.Windows) do if v == self then
table.remove(leftSide.Windows,i) break end end
for i,v in pairs(rightSide.Windows) do if v == self then
table.remove(rightSide.Windows,i) break end end
if not table.find(visibleWindows,self) then
table.insert(visibleWindows,1,self) end
self.GuiElems.Minimize.ImageLabel.Image =
"rbxassetid://5034768003"
self.Side = nil
updateWindows()
else
self:SetMinimized(false,3)
for i,v in pairs(visibleWindows) do if v == self then
table.remove(visibleWindows,i) break end end
self.GuiElems.Minimize.ImageLabel.Image =
"rbxassetid://5448127505"
end
end

funcs.Add = function(self,obj,name)
if type(obj) == "table" and obj.Gui and obj.Gui:IsA("GuiObject")
then
obj.Gui.Parent = self.ContentPane
else
obj.Parent = self.ContentPane
end
if name then self.Elements[name] = obj end
end

funcs.GetElement = function(self,obj,name)
return self.Elements[name]
end

funcs.AlignTo = function(self,side,pos,size,silent)
if table.find(side.Windows,self) or self.Closed then return end
size = size or self.SizeY
if size > 0 and size <= 1 then
local totalSideHeight = 0
for i,v in pairs(side.Windows) do totalSideHeight =
totalSideHeight + v.SizeY end
self.SizeY = (totalSideHeight > 0 and totalSideHeight *
size * 2) or size
else
self.SizeY = (size > 0 and size or 100)
end

self:SetAligned(true)
self.Side = side
self.SizeX = side.Width
self.Gui.DisplayOrder = sideDisplayOrder + 1
for i,v in pairs(side.Windows) do v.Gui.DisplayOrder =
sideDisplayOrder end
pos = math.min(#side.Windows+1, pos or 1)
self.SidePos = pos
table.insert(side.Windows, pos, self)

if not silent then


side.Hidden = false
end
-- updateWindows(silent)
end

funcs.Close = function(self)
self.Closed = true
self:SetResizableInternal(false)

Lib.FindAndRemove(leftSide.Windows,self)
Lib.FindAndRemove(rightSide.Windows,self)
Lib.FindAndRemove(visibleWindows,self)

self.MinimizeAnim.Disable()
self.CloseAnim.Disable()
self.ClosedSide = self.Side
self.Side = nil
self.OnDeactivate:Fire()

if not self.Aligned then


self:StopTweens()
local ti =
TweenInfo.new(0.2,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)

local closeTime = tick()


self.LastClose = closeTime

self:DoTween(self.GuiElems.Main,ti,{Size =
UDim2.new(0,self.SizeX,0,20)})
self:DoTween(self.GuiElems.Title,ti,{TextTransparency = 1})
self:DoTween(self.GuiElems.Minimize.ImageLabel,ti,
{ImageTransparency = 1})
self:DoTween(self.GuiElems.Close.ImageLabel,ti,
{ImageTransparency = 1})
Lib.FastWait(0.2)
if closeTime ~= self.LastClose then return end
self:DoTween(self.GuiElems.TopBar,ti,
{BackgroundTransparency = 1})
self:DoTween(self.GuiElems.Outlines,ti,{ImageTransparency =
1})
Lib.FastWait(0.2)
if closeTime ~= self.LastClose then return end
end

self.Aligned = false
self.Gui.Parent = nil
updateWindows(true)
end

funcs.Hide = funcs.Close

funcs.IsVisible = function(self)
return not self.Closed and ((self.Side and not self.Side.Hidden)
or not self.Side)
end

funcs.IsContentVisible = function(self)
return self:IsVisible() and not self.Minimized
end

funcs.Focus = function(self)
moveToTop(self)
end

funcs.MoveInBoundary = function(self)
local posX,posY = self.PosX,self.PosY
local maxX,maxY = sidesGui.AbsoluteSize.X,sidesGui.AbsoluteSize.Y
posX = math.min(posX,maxX-self.SizeX)
posY = math.min(posY,maxY-20)
self.GuiElems.Main.Position = UDim2.new(0,posX,0,posY)
end

funcs.DoTween = function(self,...)
local tween = service.TweenService:Create(...)
self.Tweens[#self.Tweens+1] = tween
tween:Play()
end

funcs.StopTweens = function(self)
for i,v in pairs(self.Tweens) do
v:Cancel()
end
self.Tweens = {}
end

funcs.Show = function(self,data)
return static.ShowWindow(self,data)
end

funcs.ShowAndFocus = function(self,data)
static.ShowWindow(self,data)
service.RunService.RenderStepped:wait()
self:Focus()
end
static.ShowWindow = function(window,data)
data = data or {}
local align = data.Align
local pos = data.Pos
local size = data.Size
local targetSide = (align == "left" and leftSide) or (align ==
"right" and rightSide)

if not window.Closed then


if not window.Aligned then
window:SetMinimized(false)
elseif window.Side and not data.Silent then
static.SetSideVisible(window.Side,true)
end
return
end

window.Closed = false
window.LastClose = tick()
window.GuiElems.Title.TextTransparency = 0
window.GuiElems.Minimize.ImageLabel.ImageTransparency = 0
window.GuiElems.Close.ImageLabel.ImageTransparency = 0
window.GuiElems.TopBar.BackgroundTransparency = 0
window.GuiElems.Outlines.ImageTransparency = 0
window.GuiElems.Minimize.ImageLabel.Image =
"rbxassetid://5034768003"
window.GuiElems.Main.Active = true
window.GuiElems.Main.Outlines.Visible = true
window:SetMinimized(false,3)
window:SetResizableInternal(true)
window.MinimizeAnim.Enable()
window.CloseAnim.Enable()

if align then
window:AlignTo(targetSide,pos,size,data.Silent)
else
if align == nil and window.ClosedSide then -- Regular open

window:AlignTo(window.ClosedSide,window.SidePos,size,true)
static.SetSideVisible(window.ClosedSide,true)
else
if table.find(visibleWindows,window) then return end

-- TODO: make better


window.GuiElems.Main.Size =
UDim2.new(0,window.SizeX,0,20)
local ti =
TweenInfo.new(0.2,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
window:StopTweens()
window:DoTween(window.GuiElems.Main,ti,{Size =
UDim2.new(0,window.SizeX,0,window.SizeY)})

window.SizeY = size or window.SizeY


table.insert(visibleWindows,1,window)
updateWindows()
end
end

window.ClosedSide = nil
window.OnActivate:Fire()
end

static.ToggleSide = function(name)
local side = (name == "left" and leftSide or rightSide)
side.Hidden = not side.Hidden
for i,v in pairs(side.Windows) do
if side.Hidden then
v.OnDeactivate:Fire()
else
v.OnActivate:Fire()
end
end
updateWindows()
end

static.SetSideVisible = function(s,vis)
local side = (type(s) == "table" and s) or (s == "left" and
leftSide or rightSide)
side.Hidden = not vis
for i,v in pairs(side.Windows) do
if side.Hidden then
v.OnDeactivate:Fire()
else
v.OnActivate:Fire()
end
end
updateWindows()
end

static.Init = function()
displayOrderStart = Main.DisplayOrders.Window
sideDisplayOrder = Main.DisplayOrders.SideWindow

sidesGui = Instance.new("ScreenGui")
local leftFrame = create({
{1,"Frame",
{Active=true,Name="LeftSide",BackgroundColor3=Color3.new(0.17647059261799,0.1764705
9261799,0.17647059261799),BorderSizePixel=0,}},
{2,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2549019753933,0.2549019753933,
0.2549019753933),BorderSizePixel=0,Font=3,Name="Resizer",Parent={1},Size=UDim2.new(
0,5,1,0),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{3,"Frame",
{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),Bo
rderSizePixel=0,Name="Line",Parent={2},Position=UDim2.new(0,0,0,0),Size=UDim2.new(0
,1,1,0),}},
{4,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2549019753933,0.2549019753933,
0.2549019753933),BorderSizePixel=0,Font=3,Name="WindowResizer",Parent={1},Position=
UDim2.new(1,-
300,0,0),Size=UDim2.new(1,0,0,4),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}
},
{5,"Frame",
{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),Bo
rderSizePixel=0,Name="Line",Parent={4},Size=UDim2.new(1,0,0,1),}},
})
leftSide.Frame = leftFrame
leftFrame.Position = UDim2.new(0,-leftSide.Width-10,0,0)
leftSide.WindowResizer = leftFrame.WindowResizer
leftFrame.WindowResizer.Parent = nil
leftFrame.Parent = sidesGui

local rightFrame = create({


{1,"Frame",
{Active=true,Name="RightSide",BackgroundColor3=Color3.new(0.17647059261799,0.176470
59261799,0.17647059261799),BorderSizePixel=0,}},
{2,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2549019753933,0.2549019753933,
0.2549019753933),BorderSizePixel=0,Font=3,Name="Resizer",Parent={1},Size=UDim2.new(
0,5,1,0),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{3,"Frame",
{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),Bo
rderSizePixel=0,Name="Line",Parent={2},Position=UDim2.new(0,4,0,0),Size=UDim2.new(0
,1,1,0),}},
{4,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2549019753933,0.2549019753933,
0.2549019753933),BorderSizePixel=0,Font=3,Name="WindowResizer",Parent={1},Position=
UDim2.new(1,-
300,0,0),Size=UDim2.new(1,0,0,4),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}
},
{5,"Frame",
{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),Bo
rderSizePixel=0,Name="Line",Parent={4},Size=UDim2.new(1,0,0,1),}},
})
rightSide.Frame = rightFrame
rightFrame.Position = UDim2.new(1,10,0,0)
rightSide.WindowResizer = rightFrame.WindowResizer
rightFrame.WindowResizer.Parent = nil
rightFrame.Parent = sidesGui

sideResizerHook(leftFrame.Resizer,"H",leftSide)
sideResizerHook(rightFrame.Resizer,"H",rightSide)

alignIndicator = Instance.new("ScreenGui")
alignIndicator.DisplayOrder = Main.DisplayOrders.Core
local indicator = Instance.new("Frame",alignIndicator)
indicator.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
indicator.BorderSizePixel = 0
indicator.BackgroundTransparency = 0.8
indicator.Name = "Indicator"
local corner = Instance.new("UICorner",indicator)
corner.CornerRadius = UDim.new(0,10)

local leftToggle = create({{1,"TextButton",


{AutoButtonColor=false,BackgroundColor3=Color3.new(0.20392157137394,0.2039215713739
4,0.20392157137394),BorderColor3=Color3.new(0.14117647707462,0.14117647707462,0.141
17647707462),BorderMode=2,Font=10,Name="LeftToggle",Position=UDim2.new(0,0,0,-
36),Size=UDim2.new(0,16,0,36),Text="<",TextColor3=Color3.new(1,1,1),TextSize=14,}}}
)
local rightToggle = leftToggle:Clone()
rightToggle.Name = "RightToggle"
rightToggle.Position = UDim2.new(1,-16,0,-36)
Lib.ButtonAnim(leftToggle,{Mode = 2,PressColor =
Color3.fromRGB(32,32,32)})
Lib.ButtonAnim(rightToggle,{Mode = 2,PressColor =
Color3.fromRGB(32,32,32)})
leftToggle.MouseButton1Click:Connect(function()
static.ToggleSide("left")
end)

rightToggle.MouseButton1Click:Connect(function()
static.ToggleSide("right")
end)

leftToggle.Parent = sidesGui
rightToggle.Parent = sidesGui

sidesGui:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
local maxWidth = math.max(300,sidesGui.AbsoluteSize.X-
static.FreeWidth)
leftSide.Width =
math.max(static.MinWidth,math.min(leftSide.Width,maxWidth-rightSide.Width))
rightSide.Width =
math.max(static.MinWidth,math.min(rightSide.Width,maxWidth-leftSide.Width))
for i = 1,#visibleWindows do
visibleWindows[i]:MoveInBoundary()
end
updateWindows(true)
end)

sidesGui.DisplayOrder = sideDisplayOrder - 1
Lib.ShowGui(sidesGui)
updateSideFrames()
end

local mt = {__index = funcs}


static.new = function()
local obj = setmetatable({
Minimized = false,
Dragging = false,
Resizing = false,
Aligned = false,
Draggable = true,
Resizable = true,
ResizableInternal = true,
Alignable = true,
Closed = true,
SizeX = 300,
SizeY = 300,
MinX = 200,
MinY = 200,
PosX = 0,
PosY = 0,
GuiElems = {},
Tweens = {},
Elements = {},
OnActivate = Lib.Signal.new(),
OnDeactivate = Lib.Signal.new(),
OnMinimize = Lib.Signal.new(),
OnRestore = Lib.Signal.new()
},mt)
obj.Gui = createGui(obj)
return obj
end
return static
end)()

Lib.ContextMenu = (function()
local funcs = {}
local mouse

local function createGui(self)


local contextGui = create({
{1,"ScreenGui",
{DisplayOrder=1000000,Name="Context",ZIndexBehavior=1,}},
{2,"Frame",
{Active=true,BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.141176
47707462),BorderColor3=Color3.new(0.14117647707462,0.14117647707462,0.1411764770746
2),Name="Main",Parent={1},Position=UDim2.new(0.5,-100,0.5,-
150),Size=UDim2.new(0,200,0,100),}},
{3,"UICorner",{CornerRadius=UDim.new(0,4),Parent={2},}},
{4,"Frame",
{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Na
me="Container",Parent={2},Position=UDim2.new(0,1,0,1),Size=UDim2.new(1,-2,1,-2),}},
{5,"UICorner",{CornerRadius=UDim.new(0,4),Parent={4},}},
{6,"ScrollingFrame",
{Active=true,BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.203921
57137394),BackgroundTransparency=1,BorderSizePixel=0,CanvasSize=UDim2.new(0,0,0,0),
Name="List",Parent={4},Position=UDim2.new(0,2,0,2),ScrollBarImageColor3=Color3.new(
0,0,0),ScrollBarThickness=4,Size=UDim2.new(1,-4,1,-4),VerticalScrollBarInset=1,}},
{7,"UIListLayout",{Parent={6},SortOrder=2,}},
{8,"Frame",
{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),Bo
rderSizePixel=0,Name="SearchFrame",Parent={4},Size=UDim2.new(1,0,0,24),Visible=fals
e,}},
{9,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.1176470592618,0.1176470592618,0.1176470592618),BorderSizePi
xel=0,Name="SearchContainer",Parent={8},Position=UDim2.new(0,3,0,3),Size=UDim2.new(
1,-6,0,18),}},
{10,"TextBox",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="SearchBox
",Parent={9},PlaceholderColor3=Color3.new(0.39215689897537,0.39215689897537,0.39215
689897537),PlaceholderText="Search",Position=UDim2.new(0,4,0,0),Size=UDim2.new(1,-
8,0,18),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=0,}},
{11,"UICorner",{CornerRadius=UDim.new(0,2),Parent={9},}},
{12,"Frame",
{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),Bo
rderSizePixel=0,Name="Line",Parent={8},Position=UDim2.new(0,0,1,0),Size=UDim2.new(1
,0,0,1),}},
{13,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.20392157137394,0.2039215713739
4,0.20392157137394),BackgroundTransparency=1,BorderColor3=Color3.new(0.337254911661
15,0.49019610881805,0.73725491762161),BorderSizePixel=0,Font=3,Name="Entry",Parent=
{1},Size=UDim2.new(1,0,0,22),Text="",TextSize=14,Visible=false,}},
{14,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Font
=3,Name="EntryName",Parent={13},Position=UDim2.new(0,24,0,0),Size=UDim2.new(1,-
24,1,0),Text="Duplicate",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.
86274516582489),TextSize=14,TextXAlignment=0,}},
{15,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Shortcut"
,Parent={13},Position=UDim2.new(0,24,0,0),Size=UDim2.new(1,-
30,1,0),Text="Ctrl+D",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.862
74516582489),TextSize=14,TextXAlignment=1,}},
{16,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ImageRectOffset=Vector
2.new(304,0),ImageRectSize=Vector2.new(16,16),Name="Icon",Parent={13},Position=UDim
2.new(0,2,0,3),ScaleType=4,Size=UDim2.new(0,16,0,16),}},
{17,"UICorner",{CornerRadius=UDim.new(0,4),Parent={13},}},
{18,"Frame",
{BackgroundColor3=Color3.new(0.21568629145622,0.21568629145622,0.21568629145622),Ba
ckgroundTransparency=1,BorderSizePixel=0,Name="Divider",Parent={1},Position=UDim2.n
ew(0,0,0,20),Size=UDim2.new(1,0,0,7),Visible=false,}},
{19,"Frame",
{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),Bo
rderSizePixel=0,Name="Line",Parent={18},Position=UDim2.new(0,0,0.5,0),Size=UDim2.ne
w(1,0,0,1),}},
{20,"TextLabel",
{AnchorPoint=Vector2.new(0,0.5),BackgroundColor3=Color3.new(1,1,1),BackgroundTransp
arency=1,BorderSizePixel=0,Font=3,Name="DividerName",Parent={18},Position=UDim2.new
(0,2,0.5,0),Size=UDim2.new(1,-
4,1,0),Text="Objects",TextColor3=Color3.new(1,1,1),TextSize=14,TextTransparency=0.6
0000002384186,TextXAlignment=0,Visible=false,}},
})
self.GuiElems.Main = contextGui.Main
self.GuiElems.List = contextGui.Main.Container.List
self.GuiElems.Entry = contextGui.Entry
self.GuiElems.Divider = contextGui.Divider
self.GuiElems.SearchFrame = contextGui.Main.Container.SearchFrame
self.GuiElems.SearchBar =
self.GuiElems.SearchFrame.SearchContainer.SearchBox
Lib.ViewportTextBox.convert(self.GuiElems.SearchBar)

self.GuiElems.SearchBar:GetPropertyChangedSignal("Text"):Connect(function()
local lower,find = string.lower,string.find
local searchText = lower(self.GuiElems.SearchBar.Text)
local items = self.Items
local map = self.ItemToEntryMap

if searchText ~= "" then


local results = {}
local count = 1
for i = 1,#items do
local item = items[i]
local entry = map[item]
if entry then
if not item.Divider and
find(lower(item.Name),searchText,1,true) then
results[count] = item
count = count + 1
else
entry.Visible = false
end
end
end
table.sort(results,function(a,b) return a.Name <
b.Name end)
for i = 1,#results do
local entry = map[results[i]]
entry.LayoutOrder = i
entry.Visible = true
end
else
for i = 1,#items do
local entry = map[items[i]]
if entry then entry.LayoutOrder = i
entry.Visible = true end
end
end

local toSize =
self.GuiElems.List.UIListLayout.AbsoluteContentSize.Y + 6
self.GuiElems.List.CanvasSize = UDim2.new(0,0,0,toSize-6)
end)

return contextGui
end

funcs.Add = function(self,item)
local newItem = {
Name = item.Name or "Item",
Icon = item.Icon or "",
Shortcut = item.Shortcut or "",
OnClick = item.OnClick,
OnHover = item.OnHover,
Disabled = item.Disabled or false,
DisabledIcon = item.DisabledIcon or "",
IconMap = item.IconMap,
OnRightClick = item.OnRightClick
}
if self.QueuedDivider then
local text = self.QueuedDividerText and
#self.QueuedDividerText > 0 and self.QueuedDividerText
self:AddDivider(text)
end
self.Items[#self.Items+1] = newItem
self.Updated = nil
end

funcs.AddRegistered = function(self,name,disabled)
if not self.Registered[name] then error(name.." is not
registered") end

if self.QueuedDivider then
local text = self.QueuedDividerText and
#self.QueuedDividerText > 0 and self.QueuedDividerText
self:AddDivider(text)
end
self.Registered[name].Disabled = disabled
self.Items[#self.Items+1] = self.Registered[name]
self.Updated = nil
end

funcs.Register = function(self,name,item)
self.Registered[name] = {
Name = item.Name or "Item",
Icon = item.Icon or "",
Shortcut = item.Shortcut or "",
OnClick = item.OnClick,
OnHover = item.OnHover,
DisabledIcon = item.DisabledIcon or "",
IconMap = item.IconMap,
OnRightClick = item.OnRightClick
}
end

funcs.UnRegister = function(self,name)
self.Registered[name] = nil
end

funcs.AddDivider = function(self,text)
self.QueuedDivider = false
local textWidth = text and
service.TextService:GetTextSize(text,14,Enum.Font.SourceSans,Vector2.new(999999999,
20)).X or nil
table.insert(self.Items,{Divider = true, Text = text, TextSize =
textWidth and textWidth+4})
self.Updated = nil
end

funcs.QueueDivider = function(self,text)
self.QueuedDivider = true
self.QueuedDividerText = text or ""
end

funcs.Clear = function(self)
self.Items = {}
self.Updated = nil
end

funcs.Refresh = function(self)
for i,v in pairs(self.GuiElems.List:GetChildren()) do
if not v:IsA("UIListLayout") then
v:Destroy()
end
end
local map = {}
self.ItemToEntryMap = map

local dividerFrame = self.GuiElems.Divider


local contextList = self.GuiElems.List
local entryFrame = self.GuiElems.Entry
local items = self.Items

for i = 1,#items do
local item = items[i]
if item.Divider then
local newDivider = dividerFrame:Clone()
newDivider.Line.BackgroundColor3 =
self.Theme.DividerColor
if item.Text then
newDivider.Size = UDim2.new(1,0,0,20)
newDivider.Line.Position =
UDim2.new(0,item.TextSize,0.5,0)
newDivider.Line.Size = UDim2.new(1,-
item.TextSize,0,1)
newDivider.DividerName.TextColor3 =
self.Theme.TextColor
newDivider.DividerName.Text = item.Text
newDivider.DividerName.Visible = true
end
newDivider.Visible = true
map[item] = newDivider
newDivider.Parent = contextList
else
local newEntry = entryFrame:Clone()
newEntry.BackgroundColor3 = self.Theme.HighlightColor
newEntry.EntryName.TextColor3 = self.Theme.TextColor
newEntry.EntryName.Text = item.Name
newEntry.Shortcut.Text = item.Shortcut
if item.Disabled then
newEntry.EntryName.TextColor3 =
Color3.new(150/255,150/255,150/255)
newEntry.Shortcut.TextColor3 =
Color3.new(150/255,150/255,150/255)
end

if self.Iconless then
newEntry.EntryName.Position =
UDim2.new(0,2,0,0)
newEntry.EntryName.Size = UDim2.new(1,-4,0,20)
newEntry.Icon.Visible = false
else
local iconIndex = item.Disabled and
item.DisabledIcon or item.Icon
if item.IconMap then
if type(iconIndex) == "number" then

item.IconMap:Display(newEntry.Icon,iconIndex)
elseif type(iconIndex) == "string" then

item.IconMap:DisplayByKey(newEntry.Icon,iconIndex)
end
elseif type(iconIndex) == "string" then
newEntry.Icon.Image = iconIndex
end
end

if not item.Disabled then


if item.OnClick then

newEntry.MouseButton1Click:Connect(function()
item.OnClick(item.Name)
if not item.NoHide then
self:Hide()
end
end)
end

if item.OnRightClick then

newEntry.MouseButton2Click:Connect(function()
item.OnRightClick(item.Name)
if not item.NoHide then
self:Hide()
end
end)
end
end

newEntry.InputBegan:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
newEntry.BackgroundTransparency = 0
end
end)

newEntry.InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
newEntry.BackgroundTransparency = 1
end
end)

newEntry.Visible = true
map[item] = newEntry
newEntry.Parent = contextList
end
end
self.Updated = true
end

funcs.Show = function(self,x,y)
-- Initialize Gui
local elems = self.GuiElems
elems.SearchFrame.Visible = self.SearchEnabled
elems.List.Position = UDim2.new(0,2,0,2 + (self.SearchEnabled and
24 or 0))
elems.List.Size = UDim2.new(1,-4,1,-4 - (self.SearchEnabled and
24 or 0))
if self.SearchEnabled and self.ClearSearchOnShow then
elems.SearchBar.Text = "" end
self.GuiElems.List.CanvasPosition = Vector2.new(0,0)

if not self.Updated then


self:Refresh() -- Create entries
end

-- Vars
local reverseY = false
local x,y = x or mouse.X, y or mouse.Y
local maxX,maxY = mouse.ViewSizeX,mouse.ViewSizeY

-- Position and show


if x + self.Width > maxX then
x = self.ReverseX and x - self.Width or maxX - self.Width
end
elems.Main.Position = UDim2.new(0,x,0,y)
elems.Main.Size = UDim2.new(0,self.Width,0,0)
self.Gui.DisplayOrder = Main.DisplayOrders.Menu
Lib.ShowGui(self.Gui)

-- Size adjustment
local toSize = elems.List.UIListLayout.AbsoluteContentSize.Y + 6
-- Padding
if self.MaxHeight and toSize > self.MaxHeight then
elems.List.CanvasSize = UDim2.new(0,0,0,toSize-6)
toSize = self.MaxHeight
else
elems.List.CanvasSize = UDim2.new(0,0,0,0)
end
if y + toSize > maxY then reverseY = true end

-- Close event
local closable
if self.CloseEvent then self.CloseEvent:Disconnect() end
self.CloseEvent =
service.UserInputService.InputBegan:Connect(function(input)
if not closable or input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end

if not Lib.CheckMouseInGui(elems.Main) then


self.CloseEvent:Disconnect()
self:Hide()
end
end)

-- Resize
if reverseY then
elems.Main.Position = UDim2.new(0,x,0,y-
(self.ReverseYOffset or 0))
local newY = y - toSize - (self.ReverseYOffset or 0)
y = newY >= 0 and newY or 0

elems.Main:TweenSizeAndPosition(UDim2.new(0,self.Width,0,toSize),UDim2.new(0,x,0,y)
,Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.2,true)
else

elems.Main:TweenSize(UDim2.new(0,self.Width,0,toSize),Enum.EasingDirection.Out,Enum
.EasingStyle.Quart,0.2,true)
end

-- Close debounce
Lib.FastWait()
if self.SearchEnabled and self.FocusSearchOnShow then
elems.SearchBar:CaptureFocus() end
closable = true
end

funcs.Hide = function(self)
self.Gui.Parent = nil
end

funcs.ApplyTheme = function(self,data)
local theme = self.Theme
theme.ContentColor = data.ContentColor or Settings.Theme.Menu
theme.OutlineColor = data.OutlineColor or Settings.Theme.Menu
theme.DividerColor = data.DividerColor or Settings.Theme.Outline2
theme.TextColor = data.TextColor or Settings.Theme.Text
theme.HighlightColor = data.HighlightColor or
Settings.Theme.Main1
self.GuiElems.Main.BackgroundColor3 = theme.OutlineColor
self.GuiElems.Main.Container.BackgroundColor3 =
theme.ContentColor
end

local mt = {__index = funcs}


local function new()
if not mouse then mouse = Main.Mouse or
service.Players.LocalPlayer:GetMouse() end

local obj = setmetatable({


Width = 200,
MaxHeight = nil,
Iconless = false,
SearchEnabled = false,
ClearSearchOnShow = true,
FocusSearchOnShow = true,
Updated = false,
QueuedDivider = false,
QueuedDividerText = "",
Items = {},
Registered = {},
GuiElems = {},
Theme = {}
},mt)
obj.Gui = createGui(obj)
obj:ApplyTheme({})
return obj
end

return {new = new}


end)()

Lib.CodeFrame = (function()
local funcs = {}

local typeMap = {
[1] = "String",
[2] = "String",
[3] = "String",
[4] = "Comment",
[5] = "Operator",
[6] = "Number",
[7] = "Keyword",
[8] = "BuiltIn",
[9] = "LocalMethod",
[10] = "LocalProperty",
[11] = "Nil",
[12] = "Bool",
[13] = "Function",
[14] = "Local",
[15] = "Self",
[16] = "FunctionName",
[17] = "Bracket"
}

local specialKeywordsTypes = {
["nil"] = 11,
["true"] = 12,
["false"] = 12,
["function"] = 13,
["local"] = 14,
["self"] = 15
}

local keywords = {
["and"] = true,
["break"] = true,
["do"] = true,
["else"] = true,
["elseif"] = true,
["end"] = true,
["false"] = true,
["for"] = true,
["function"] = true,
["if"] = true,
["in"] = true,
["local"] = true,
["nil"] = true,
["not"] = true,
["or"] = true,
["repeat"] = true,
["return"] = true,
["then"] = true,
["true"] = true,
["until"] = true,
["while"] = true,
["plugin"] = true
}

local builtIns = {
["delay"] = true,
["elapsedTime"] = true,
["require"] = true,
["spawn"] = true,
["tick"] = true,
["time"] = true,
["typeof"] = true,
["UserSettings"] = true,
["wait"] = true,
["warn"] = true,
["game"] = true,
["shared"] = true,
["script"] = true,
["workspace"] = true,
["assert"] = true,
["collectgarbage"] = true,
["error"] = true,
["getfenv"] = true,
["getmetatable"] = true,
["ipairs"] = true,
["loadstring"] = true,
["newproxy"] = true,
["next"] = true,
["pairs"] = true,
["pcall"] = true,
["print"] = true,
["rawequal"] = true,
["rawget"] = true,
["rawset"] = true,
["select"] = true,
["setfenv"] = true,
["setmetatable"] = true,
["tonumber"] = true,
["tostring"] = true,
["type"] = true,
["unpack"] = true,
["xpcall"] = true,
["_G"] = true,
["_VERSION"] = true,
["coroutine"] = true,
["debug"] = true,
["math"] = true,
["os"] = true,
["string"] = true,
["table"] = true,
["bit32"] = true,
["utf8"] = true,
["Axes"] = true,
["BrickColor"] = true,
["CFrame"] = true,
["Color3"] = true,
["ColorSequence"] = true,
["ColorSequenceKeypoint"] = true,
["DockWidgetPluginGuiInfo"] = true,
["Enum"] = true,
["Faces"] = true,
["Instance"] = true,
["NumberRange"] = true,
["NumberSequence"] = true,
["NumberSequenceKeypoint"] = true,
["PathWaypoint"] = true,
["PhysicalProperties"] = true,
["Random"] = true,
["Ray"] = true,
["Rect"] = true,
["Region3"] = true,
["Region3int16"] = true,
["TweenInfo"] = true,
["UDim"] = true,
["UDim2"] = true,
["Vector2"] = true,
["Vector2int16"] = true,
["Vector3"] = true,
["Vector3int16"] = true
}

local builtInInited = false

local richReplace = {
["'"] = "&apos;",
["\""] = "&quot;",
["<"] = "&lt;",
[">"] = "&gt;",
["&"] = "&amp;"
}
local tabSub = "\205"
local tabReplacement = (" %s%s "):format(tabSub,tabSub)

local tabJumps = {
[("[^%s] %s"):format(tabSub,tabSub)] = 0,
[(" %s%s"):format(tabSub,tabSub)] = -1,
[("%s%s "):format(tabSub,tabSub)] = 2,
[("%s [^%s]"):format(tabSub,tabSub)] = 1,
}

local tweenService = service.TweenService


local lineTweens = {}

local function initBuiltIn()


local env = getfenv()
local type = type
local tostring = tostring
for name,_ in next,builtIns do
local envVal = env[name]
if type(envVal) == "table" then
local items = {}
for i,v in next,envVal do
items[i] = true
end
builtIns[name] = items
end
end

local enumEntries = {}
local enums = Enum:GetEnums()
for i = 1,#enums do
enumEntries[tostring(enums[i])] = true
end
builtIns["Enum"] = enumEntries

builtInInited = true
end

local function setupEditBox(obj)


local editBox = obj.GuiElems.EditBox

editBox.Focused:Connect(function()
obj:ConnectEditBoxEvent()
obj.Editing = true
end)

editBox.FocusLost:Connect(function()
obj:DisconnectEditBoxEvent()
obj.Editing = false
end)

editBox:GetPropertyChangedSignal("Text"):Connect(function()
local text = editBox.Text
if #text == 0 or obj.EditBoxCopying then return end
editBox.Text = ""
obj:AppendText(text)
end)
end
local function setupMouseSelection(obj)
local mouse = plr:GetMouse()
local codeFrame = obj.GuiElems.LinesFrame
local lines = obj.Lines

codeFrame.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
then
local fontSizeX,fontSizeY =
math.ceil(obj.FontSize/2),obj.FontSize

local relX = mouse.X - codeFrame.AbsolutePosition.X


local relY = mouse.Y - codeFrame.AbsolutePosition.Y
local selX = math.round(relX / fontSizeX) + obj.ViewX
local selY = math.floor(relY / fontSizeY) + obj.ViewY
local releaseEvent,mouseEvent,scrollEvent
local scrollPowerV,scrollPowerH = 0,0
selY = math.min(#lines-1,selY)
local relativeLine = lines[selY+1] or ""
selX = math.min(#relativeLine, selX +
obj:TabAdjust(selX,selY))

obj.SelectionRange = {{-1,-1},{-1,-1}}
obj:MoveCursor(selX,selY)
obj.FloatCursorX = selX

local function updateSelection()


local relX = mouse.X -
codeFrame.AbsolutePosition.X
local relY = mouse.Y -
codeFrame.AbsolutePosition.Y
local sel2X = math.max(0,math.round(relX /
fontSizeX) + obj.ViewX)
local sel2Y = math.max(0,math.floor(relY /
fontSizeY) + obj.ViewY)

sel2Y = math.min(#lines-1,sel2Y)
local relativeLine = lines[sel2Y+1] or ""
sel2X = math.min(#relativeLine, sel2X +
obj:TabAdjust(sel2X,sel2Y))

if sel2Y < selY or (sel2Y == selY and sel2X <


selX) then
obj.SelectionRange = {{sel2X,sel2Y},
{selX,selY}}
else
obj.SelectionRange = {{selX,selY},
{sel2X,sel2Y}}
end

obj:MoveCursor(sel2X,sel2Y)
obj.FloatCursorX = sel2X
obj:Refresh()
end

releaseEvent =
service.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseButton1 then
releaseEvent:Disconnect()
mouseEvent:Disconnect()
scrollEvent:Disconnect()
obj:SetCopyableSelection()
--updateSelection()
end
end)

mouseEvent =
service.UserInputService.InputChanged:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
local upDelta = mouse.Y -
codeFrame.AbsolutePosition.Y
local downDelta = mouse.Y -
codeFrame.AbsolutePosition.Y - codeFrame.AbsoluteSize.Y
local leftDelta = mouse.X -
codeFrame.AbsolutePosition.X
local rightDelta = mouse.X -
codeFrame.AbsolutePosition.X - codeFrame.AbsoluteSize.X
scrollPowerV = 0
scrollPowerH = 0
if downDelta > 0 then
scrollPowerV =
math.floor(downDelta*0.05) + 1
elseif upDelta < 0 then
scrollPowerV =
math.ceil(upDelta*0.05) - 1
end
if rightDelta > 0 then
scrollPowerH =
math.floor(rightDelta*0.05) + 1
elseif leftDelta < 0 then
scrollPowerH =
math.ceil(leftDelta*0.05) - 1
end
updateSelection()
end
end)

scrollEvent =
clonerefs(game:GetService("RunService")).RenderStepped:Connect(function()
if scrollPowerV ~= 0 or scrollPowerH ~= 0 then

obj:ScrollDelta(scrollPowerH,scrollPowerV)
updateSelection()
end
end)

obj:Refresh()
end
end)
end

local function makeFrame(obj)


local frame = create({
{1,"Frame",
{BackgroundColor3=Color3.new(0.15686275064945,0.15686275064945,0.15686275064945),Bo
rderSizePixel = 0,Position=UDim2.new(0.5,-300,0.5,-
200),Size=UDim2.new(0,600,0,400),}},
})
local elems = {}

local linesFrame = Instance.new("Frame")


linesFrame.Name = "Lines"
linesFrame.BackgroundTransparency = 1
linesFrame.Size = UDim2.new(1,0,1,0)
linesFrame.ClipsDescendants = true
linesFrame.Parent = frame

local lineNumbersLabel = Instance.new("TextLabel")


lineNumbersLabel.Name = "LineNumbers"
lineNumbersLabel.BackgroundTransparency = 1
lineNumbersLabel.Font = Enum.Font.Code
lineNumbersLabel.TextXAlignment = Enum.TextXAlignment.Right
lineNumbersLabel.TextYAlignment = Enum.TextYAlignment.Top
lineNumbersLabel.ClipsDescendants = true
lineNumbersLabel.RichText = true
lineNumbersLabel.Parent = frame

local cursor = Instance.new("Frame")


cursor.Name = "Cursor"
cursor.BackgroundColor3 = Color3.fromRGB(220,220,220)
cursor.BorderSizePixel = 0
cursor.Parent = frame

local editBox = Instance.new("TextBox")


editBox.Name = "EditBox"
editBox.MultiLine = true
editBox.Visible = false
editBox.Parent = frame

lineTweens.Invis =
tweenService:Create(cursor,TweenInfo.new(0.4,Enum.EasingStyle.Quart,Enum.EasingDire
ction.Out),{BackgroundTransparency = 1})
lineTweens.Vis =
tweenService:Create(cursor,TweenInfo.new(0.2,Enum.EasingStyle.Quart,Enum.EasingDire
ction.Out),{BackgroundTransparency = 0})

elems.LinesFrame = linesFrame
elems.LineNumbersLabel = lineNumbersLabel
elems.Cursor = cursor
elems.EditBox = editBox
elems.ScrollCorner = create({{1,"Frame",
{BackgroundColor3=Color3.new(0.15686275064945,0.15686275064945,0.15686275064945),Bo
rderSizePixel=0,Name="ScrollCorner",Position=UDim2.new(1,-16,1,-
16),Size=UDim2.new(0,16,0,16),Visible=false,}}})

elems.ScrollCorner.Parent = frame
linesFrame.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
then
obj:SetEditing(true,input)
end
end)

obj.Frame = frame
obj.Gui = frame
obj.GuiElems = elems
setupEditBox(obj)
setupMouseSelection(obj)

return frame
end

funcs.GetSelectionText = function(self)
if not self:IsValidRange() then return "" end

local selectionRange = self.SelectionRange


local selX,selY = selectionRange[1][1], selectionRange[1][2]
local sel2X,sel2Y = selectionRange[2][1], selectionRange[2][2]
local deltaLines = sel2Y-selY
local lines = self.Lines

if not lines[selY+1] or not lines[sel2Y+1] then return "" end

if deltaLines == 0 then
return self:ConvertText(lines[selY+1]:sub(selX+1,sel2X),
false)
end

local leftSub = lines[selY+1]:sub(selX+1)


local rightSub = lines[sel2Y+1]:sub(1,sel2X)

local result = leftSub.."\n"


for i = selY+1,sel2Y-1 do
result = result..lines[i+1].."\n"
end
result = result..rightSub

return self:ConvertText(result,false)
end

funcs.SetCopyableSelection = function(self)
local text = self:GetSelectionText()
local editBox = self.GuiElems.EditBox

self.EditBoxCopying = true
editBox.Text = text
editBox.SelectionStart = 1
editBox.CursorPosition = #editBox.Text + 1
self.EditBoxCopying = false
end

funcs.ConnectEditBoxEvent = function(self)
if self.EditBoxEvent then
self.EditBoxEvent:Disconnect()
end

self.EditBoxEvent =
service.UserInputService.InputBegan:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.Keyboard then
return end

local keycodes = Enum.KeyCode


local keycode = input.KeyCode
local function setupMove(key,func)
local endCon,finished
endCon =
service.UserInputService.InputEnded:Connect(function(input)
if input.KeyCode ~= key then return end
endCon:Disconnect()
finished = true
end)
func()
Lib.FastWait(0.5)
while not finished do func() Lib.FastWait(0.03) end
end

if keycode == keycodes.Down then


setupMove(keycodes.Down,function()
self.CursorX = self.FloatCursorX
self.CursorY = self.CursorY + 1
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Up then
setupMove(keycodes.Up,function()
self.CursorX = self.FloatCursorX
self.CursorY = self.CursorY - 1
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Left then
setupMove(keycodes.Left,function()
local line = self.Lines[self.CursorY+1] or ""
self.CursorX = self.CursorX - 1 -
(line:sub(self.CursorX-3,self.CursorX) == tabReplacement and 3 or 0)
if self.CursorX < 0 then
self.CursorY = self.CursorY - 1
local line2 = self.Lines[self.CursorY+1]
or ""
self.CursorX = #line2
end
self.FloatCursorX = self.CursorX
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Right then
setupMove(keycodes.Right,function()
local line = self.Lines[self.CursorY+1] or ""
self.CursorX = self.CursorX + 1 +
(line:sub(self.CursorX+1,self.CursorX+4) == tabReplacement and 3 or 0)
if self.CursorX > #line then
self.CursorY = self.CursorY + 1
self.CursorX = 0
end
self.FloatCursorX = self.CursorX
self:UpdateCursor()
self:JumpToCursor()
end)
elseif keycode == keycodes.Backspace then
setupMove(keycodes.Backspace,function()
local startRange,endRange
if self:IsValidRange() then
startRange = self.SelectionRange[1]
endRange = self.SelectionRange[2]
else
endRange = {self.CursorX,self.CursorY}
end

if not startRange then


local line = self.Lines[self.CursorY+1]
or ""
self.CursorX = self.CursorX - 1 -
(line:sub(self.CursorX-3,self.CursorX) == tabReplacement and 3 or 0)
if self.CursorX < 0 then
self.CursorY = self.CursorY - 1
local line2 =
self.Lines[self.CursorY+1] or ""
self.CursorX = #line2
end
self.FloatCursorX = self.CursorX
self:UpdateCursor()

startRange = startRange or
{self.CursorX,self.CursorY}
end

self:DeleteRange({startRange,endRange},false,true)
self:ResetSelection(true)
self:JumpToCursor()
end)
elseif keycode == keycodes.Delete then
setupMove(keycodes.Delete,function()
local startRange,endRange
if self:IsValidRange() then
startRange = self.SelectionRange[1]
endRange = self.SelectionRange[2]
else
startRange = {self.CursorX,self.CursorY}
end

if not endRange then


local line = self.Lines[self.CursorY+1]
or ""
local endCursorX = self.CursorX + 1 +
(line:sub(self.CursorX+1,self.CursorX+4) == tabReplacement and 3 or 0)
local endCursorY = self.CursorY
if endCursorX > #line then
endCursorY = endCursorY + 1
endCursorX = 0
end
self:UpdateCursor()

endRange = endRange or
{endCursorX,endCursorY}
end

self:DeleteRange({startRange,endRange},false,true)
self:ResetSelection(true)
self:JumpToCursor()
end)
elseif
service.UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) then
if keycode == keycodes.A then
self.SelectionRange = {{0,0},
{#self.Lines[#self.Lines],#self.Lines-1}}
self:SetCopyableSelection()
self:Refresh()
end
end
end)
end

funcs.DisconnectEditBoxEvent = function(self)
if self.EditBoxEvent then
self.EditBoxEvent:Disconnect()
end
end

funcs.ResetSelection = function(self,norefresh)
self.SelectionRange = {{-1,-1},{-1,-1}}
if not norefresh then self:Refresh() end
end

funcs.IsValidRange = function(self,range)
local selectionRange = range or self.SelectionRange
local selX,selY = selectionRange[1][1], selectionRange[1][2]
local sel2X,sel2Y = selectionRange[2][1], selectionRange[2][2]

if selX == -1 or (selX == sel2X and selY == sel2Y) then return


false end

return true
end

funcs.DeleteRange = function(self,range,noprocess,updatemouse)
range = range or self.SelectionRange
if not self:IsValidRange(range) then return end

local lines = self.Lines


local selX,selY = range[1][1], range[1][2]
local sel2X,sel2Y = range[2][1], range[2][2]
local deltaLines = sel2Y-selY

if not lines[selY+1] or not lines[sel2Y+1] then return end

local leftSub = lines[selY+1]:sub(1,selX)


local rightSub = lines[sel2Y+1]:sub(sel2X+1)
lines[selY+1] = leftSub..rightSub

local remove = table.remove


for i = 1,deltaLines do
remove(lines,selY+2)
end

if range == self.SelectionRange then self.SelectionRange = {{-1,-


1},{-1,-1}} end
if updatemouse then
self.CursorX = selX
self.CursorY = selY
self:UpdateCursor()
end

if not noprocess then


self:ProcessTextChange()
end
end

funcs.AppendText = function(self,text)
self:DeleteRange(nil,true,true)
local lines,cursorX,cursorY =
self.Lines,self.CursorX,self.CursorY
local line = lines[cursorY+1]
local before = line:sub(1,cursorX)
local after = line:sub(cursorX+1)

text = text:gsub("\r\n","\n")
text = self:ConvertText(text,true) -- Tab Convert

local textLines = text:split("\n")


local insert = table.insert

for i = 1,#textLines do
local linePos = cursorY+i
if i > 1 then insert(lines,linePos,"") end

local textLine = textLines[i]


local newBefore = (i == 1 and before or "")
local newAfter = (i == #textLines and after or "")

lines[linePos] = newBefore..textLine..newAfter
end

if #textLines > 1 then cursorX = 0 end

self:ProcessTextChange()
self.CursorX = cursorX + #textLines[#textLines]
self.CursorY = cursorY + #textLines-1
self:UpdateCursor()
end

funcs.ScrollDelta = function(self,x,y)
self.ScrollV:ScrollTo(self.ScrollV.Index + y)
self.ScrollH:ScrollTo(self.ScrollH.Index + x)
end

-- x and y starts at 0
funcs.TabAdjust = function(self,x,y)
local lines = self.Lines
local line = lines[y+1]
x=x+1

if line then
local left = line:sub(x-1,x-1)
local middle = line:sub(x,x)
local right = line:sub(x+1,x+1)
local selRange = (#left > 0 and left or " ") .. (#middle >
0 and middle or " ") .. (#right > 0 and right or " ")
for i,v in pairs(tabJumps) do
if selRange:find(i) then
return v
end
end
end
return 0
end

funcs.SetEditing = function(self,on,input)
self:UpdateCursor(input)

if on then
if self.Editable then
self.GuiElems.EditBox.Text = ""
self.GuiElems.EditBox:CaptureFocus()
end
else
self.GuiElems.EditBox:ReleaseFocus()
end
end

funcs.CursorAnim = function(self,on)
local cursor = self.GuiElems.Cursor
local animTime = tick()
self.LastAnimTime = animTime

if not on then return end

lineTweens.Invis:Cancel()
lineTweens.Vis:Cancel()
cursor.BackgroundTransparency = 0

coroutine.wrap(function()
while self.Editable do
Lib.FastWait(0.5)
if self.LastAnimTime ~= animTime then return end
lineTweens.Invis:Play()
Lib.FastWait(0.4)
if self.LastAnimTime ~= animTime then return end
lineTweens.Vis:Play()
Lib.FastWait(0.2)
end
end)()
end

funcs.MoveCursor = function(self,x,y)
self.CursorX = x
self.CursorY = y
self:UpdateCursor()
self:JumpToCursor()
end

funcs.JumpToCursor = function(self)
self:Refresh()
end

funcs.UpdateCursor = function(self,input)
local linesFrame = self.GuiElems.LinesFrame
local cursor = self.GuiElems.Cursor
local hSize = math.max(0,linesFrame.AbsoluteSize.X)
local vSize = math.max(0,linesFrame.AbsoluteSize.Y)
local maxLines = math.ceil(vSize / self.FontSize)
local maxCols = math.ceil(hSize / math.ceil(self.FontSize/2))
local viewX,viewY = self.ViewX,self.ViewY
local totalLinesStr = tostring(#self.Lines)
local fontWidth = math.ceil(self.FontSize / 2)
local linesOffset = #totalLinesStr*fontWidth + 4*fontWidth

if input then
local linesFrame = self.GuiElems.LinesFrame
local frameX,frameY =
linesFrame.AbsolutePosition.X,linesFrame.AbsolutePosition.Y
local mouseX,mouseY = input.Position.X,input.Position.Y
local fontSizeX,fontSizeY =
math.ceil(self.FontSize/2),self.FontSize

self.CursorX = self.ViewX + math.round((mouseX - frameX) /


fontSizeX)
self.CursorY = self.ViewY + math.floor((mouseY - frameY) /
fontSizeY)
end

local cursorX,cursorY = self.CursorX,self.CursorY

local line = self.Lines[cursorY+1] or ""


if cursorX > #line then cursorX = #line
elseif cursorX < 0 then cursorX = 0 end

if cursorY >= #self.Lines then


cursorY = math.max(0,#self.Lines-1)
elseif cursorY < 0 then
cursorY = 0
end

cursorX = cursorX + self:TabAdjust(cursorX,cursorY)

-- Update modified
self.CursorX = cursorX
self.CursorY = cursorY

local cursorVisible = (cursorX >= viewX) and (cursorY >= viewY)


and (cursorX <= viewX + maxCols) and (cursorY <= viewY + maxLines)
if cursorVisible then
local offX = (cursorX - viewX)
local offY = (cursorY - viewY)
cursor.Position = UDim2.new(0,linesOffset +
offX*math.ceil(self.FontSize/2) - 1,0,offY*self.FontSize)
cursor.Size = UDim2.new(0,1,0,self.FontSize+2)
cursor.Visible = true
self:CursorAnim(true)
else
cursor.Visible = false
end
end

funcs.MapNewLines = function(self)
local newLines = {}
local count = 1
local text = self.Text
local find = string.find
local init = 1

local pos = find(text,"\n",init,true)


while pos do
newLines[count] = pos
count = count + 1
init = pos + 1
pos = find(text,"\n",init,true)
end

self.NewLines = newLines
end

funcs.PreHighlight = function(self)
local start = tick()
local text = self.Text:gsub("\\\\"," ")
--print("BACKSLASH SUB",tick()-start)
local textLen = #text
local found = {}
local foundMap = {}
local extras = {}
local find = string.find
local sub = string.sub
self.ColoredLines = {}

local function findAll(str,pattern,typ,raw)


local count = #found+1
local init = 1
local x,y,extra = find(str,pattern,init,raw)
while x do
found[count] = x
foundMap[x] = typ
if extra then
extras[x] = extra
end

count = count+1
init = y+1
x,y,extra = find(str,pattern,init,raw)
end
end
local start = tick()
findAll(text,'"',1,true)
findAll(text,"'",2,true)
findAll(text,"%[(=*)%[",3)
findAll(text,"--",4,true)
table.sort(found)

local newLines = self.NewLines


local curLine = 0
local lineTableCount = 1
local lineStart = 0
local lineEnd = 0
local lastEnding = 0
local foundHighlights = {}
for i = 1,#found do
local pos = found[i]
if pos <= lastEnding then continue end

local ending = pos


local typ = foundMap[pos]
if typ == 1 then
ending = find(text,'"',pos+1,true)
while ending and sub(text,ending-1,ending-1) == "\\"
do
ending = find(text,'"',ending+1,true)
end
if not ending then ending = textLen end
elseif typ == 2 then
ending = find(text,"'",pos+1,true)
while ending and sub(text,ending-1,ending-1) == "\\"
do
ending = find(text,"'",ending+1,true)
end
if not ending then ending = textLen end
elseif typ == 3 then
_,ending =
find(text,"]"..extras[pos].."]",pos+1,true)
if not ending then ending = textLen end
elseif typ == 4 then
local ahead = foundMap[pos+2]

if ahead == 3 then
_,ending =
find(text,"]"..extras[pos+2].."]",pos+1,true)
if not ending then ending = textLen end
else
ending = find(text,"\n",pos+1,true) or textLen
end
end

while pos > lineEnd do


curLine = curLine + 1
--lineTableCount = 1
lineEnd = newLines[curLine] or textLen+1
end
while true do
local lineTable = foundHighlights[curLine]
if not lineTable then lineTable = {}
foundHighlights[curLine] = lineTable end
lineTable[pos] = {typ,ending}
--lineTableCount = lineTableCount + 1

if ending > lineEnd then


curLine = curLine + 1
lineEnd = newLines[curLine] or textLen+1
else
break
end
end

lastEnding = ending
--if i < 200 then print(curLine) end
end
self.PreHighlights = foundHighlights
--print(tick()-start)
--print(#found,curLine)
end

funcs.HighlightLine = function(self,line)
local cached = self.ColoredLines[line]
if cached then return cached end

local sub = string.sub


local find = string.find
local match = string.match
local highlights = {}
local preHighlights = self.PreHighlights[line] or {}
local lineText = self.Lines[line] or ""
local lineLen = #lineText
local lastEnding = 0
local currentType = 0
local lastWord = nil
local wordBeginsDotted = false
local funcStatus = 0
local lineStart = self.NewLines[line-1] or 0

local preHighlightMap = {}
for pos,data in next,preHighlights do
local relativePos = pos-lineStart
if relativePos < 1 then
currentType = data[1]
lastEnding = data[2] - lineStart
--warn(pos,data[2])
else
preHighlightMap[relativePos] = {data[1],data[2]-
lineStart}
end
end

for col = 1,#lineText do


if col <= lastEnding then highlights[col] = currentType
continue end

local pre = preHighlightMap[col]


if pre then
currentType = pre[1]
lastEnding = pre[2]
highlights[col] = currentType
wordBeginsDotted = false
lastWord = nil
funcStatus = 0
else
local char = sub(lineText,col,col)
if find(char,"[%a_]") then
local word = match(lineText,"[%a%d_]+",col)
local wordType = (keywords[word] and 7) or
(builtIns[word] and 8)

lastEnding = col+#word-1

if wordType ~= 7 then
if wordBeginsDotted then
local prevBuiltIn = lastWord and
builtIns[lastWord]
wordType = (prevBuiltIn and
type(prevBuiltIn) == "table" and prevBuiltIn[word] and 8) or 10
end

if wordType ~= 8 then
local x,y,br = find(lineText,"^
%s*([%({\"'])",lastEnding+1)
if x then
wordType = (funcStatus > 0
and br == "(" and 16) or 9
funcStatus = 0
end
end
else
wordType = specialKeywordsTypes[word] or
wordType
funcStatus = (word == "function" and 1 or
0)
end

lastWord = word
wordBeginsDotted = false
if funcStatus > 0 then funcStatus = 1 end

if wordType then
currentType = wordType
highlights[col] = currentType
else
currentType = nil
end
elseif find(char,"%p") then
local isDot = (char == ".")
local isNum = isDot and
find(sub(lineText,col+1,col+1),"%d")
highlights[col] = (isNum and 6 or 5)

if not isNum then


local dotStr = isDot and
match(lineText,"%.%.?%.?",col)
if dotStr and #dotStr > 1 then
currentType = 5
lastEnding = col+#dotStr-1
wordBeginsDotted = false
lastWord = nil
funcStatus = 0
else
if isDot then
if wordBeginsDotted then
lastWord = nil
else
wordBeginsDotted = true
end
else
wordBeginsDotted = false
lastWord = nil
end
funcStatus = ((isDot or char ==
":") and funcStatus == 1 and 2) or 0
end
end
elseif find(char,"%d") then
local _,endPos = find(lineText,"%x+",col)
local endPart = sub(lineText,endPos,endPos+1)
if (endPart == "e+" or endPart == "e-") and
find(sub(lineText,endPos+2,endPos+2),"%d") then
endPos = endPos + 1
end
currentType = 6
lastEnding = endPos
highlights[col] = 6
wordBeginsDotted = false
lastWord = nil
funcStatus = 0
else
highlights[col] = currentType
local _,endPos = find(lineText,"%s+",col)
if endPos then
lastEnding = endPos
end
end
end
end

self.ColoredLines[line] = highlights
return highlights
end

funcs.Refresh = function(self)
local start = tick()

local linesFrame = self.Frame.Lines


local hSize = math.max(0,linesFrame.AbsoluteSize.X)
local vSize = math.max(0,linesFrame.AbsoluteSize.Y)
local maxLines = math.ceil(vSize / self.FontSize)
local maxCols = math.ceil(hSize / math.ceil(self.FontSize/2))
local gsub = string.gsub
local sub = string.sub

local viewX,viewY = self.ViewX,self.ViewY

local lineNumberStr = ""

for row = 1,maxLines do


local lineFrame = self.LineFrames[row]
if not lineFrame then
lineFrame = Instance.new("Frame")
lineFrame.Name = "Line"
lineFrame.Position = UDim2.new(0,0,0,(row-
1)*self.FontSize)
lineFrame.Size = UDim2.new(1,0,0,self.FontSize)
lineFrame.BorderSizePixel = 0
lineFrame.BackgroundTransparency = 1

local selectionHighlight = Instance.new("Frame")


selectionHighlight.Name = "SelectionHighlight"
selectionHighlight.BorderSizePixel = 0
selectionHighlight.BackgroundColor3 =
Settings.Theme.Syntax.SelectionBack
selectionHighlight.Parent = lineFrame

local label = Instance.new("TextLabel")


label.Name = "Label"
label.BackgroundTransparency = 1
label.Font = Enum.Font.Code
label.TextSize = self.FontSize
label.Size = UDim2.new(1,0,0,self.FontSize)
label.RichText = true
label.TextXAlignment = Enum.TextXAlignment.Left
label.TextColor3 = self.Colors.Text
label.ZIndex = 2
label.Parent = lineFrame

lineFrame.Parent = linesFrame
self.LineFrames[row] = lineFrame
end

local relaY = viewY + row


local lineText = self.Lines[relaY] or ""
local resText = ""
local highlights = self:HighlightLine(relaY)
local colStart = viewX + 1

local richTemplates = self.RichTemplates


local textTemplate = richTemplates.Text
local selectionTemplate = richTemplates.Selection
local curType = highlights[colStart]
local curTemplate = richTemplates[typeMap[curType]] or
textTemplate

-- Selection Highlight
local selectionRange = self.SelectionRange
local selPos1 = selectionRange[1]
local selPos2 = selectionRange[2]
local selRow,selColumn = selPos1[2],selPos1[1]
local sel2Row,sel2Column = selPos2[2],selPos2[1]
local selRelaX,selRelaY = viewX,relaY-1

if selRelaY >= selPos1[2] and selRelaY <= selPos2[2] then


local fontSizeX = math.ceil(self.FontSize/2)
local posX = (selRelaY == selPos1[2] and selPos1[1]
or 0) - viewX
local sizeX = (selRelaY == selPos2[2] and selPos2[1]-
posX-viewX or maxCols+viewX)

lineFrame.SelectionHighlight.Position =
UDim2.new(0,posX*fontSizeX,0,0)
lineFrame.SelectionHighlight.Size =
UDim2.new(0,sizeX*fontSizeX,1,0)
lineFrame.SelectionHighlight.Visible = true
else
lineFrame.SelectionHighlight.Visible = false
end
-- Selection Text Color for first char
local inSelection = selRelaY >= selRow and selRelaY <=
sel2Row and (selRelaY == selRow and viewX >= selColumn or selRelaY ~= selRow) and
(selRelaY == sel2Row and viewX < sel2Column or selRelaY ~= sel2Row)
if inSelection then
curType = -999
curTemplate = selectionTemplate
end

for col = 2,maxCols do


local relaX = viewX + col
local selRelaX = relaX-1
local posType = highlights[relaX]

-- Selection Text Color


local inSelection = selRelaY >= selRow and selRelaY
<= sel2Row and (selRelaY == selRow and selRelaX >= selColumn or selRelaY ~= selRow)
and (selRelaY == sel2Row and selRelaX < sel2Column or selRelaY ~= sel2Row)
if inSelection then
posType = -999
end

if posType ~= curType then


local template = (inSelection and
selectionTemplate) or richTemplates[typeMap[posType]] or textTemplate

if template ~= curTemplate then


local nextText =
gsub(sub(lineText,colStart,relaX-1),"['\"<>&]",richReplace)
resText = resText .. (curTemplate ~=
textTemplate and (curTemplate .. nextText .. "</font>") or nextText)
colStart = relaX
curTemplate = template
end
curType = posType
end
end

local lastText =
gsub(sub(lineText,colStart,viewX+maxCols),"['\"<>&]",richReplace)
--warn("SUB",colStart,viewX+maxCols-1)
if #lastText > 0 then
resText = resText .. (curTemplate ~= textTemplate and
(curTemplate .. lastText .. "</font>") or lastText)
end

if self.Lines[relaY] then
lineNumberStr = lineNumberStr .. (relaY ==
self.CursorY and ("<b>"..relaY.."</b>\n") or relaY .. "\n")
end

lineFrame.Label.Text = resText
end

for i = maxLines+1,#self.LineFrames do
self.LineFrames[i]:Destroy()
self.LineFrames[i] = nil
end
self.Frame.LineNumbers.Text = lineNumberStr
self:UpdateCursor()

--print("REFRESH TIME",tick()-start)
end

funcs.UpdateView = function(self)
local totalLinesStr = tostring(#self.Lines)
local fontWidth = math.ceil(self.FontSize / 2)
local linesOffset = #totalLinesStr*fontWidth + 4*fontWidth

local linesFrame = self.Frame.Lines


local hSize = linesFrame.AbsoluteSize.X
local vSize = linesFrame.AbsoluteSize.Y
local maxLines = math.ceil(vSize / self.FontSize)
local totalWidth = self.MaxTextCols*fontWidth
local scrollV = self.ScrollV
local scrollH = self.ScrollH

scrollV.VisibleSpace = maxLines
scrollV.TotalSpace = #self.Lines + 1
scrollH.VisibleSpace = math.ceil(hSize/fontWidth)
scrollH.TotalSpace = self.MaxTextCols + 1

scrollV.Gui.Visible = #self.Lines + 1 > maxLines


scrollH.Gui.Visible = totalWidth > hSize

local oldOffsets = self.FrameOffsets


self.FrameOffsets = Vector2.new(scrollV.Gui.Visible and -16 or 0,
scrollH.Gui.Visible and -16 or 0)
if oldOffsets ~= self.FrameOffsets then
self:UpdateView()
else
scrollV:ScrollTo(self.ViewY,true)
scrollH:ScrollTo(self.ViewX,true)

if scrollV.Gui.Visible and scrollH.Gui.Visible then


scrollV.Gui.Size = UDim2.new(0,16,1,-16)
scrollH.Gui.Size = UDim2.new(1,-16,0,16)
self.GuiElems.ScrollCorner.Visible = true
else
scrollV.Gui.Size = UDim2.new(0,16,1,0)
scrollH.Gui.Size = UDim2.new(1,0,0,16)
self.GuiElems.ScrollCorner.Visible = false
end

self.ViewY = scrollV.Index
self.ViewX = scrollH.Index
self.Frame.Lines.Position = UDim2.new(0,linesOffset,0,0)
self.Frame.Lines.Size = UDim2.new(1,-
linesOffset+oldOffsets.X,1,oldOffsets.Y)
self.Frame.LineNumbers.Position =
UDim2.new(0,fontWidth,0,0)
self.Frame.LineNumbers.Size =
UDim2.new(0,#totalLinesStr*fontWidth,1,oldOffsets.Y)
self.Frame.LineNumbers.TextSize = self.FontSize
end
end
funcs.ProcessTextChange = function(self)
local maxCols = 0
local lines = self.Lines

for i = 1,#lines do
local lineLen = #lines[i]
if lineLen > maxCols then
maxCols = lineLen
end
end

self.MaxTextCols = maxCols
self:UpdateView()
self.Text = table.concat(self.Lines,"\n")
self:MapNewLines()
self:PreHighlight()
self:Refresh()
--self.TextChanged:Fire()
end

funcs.ConvertText = function(self,text,toEditor)
if toEditor then
return text:gsub("\t",(" %s%s "):format(tabSub,tabSub))
else
return text:gsub((" %s%s "):format(tabSub,tabSub),"\t")
end
end

funcs.GetText = function(self) -- TODO: better (use new tab format)


local source = table.concat(self.Lines,"\n")
return self:ConvertText(source,false) -- Tab Convert
end

funcs.SetText = function(self,txt)
txt = self:ConvertText(txt,true) -- Tab Convert
local lines = self.Lines
table.clear(lines)
local count = 1

for line in txt:gmatch("([^\n\r]*)[\n\r]?") do


local len = #line
lines[count] = line
count = count + 1
end

self:ProcessTextChange()
end

funcs.MakeRichTemplates = function(self)
local floor = math.floor
local templates = {}

for name,color in pairs(self.Colors) do


templates[name] = ('<font color="rgb(%s,%s,
%s)">'):format(floor(color.r*255),floor(color.g*255),floor(color.b*255))
end

self.RichTemplates = templates
end
funcs.ApplyTheme = function(self)
local colors = Settings.Theme.Syntax
self.Colors = colors
self.Frame.LineNumbers.TextColor3 = colors.Text
self.Frame.BackgroundColor3 = colors.Background
end

local mt = {__index = funcs}

local function new()


if not builtInInited then initBuiltIn() end

local scrollV = Lib.ScrollBar.new()


local scrollH = Lib.ScrollBar.new(true)
scrollH.Gui.Position = UDim2.new(0,0,1,-16)
local obj = setmetatable({
FontSize = 15,
ViewX = 0,
ViewY = 0,
Colors = Settings.Theme.Syntax,
ColoredLines = {},
Lines = {""},
LineFrames = {},
Editable = true,
Editing = false,
CursorX = 0,
CursorY = 0,
FloatCursorX = 0,
Text = "",
PreHighlights = {},
SelectionRange = {{-1,-1},{-1,-1}},
NewLines = {},
FrameOffsets = Vector2.new(0,0),
MaxTextCols = 0,
ScrollV = scrollV,
ScrollH = scrollH
},mt)

scrollV.WheelIncrement = 3
scrollH.Increment = 2
scrollH.WheelIncrement = 7

scrollV.Scrolled:Connect(function()
obj.ViewY = scrollV.Index
obj:Refresh()
end)

scrollH.Scrolled:Connect(function()
obj.ViewX = scrollH.Index
obj:Refresh()
end)

makeFrame(obj)
obj:MakeRichTemplates()
obj:ApplyTheme()
scrollV:SetScrollFrame(obj.Frame.Lines)
scrollV.Gui.Parent = obj.Frame
scrollH.Gui.Parent = obj.Frame
obj:UpdateView()

obj.Frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
obj:UpdateView()
obj:Refresh()
end)

return obj
end

return {new = new}


end)()

Lib.Checkbox = (function()
local funcs = {}
local c3 = Color3.fromRGB
local v2 = Vector2.new
local ud2s = UDim2.fromScale
local ud2o = UDim2.fromOffset
local ud = UDim.new
local max = math.max
local new = Instance.new
local TweenSize = new("Frame").TweenSize
local ti = TweenInfo.new
local delay = delay

local function ripple(object, color)


local circle = new('Frame')
circle.BackgroundColor3 = color
circle.BackgroundTransparency = 0.75
circle.BorderSizePixel = 0
circle.AnchorPoint = v2(0.5, 0.5)
circle.Size = ud2o()
circle.Position = ud2s(0.5, 0.5)
circle.Parent = object
local rounding = new('UICorner')
rounding.CornerRadius = ud(1)
rounding.Parent = circle

local abssz = object.AbsoluteSize


local size = max(abssz.X, abssz.Y) * 5/3

TweenSize(circle, ud2o(size, size), "Out", "Quart", 0.4)


service.TweenService:Create(circle, ti(0.4,
Enum.EasingStyle.Quart, Enum.EasingDirection.In), {BackgroundTransparency =
1}):Play()

service.Debris:AddItem(circle, 0.4)
end

local function initGui(self,frame)


local checkbox = frame or create({
{1,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name
="Checkbox",Position=UDim2.new(0,3,0,3),Size=UDim2.new(0,16,0,16),}},
{2,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name
="ripples",Parent={1},Size=UDim2.new(1,0,1,0),}},
{3,"Frame",
{BackgroundColor3=Color3.new(0.10196078568697,0.10196078568697,0.10196078568697),Bo
rderSizePixel=0,Name="outline",Parent={1},Size=UDim2.new(0,16,0,16),}},
{4,"Frame",
{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),Bo
rderSizePixel=0,Name="filler",Parent={3},Position=UDim2.new(0,1,0,1),Size=UDim2.new
(0,14,0,14),}},
{5,"Frame",
{BackgroundColor3=Color3.new(0.90196084976196,0.90196084976196,0.90196084976196),Bo
rderSizePixel=0,Name="top",Parent={4},Size=UDim2.new(0,16,0,0),}},
{6,"Frame",
{AnchorPoint=Vector2.new(0,1),BackgroundColor3=Color3.new(0.90196084976196,0.901960
84976196,0.90196084976196),BorderSizePixel=0,Name="bottom",Parent={4},Position=UDim
2.new(0,0,0,14),Size=UDim2.new(0,16,0,0),}},
{7,"Frame",
{BackgroundColor3=Color3.new(0.90196084976196,0.90196084976196,0.90196084976196),Bo
rderSizePixel=0,Name="left",Parent={4},Size=UDim2.new(0,0,0,16),}},
{8,"Frame",
{AnchorPoint=Vector2.new(1,0),BackgroundColor3=Color3.new(0.90196084976196,0.901960
84976196,0.90196084976196),BorderSizePixel=0,Name="right",Parent={4},Position=UDim2
.new(0,14,0,0),Size=UDim2.new(0,0,0,16),}},
{9,"Frame",
{AnchorPoint=Vector2.new(0.5,0.5),BackgroundColor3=Color3.new(1,1,1),BackgroundTran
sparency=1,BorderSizePixel=0,ClipsDescendants=true,Name="checkmark",Parent={4},Posi
tion=UDim2.new(0.5,0,0.5,0),Size=UDim2.new(0,0,0,20),}},
{10,"ImageLabel",
{AnchorPoint=Vector2.new(0.5,0.5),BackgroundColor3=Color3.new(1,1,1),BackgroundTran
sparency=1,BorderSizePixel=0,Image="rbxassetid://
6234266378",Parent={9},Position=UDim2.new(0.5,0,0.5,0),ScaleType=3,Size=UDim2.new(0
,15,0,11),}},
{11,"ImageLabel",
{AnchorPoint=Vector2.new(0.5,0.5),BackgroundColor3=Color3.new(1,1,1),BackgroundTran
sparency=1,Image="rbxassetid://
6401617475",ImageColor3=Color3.new(0.20784313976765,0.69803923368454,0.984313726425
17),Name="checkmark2",Parent={4},Position=UDim2.new(0.5,0,0.5,0),Size=UDim2.new(0,1
2,0,12),Visible=false,}},
{12,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
6425281788",ImageTransparency=0.20000000298023,Name="middle",Parent={4},ScaleType=2
,Size=UDim2.new(1,0,1,0),TileSize=UDim2.new(0,2,0,2),Visible=false,}},
{13,"UICorner",{CornerRadius=UDim.new(0,2),Parent={3},}},
})
local outline = checkbox.outline
local filler = outline.filler
local checkmark = filler.checkmark
local ripples_container = checkbox.ripples

-- walls
local top, bottom, left, right = filler.top, filler.bottom,
filler.left, filler.right

self.Gui = checkbox
self.GuiElems = {
Top = top,
Bottom = bottom,
Left = left,
Right = right,
Outline = outline,
Filler = filler,
Checkmark = checkmark,
Checkmark2 = filler.checkmark2,
Middle = filler.middle
}

checkbox.InputBegan:Connect(function(i)
if i.UserInputType == Enum.UserInputType.MouseButton1 then
local release
release =
service.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseButton1 then
release:Disconnect()

if Lib.CheckMouseInGui(checkbox) then
if self.Style == 0 then
ripple(ripples_container,
self.Disabled and self.Colors.Disabled or self.Colors.Primary)
end

if not self.Disabled then


self:SetState(not
self.Toggled,true)
else
self:Paint()
end

self.OnInput:Fire()
end
end
end)
end
end)

self:Paint()
end

funcs.Collapse = function(self,anim)
local guiElems = self.GuiElems
if anim then
TweenSize(guiElems.Top, ud2o(14, 14), "In", "Quart", 4/15,
true)
TweenSize(guiElems.Bottom, ud2o(14, 14), "In", "Quart",
4/15, true)
TweenSize(guiElems.Left, ud2o(14, 14), "In", "Quart", 4/15,
true)
TweenSize(guiElems.Right, ud2o(14, 14), "In", "Quart",
4/15, true)
else
guiElems.Top.Size = ud2o(14, 14)
guiElems.Bottom.Size = ud2o(14, 14)
guiElems.Left.Size = ud2o(14, 14)
guiElems.Right.Size = ud2o(14, 14)
end
end

funcs.Expand = function(self,anim)
local guiElems = self.GuiElems
if anim then
TweenSize(guiElems.Top, ud2o(14, 0), "InOut", "Quart",
4/15, true)
TweenSize(guiElems.Bottom, ud2o(14, 0), "InOut", "Quart",
4/15, true)
TweenSize(guiElems.Left, ud2o(0, 14), "InOut", "Quart",
4/15, true)
TweenSize(guiElems.Right, ud2o(0, 14), "InOut", "Quart",
4/15, true)
else
guiElems.Top.Size = ud2o(14, 0)
guiElems.Bottom.Size = ud2o(14, 0)
guiElems.Left.Size = ud2o(0, 14)
guiElems.Right.Size = ud2o(0, 14)
end
end

funcs.Paint = function(self)
local guiElems = self.GuiElems

if self.Style == 0 then
local color_base = self.Disabled and self.Colors.Disabled
guiElems.Outline.BackgroundColor3 = color_base or
(self.Toggled and self.Colors.Primary) or self.Colors.Secondary
local walls_color = color_base or self.Colors.Primary
guiElems.Top.BackgroundColor3 = walls_color
guiElems.Bottom.BackgroundColor3 = walls_color
guiElems.Left.BackgroundColor3 = walls_color
guiElems.Right.BackgroundColor3 = walls_color
else
guiElems.Outline.BackgroundColor3 = self.Disabled and
self.Colors.Disabled or self.Colors.Secondary
guiElems.Filler.BackgroundColor3 = self.Disabled and
self.Colors.DisabledBackground or self.Colors.Background
guiElems.Checkmark2.ImageColor3 = self.Disabled and
self.Colors.DisabledCheck or self.Colors.Primary
end
end

funcs.SetState = function(self,val,anim)
self.Toggled = val

if self.OutlineColorTween then self.OutlineColorTween:Cancel()


end
local setStateTime = tick()
self.LastSetStateTime = setStateTime

if self.Toggled then
if self.Style == 0 then
if anim then
self.OutlineColorTween =
service.TweenService:Create(self.GuiElems.Outline, ti(4/15,
Enum.EasingStyle.Circular, Enum.EasingDirection.Out), {BackgroundColor3 =
self.Colors.Primary})
self.OutlineColorTween:Play()
delay(0.15, function()
if setStateTime ~= self.LastSetStateTime
then return end
self:Paint()
TweenSize(self.GuiElems.Checkmark,
ud2o(14, 20), "Out", "Bounce", 2/15, true)
end)
else
self.GuiElems.Outline.BackgroundColor3 =
self.Colors.Primary
self:Paint()
self.GuiElems.Checkmark.Size = ud2o(14, 20)
end
self:Collapse(anim)
else
self:Paint()
self.GuiElems.Checkmark2.Visible = true
self.GuiElems.Middle.Visible = false
end
else
if self.Style == 0 then
if anim then
self.OutlineColorTween =
service.TweenService:Create(self.GuiElems.Outline, ti(4/15,
Enum.EasingStyle.Circular, Enum.EasingDirection.In), {BackgroundColor3 =
self.Colors.Secondary})
self.OutlineColorTween:Play()
delay(0.15, function()
if setStateTime ~= self.LastSetStateTime
then return end
self:Paint()
TweenSize(self.GuiElems.Checkmark,
ud2o(0, 20), "Out", "Quad", 1/15, true)
end)
else
self.GuiElems.Outline.BackgroundColor3 =
self.Colors.Secondary
self:Paint()
self.GuiElems.Checkmark.Size = ud2o(0, 20)
end
self:Expand(anim)
else
self:Paint()
self.GuiElems.Checkmark2.Visible = false
self.GuiElems.Middle.Visible = self.Toggled == nil
end
end
end

local mt = {__index = funcs}

local function new(style)


local obj = setmetatable({
Toggled = false,
Disabled = false,
OnInput = Lib.Signal.new(),
Style = style or 0,
Colors = {
Background = c3(36,36,36),
Primary = c3(49,176,230),
Secondary = c3(25,25,25),
Disabled = c3(64,64,64),
DisabledBackground = c3(52,52,52),
DisabledCheck = c3(80,80,80)
}
},mt)
initGui(obj)
return obj
end

local function fromFrame(frame)


local obj = setmetatable({
Toggled = false,
Disabled = false,
Colors = {
Background = c3(36,36,36),
Primary = c3(49,176,230),
Secondary = c3(25,25,25),
Disabled = c3(64,64,64),
DisabledBackground = c3(52,52,52)
}
},mt)
initGui(obj,frame)
return obj
end

return {new = new, fromFrame}


end)()

Lib.BrickColorPicker = (function()
local funcs = {}
local paletteCount = 0
local mouse = service.Players.LocalPlayer:GetMouse()
local hexStartX = 4
local hexSizeX = 27
local hexTriangleStart = 1
local hexTriangleSize = 8

local bottomColors = {
Color3.fromRGB(17,17,17),
Color3.fromRGB(99,95,98),
Color3.fromRGB(163,162,165),
Color3.fromRGB(205,205,205),
Color3.fromRGB(223,223,222),
Color3.fromRGB(237,234,234),
Color3.fromRGB(27,42,53),
Color3.fromRGB(91,93,105),
Color3.fromRGB(159,161,172),
Color3.fromRGB(202,203,209),
Color3.fromRGB(231,231,236),
Color3.fromRGB(248,248,248)
}

local function isMouseInHexagon(hex)


local relativeX = mouse.X - hex.AbsolutePosition.X
local relativeY = mouse.Y - hex.AbsolutePosition.Y
if relativeX >= hexStartX and relativeX < hexStartX + hexSizeX
then
relativeX = relativeX - 4
local relativeWidth = (13-math.min(relativeX,26 -
relativeX))/13
if relativeY >= hexTriangleStart +
hexTriangleSize*relativeWidth and relativeY < hex.AbsoluteSize.Y - hexTriangleStart
- hexTriangleSize*relativeWidth then
return true
end
end

return false
end

local function hexInput(self,hex,color)


hex.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
and isMouseInHexagon(hex) then
self.OnSelect:Fire(color)
self:Close()
end
end)

hex.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
and isMouseInHexagon(hex) then
self.OnPreview:Fire(color)
end
end)
end

local function createGui(self)


local gui = create({
{1,"ScreenGui",{Name="BrickColor",}},
{2,"Frame",
{Active=true,BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.176470
59261799),BorderColor3=Color3.new(0.1294117718935,0.1294117718935,0.1294117718935),
Parent={1},Position=UDim2.new(0.40000000596046,0,0.40000000596046,0),Size=UDim2.new
(0,337,0,380),}},
{3,"TextButton",
{BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,0.2352941185236),Borde
rColor3=Color3.new(0.21568627655506,0.21568627655506,0.21568627655506),BorderSizePi
xel=0,Font=3,Name="MoreColors",Parent={2},Position=UDim2.new(0,5,1,-
30),Size=UDim2.new(1,-10,0,25),Text="More
Colors",TextColor3=Color3.new(1,1,1),TextSize=14,}},
{4,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Imag
e="rbxassetid://
1281023007",ImageColor3=Color3.new(0.33333334326744,0.33333334326744,0.498039245605
47),Name="Hex",Parent={2},Size=UDim2.new(0,35,0,35),Visible=false,}},
})
local colorFrame = gui.Frame
local hex = colorFrame.Hex

for row = 1,13 do


local columns = math.min(row,14-row)+6
for column = 1,columns do
local nextColor =
BrickColor.palette(paletteCount).Color
local newHex = hex:Clone()
newHex.Position = UDim2.new(0, (column-1)*25-
(columns-7)*13+3*26 + 1, 0, (row-1)*23 + 4)
newHex.ImageColor3 = nextColor
newHex.Visible = true
hexInput(self,newHex,nextColor)
newHex.Parent = colorFrame
paletteCount = paletteCount + 1
end
end

for column = 1,12 do


local nextColor = bottomColors[column]
local newHex = hex:Clone()
newHex.Position = UDim2.new(0, (column-1)*25-(12-7)*13+3*26
+ 3, 0, 308)
newHex.ImageColor3 = nextColor
newHex.Visible = true
hexInput(self,newHex,nextColor)
newHex.Parent = colorFrame
paletteCount = paletteCount + 1
end

colorFrame.MoreColors.MouseButton1Click:Connect(function()
self.OnMoreColors:Fire()
self:Close()
end)

self.Gui = gui
end

funcs.SetMoreColorsVisible = function(self,vis)
local colorFrame = self.Gui.Frame
colorFrame.Size = UDim2.new(0,337,0,380 - (not vis and 33 or 0))
colorFrame.MoreColors.Visible = vis
end

funcs.Show = function(self,x,y,prevColor)
self.PrevColor = prevColor or self.PrevColor

local reverseY = false

local x,y = x or mouse.X, y or mouse.Y


local maxX,maxY = mouse.ViewSizeX,mouse.ViewSizeY
Lib.ShowGui(self.Gui)
local sizeX,sizeY =
self.Gui.Frame.AbsoluteSize.X,self.Gui.Frame.AbsoluteSize.Y

if x + sizeX > maxX then x = self.ReverseX and x - sizeX or maxX


- sizeX end
if y + sizeY > maxY then reverseY = true end

local closable = false


if self.CloseEvent then self.CloseEvent:Disconnect() end
self.CloseEvent =
service.UserInputService.InputBegan:Connect(function(input)
if not closable or input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end

if not Lib.CheckMouseInGui(self.Gui.Frame) then


self.CloseEvent:Disconnect()
self:Close()
end
end)
if reverseY then
local newY = y - sizeY - (self.ReverseYOffset or 0)
y = newY >= 0 and newY or 0
end

self.Gui.Frame.Position = UDim2.new(0,x,0,y)

Lib.FastWait()
closable = true
end

funcs.Close = function(self)
self.Gui.Parent = nil
self.OnCancel:Fire()
end

local mt = {__index = funcs}

local function new()


local obj = setmetatable({
OnPreview = Lib.Signal.new(),
OnSelect = Lib.Signal.new(),
OnCancel = Lib.Signal.new(),
OnMoreColors = Lib.Signal.new(),
PrevColor = Color3.new(0,0,0)
},mt)
createGui(obj)
return obj
end

return {new = new}


end)()

Lib.ColorPicker = (function() -- TODO: Convert to newer class model


local funcs = {}

local function new()


local newMt = setmetatable({},{})

newMt.OnSelect = Lib.Signal.new()
newMt.OnCancel = Lib.Signal.new()
newMt.OnPreview = Lib.Signal.new()

local guiContents = create({


{1,"Frame",
{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Bo
rderSizePixel=0,ClipsDescendants=true,Name="Content",Position=UDim2.new(0,0,0,20),S
ize=UDim2.new(1,0,1,-20),}},
{2,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="BasicColors",Par
ent={1},Position=UDim2.new(0,5,0,5),Size=UDim2.new(0,180,0,200),}},
{3,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={2},Position=UDim2.new(0,0,0,-5),Size=UDim2.new(1,0,0,26),Text="Basic
Colors",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.86274516582489),T
extSize=14,TextXAlignment=0,}},
{4,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Blu
e",Parent={1},Position=UDim2.new(1,-63,0,255),Size=UDim2.new(0,52,0,16),}},
{5,"TextBox",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),Font=3,Name="Input",Parent={4},Position=UDim2.new(0,2,0,0),Size=UDi
m2.new(0,50,0,16),Text="0",TextColor3=Color3.new(0.86274516582489,0.86274516582489,
0.86274516582489),TextSize=14,TextXAlignment=0,}},
{6,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name
="ArrowFrame",Parent={5},Position=UDim2.new(1,-16,0,0),Size=UDim2.new(0,16,1,0),}},
{7,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Up",Parent={6},Size=UDim2.new(1,0,0,8),Text="",TextS
ize=14,}},
{8,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={7},Size=UDim2.new(0,16,0,8),}},
{9,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={8},Position=UDim2.new(0,8,0,3),Size=UDim2.new(0,1,0,1),}},
{10,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={8},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{11,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={8},Position=UDim2.new(0,6,0,5),Size=UDim2.new(0,5,0,1),}},
{12,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Down",Parent={6},Position=UDim2.new(0,0,0,8),Size=UD
im2.new(1,0,0,8),Text="",TextSize=14,}},
{13,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={12},Size=UDim2.new(0,16,0,8),}},
{14,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={13},Position=UDim2.new(0,8,0,5),Size=UDim2.new(0,1,0,1),}},
{15,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={13},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{16,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={13},Position=UDim2.new(0,6,0,3),Size=UDim2.new(0,5,0,1),}},
{17,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={4},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Blue:",TextColor3=Color3.new(0.8627451658248
9,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{18,"Frame",
{BackgroundColor3=Color3.new(0.21568627655506,0.21568627655506,0.21568627655506),Bo
rderSizePixel=0,ClipsDescendants=true,Name="ColorSpaceFrame",Parent={1},Position=UD
im2.new(1,-261,0,4),Size=UDim2.new(0,222,0,202),}},
{19,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BorderColor3=Color3.new(0.37647062540054,0.3764
7062540054,0.37647062540054),BorderSizePixel=0,Image="rbxassetid://
1072518406",Name="ColorSpace",Parent={18},Position=UDim2.new(0,1,0,1),Size=UDim2.ne
w(0,220,0,200),}},
{20,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name
="Scope",Parent={19},Position=UDim2.new(0,210,0,190),Size=UDim2.new(0,20,0,20),}},
{21,"Frame",
{BackgroundColor3=Color3.new(0,0,0),BorderSizePixel=0,Name="Line",Parent={20},Posit
ion=UDim2.new(0,9,0,0),Size=UDim2.new(0,2,0,20),}},
{22,"Frame",
{BackgroundColor3=Color3.new(0,0,0),BorderSizePixel=0,Name="Line",Parent={20},Posit
ion=UDim2.new(0,0,0,9),Size=UDim2.new(0,20,0,2),}},
{23,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="CustomColors",Pa
rent={1},Position=UDim2.new(0,5,0,210),Size=UDim2.new(0,180,0,90),}},
{24,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={23},Size=UDim2.new(1,0,0,20),Text="Custom Colors (RC =
Set)",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.86274516582489),Tex
tSize=14,TextXAlignment=0,}},
{25,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Gre
en",Parent={1},Position=UDim2.new(1,-63,0,233),Size=UDim2.new(0,52,0,16),}},
{26,"TextBox",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),Font=3,Name="Input",Parent={25},Position=UDim2.new(0,2,0,0),Size=UD
im2.new(0,50,0,16),Text="0",TextColor3=Color3.new(0.86274516582489,0.86274516582489
,0.86274516582489),TextSize=14,TextXAlignment=0,}},
{27,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name
="ArrowFrame",Parent={26},Position=UDim2.new(1,-
16,0,0),Size=UDim2.new(0,16,1,0),}},
{28,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Up",Parent={27},Size=UDim2.new(1,0,0,8),Text="",Text
Size=14,}},
{29,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={28},Size=UDim2.new(0,16,0,8),}},
{30,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={29},Position=UDim2.new(0,8,0,3),Size=UDim2.new(0,1,0,1),}},
{31,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={29},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{32,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={29},Position=UDim2.new(0,6,0,5),Size=UDim2.new(0,5,0,1),}},
{33,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Down",Parent={27},Position=UDim2.new(0,0,0,8),Size=U
Dim2.new(1,0,0,8),Text="",TextSize=14,}},
{34,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={33},Size=UDim2.new(0,16,0,8),}},
{35,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={34},Position=UDim2.new(0,8,0,5),Size=UDim2.new(0,1,0,1),}},
{36,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={34},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{37,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={34},Position=UDim2.new(0,6,0,3),Size=UDim2.new(0,5,0,1),}},
{38,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={25},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Green:",TextColor3=Color3.new(0.862745165824
89,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{39,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Hue
",Parent={1},Position=UDim2.new(1,-180,0,211),Size=UDim2.new(0,52,0,16),}},
{40,"TextBox",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),Font=3,Name="Input",Parent={39},Position=UDim2.new(0,2,0,0),Size=UD
im2.new(0,50,0,16),Text="0",TextColor3=Color3.new(0.86274516582489,0.86274516582489
,0.86274516582489),TextSize=14,TextXAlignment=0,}},
{41,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name
="ArrowFrame",Parent={40},Position=UDim2.new(1,-
16,0,0),Size=UDim2.new(0,16,1,0),}},
{42,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Up",Parent={41},Size=UDim2.new(1,0,0,8),Text="",Text
Size=14,}},
{43,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={42},Size=UDim2.new(0,16,0,8),}},
{44,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={43},Position=UDim2.new(0,8,0,3),Size=UDim2.new(0,1,0,1),}},
{45,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={43},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{46,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={43},Position=UDim2.new(0,6,0,5),Size=UDim2.new(0,5,0,1),}},
{47,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Down",Parent={41},Position=UDim2.new(0,0,0,8),Size=U
Dim2.new(1,0,0,8),Text="",TextSize=14,}},
{48,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={47},Size=UDim2.new(0,16,0,8),}},
{49,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={48},Position=UDim2.new(0,8,0,5),Size=UDim2.new(0,1,0,1),}},
{50,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={48},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{51,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={48},Position=UDim2.new(0,6,0,3),Size=UDim2.new(0,5,0,1),}},
{52,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={39},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Hue:",TextColor3=Color3.new(0.86274516582489
,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{53,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BorderColor3=Color3.new(0.21568627655506,0.2156
8627655506,0.21568627655506),Name="Preview",Parent={1},Position=UDim2.new(1,-
260,0,211),Size=UDim2.new(0,35,1,-245),}},
{54,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Red
",Parent={1},Position=UDim2.new(1,-63,0,211),Size=UDim2.new(0,52,0,16),}},
{55,"TextBox",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),Font=3,Name="Input",Parent={54},Position=UDim2.new(0,2,0,0),Size=UD
im2.new(0,50,0,16),Text="0",TextColor3=Color3.new(0.86274516582489,0.86274516582489
,0.86274516582489),TextSize=14,TextXAlignment=0,}},
{56,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name
="ArrowFrame",Parent={55},Position=UDim2.new(1,-
16,0,0),Size=UDim2.new(0,16,1,0),}},
{57,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Up",Parent={56},Size=UDim2.new(1,0,0,8),Text="",Text
Size=14,}},
{58,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={57},Size=UDim2.new(0,16,0,8),}},
{59,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={58},Position=UDim2.new(0,8,0,3),Size=UDim2.new(0,1,0,1),}},
{60,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={58},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{61,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={58},Position=UDim2.new(0,6,0,5),Size=UDim2.new(0,5,0,1),}},
{62,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Down",Parent={56},Position=UDim2.new(0,0,0,8),Size=U
Dim2.new(1,0,0,8),Text="",TextSize=14,}},
{63,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={62},Size=UDim2.new(0,16,0,8),}},
{64,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={63},Position=UDim2.new(0,8,0,5),Size=UDim2.new(0,1,0,1),}},
{65,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={63},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{66,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={63},Position=UDim2.new(0,6,0,3),Size=UDim2.new(0,5,0,1),}},
{67,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={54},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Red:",TextColor3=Color3.new(0.86274516582489
,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{68,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Sat
",Parent={1},Position=UDim2.new(1,-180,0,233),Size=UDim2.new(0,52,0,16),}},
{69,"TextBox",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),Font=3,Name="Input",Parent={68},Position=UDim2.new(0,2,0,0),Size=UD
im2.new(0,50,0,16),Text="0",TextColor3=Color3.new(0.86274516582489,0.86274516582489
,0.86274516582489),TextSize=14,TextXAlignment=0,}},
{70,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name
="ArrowFrame",Parent={69},Position=UDim2.new(1,-
16,0,0),Size=UDim2.new(0,16,1,0),}},
{71,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Up",Parent={70},Size=UDim2.new(1,0,0,8),Text="",Text
Size=14,}},
{72,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={71},Size=UDim2.new(0,16,0,8),}},
{73,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={72},Position=UDim2.new(0,8,0,3),Size=UDim2.new(0,1,0,1),}},
{74,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={72},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{75,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={72},Position=UDim2.new(0,6,0,5),Size=UDim2.new(0,5,0,1),}},
{76,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Down",Parent={70},Position=UDim2.new(0,0,0,8),Size=U
Dim2.new(1,0,0,8),Text="",TextSize=14,}},
{77,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={76},Size=UDim2.new(0,16,0,8),}},
{78,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={77},Position=UDim2.new(0,8,0,5),Size=UDim2.new(0,1,0,1),}},
{79,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={77},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{80,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={77},Position=UDim2.new(0,6,0,3),Size=UDim2.new(0,5,0,1),}},
{81,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={68},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Sat:",TextColor3=Color3.new(0.86274516582489
,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{82,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Val
",Parent={1},Position=UDim2.new(1,-180,0,255),Size=UDim2.new(0,52,0,16),}},
{83,"TextBox",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),Font=3,Name="Input",Parent={82},Position=UDim2.new(0,2,0,0),Size=UD
im2.new(0,50,0,16),Text="255",TextColor3=Color3.new(0.86274516582489,0.862745165824
89,0.86274516582489),TextSize=14,TextXAlignment=0,}},
{84,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name
="ArrowFrame",Parent={83},Position=UDim2.new(1,-
16,0,0),Size=UDim2.new(0,16,1,0),}},
{85,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Up",Parent={84},Size=UDim2.new(1,0,0,8),Text="",Text
Size=14,}},
{86,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={85},Size=UDim2.new(0,16,0,8),}},
{87,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={86},Position=UDim2.new(0,8,0,3),Size=UDim2.new(0,1,0,1),}},
{88,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={86},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{89,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={86},Position=UDim2.new(0,6,0,5),Size=UDim2.new(0,5,0,1),}},
{90,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,
BorderSizePixel=0,Font=3,Name="Down",Parent={84},Position=UDim2.new(0,0,0,8),Size=U
Dim2.new(1,0,0,8),Text="",TextSize=14,}},
{91,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={90},Size=UDim2.new(0,16,0,8),}},
{92,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={91},Position=UDim2.new(0,8,0,5),Size=UDim2.new(0,1,0,1),}},
{93,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={91},Position=UDim2.new(0,7,0,4),Size=UDim2.new(0,3,0,1),}},
{94,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={91},Position=UDim2.new(0,6,0,3),Size=UDim2.new(0,5,0,1),}},
{95,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={82},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Val:",TextColor3=Color3.new(0.86274516582489
,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{96,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,
0.2352941185236),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.215686
27655506),Font=3,Name="Cancel",Parent={1},Position=UDim2.new(1,-105,1,-
28),Size=UDim2.new(0,100,0,25),Text="Cancel",TextColor3=Color3.new(0.86274516582489
,0.86274516582489,0.86274516582489),TextSize=14,}},
{97,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,
0.2352941185236),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.215686
27655506),Font=3,Name="Ok",Parent={1},Position=UDim2.new(1,-210,1,-
28),Size=UDim2.new(0,100,0,25),Text="OK",TextColor3=Color3.new(0.86274516582489,0.8
6274516582489,0.86274516582489),TextSize=14,}},
{98,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BorderColor3=Color3.new(0.21568627655506,0.2156
8627655506,0.21568627655506),Image="rbxassetid://
1072518502",Name="ColorStrip",Parent={1},Position=UDim2.new(1,-
30,0,5),Size=UDim2.new(0,13,0,200),}},
{99,"Frame",
{BackgroundColor3=Color3.new(0.3137255012989,0.3137255012989,0.3137255012989),Backg
roundTransparency=1,BorderSizePixel=0,Name="ArrowFrame",Parent={1},Position=UDim2.n
ew(1,-16,0,1),Size=UDim2.new(0,5,0,208),}},
{100,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={99},Position=UDim2.new(0,-2,0,-
4),Size=UDim2.new(0,8,0,16),}},
{101,"Frame",
{BackgroundColor3=Color3.new(0,0,0),BorderSizePixel=0,Parent={100},Position=UDim2.n
ew(0,2,0,8),Size=UDim2.new(0,1,0,1),}},
{102,"Frame",
{BackgroundColor3=Color3.new(0,0,0),BorderSizePixel=0,Parent={100},Position=UDim2.n
ew(0,3,0,7),Size=UDim2.new(0,1,0,3),}},
{103,"Frame",
{BackgroundColor3=Color3.new(0,0,0),BorderSizePixel=0,Parent={100},Position=UDim2.n
ew(0,4,0,6),Size=UDim2.new(0,1,0,5),}},
{104,"Frame",
{BackgroundColor3=Color3.new(0,0,0),BorderSizePixel=0,Parent={100},Position=UDim2.n
ew(0,5,0,5),Size=UDim2.new(0,1,0,7),}},
{105,"Frame",
{BackgroundColor3=Color3.new(0,0,0),BorderSizePixel=0,Parent={100},Position=UDim2.n
ew(0,6,0,4),Size=UDim2.new(0,1,0,9),}},
})
local window = Lib.Window.new()
window.Resizable = false
window.Alignable = false
window:SetTitle("Color Picker")
window:Resize(450,330)
for i,v in pairs(guiContents:GetChildren()) do
v.Parent = window.GuiElems.Content
end
newMt.Window = window
newMt.Gui = window.Gui
local pickerGui = window.Gui.Main
local pickerTopBar = pickerGui.TopBar
local pickerFrame = pickerGui.Content
local colorSpace = pickerFrame.ColorSpaceFrame.ColorSpace
local colorStrip = pickerFrame.ColorStrip
local previewFrame = pickerFrame.Preview
local basicColorsFrame = pickerFrame.BasicColors
local customColorsFrame = pickerFrame.CustomColors
local okButton = pickerFrame.Ok
local cancelButton = pickerFrame.Cancel
local closeButton = pickerTopBar.Close

local colorScope = colorSpace.Scope


local colorArrow = pickerFrame.ArrowFrame.Arrow

local hueInput = pickerFrame.Hue.Input


local satInput = pickerFrame.Sat.Input
local valInput = pickerFrame.Val.Input

local redInput = pickerFrame.Red.Input


local greenInput = pickerFrame.Green.Input
local blueInput = pickerFrame.Blue.Input

local user = clonerefs(game:GetService("UserInputService"))


local mouse =
clonerefs(game:GetService("Players")).LocalPlayer:GetMouse()

local hue,sat,val = 0,0,1


local red,green,blue = 1,1,1
local chosenColor = Color3.new(0,0,0)

local basicColors =
{Color3.new(0,0,0),Color3.new(0.66666668653488,0,0),Color3.new(0,0.33333334326744,0
),Color3.new(0.66666668653488,0.33333334326744,0),Color3.new(0,0.66666668653488,0),
Color3.new(0.66666668653488,0.66666668653488,0),Color3.new(0,1,0),Color3.new(0.6666
6668653488,1,0),Color3.new(0,0,0.49803924560547),Color3.new(0.66666668653488,0,0.49
803924560547),Color3.new(0,0.33333334326744,0.49803924560547),Color3.new(0.66666668
653488,0.33333334326744,0.49803924560547),Color3.new(0,0.66666668653488,0.498039245
60547),Color3.new(0.66666668653488,0.66666668653488,0.49803924560547),Color3.new(0,
1,0.49803924560547),Color3.new(0.66666668653488,1,0.49803924560547),Color3.new(0,0,
1),Color3.new(0.66666668653488,0,1),Color3.new(0,0.33333334326744,1),Color3.new(0.6
6666668653488,0.33333334326744,1),Color3.new(0,0.66666668653488,1),Color3.new(0.666
66668653488,0.66666668653488,1),Color3.new(0,1,1),Color3.new(0.66666668653488,1,1),
Color3.new(0.33333334326744,0,0),Color3.new(1,0,0),Color3.new(0.33333334326744,0.33
333334326744,0),Color3.new(1,0.33333334326744,0),Color3.new(0.33333334326744,0.6666
6668653488,0),Color3.new(1,0.66666668653488,0),Color3.new(0.33333334326744,1,0),Col
or3.new(1,1,0),Color3.new(0.33333334326744,0,0.49803924560547),Color3.new(1,0,0.498
03924560547),Color3.new(0.33333334326744,0.33333334326744,0.49803924560547),Color3.
new(1,0.33333334326744,0.49803924560547),Color3.new(0.33333334326744,0.666666686534
88,0.49803924560547),Color3.new(1,0.66666668653488,0.49803924560547),Color3.new(0.3
3333334326744,1,0.49803924560547),Color3.new(1,1,0.49803924560547),Color3.new(0.333
33334326744,0,1),Color3.new(1,0,1),Color3.new(0.33333334326744,0.33333334326744,1),
Color3.new(1,0.33333334326744,1),Color3.new(0.33333334326744,0.66666668653488,1),Co
lor3.new(1,0.66666668653488,1),Color3.new(0.33333334326744,1,1),Color3.new(1,1,1)}
local customColors = {}

local function updateColor(noupdate)


local relativeX,relativeY,relativeStripY = 219 - hue*219,
199 - sat*199, 199 - val*199
local hsvColor = Color3.fromHSV(hue,sat,val)

if noupdate == 2 or not noupdate then


hueInput.Text = tostring(math.ceil(359*hue))
satInput.Text = tostring(math.ceil(255*sat))
valInput.Text = tostring(math.floor(255*val))
end
if noupdate == 1 or not noupdate then
redInput.Text = tostring(math.floor(255*red))
greenInput.Text = tostring(math.floor(255*green))
blueInput.Text = tostring(math.floor(255*blue))
end

chosenColor = Color3.new(red,green,blue)

colorScope.Position = UDim2.new(0,relativeX-9,0,relativeY-
9)
colorStrip.ImageColor3 = Color3.fromHSV(hue,sat,1)
colorArrow.Position = UDim2.new(0,-2,0,relativeStripY-4)
previewFrame.BackgroundColor3 = chosenColor

newMt.Color = chosenColor
newMt.OnPreview:Fire(chosenColor)
end

local function colorSpaceInput()


local relativeX = mouse.X - colorSpace.AbsolutePosition.X
local relativeY = mouse.Y - colorSpace.AbsolutePosition.Y

if relativeX < 0 then relativeX = 0 elseif relativeX > 219


then relativeX = 219 end
if relativeY < 0 then relativeY = 0 elseif relativeY > 199
then relativeY = 199 end

hue = (219 - relativeX)/219


sat = (199 - relativeY)/199

local hsvColor = Color3.fromHSV(hue,sat,val)


red,green,blue = hsvColor.r,hsvColor.g,hsvColor.b

updateColor()
end
local function colorStripInput()
local relativeY = mouse.Y - colorStrip.AbsolutePosition.Y

if relativeY < 0 then relativeY = 0 elseif relativeY > 199


then relativeY = 199 end

val = (199 - relativeY)/199

local hsvColor = Color3.fromHSV(hue,sat,val)


red,green,blue = hsvColor.r,hsvColor.g,hsvColor.b

updateColor()
end

local function hookButtons(frame,func)


frame.ArrowFrame.Up.InputBegan:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
frame.ArrowFrame.Up.BackgroundTransparency =
0.5
elseif input.UserInputType ==
Enum.UserInputType.MouseButton1 then
local releaseEvent,runEvent

local startTime = tick()


local pressing = true
local startNum = tonumber(frame.Text)

if not startNum then return end

releaseEvent =
user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
pressing = false
end)

startNum = startNum + 1
func(startNum)
while pressing do
if tick()-startTime > 0.3 then
startNum = startNum + 1
func(startNum)
end
wait(0.1)
end
end
end)

frame.ArrowFrame.Up.InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
frame.ArrowFrame.Up.BackgroundTransparency = 1
end
end)

frame.ArrowFrame.Down.InputBegan:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
frame.ArrowFrame.Down.BackgroundTransparency =
0.5
elseif input.UserInputType ==
Enum.UserInputType.MouseButton1 then
local releaseEvent,runEvent

local startTime = tick()


local pressing = true
local startNum = tonumber(frame.Text)

if not startNum then return end

releaseEvent =
user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
pressing = false
end)

startNum = startNum - 1
func(startNum)
while pressing do
if tick()-startTime > 0.3 then
startNum = startNum - 1
func(startNum)
end
wait(0.1)
end
end
end)

frame.ArrowFrame.Down.InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
frame.ArrowFrame.Down.BackgroundTransparency =
1
end
end)
end

colorSpace.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
then
local releaseEvent,mouseEvent

releaseEvent =
user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
mouseEvent:Disconnect()
end)

mouseEvent =
user.InputChanged:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
colorSpaceInput()
end
end)

colorSpaceInput()
end
end)

colorStrip.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
then
local releaseEvent,mouseEvent

releaseEvent =
user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
releaseEvent:Disconnect()
mouseEvent:Disconnect()
end)

mouseEvent =
user.InputChanged:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
colorStripInput()
end
end)

colorStripInput()
end
end)

local function updateHue(str)


local num = tonumber(str)
if num then
hue = math.clamp(math.floor(num),0,359)/359
local hsvColor = Color3.fromHSV(hue,sat,val)
red,green,blue = hsvColor.r,hsvColor.g,hsvColor.b
hueInput.Text = tostring(hue*359)
updateColor(1)
end
end
hueInput.FocusLost:Connect(function() updateHue(hueInput.Text)
end) hookButtons(hueInput,updateHue)

local function updateSat(str)


local num = tonumber(str)
if num then
sat = math.clamp(math.floor(num),0,255)/255
local hsvColor = Color3.fromHSV(hue,sat,val)
red,green,blue = hsvColor.r,hsvColor.g,hsvColor.b
satInput.Text = tostring(sat*255)
updateColor(1)
end
end
satInput.FocusLost:Connect(function() updateSat(satInput.Text)
end) hookButtons(satInput,updateSat)
local function updateVal(str)
local num = tonumber(str)
if num then
val = math.clamp(math.floor(num),0,255)/255
local hsvColor = Color3.fromHSV(hue,sat,val)
red,green,blue = hsvColor.r,hsvColor.g,hsvColor.b
valInput.Text = tostring(val*255)
updateColor(1)
end
end
valInput.FocusLost:Connect(function() updateVal(valInput.Text)
end) hookButtons(valInput,updateVal)

local function updateRed(str)


local num = tonumber(str)
if num then
red = math.clamp(math.floor(num),0,255)/255
local newColor = Color3.new(red,green,blue)
hue,sat,val = Color3.toHSV(newColor)
redInput.Text = tostring(red*255)
updateColor(2)
end
end
redInput.FocusLost:Connect(function() updateRed(redInput.Text)
end) hookButtons(redInput,updateRed)

local function updateGreen(str)


local num = tonumber(str)
if num then
green = math.clamp(math.floor(num),0,255)/255
local newColor = Color3.new(red,green,blue)
hue,sat,val = Color3.toHSV(newColor)
greenInput.Text = tostring(green*255)
updateColor(2)
end
end
greenInput.FocusLost:Connect(function()
updateGreen(greenInput.Text) end) hookButtons(greenInput,updateGreen)

local function updateBlue(str)


local num = tonumber(str)
if num then
blue = math.clamp(math.floor(num),0,255)/255
local newColor = Color3.new(red,green,blue)
hue,sat,val = Color3.toHSV(newColor)
blueInput.Text = tostring(blue*255)
updateColor(2)
end
end
blueInput.FocusLost:Connect(function() updateBlue(blueInput.Text)
end) hookButtons(blueInput,updateBlue)

local colorChoice = Instance.new("TextButton")


colorChoice.Name = "Choice"
colorChoice.Size = UDim2.new(0,25,0,18)
colorChoice.BorderColor3 = Color3.fromRGB(55,55,55)
colorChoice.Text = ""
colorChoice.AutoButtonColor = false
local row = 0
local column = 0
for i,v in pairs(basicColors) do
local newColor = colorChoice:Clone()
newColor.BackgroundColor3 = v
newColor.Position = UDim2.new(0,1 + 30*column,0,21 +
23*row)

newColor.MouseButton1Click:Connect(function()
red,green,blue = v.r,v.g,v.b
local newColor = Color3.new(red,green,blue)
hue,sat,val = Color3.toHSV(newColor)
updateColor()
end)

newColor.Parent = basicColorsFrame
column = column + 1
if column == 6 then row = row + 1 column = 0 end
end

row = 0
column = 0
for i = 1,12 do
local color = customColors[i] or Color3.new(0,0,0)
local newColor = colorChoice:Clone()
newColor.BackgroundColor3 = color
newColor.Position = UDim2.new(0,1 + 30*column,0,20 +
23*row)

newColor.MouseButton1Click:Connect(function()
local curColor = customColors[i] or Color3.new(0,0,0)
red,green,blue = curColor.r,curColor.g,curColor.b
hue,sat,val = Color3.toHSV(curColor)
updateColor()
end)

newColor.MouseButton2Click:Connect(function()
customColors[i] = chosenColor
newColor.BackgroundColor3 = chosenColor
end)

newColor.Parent = customColorsFrame
column = column + 1
if column == 6 then row = row + 1 column = 0 end
end

okButton.MouseButton1Click:Connect(function()
newMt.OnSelect:Fire(chosenColor) window:Close() end)
okButton.InputBegan:Connect(function(input) if
input.UserInputType == Enum.UserInputType.MouseMovement then
okButton.BackgroundTransparency = 0.4 end end)
okButton.InputEnded:Connect(function(input) if
input.UserInputType == Enum.UserInputType.MouseMovement then
okButton.BackgroundTransparency = 0 end end)

cancelButton.MouseButton1Click:Connect(function()
newMt.OnCancel:Fire() window:Close() end)
cancelButton.InputBegan:Connect(function(input) if
input.UserInputType == Enum.UserInputType.MouseMovement then
cancelButton.BackgroundTransparency = 0.4 end end)
cancelButton.InputEnded:Connect(function(input) if
input.UserInputType == Enum.UserInputType.MouseMovement then
cancelButton.BackgroundTransparency = 0 end end)

updateColor()

newMt.SetColor = function(self,color)
red,green,blue = color.r,color.g,color.b
hue,sat,val = Color3.toHSV(color)
updateColor()
end

newMt.Show = function(self)
self.Window:Show()
end

return newMt
end

return {new = new}


end)()

Lib.NumberSequenceEditor = (function()
local function new() -- TODO: Convert to newer class model
local newMt = setmetatable({},{})
newMt.OnSelect = Lib.Signal.new()
newMt.OnCancel = Lib.Signal.new()
newMt.OnPreview = Lib.Signal.new()

local guiContents = create({


{1,"Frame",
{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Bo
rderSizePixel=0,ClipsDescendants=true,Name="Content",Position=UDim2.new(0,0,0,20),S
ize=UDim2.new(1,0,1,-20),}},
{2,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Tim
e",Parent={1},Position=UDim2.new(0,40,0,210),Size=UDim2.new(0,60,0,20),}},
{3,"TextBox",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),ClipsDescendants=true,Font=3,Name="Input",Parent={2},Position=UDim2
.new(0,2,0,0),Size=UDim2.new(0,58,0,20),Text="0",TextColor3=Color3.new(0.8627451658
2489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=0,}},
{4,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={2},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Time",TextColor3=Color3.new(0.86274516582489
,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{5,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,
0.2352941185236),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.215686
27655506),Font=3,Name="Close",Parent={1},Position=UDim2.new(1,-
90,0,210),Size=UDim2.new(0,80,0,20),Text="Close",TextColor3=Color3.new(0.8627451658
2489,0.86274516582489,0.86274516582489),TextSize=14,}},
{6,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,
0.2352941185236),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.215686
27655506),Font=3,Name="Reset",Parent={1},Position=UDim2.new(1,-
180,0,210),Size=UDim2.new(0,80,0,20),Text="Reset",TextColor3=Color3.new(0.862745165
82489,0.86274516582489,0.86274516582489),TextSize=14,}},
{7,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,
0.2352941185236),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.215686
27655506),Font=3,Name="Delete",Parent={1},Position=UDim2.new(0,380,0,210),Size=UDim
2.new(0,80,0,20),Text="Delete",TextColor3=Color3.new(0.86274516582489,0.86274516582
489,0.86274516582489),TextSize=14,}},
{8,"Frame",
{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Bo
rderColor3=Color3.new(0.21568627655506,0.21568627655506,0.21568627655506),Name="Num
berLineOutlines",Parent={1},Position=UDim2.new(0,10,0,20),Size=UDim2.new(1,-
20,0,170),}},
{9,"Frame",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),Name="NumberLine",Parent={1},Position=UDim2.new(0,10,0,20),Size=UDi
m2.new(1,-20,0,170),}},
{10,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Val
ue",Parent={1},Position=UDim2.new(0,170,0,210),Size=UDim2.new(0,60,0,20),}},
{11,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={10},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Value",TextColor3=Color3.new(0.8627451658248
9,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{12,"TextBox",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),ClipsDescendants=true,Font=3,Name="Input",Parent={10},Position=UDim
2.new(0,2,0,0),Size=UDim2.new(0,58,0,20),Text="0",TextColor3=Color3.new(0.862745165
82489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=0,}},
{13,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Env
elope",Parent={1},Position=UDim2.new(0,300,0,210),Size=UDim2.new(0,60,0,20),}},
{14,"TextBox",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),ClipsDescendants=true,Font=3,Name="Input",Parent={13},Position=UDim
2.new(0,2,0,0),Size=UDim2.new(0,58,0,20),Text="0",TextColor3=Color3.new(0.862745165
82489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=0,}},
{15,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={13},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Envelope",TextColor3=Color3.new(0.8627451658
2489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
})
local window = Lib.Window.new()
window.Resizable = false
window:Resize(680,265)
window:SetTitle("NumberSequence Editor")
newMt.Window = window
newMt.Gui = window.Gui
for i,v in pairs(guiContents:GetChildren()) do
v.Parent = window.GuiElems.Content
end
local gui = window.Gui
local pickerGui = gui.Main
local pickerTopBar = pickerGui.TopBar
local pickerFrame = pickerGui.Content
local numberLine = pickerFrame.NumberLine
local numberLineOutlines = pickerFrame.NumberLineOutlines
local timeBox = pickerFrame.Time.Input
local valueBox = pickerFrame.Value.Input
local envelopeBox = pickerFrame.Envelope.Input
local deleteButton = pickerFrame.Delete
local resetButton = pickerFrame.Reset
local closeButton = pickerFrame.Close
local topClose = pickerTopBar.Close

local points = {{1,0,3},{8,0.05,1},{5,0.6,2},{4,0.7,4},{6,1,4}}


local lines = {}
local eLines = {}
local beginPoint = points[1]
local endPoint = points[#points]
local currentlySelected = nil
local currentPoint = nil
local resetSequence = nil

local user = clonerefs(game:GetService("UserInputService"))


local mouse =
clonerefs(game:GetService("Players")).LocalPlayer:GetMouse()

for i = 2,10 do
local newLine = Instance.new("Frame")
newLine.BackgroundTransparency = 0.5
newLine.BackgroundColor3 = Color3.new(96/255,96/255,96/255)
newLine.BorderSizePixel = 0
newLine.Size = UDim2.new(0,1,1,0)
newLine.Position = UDim2.new((i-1)/(11-1),0,0,0)
newLine.Parent = numberLineOutlines
end

for i = 2,4 do
local newLine = Instance.new("Frame")
newLine.BackgroundTransparency = 0.5
newLine.BackgroundColor3 = Color3.new(96/255,96/255,96/255)
newLine.BorderSizePixel = 0
newLine.Size = UDim2.new(1,0,0,1)
newLine.Position = UDim2.new(0,0,(i-1)/(5-1),0)
newLine.Parent = numberLineOutlines
end

local lineTemp = Instance.new("Frame")


lineTemp.BackgroundColor3 = Color3.new(0,0,0)
lineTemp.BorderSizePixel = 0
lineTemp.Size = UDim2.new(0,1,0,1)

local sequenceLine = Instance.new("Frame")


sequenceLine.BackgroundColor3 = Color3.new(0,0,0)
sequenceLine.BorderSizePixel = 0
sequenceLine.Size = UDim2.new(0,1,0,0)

for i = 1,numberLine.AbsoluteSize.X do
local line = sequenceLine:Clone()
eLines[i] = line
line.Name = "E"..tostring(i)
line.BackgroundTransparency = 0.5
line.BackgroundColor3 = Color3.new(199/255,44/255,28/255)
line.Position = UDim2.new(0,i-1,0,0)
line.Parent = numberLine
end

for i = 1,numberLine.AbsoluteSize.X do
local line = sequenceLine:Clone()
lines[i] = line
line.Name = tostring(i)
line.Position = UDim2.new(0,i-1,0,0)
line.Parent = numberLine
end

local envelopeDrag = Instance.new("Frame")


envelopeDrag.BackgroundTransparency = 1
envelopeDrag.BackgroundColor3 = Color3.new(0,0,0)
envelopeDrag.BorderSizePixel = 0
envelopeDrag.Size = UDim2.new(0,7,0,20)
envelopeDrag.Visible = false
envelopeDrag.ZIndex = 2
local envelopeDragLine = Instance.new("Frame",envelopeDrag)
envelopeDragLine.Name = "Line"
envelopeDragLine.BackgroundColor3 = Color3.new(0,0,0)
envelopeDragLine.BorderSizePixel = 0
envelopeDragLine.Position = UDim2.new(0,3,0,0)
envelopeDragLine.Size = UDim2.new(0,1,0,20)
envelopeDragLine.ZIndex = 2

local envelopeDragTop,envelopeDragBottom =
envelopeDrag:Clone(),envelopeDrag:Clone()
envelopeDragTop.Parent = numberLine
envelopeDragBottom.Parent = numberLine

local function buildSequence()


local newPoints = {}
for i,v in pairs(points) do

table.insert(newPoints,NumberSequenceKeypoint.new(v[2],v[1],v[3]))
end
newMt.Sequence = NumberSequence.new(newPoints)
newMt.OnSelect:Fire(newMt.Sequence)
end

local function round(num,places)


local multi = 10^places
return math.floor(num*multi + 0.5)/multi
end

local function updateInputs(point)


if point then
currentPoint = point
local rawT,rawV,rawE = point[2],point[1],point[3]
timeBox.Text = round(rawT,(rawT < 0.01 and 5) or
(rawT < 0.1 and 4) or 3)
valueBox.Text = round(rawV,(rawV < 0.01 and 5) or
(rawV < 0.1 and 4) or (rawV < 1 and 3) or 2)
envelopeBox.Text = round(rawE,(rawE < 0.01 and 5) or
(rawE < 0.1 and 4) or (rawV < 1 and 3) or 2)

local envelopeDistance =
numberLine.AbsoluteSize.Y*(point[3]/10)
envelopeDragTop.Position =
UDim2.new(0,point[4].Position.X.Offset-1,0,point[4].Position.Y.Offset-
envelopeDistance-17)
envelopeDragTop.Visible = true
envelopeDragBottom.Position =
UDim2.new(0,point[4].Position.X.Offset-
1,0,point[4].Position.Y.Offset+envelopeDistance+2)
envelopeDragBottom.Visible = true
end
end

envelopeDragTop.InputBegan:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1
or not currentPoint or Lib.CheckMouseInGui(currentPoint[4].Select) then return end
local mouseEvent,releaseEvent
local maxSize = numberLine.AbsoluteSize.Y

local mouseDelta =
math.abs(envelopeDragTop.AbsolutePosition.Y - mouse.Y)

envelopeDragTop.Line.Position = UDim2.new(0,2,0,0)
envelopeDragTop.Line.Size = UDim2.new(0,3,0,20)

releaseEvent = user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
mouseEvent:Disconnect()
releaseEvent:Disconnect()
envelopeDragTop.Line.Position = UDim2.new(0,3,0,0)
envelopeDragTop.Line.Size = UDim2.new(0,1,0,20)
end)

mouseEvent = user.InputChanged:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
local topDiff =
(currentPoint[4].AbsolutePosition.Y+2)-(mouse.Y-mouseDelta)-19
local newEnvelope =
10*(math.max(topDiff,0)/maxSize)
local maxEnvelope =
math.min(currentPoint[1],10-currentPoint[1])
currentPoint[3] =
math.min(newEnvelope,maxEnvelope)
newMt:Redraw()
buildSequence()
updateInputs(currentPoint)
end
end)
end)

envelopeDragBottom.InputBegan:Connect(function(input)
if input.UserInputType ~= Enum.UserInputType.MouseButton1
or not currentPoint or Lib.CheckMouseInGui(currentPoint[4].Select) then return end
local mouseEvent,releaseEvent
local maxSize = numberLine.AbsoluteSize.Y

local mouseDelta =
math.abs(envelopeDragBottom.AbsolutePosition.Y - mouse.Y)

envelopeDragBottom.Line.Position = UDim2.new(0,2,0,0)
envelopeDragBottom.Line.Size = UDim2.new(0,3,0,20)

releaseEvent = user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
mouseEvent:Disconnect()
releaseEvent:Disconnect()
envelopeDragBottom.Line.Position = UDim2.new(0,3,0,0)
envelopeDragBottom.Line.Size = UDim2.new(0,1,0,20)
end)

mouseEvent = user.InputChanged:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
local bottomDiff = (mouse.Y+(20-mouseDelta))-
(currentPoint[4].AbsolutePosition.Y+2)-19
local newEnvelope =
10*(math.max(bottomDiff,0)/maxSize)
local maxEnvelope =
math.min(currentPoint[1],10-currentPoint[1])
currentPoint[3] =
math.min(newEnvelope,maxEnvelope)
newMt:Redraw()
buildSequence()
updateInputs(currentPoint)
end
end)
end)

local function placePoint(point)


local newPoint = Instance.new("Frame")
newPoint.Name = "Point"
newPoint.BorderSizePixel = 0
newPoint.Size = UDim2.new(0,5,0,5)
newPoint.Position =
UDim2.new(0,math.floor((numberLine.AbsoluteSize.X-1) * point[2])-
2,0,numberLine.AbsoluteSize.Y*(10-point[1])/10-2)
newPoint.BackgroundColor3 = Color3.new(0,0,0)

local newSelect = Instance.new("Frame")


newSelect.Name = "Select"
newSelect.BackgroundTransparency = 1
newSelect.BackgroundColor3 =
Color3.new(199/255,44/255,28/255)
newSelect.Position = UDim2.new(0,-2,0,-2)
newSelect.Size = UDim2.new(0,9,0,9)
newSelect.Parent = newPoint

newPoint.Parent = numberLine

newSelect.InputBegan:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
for i,v in pairs(points) do
v[4].Select.BackgroundTransparency = 1 end
newSelect.BackgroundTransparency = 0
updateInputs(point)
end
if input.UserInputType ==
Enum.UserInputType.MouseButton1 and not currentlySelected then
currentPoint = point
local mouseEvent,releaseEvent
currentlySelected = true
newSelect.BackgroundColor3 =
Color3.new(249/255,191/255,59/255)

local oldEnvelope = point[3]

releaseEvent =
user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
mouseEvent:Disconnect()
releaseEvent:Disconnect()
currentlySelected = nil
newSelect.BackgroundColor3 =
Color3.new(199/255,44/255,28/255)
end)

mouseEvent =
user.InputChanged:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
local maxX =
numberLine.AbsoluteSize.X-1
local relativeX = mouse.X -
numberLine.AbsolutePosition.X
if relativeX < 0 then relativeX = 0
end
if relativeX > maxX then relativeX
= maxX end
local maxY =
numberLine.AbsoluteSize.Y-1
local relativeY = mouse.Y -
numberLine.AbsolutePosition.Y
if relativeY < 0 then relativeY = 0
end
if relativeY > maxY then relativeY
= maxY end
if point ~= beginPoint and point ~=
endPoint then
point[2] = relativeX/maxX
end
point[1] = 10-(relativeY/maxY)*10
local maxEnvelope =
math.min(point[1],10-point[1])
point[3] =
math.min(oldEnvelope,maxEnvelope)
newMt:Redraw()
updateInputs(point)
for i,v in pairs(points) do
v[4].Select.BackgroundTransparency = 1 end
newSelect.BackgroundTransparency =
0
buildSequence()
end
end)
end
end)

return newPoint
end

local function placePoints()


for i,v in pairs(points) do
v[4] = placePoint(v)
end
end

local function redraw(self)


local numberLineSize = numberLine.AbsoluteSize
table.sort(points,function(a,b) return a[2] < b[2] end)
for i,v in pairs(points) do
v[4].Position =
UDim2.new(0,math.floor((numberLineSize.X-1) * v[2])-2,0,(numberLineSize.Y-1)*(10-
v[1])/10-2)
end
lines[1].Size = UDim2.new(0,1,0,0)
for i = 1,#points-1 do
local fromPoint = points[i]
local toPoint = points[i+1]
local deltaY = toPoint[4].Position.Y.Offset-
fromPoint[4].Position.Y.Offset
local deltaX = toPoint[4].Position.X.Offset-
fromPoint[4].Position.X.Offset
local slope = deltaY/deltaX

local fromEnvelope = fromPoint[3]


local nextEnvelope = toPoint[3]

local currentRise = math.abs(slope)


local totalRise = 0
local maxRise =
math.abs(toPoint[4].Position.Y.Offset-fromPoint[4].Position.Y.Offset)

for lineCount =
math.min(fromPoint[4].Position.X.Offset+1,toPoint[4].Position.X.Offset),toPoint[4].
Position.X.Offset do
if deltaX == 0 and deltaY == 0 then return end
local riseNow = math.floor(currentRise)
local line = lines[lineCount+3]
if line then
if totalRise+riseNow > maxRise then
riseNow = maxRise-totalRise end
if math.sign(slope) == -1 then
line.Position =
UDim2.new(0,lineCount+2,0,fromPoint[4].Position.Y.Offset + -(totalRise+riseNow)+2)
else
line.Position =
UDim2.new(0,lineCount+2,0,fromPoint[4].Position.Y.Offset + totalRise+2)
end
line.Size =
UDim2.new(0,1,0,math.max(riseNow,1))
end
totalRise = totalRise + riseNow
currentRise = currentRise - riseNow +
math.abs(slope)

local envPercent = (lineCount-


fromPoint[4].Position.X.Offset)/(toPoint[4].Position.X.Offset-
fromPoint[4].Position.X.Offset)
local envLerp = fromEnvelope+(nextEnvelope-
fromEnvelope)*envPercent
local relativeSize =
(envLerp/10)*numberLineSize.Y

local line = eLines[lineCount + 3]


if line then
line.Position =
UDim2.new(0,lineCount+2,0,lines[lineCount+3].Position.Y.Offset-
math.floor(relativeSize))
line.Size =
UDim2.new(0,1,0,math.floor(relativeSize*2))
end
end
end
end
newMt.Redraw = redraw

local function loadSequence(self,seq)


resetSequence = seq
for i,v in pairs(points) do if v[4] then v[4]:Destroy() end
end
points = {}
for i,v in pairs(seq.Keypoints) do
local maxEnvelope = math.min(v.Value,10-v.Value)
local newPoint =
{v.Value,v.Time,math.min(v.Envelope,maxEnvelope)}
newPoint[4] = placePoint(newPoint)
table.insert(points,newPoint)
end
beginPoint = points[1]
endPoint = points[#points]
currentlySelected = nil
redraw()
envelopeDragTop.Visible = false
envelopeDragBottom.Visible = false
end
newMt.SetSequence = loadSequence

timeBox.FocusLost:Connect(function()
local point = currentPoint
local num = tonumber(timeBox.Text)
if point and num and point ~= beginPoint and point ~=
endPoint then
num = math.clamp(num,0,1)
point[2] = num
redraw()
buildSequence()
updateInputs(point)
end
end)

valueBox.FocusLost:Connect(function()
local point = currentPoint
local num = tonumber(valueBox.Text)
if point and num then
local oldEnvelope = point[3]
num = math.clamp(num,0,10)
point[1] = num
local maxEnvelope = math.min(point[1],10-point[1])
point[3] = math.min(oldEnvelope,maxEnvelope)
redraw()
buildSequence()
updateInputs(point)
end
end)

envelopeBox.FocusLost:Connect(function()
local point = currentPoint
local num = tonumber(envelopeBox.Text)
if point and num then
num = math.clamp(num,0,5)
local maxEnvelope = math.min(point[1],10-point[1])
point[3] = math.min(num,maxEnvelope)
redraw()
buildSequence()
updateInputs(point)
end
end)

local function buttonAnimations(button,inverse)


button.InputBegan:Connect(function(input) if
input.UserInputType == Enum.UserInputType.MouseMovement then
button.BackgroundTransparency = (inverse and 0.5 or 0.4) end end)
button.InputEnded:Connect(function(input) if
input.UserInputType == Enum.UserInputType.MouseMovement then
button.BackgroundTransparency = (inverse and 1 or 0) end end)
end

numberLine.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
and #points < 20 then
if Lib.CheckMouseInGui(envelopeDragTop) or
Lib.CheckMouseInGui(envelopeDragBottom) then return end
for i,v in pairs(points) do
if Lib.CheckMouseInGui(v[4].Select) then return
end
end
local maxX = numberLine.AbsoluteSize.X-1
local relativeX = mouse.X -
numberLine.AbsolutePosition.X
if relativeX < 0 then relativeX = 0 end
if relativeX > maxX then relativeX = maxX end
local maxY = numberLine.AbsoluteSize.Y-1
local relativeY = mouse.Y -
numberLine.AbsolutePosition.Y
if relativeY < 0 then relativeY = 0 end
if relativeY > maxY then relativeY = maxY end
local raw = relativeX/maxX
local newPoint = {10-(relativeY/maxY)*10,raw,0}
newPoint[4] = placePoint(newPoint)
table.insert(points,newPoint)
redraw()
buildSequence()
end
end)

deleteButton.MouseButton1Click:Connect(function()
if currentPoint and currentPoint ~= beginPoint and
currentPoint ~= endPoint then
for i,v in pairs(points) do
if v == currentPoint then
v[4]:Destroy()
table.remove(points,i)
break
end
end
currentlySelected = nil
redraw()
buildSequence()
updateInputs(points[1])
end
end)

resetButton.MouseButton1Click:Connect(function()
if resetSequence then
newMt:SetSequence(resetSequence)
buildSequence()
end
end)

closeButton.MouseButton1Click:Connect(function()
window:Close()
end)

buttonAnimations(deleteButton)
buttonAnimations(resetButton)
buttonAnimations(closeButton)

placePoints()
redraw()

newMt.Show = function(self)
window:Show()
end

return newMt
end

return {new = new}


end)()

Lib.ColorSequenceEditor = (function() -- TODO: Convert to newer class model


local function new()
local newMt = setmetatable({},{})
newMt.OnSelect = Lib.Signal.new()
newMt.OnCancel = Lib.Signal.new()
newMt.OnPreview = Lib.Signal.new()
newMt.OnPickColor = Lib.Signal.new()

local guiContents = create({


{1,"Frame",
{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Bo
rderSizePixel=0,ClipsDescendants=true,Name="Content",Position=UDim2.new(0,0,0,20),S
ize=UDim2.new(1,0,1,-20),}},
{2,"Frame",
{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Bo
rderColor3=Color3.new(0.21568627655506,0.21568627655506,0.21568627655506),Name="Col
orLine",Parent={1},Position=UDim2.new(0,10,0,5),Size=UDim2.new(1,-20,0,70),}},
{3,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BorderSizePixel=0,Name="Gradient",Parent={2},Si
ze=UDim2.new(1,0,1,0),}},
{4,"UIGradient",{Parent={3},}},
{5,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name
="Arrows",Parent={1},Position=UDim2.new(0,1,0,73),Size=UDim2.new(1,-2,0,16),}},
{6,"Frame",
{BackgroundColor3=Color3.new(0,0,0),BackgroundTransparency=0.5,BorderSizePixel=0,Na
me="Cursor",Parent={1},Position=UDim2.new(0,10,0,0),Size=UDim2.new(0,1,0,80),}},
{7,"Frame",
{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),Bo
rderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Tim
e",Parent={1},Position=UDim2.new(0,40,0,95),Size=UDim2.new(0,100,0,20),}},
{8,"TextBox",
{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),Ba
ckgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.
37647062540054),ClipsDescendants=true,Font=3,Name="Input",Parent={7},Position=UDim2
.new(0,2,0,0),Size=UDim2.new(0,98,0,20),Text="0",TextColor3=Color3.new(0.8627451658
2489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=0,}},
{9,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={7},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Time",TextColor3=Color3.new(0.86274516582489
,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{10,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BorderColor3=Color3.new(0.21568627655506,0.2156
8627655506,0.21568627655506),Name="ColorBox",Parent={1},Position=UDim2.new(0,220,0,
95),Size=UDim2.new(0,20,0,20),}},
{11,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Pa
rent={10},Position=UDim2.new(0,-
40,0,0),Size=UDim2.new(0,34,1,0),Text="Color",TextColor3=Color3.new(0.8627451658248
9,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}},
{12,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,
0.2352941185236),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.215686
27655506),BorderSizePixel=0,Font=3,Name="Close",Parent={1},Position=UDim2.new(1,-
90,0,95),Size=UDim2.new(0,80,0,20),Text="Close",TextColor3=Color3.new(0.86274516582
489,0.86274516582489,0.86274516582489),TextSize=14,}},
{13,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,
0.2352941185236),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.215686
27655506),BorderSizePixel=0,Font=3,Name="Reset",Parent={1},Position=UDim2.new(1,-
180,0,95),Size=UDim2.new(0,80,0,20),Text="Reset",TextColor3=Color3.new(0.8627451658
2489,0.86274516582489,0.86274516582489),TextSize=14,}},
{14,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,
0.2352941185236),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.215686
27655506),BorderSizePixel=0,Font=3,Name="Delete",Parent={1},Position=UDim2.new(0,28
0,0,95),Size=UDim2.new(0,80,0,20),Text="Delete",TextColor3=Color3.new(0.86274516582
489,0.86274516582489,0.86274516582489),TextSize=14,}},
{15,"Frame",
{BackgroundTransparency=1,Name="Arrow",Parent={1},Size=UDim2.new(0,16,0,16),Visible
=false,}},
{16,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={15},Position=UDim2.new(0,8,0,3),Size=UDim2.new(0,1,0,2),}},
{17,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={15},Position=UDim2.new(0,7,0,5),Size=UDim2.new(0,3,0,2),}},
{18,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={15},Position=UDim2.new(0,6,0,7),Size=UDim2.new(0,5,0,2),}},
{19,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={15},Position=UDim2.new(0,5,0,9),Size=UDim2.new(0,7,0,2),}},
{20,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={15},Position=UDim2.new(0,4,0,11),Size=UDim2.new(0,9,0,2),}}
,
})
local window = Lib.Window.new()
window.Resizable = false
window:Resize(650,150)
window:SetTitle("ColorSequence Editor")
newMt.Window = window
newMt.Gui = window.Gui
for i,v in pairs(guiContents:GetChildren()) do
v.Parent = window.GuiElems.Content
end
local gui = window.Gui
local pickerGui = gui.Main
local pickerTopBar = pickerGui.TopBar
local pickerFrame = pickerGui.Content
local colorLine = pickerFrame.ColorLine
local gradient = colorLine.Gradient.UIGradient
local arrowFrame = pickerFrame.Arrows
local arrow = pickerFrame.Arrow
local cursor = pickerFrame.Cursor
local timeBox = pickerFrame.Time.Input
local colorBox = pickerFrame.ColorBox
local deleteButton = pickerFrame.Delete
local resetButton = pickerFrame.Reset
local closeButton = pickerFrame.Close
local topClose = pickerTopBar.Close

local user = clonerefs(game:GetService("UserInputService"))


local mouse =
clonerefs(game:GetService("Players")).LocalPlayer:GetMouse()

local colors = {{Color3.new(1,0,1),0},


{Color3.new(0.2,0.9,0.2),0.2},{Color3.new(0.4,0.5,0.9),0.7},
{Color3.new(0.6,1,1),1}}
local resetSequence = nil
local beginPoint = colors[1]
local endPoint = colors[#colors]

local currentlySelected = nil


local currentPoint = nil

local sequenceLine = Instance.new("Frame")


sequenceLine.BorderSizePixel = 0
sequenceLine.Size = UDim2.new(0,1,1,0)

newMt.Sequence = ColorSequence.new(Color3.new(1,1,1))
local function buildSequence(noupdate)
local newPoints = {}
table.sort(colors,function(a,b) return a[2] < b[2] end)
for i,v in pairs(colors) do

table.insert(newPoints,ColorSequenceKeypoint.new(v[2],v[1]))
end
newMt.Sequence = ColorSequence.new(newPoints)
if not noupdate then newMt.OnSelect:Fire(newMt.Sequence)
end
end

local function round(num,places)


local multi = 10^places
return math.floor(num*multi + 0.5)/multi
end

local function updateInputs(point)


if point then
currentPoint = point
local raw = point[2]
timeBox.Text = round(raw,(raw < 0.01 and 5) or (raw <
0.1 and 4) or 3)
colorBox.BackgroundColor3 = point[1]
end
end

local function placeArrow(ind,point)


local newArrow = arrow:Clone()
newArrow.Position = UDim2.new(0,ind-1,0,0)
newArrow.Visible = true
newArrow.Parent = arrowFrame

newArrow.InputBegan:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
cursor.Visible = true
cursor.Position = UDim2.new(0,9 +
newArrow.Position.X.Offset,0,0)
end
if input.UserInputType ==
Enum.UserInputType.MouseButton1 then
updateInputs(point)
if point == beginPoint or point == endPoint or
currentlySelected then return end

local mouseEvent,releaseEvent
currentlySelected = true

releaseEvent =
user.InputEnded:Connect(function(input)
if input.UserInputType ~=
Enum.UserInputType.MouseButton1 then return end
mouseEvent:Disconnect()
releaseEvent:Disconnect()
currentlySelected = nil
cursor.Visible = false
end)

mouseEvent =
user.InputChanged:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
local maxSize =
colorLine.AbsoluteSize.X-1
local relativeX = mouse.X -
colorLine.AbsolutePosition.X
if relativeX < 0 then relativeX = 0
end
if relativeX > maxSize then
relativeX = maxSize end
local raw = relativeX/maxSize
point[2] = relativeX/maxSize
updateInputs(point)
cursor.Visible = true
cursor.Position = UDim2.new(0,9 +
newArrow.Position.X.Offset,0,0)
buildSequence()
newMt:Redraw()
end
end)
end
end)

newArrow.InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType.MouseMovement then
cursor.Visible = false
end
end)

return newArrow
end

local function placeArrows()


for i,v in pairs(colors) do
v[3] =
placeArrow(math.floor((colorLine.AbsoluteSize.X-1) * v[2]) + 1,v)
end
end

local function redraw(self)


gradient.Color = newMt.Sequence or
ColorSequence.new(Color3.new(1,1,1))

for i = 2,#colors do
local nextColor = colors[i]
local endPos = math.floor((colorLine.AbsoluteSize.X-
1) * nextColor[2]) + 1
nextColor[3].Position = UDim2.new(0,endPos,0,0)
end
end
newMt.Redraw = redraw

local function loadSequence(self,seq)


resetSequence = seq
for i,v in pairs(colors) do if v[3] then v[3]:Destroy() end
end
colors = {}
currentlySelected = nil
for i,v in pairs(seq.Keypoints) do
local newPoint = {v.Value,v.Time}
newPoint[3] = placeArrow(v.Time,newPoint)
table.insert(colors,newPoint)
end
beginPoint = colors[1]
endPoint = colors[#colors]
currentlySelected = nil
updateInputs(colors[1])
buildSequence(true)
redraw()
end
newMt.SetSequence = loadSequence

local function buttonAnimations(button,inverse)


button.InputBegan:Connect(function(input) if
input.UserInputType == Enum.UserInputType.MouseMovement then
button.BackgroundTransparency = (inverse and 0.5 or 0.4) end end)
button.InputEnded:Connect(function(input) if
input.UserInputType == Enum.UserInputType.MouseMovement then
button.BackgroundTransparency = (inverse and 1 or 0) end end)
end

colorLine.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
and #colors < 20 then
local maxSize = colorLine.AbsoluteSize.X-1
local relativeX = mouse.X -
colorLine.AbsolutePosition.X
if relativeX < 0 then relativeX = 0 end
if relativeX > maxSize then relativeX = maxSize end

local raw = relativeX/maxSize


local fromColor = nil
local toColor = nil
for i,col in pairs(colors) do
if col[2] >= raw then
fromColor = colors[math.max(i-1,1)]
toColor = colors[i]
break
end
end
local lerpColor = fromColor[1]:lerp(toColor[1],(raw-
fromColor[2])/(toColor[2]-fromColor[2]))
local newPoint = {lerpColor,raw}
newPoint[3] = placeArrow(newPoint[2],newPoint)
table.insert(colors,newPoint)
updateInputs(newPoint)
buildSequence()
redraw()
end
end)

colorLine.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
then
local maxSize = colorLine.AbsoluteSize.X-1
local relativeX = mouse.X -
colorLine.AbsolutePosition.X
if relativeX < 0 then relativeX = 0 end
if relativeX > maxSize then relativeX = maxSize end
cursor.Visible = true
cursor.Position = UDim2.new(0,10 + relativeX,0,0)
end
end)

colorLine.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement
then
local inArrow = false
for i,v in pairs(colors) do
if Lib.CheckMouseInGui(v[3]) then
inArrow = v[3]
end
end
cursor.Visible = inArrow and true or false
if inArrow then cursor.Position = UDim2.new(0,9 +
inArrow.Position.X.Offset,0,0) end
end
end)

timeBox:GetPropertyChangedSignal("Text"):Connect(function()
local point = currentPoint
local num = tonumber(timeBox.Text)
if point and num and point ~= beginPoint and point ~=
endPoint then
num = math.clamp(num,0,1)
point[2] = num
buildSequence()
redraw()
end
end)

colorBox.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
then
local editor = newMt.ColorPicker
if not editor then
editor = Lib.ColorPicker.new()
editor.Window:SetTitle("ColorSequence Color
Picker")

editor.OnSelect:Connect(function(col)
if currentPoint then
currentPoint[1] = col
end
buildSequence()
redraw()
end)

newMt.ColorPicker = editor
end

editor.Window:ShowAndFocus()
end
end)

deleteButton.MouseButton1Click:Connect(function()
if currentPoint and currentPoint ~= beginPoint and
currentPoint ~= endPoint then
for i,v in pairs(colors) do
if v == currentPoint then
v[3]:Destroy()
table.remove(colors,i)
break
end
end
currentlySelected = nil
updateInputs(colors[1])
buildSequence()
redraw()
end
end)

resetButton.MouseButton1Click:Connect(function()
if resetSequence then
newMt:SetSequence(resetSequence)
end
end)

closeButton.MouseButton1Click:Connect(function()
window:Close()
end)

topClose.MouseButton1Click:Connect(function()
window:Close()
end)

buttonAnimations(deleteButton)
buttonAnimations(resetButton)
buttonAnimations(closeButton)

placeArrows()
redraw()

newMt.Show = function(self)
window:Show()
end

return newMt
end

return {new = new}


end)()

Lib.ViewportTextBox = (function()
local textService = clonerefs(game:GetService("TextService"))

local props = {
OffsetX = 0,
TextBox = PH,
CursorPos = -1,
Gui = PH,
View = PH
}
local funcs = {}
funcs.Update = function(self)
local cursorPos = self.CursorPos or -1
local text = self.TextBox.Text
if text == "" then self.TextBox.Position = UDim2.new(0,0,0,0)
return end
if cursorPos == -1 then return end

local cursorText = text:sub(1,cursorPos-1)


local pos = nil
local leftEnd = -self.TextBox.Position.X.Offset
local rightEnd = leftEnd + self.View.AbsoluteSize.X

local totalTextSize =
textService:GetTextSize(text,self.TextBox.TextSize,self.TextBox.Font,Vector2.new(99
9999999,100)).X
local cursorTextSize =
textService:GetTextSize(cursorText,self.TextBox.TextSize,self.TextBox.Font,Vector2.
new(999999999,100)).X

if cursorTextSize > rightEnd then


pos = math.max(-1,cursorTextSize - self.View.AbsoluteSize.X
+ 2)
elseif cursorTextSize < leftEnd then
pos = math.max(-1,cursorTextSize-2)
elseif totalTextSize < rightEnd then
pos = math.max(-1,totalTextSize - self.View.AbsoluteSize.X
+ 2)
end

if pos then
self.TextBox.Position = UDim2.new(0,-pos,0,0)
self.TextBox.Size = UDim2.new(1,pos,1,0)
end
end

funcs.GetText = function(self)
return self.TextBox.Text
end

funcs.SetText = function(self,text)
self.TextBox.Text = text
end

local mt = getGuiMT(props,funcs)

local function convert(textbox)


local obj = initObj(props,mt)

local view = Instance.new("Frame")


view.BackgroundTransparency = textbox.BackgroundTransparency
view.BackgroundColor3 = textbox.BackgroundColor3
view.BorderSizePixel = textbox.BorderSizePixel
view.BorderColor3 = textbox.BorderColor3
view.Position = textbox.Position
view.Size = textbox.Size
view.ClipsDescendants = true
view.Name = textbox.Name
textbox.BackgroundTransparency = 1
textbox.Position = UDim2.new(0,0,0,0)
textbox.Size = UDim2.new(1,0,1,0)
textbox.TextXAlignment = Enum.TextXAlignment.Left
textbox.Name = "Input"

obj.TextBox = textbox
obj.View = view
obj.Gui = view

textbox.Changed:Connect(function(prop)
if prop == "Text" or prop == "CursorPosition" or prop ==
"AbsoluteSize" then
local cursorPos = obj.TextBox.CursorPosition
if cursorPos ~= -1 then obj.CursorPos = cursorPos end
obj:Update()
end
end)

obj:Update()

view.Parent = textbox.Parent
textbox.Parent = view

return obj
end

local function new()


local textBox = Instance.new("TextBox")
textBox.Size = UDim2.new(0,100,0,20)
textBox.BackgroundColor3 = Settings.Theme.TextBox
textBox.BorderColor3 = Settings.Theme.Outline3
textBox.ClearTextOnFocus = false
textBox.TextColor3 = Settings.Theme.Text
textBox.Font = Enum.Font.SourceSans
textBox.TextSize = 14
textBox.Text = ""
return convert(textBox)
end

return {new = new, convert = convert}


end)()

Lib.Label = (function()
local props,funcs = {},{}

local mt = getGuiMT(props,funcs)
local function new()
local label = Instance.new("TextLabel")
label.BackgroundTransparency = 1
label.TextXAlignment = Enum.TextXAlignment.Left
label.TextColor3 = Settings.Theme.Text
label.TextTransparency = 0.1
label.Size = UDim2.new(0,100,0,20)
label.Font = Enum.Font.SourceSans
label.TextSize = 14

local obj = setmetatable({


Gui = label
},mt)
return obj
end

return {new = new}


end)()

Lib.Frame = (function()
local props,funcs = {},{}

local mt = getGuiMT(props,funcs)

local function new()


local fr = Instance.new("Frame")
fr.BackgroundColor3 = Settings.Theme.Main1
fr.BorderColor3 = Settings.Theme.Outline1
fr.Size = UDim2.new(0,50,0,50)

local obj = setmetatable({


Gui = fr
},mt)
return obj
end

return {new = new}


end)()

Lib.Button = (function()
local props = {
Gui = PH,
Anim = PH,
Disabled = false,
OnClick = SIGNAL,
OnDown = SIGNAL,
OnUp = SIGNAL,
AllowedButtons = {1}
}
local funcs = {}
local tableFind = table.find

funcs.Trigger = function(self,event,button)
if not self.Disabled and tableFind(self.AllowedButtons,button)
then
self["On"..event]:Fire(button)
end
end
funcs.SetDisabled = function(self,dis)
self.Disabled = dis

if dis then
self.Anim:Disable()
self.Gui.TextTransparency = 0.5
else
self.Anim.Enable()
self.Gui.TextTransparency = 0
end
end

local mt = getGuiMT(props,funcs)

local function new()


local b = Instance.new("TextButton")
b.AutoButtonColor = false
b.TextColor3 = Settings.Theme.Text
b.TextTransparency = 0.1
b.Size = UDim2.new(0,100,0,20)
b.Font = Enum.Font.SourceSans
b.TextSize = 14
b.BackgroundColor3 = Settings.Theme.Button
b.BorderColor3 = Settings.Theme.Outline2

local obj = initObj(props,mt)


obj.Gui = b
obj.Anim = Lib.ButtonAnim(b,{Mode = 2, StartColor =
Settings.Theme.Button, HoverColor = Settings.Theme.ButtonHover, PressColor =
Settings.Theme.ButtonPress, OutlineColor = Settings.Theme.Outline2})

b.MouseButton1Click:Connect(function() obj:Trigger("Click",1)
end)
b.MouseButton1Down:Connect(function() obj:Trigger("Down",1) end)
b.MouseButton1Up:Connect(function() obj:Trigger("Up",1) end)

b.MouseButton2Click:Connect(function() obj:Trigger("Click",2)
end)
b.MouseButton2Down:Connect(function() obj:Trigger("Down",2) end)
b.MouseButton2Up:Connect(function() obj:Trigger("Up",2) end)

return obj
end

return {new = new}


end)()

Lib.DropDown = (function()
local props = {
Gui = PH,
Anim = PH,
Context = PH,
Selected = PH,
Disabled = false,
CanBeEmpty = true,
Options = {},
GuiElems = {},
OnSelect = SIGNAL
}
local funcs = {}

funcs.Update = function(self)
local options = self.Options

if #options > 0 then


if not self.Selected then
if not self.CanBeEmpty then
self.Selected = options[1]
self.GuiElems.Label.Text = options[1]
else
self.GuiElems.Label.Text = "- Select -"
end
else
self.GuiElems.Label.Text = self.Selected
end
else
self.GuiElems.Label.Text = "- Select -"
end
end

funcs.ShowOptions = function(self)
local context = self.Context

context.Width = self.Gui.AbsoluteSize.X
context.ReverseYOffset = self.Gui.AbsoluteSize.Y
context:Show(self.Gui.AbsolutePosition.X,
self.Gui.AbsolutePosition.Y + context.ReverseYOffset)
end

funcs.SetOptions = function(self,opts)
self.Options = opts

local context = self.Context


local options = self.Options
context:Clear()

local onClick = function(option) self.Selected = option


self.OnSelect:Fire(option) self:Update() end

if self.CanBeEmpty then
context:Add({Name = "- Select -", OnClick = function()
self.Selected = nil self.OnSelect:Fire(nil) self:Update() end})
end

for i = 1,#options do
context:Add({Name = options[i], OnClick = onClick})
end

self:Update()
end

funcs.SetSelected = function(self,opt)
self.Selected = type(opt) == "number" and self.Options[opt] or
opt
self:Update()
end

local mt = getGuiMT(props,funcs)
local function new()
local f = Instance.new("TextButton")
f.AutoButtonColor = false
f.Text = ""
f.Size = UDim2.new(0,100,0,20)
f.BackgroundColor3 = Settings.Theme.TextBox
f.BorderColor3 = Settings.Theme.Outline3

local label = Lib.Label.new()


label.Position = UDim2.new(0,2,0,0)
label.Size = UDim2.new(1,-22,1,0)
label.TextTruncate = Enum.TextTruncate.AtEnd
label.Parent = f
local arrow = create({
{1,"Frame",
{BackgroundTransparency=1,Name="EnumArrow",Position=UDim2.new(1,-
16,0,2),Size=UDim2.new(0,16,0,16),}},
{2,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={1},Position=UDim2.new(0,8,0,9),Size=UDim2.new(0,1,0,1),}},
{3,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={1},Position=UDim2.new(0,7,0,8),Size=UDim2.new(0,3,0,1),}},
{4,"Frame",
{BackgroundColor3=Color3.new(0.86274510622025,0.86274510622025,0.86274510622025),Bo
rderSizePixel=0,Parent={1},Position=UDim2.new(0,6,0,7),Size=UDim2.new(0,5,0,1),}},
})
arrow.Parent = f

local obj = initObj(props,mt)


obj.Gui = f
obj.Anim = Lib.ButtonAnim(f,{Mode = 2, StartColor =
Settings.Theme.TextBox, LerpTo = Settings.Theme.Button, LerpDelta = 0.15})
obj.Context = Lib.ContextMenu.new()
obj.Context.Iconless = true
obj.Context.MaxHeight = 200
obj.Selected = nil
obj.GuiElems = {Label = label}
f.MouseButton1Down:Connect(function() obj:ShowOptions() end)
obj:Update()
return obj
end

return {new = new}


end)()

Lib.ClickSystem = (function()
local props = {
LastItem = PH,
OnDown = SIGNAL,
OnRelease = SIGNAL,
AllowedButtons = {1},
Combo = 0,
MaxCombo = 2,
ComboTime = 0.5,
Items = {},
ItemCons = {},
ClickId = -1,
LastButton = ""
}
local funcs = {}
local tostring = tostring

local disconnect = function(con)


local pos = table.find(con.Signal.Connections,con)
if pos then table.remove(con.Signal.Connections,pos) end
end

funcs.Trigger = function(self,item,button)
if table.find(self.AllowedButtons,button) then
if self.LastButton ~= button or self.LastItem ~= item or
self.Combo == self.MaxCombo or tick() - self.ClickId > self.ComboTime then
self.Combo = 0
self.LastButton = button
self.LastItem = item
end
self.Combo = self.Combo + 1
self.ClickId = tick()

local release
release =
service.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType ==
Enum.UserInputType["MouseButton"..button] then
release:Disconnect()
if Lib.CheckMouseInGui(item) and
self.LastButton == button and self.LastItem == item then

self["OnRelease"]:Fire(item,self.Combo,button)
end
end
end)

self["OnDown"]:Fire(item,self.Combo,button)
end
end

funcs.Add = function(self,item)
if table.find(self.Items,item) then return end

local cons = {}
cons[1] = item.MouseButton1Down:Connect(function()
self:Trigger(item,1) end)
cons[2] = item.MouseButton2Down:Connect(function()
self:Trigger(item,2) end)

self.ItemCons[item] = cons
self.Items[#self.Items+1] = item
end

funcs.Remove = function(self,item)
local ind = table.find(self.Items,item)
if not ind then return end

for i,v in pairs(self.ItemCons[item]) do


v:Disconnect()
end
self.ItemCons[item] = nil
table.remove(self.Items,ind)
end

local mt = {__index = funcs}

local function new()


local obj = initObj(props,mt)

return obj
end

return {new = new}


end)()

return Lib
end

return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main}


end
}

-- Main vars
local Main, Explorer, Properties, ScriptViewer, DefaultSettings, Notebook,
Serializer, Lib
local API, RMD

-- Default Settings
DefaultSettings = (function()
local rgb = Color3.fromRGB
return {
Explorer = {
_Recurse = true,
Sorting = true,
TeleportToOffset = Vector3.new(0,0,0),
ClickToRename = true,
AutoUpdateSearch = true,
AutoUpdateMode = 0, -- 0 Default, 1 no tree update, 2 no
descendant events, 3 frozen
PartSelectionBox = true,
GuiSelectionBox = true,
CopyPathUseGetChildren = true
},
Properties = {
_Recurse = true,
MaxConflictCheck = 50,
ShowDeprecated = false,
ShowHidden = false,
ClearOnFocus = false,
LoadstringInput = true,
NumberRounding = 3,
ShowAttributes = false,
MaxAttributes = 50,
ScaleType = 1 -- 0 Full Name Shown, 1 Equal Halves
},
Theme = {
_Recurse = true,
Main1 = rgb(52,52,52),
Main2 = rgb(45,45,45),
Outline1 = rgb(33,33,33), -- Mainly frames
Outline2 = rgb(55,55,55), -- Mainly button
Outline3 = rgb(30,30,30), -- Mainly textbox
TextBox = rgb(38,38,38),
Menu = rgb(32,32,32),
ListSelection = rgb(11,90,175),
Button = rgb(60,60,60),
ButtonHover = rgb(68,68,68),
ButtonPress = rgb(40,40,40),
Highlight = rgb(75,75,75),
Text = rgb(255,255,255),
PlaceholderText = rgb(100,100,100),
Important = rgb(255,0,0),
ExplorerIconMap = "",
MiscIconMap = "",
Syntax = {
Text = rgb(204,204,204),
Background = rgb(36,36,36),
Selection = rgb(255,255,255),
SelectionBack = rgb(11,90,175),
Operator = rgb(204,204,204),
Number = rgb(255,198,0),
String = rgb(173,241,149),
Comment = rgb(102,102,102),
Keyword = rgb(248,109,124),
Error = rgb(255,0,0),
FindBackground = rgb(141,118,0),
MatchingWord = rgb(85,85,85),
BuiltIn = rgb(132,214,247),
CurrentLine = rgb(45,50,65),
LocalMethod = rgb(253,251,172),
LocalProperty = rgb(97,161,241),
Nil = rgb(255,198,0),
Bool = rgb(255,198,0),
Function = rgb(248,109,124),
Local = rgb(248,109,124),
Self = rgb(248,109,124),
FunctionName = rgb(253,251,172),
Bracket = rgb(204,204,204)
},
}
}
end)()

-- Vars
local Settings = {}
local Apps = {}
local env = {}
local service = setmetatable({},{__index = function(self,name)
local serv = clonerefs(game:GetService(name))
self[name] = serv
return serv
end})
local plr = service.Players.LocalPlayer or service.Players.PlayerAdded:wait()

local create = function(data)


local insts = {}
for i,v in pairs(data) do insts[v[1]] = Instance.new(v[2]) end
for _,v in pairs(data) do
for prop,val in pairs(v[3]) do
if type(val) == "table" then
insts[v[1]][prop] = insts[val[1]]
else
insts[v[1]][prop] = val
end
end
end

return insts[1]
end

local createSimple = function(class,props)


local inst = Instance.new(class)
for i,v in next,props do
inst[i] = v
end
return inst
end

Main = (function()
local Main = {}

Main.ModuleList = {"Explorer","Properties","ScriptViewer"}
Main.Elevated = false
Main.MissingEnv = {}
Main.Version = "" -- Beta 1.0.0
Main.Mouse = plr:GetMouse()
Main.AppControls = {}
Main.Apps = Apps
Main.MenuApps = {}

Main.DisplayOrders = {
SideWindow = 8,
Window = 10,
Menu = 100000,
Core = 101000
}

Main.GetInitDeps = function()
return {
Main = Main,
Lib = Lib,
Apps = Apps,
Settings = Settings,

API = API,
RMD = RMD,
env = env,
service = service,
plr = plr,
create = create,
createSimple = createSimple
}
end

Main.Error = function(str)
if rconsoleprint then
rconsoleprint("DEX ERROR: "..tostring(str).."\n")
wait(9e9)
else
error(str)
end
end

Main.LoadModule = function(name)
if Main.Elevated then -- If you don't have filesystem api then ur outta
luck tbh
local control

if EmbeddedModules then -- Offline Modules


control = EmbeddedModules[name]()

if not control then Main.Error("Missing Embedded Module:


"..name) end
end

Main.AppControls[name] = control
control.InitDeps(Main.GetInitDeps())

local moduleData = control.Main()


Apps[name] = moduleData
return moduleData
else
local module =
script:WaitForChild("Modules"):WaitForChild(name,2)
if not module then Main.Error("CANNOT FIND MODULE "..name) end

local control = require(module)


Main.AppControls[name] = control
control.InitDeps(Main.GetInitDeps())

local moduleData = control.Main()


Apps[name] = moduleData
return moduleData
end
end

Main.LoadModules = function()
for i,v in pairs(Main.ModuleList) do
local s,e = pcall(Main.LoadModule,v)
if not s then
Main.Error("FAILED LOADING " + v + " CAUSE " + e)
end
end

-- Init Major Apps and define them in modules


Explorer = Apps.Explorer
Properties = Apps.Properties
ScriptViewer = Apps.ScriptViewer
Notebook = Apps.Notebook
local appTable = {
Explorer = Explorer,
Properties = Properties,
ScriptViewer = ScriptViewer,
Notebook = Notebook
}
Main.AppControls.Lib.InitAfterMain(appTable)
for i,v in pairs(Main.ModuleList) do
local control = Main.AppControls[v]
if control then
control.InitAfterMain(appTable)
end
end
end

Main.InitEnv = function()
setmetatable(env, {__newindex = function(self, name, func)
if not func then Main.MissingEnv[#Main.MissingEnv + 1] = name
return end
rawset(self, name, func)
end})

-- file
env.readfile = readfile
env.writefile = writefile
env.appendfile = appendfile
env.makefolder = makefolder
env.listfiles = listfiles
env.loadfile = loadfile
env.saveinstance = saveinstance

-- debug
env.getupvalues = debug.getupvalues or getupvals
env.getconstants = debug.getconstants or getconsts
env.islclosure = islclosure or is_l_closure
env.checkcaller = checkcaller
env.getreg = getreg
env.getgc = getgc

-- other
env.setfflag = setfflag
env.decompile = decompile
env.protectgui = protect_gui or (syn and syn.protect_gui)
env.gethui = gethui
env.setclipboard = setclipboard
env.getnilinstances = getnilinstances or get_nil_instances
env.getloadedmodules = getloadedmodules

if identifyexecutor then Main.Executor = identifyexecutor() end

Main.GuiHolder = Main.Elevated and service.CoreGui or


plr:FindFirstChildOfClass("PlayerGui")

setmetatable(env, nil)
end

Main.LoadSettings = function()
local s,data = pcall(env.readfile or error,"DexSettings.json")
if s and data and data ~= "" then
local s,decoded = service.HttpService:JSONDecode(data)
if s and decoded then
for i,v in next,decoded do

end
else
-- TODO: Notification
end
else
Main.ResetSettings()
end
end

Main.ResetSettings = function()
local function recur(t,res)
for set,val in pairs(t) do
if type(val) == "table" and val._Recurse then
if type(res[set]) ~= "table" then
res[set] = {}
end
recur(val,res[set])
else
res[set] = val
end
end
return res
end
recur(DefaultSettings,Settings)
end

Main.FetchAPI = function()
local api,rawAPI
if Main.Elevated then
if Main.LocalDepsUpToDate() then
local localAPI = Lib.ReadFile("dex/rbx_api.dat")
if localAPI then
rawAPI = localAPI
else
Main.DepsVersionData[1] = ""
end
end
rawAPI = rawAPI or
game:HttpGet("http://setup.roblox.com/"..Main.RobloxVersion.."-API-Dump.json")
else
if script:FindFirstChild("API") then
rawAPI = require(script.API)
else
error("NO API EXISTS")
end
end
Main.RawAPI = rawAPI
api = service.HttpService:JSONDecode(rawAPI)

local classes,enums = {},{}


local categoryOrder,seenCategories = {},{}

local function insertAbove(t,item,aboveItem)


local findPos = table.find(t,item)
if not findPos then return end
table.remove(t,findPos)

local pos = table.find(t,aboveItem)


if not pos then return end
table.insert(t,pos,item)
end

for _,class in pairs(api.Classes) do


local newClass = {}
newClass.Name = class.Name
newClass.Superclass = class.Superclass
newClass.Properties = {}
newClass.Functions = {}
newClass.Events = {}
newClass.Callbacks = {}
newClass.Tags = {}

if class.Tags then for c,tag in pairs(class.Tags) do


newClass.Tags[tag] = true end end
for __,member in pairs(class.Members) do
local newMember = {}
newMember.Name = member.Name
newMember.Class = class.Name
newMember.Security = member.Security
newMember.Tags ={}
if member.Tags then for c,tag in pairs(member.Tags) do
newMember.Tags[tag] = true end end

local mType = member.MemberType


if mType == "Property" then
local propCategory = member.Category or "Other"
propCategory = propCategory:match("^%s*(.-)%s*$")
if not seenCategories[propCategory] then
categoryOrder[#categoryOrder+1] = propCategory
seenCategories[propCategory] = true
end
newMember.ValueType = member.ValueType
newMember.Category = propCategory
newMember.Serialization = member.Serialization
table.insert(newClass.Properties,newMember)
elseif mType == "Function" then
newMember.Parameters = {}
newMember.ReturnType = member.ReturnType.Name
for c,param in pairs(member.Parameters) do
table.insert(newMember.Parameters,{Name =
param.Name, Type = param.Type.Name})
end
table.insert(newClass.Functions,newMember)
elseif mType == "Event" then
newMember.Parameters = {}
for c,param in pairs(member.Parameters) do
table.insert(newMember.Parameters,{Name =
param.Name, Type = param.Type.Name})
end
table.insert(newClass.Events,newMember)
end
end

classes[class.Name] = newClass
end

for _,class in pairs(classes) do


class.Superclass = classes[class.Superclass]
end
for _,enum in pairs(api.Enums) do
local newEnum = {}
newEnum.Name = enum.Name
newEnum.Items = {}
newEnum.Tags = {}

if enum.Tags then for c,tag in pairs(enum.Tags) do


newEnum.Tags[tag] = true end end
for __,item in pairs(enum.Items) do
local newItem = {}
newItem.Name = item.Name
newItem.Value = item.Value
table.insert(newEnum.Items,newItem)
end

enums[enum.Name] = newEnum
end

local function getMember(class,member)


if not classes[class] or not classes[class][member] then return
end
local result = {}

local currentClass = classes[class]


while currentClass do
for _,entry in pairs(currentClass[member]) do
result[#result+1] = entry
end
currentClass = currentClass.Superclass
end

table.sort(result,function(a,b) return a.Name < b.Name end)


return result
end

insertAbove(categoryOrder,"Behavior","Tuning")
insertAbove(categoryOrder,"Appearance","Data")
insertAbove(categoryOrder,"Attachments","Axes")
insertAbove(categoryOrder,"Cylinder","Slider")
insertAbove(categoryOrder,"Localization","Jump Settings")
insertAbove(categoryOrder,"Surface","Motion")
insertAbove(categoryOrder,"Surface Inputs","Surface")
insertAbove(categoryOrder,"Part","Surface Inputs")
insertAbove(categoryOrder,"Assembly","Surface Inputs")
insertAbove(categoryOrder,"Character","Controls")
categoryOrder[#categoryOrder+1] = "Unscriptable"
categoryOrder[#categoryOrder+1] = "Attributes"

local categoryOrderMap = {}
for i = 1,#categoryOrder do
categoryOrderMap[categoryOrder[i]] = i
end

return {
Classes = classes,
Enums = enums,
CategoryOrder = categoryOrderMap,
GetMember = getMember
}
end

Main.FetchRMD = function()
local rawXML
if Main.Elevated then
if Main.LocalDepsUpToDate() then
local localRMD = Lib.ReadFile("dex/rbx_rmd.dat")
if localRMD then
rawXML = localRMD
else
Main.DepsVersionData[1] = ""
end
end
rawXML = rawXML or
game:HttpGet("https://raw.githubusercontent.com/CloneTrooper1019/Roblox-Client-
Tracker/roblox/ReflectionMetadata.xml")
else
if script:FindFirstChild("RMD") then
rawXML = require(script.RMD)
else
error("NO RMD EXISTS")
end
end
Main.RawRMD = rawXML
local parsed = Lib.ParseXML(rawXML)
local classList = parsed.children[1].children[1].children
local enumList = parsed.children[1].children[2].children
local propertyOrders = {}

local classes,enums = {},{}


for _,class in pairs(classList) do
local className = ""
for _,child in pairs(class.children) do
if child.tag == "Properties" then
local data = {Properties = {}, Functions = {}}
local props = child.children
for _,prop in pairs(props) do
local name = prop.attrs.name
name = name:sub(1,1):upper()..name:sub(2)
data[name] = prop.children[1].text
end
className = data.Name
classes[className] = data
elseif child.attrs.class == "ReflectionMetadataProperties"
then
local members = child.children
for _,member in pairs(members) do
if member.attrs.class ==
"ReflectionMetadataMember" then
local data = {}
if member.children[1].tag == "Properties"
then
local props =
member.children[1].children
for _,prop in pairs(props) do
if prop.attrs then
local name =
prop.attrs.name
name =
name:sub(1,1):upper()..name:sub(2)
data[name] =
prop.children[1].text
end
end
if data.PropertyOrder then
local orders =
propertyOrders[className]
if not orders then orders =
{} propertyOrders[className] = orders end
orders[data.Name] =
tonumber(data.PropertyOrder)
end

classes[className].Properties[data.Name] = data
end
end
end
elseif child.attrs.class == "ReflectionMetadataFunctions"
then
local members = child.children
for _,member in pairs(members) do
if member.attrs.class ==
"ReflectionMetadataMember" then
local data = {}
if member.children[1].tag == "Properties"
then
local props =
member.children[1].children
for _,prop in pairs(props) do
if prop.attrs then
local name =
prop.attrs.name
name =
name:sub(1,1):upper()..name:sub(2)
data[name] =
prop.children[1].text
end
end

classes[className].Functions[data.Name] = data
end
end
end
end
end
end

for _,enum in pairs(enumList) do


local enumName = ""
for _,child in pairs(enum.children) do
if child.tag == "Properties" then
local data = {Items = {}}
local props = child.children
for _,prop in pairs(props) do
local name = prop.attrs.name
name = name:sub(1,1):upper()..name:sub(2)
data[name] = prop.children[1].text
end
enumName = data.Name
enums[enumName] = data
elseif child.attrs.class == "ReflectionMetadataEnumItem"
then
local data = {}
if child.children[1].tag == "Properties" then
local props = child.children[1].children
for _,prop in pairs(props) do
local name = prop.attrs.name
name = name:sub(1,1):upper()..name:sub(2)
data[name] = prop.children[1].text
end
enums[enumName].Items[data.Name] = data
end
end
end
end

return {Classes = classes, Enums = enums, PropertyOrders =


propertyOrders}
end

Main.ShowGui = function(gui)
if env.protectgui then
env.protectgui(gui)
end
gui.Parent = Main.GuiHolder
end

Main.CreateIntro = function(initStatus) -- TODO: Must theme and show errors


local gui = create({
{1,"ScreenGui",{Name="Intro",}},
{2,"Frame",
{Active=true,BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.203921
57137394),BorderSizePixel=0,Name="Main",Parent={1},Position=UDim2.new(0.5,-
175,0.5,-100),Size=UDim2.new(0,350,0,200),}},
{3,"Frame",
{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),Bo
rderSizePixel=0,ClipsDescendants=true,Name="Holder",Parent={2},Size=UDim2.new(1,0,1
,0),}},
{4,"UIGradient",
{Parent={3},Rotation=30,Transparency=NumberSequence.new({NumberSequenceKeypoint.new
(0,1,0),NumberSequenceKeypoint.new(1,1,0),}),}},
{5,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=4,Name="Title",Pa
rent={3},Position=UDim2.new(0,-
190,0,15),Size=UDim2.new(0,100,0,50),Text="Dex",TextColor3=Color3.new(1,1,1),TextSi
ze=50,TextTransparency=1,}},
{6,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Desc",Par
ent={3},Position=UDim2.new(0,-230,0,60),Size=UDim2.new(0,180,0,25),Text="Ultimate
Debugging Suite",TextColor3=Color3.new(1,1,1),TextSize=18,TextTransparency=1,}},
{7,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="StatusTex
t",Parent={3},Position=UDim2.new(0,20,0,110),Size=UDim2.new(0,180,0,25),Text="Fetch
ing API",TextColor3=Color3.new(1,1,1),TextSize=14,TextTransparency=1,}},
{8,"Frame",
{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),Bo
rderSizePixel=0,Name="ProgressBar",Parent={3},Position=UDim2.new(0,110,0,145),Size=
UDim2.new(0,0,0,4),}},
{9,"Frame",
{BackgroundColor3=Color3.new(0.2392156869173,0.56078433990479,0.86274510622025),Bor
derSizePixel=0,Name="Bar",Parent={8},Size=UDim2.new(0,0,1,0),}},
{10,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
2764171053",ImageColor3=Color3.new(0.17647059261799,0.17647059261799,0.176470592617
99),Parent={8},ScaleType=1,Size=UDim2.new(1,0,1,0),SliceCenter=Rect.new(2,2,254,254
),}},
{11,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Creator",
Parent={2},Position=UDim2.new(1,-110,1,-
20),Size=UDim2.new(0,105,0,20),Text="Developed by
Moon",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=1,}},
{12,"UIGradient",
{Parent={11},Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),Num
berSequenceKeypoint.new(1,1,0),}),}},
{13,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Version",
Parent={2},Position=UDim2.new(1,-110,1,-
35),Size=UDim2.new(0,105,0,20),Text=Main.Version,TextColor3=Color3.new(1,1,1),TextS
ize=14,TextXAlignment=1,}},
{14,"UIGradient",
{Parent={13},Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),Num
berSequenceKeypoint.new(1,1,0),}),}},
{15,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Imag
e="rbxassetid://1427967925",Name="Outlines",Parent={2},Position=UDim2.new(0,-5,0,-
5),ScaleType=1,Size=UDim2.new(1,10,1,10),SliceCenter=Rect.new(6,6,25,25),TileSize=U
Dim2.new(0,20,0,20),}},
{16,"UIGradient",{Parent={15},Rotation=-
30,Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenc
eKeypoint.new(1,1,0),}),}},
{17,"UIGradient",{Parent={2},Rotation=-
30,Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenc
eKeypoint.new(1,1,0),}),}},
})
Main.ShowGui(gui)
local backGradient = gui.Main.UIGradient
local outlinesGradient = gui.Main.Outlines.UIGradient
local holderGradient = gui.Main.Holder.UIGradient
local titleText = gui.Main.Holder.Title
local descText = gui.Main.Holder.Desc
local versionText = gui.Main.Version
local versionGradient = versionText.UIGradient
local creatorText = gui.Main.Creator
local creatorGradient = creatorText.UIGradient
local statusText = gui.Main.Holder.StatusText
local progressBar = gui.Main.Holder.ProgressBar
local tweenS = service.TweenService

local renderStepped = service.RunService.RenderStepped


local signalWait = renderStepped.wait
local fastwait = function(s)
if not s then return signalWait(renderStepped) end
local start = tick()
while tick() - start < s do signalWait(renderStepped) end
end
statusText.Text = initStatus

local function tweenNumber(n,ti,func)


local tweenVal = Instance.new("IntValue")
tweenVal.Value = 0
tweenVal.Changed:Connect(func)
local tween = tweenS:Create(tweenVal,ti,{Value = n})
tween:Play()
tween.Completed:Connect(function()
tweenVal:Destroy()
end)
end

local ti =
TweenInfo.new(0.4,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
tweenNumber(100,ti,function(val)
val = val/200
local start = NumberSequenceKeypoint.new(0,0)
local a1 = NumberSequenceKeypoint.new(val,0)
local a2 =
NumberSequenceKeypoint.new(math.min(0.5,val+math.min(0.05,val)),1)
if a1.Time == a2.Time then a2 = a1 end
local b1 = NumberSequenceKeypoint.new(1-val,0)
local b2 = NumberSequenceKeypoint.new(math.max(0.5,1-val-
math.min(0.05,val)),1)
if b1.Time == b2.Time then b2 = b1 end
local goal = NumberSequenceKeypoint.new(1,0)
backGradient.Transparency =
NumberSequence.new({start,a1,a2,b2,b1,goal})
outlinesGradient.Transparency =
NumberSequence.new({start,a1,a2,b2,b1,goal})
end)

fastwait(0.4)

tweenNumber(100,ti,function(val)
val = val/166.66
local start = NumberSequenceKeypoint.new(0,0)
local a1 = NumberSequenceKeypoint.new(val,0)
local a2 = NumberSequenceKeypoint.new(val+0.01,1)
local goal = NumberSequenceKeypoint.new(1,1)
holderGradient.Transparency =
NumberSequence.new({start,a1,a2,goal})
end)

tweenS:Create(titleText,ti,{Position = UDim2.new(0,60,0,15),
TextTransparency = 0}):Play()
tweenS:Create(descText,ti,{Position = UDim2.new(0,20,0,60),
TextTransparency = 0}):Play()

local function rightTextTransparency(obj)


tweenNumber(100,ti,function(val)
val = val/100
local a1 = NumberSequenceKeypoint.new(1-val,0)
local a2 = NumberSequenceKeypoint.new(math.max(0,1-val-
0.01),1)
if a1.Time == a2.Time then a2 = a1 end
local start = NumberSequenceKeypoint.new(0,a1 == a2 and 0
or 1)
local goal = NumberSequenceKeypoint.new(1,0)
obj.Transparency = NumberSequence.new({start,a2,a1,goal})
end)
end
rightTextTransparency(versionGradient)
rightTextTransparency(creatorGradient)

fastwait(0.9)

local progressTI =
TweenInfo.new(0.25,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)

tweenS:Create(statusText,progressTI,{Position = UDim2.new(0,20,0,120),
TextTransparency = 0}):Play()
tweenS:Create(progressBar,progressTI,{Position = UDim2.new(0,60,0,145),
Size = UDim2.new(0,100,0,4)}):Play()

fastwait(0.25)

local function setProgress(text,n)


statusText.Text = text
tweenS:Create(progressBar.Bar,progressTI,{Size =
UDim2.new(n,0,1,0)}):Play()
end

local function close()


tweenS:Create(titleText,progressTI,{TextTransparency = 1}):Play()
tweenS:Create(descText,progressTI,{TextTransparency = 1}):Play()
tweenS:Create(versionText,progressTI,{TextTransparency =
1}):Play()
tweenS:Create(creatorText,progressTI,{TextTransparency =
1}):Play()
tweenS:Create(statusText,progressTI,{TextTransparency =
1}):Play()
tweenS:Create(progressBar,progressTI,{BackgroundTransparency =
1}):Play()
tweenS:Create(progressBar.Bar,progressTI,{BackgroundTransparency
= 1}):Play()
tweenS:Create(progressBar.ImageLabel,progressTI,
{ImageTransparency = 1}):Play()

tweenNumber(100,TweenInfo.new(0.4,Enum.EasingStyle.Back,Enum.EasingDirection.In),fu
nction(val)
val = val/250
local start = NumberSequenceKeypoint.new(0,0)
local a1 = NumberSequenceKeypoint.new(0.6+val,0)
local a2 =
NumberSequenceKeypoint.new(math.min(1,0.601+val),1)
if a1.Time == a2.Time then a2 = a1 end
local goal = NumberSequenceKeypoint.new(1,a1 == a2 and 0 or
1)
holderGradient.Transparency =
NumberSequence.new({start,a1,a2,goal})
end)

fastwait(0.5)
gui.Main.BackgroundTransparency = 1
outlinesGradient.Rotation = 30

tweenNumber(100,ti,function(val)
val = val/100
local start = NumberSequenceKeypoint.new(0,1)
local a1 = NumberSequenceKeypoint.new(val,1)
local a2 =
NumberSequenceKeypoint.new(math.min(1,val+math.min(0.05,val)),0)
if a1.Time == a2.Time then a2 = a1 end
local goal = NumberSequenceKeypoint.new(1,a1 == a2 and 1 or
0)
outlinesGradient.Transparency =
NumberSequence.new({start,a1,a2,goal})
holderGradient.Transparency =
NumberSequence.new({start,a1,a2,goal})
end)

fastwait(0.45)
gui:Destroy()
end

return {SetProgress = setProgress, Close = close}


end

Main.CreateApp = function(data)
if Main.MenuApps[data.Name] then return end -- TODO: Handle conflict
local control = {}

local app = Main.AppTemplate:Clone()

local iconIndex = data.Icon


if data.IconMap and iconIndex then
if type(iconIndex) == "number" then
data.IconMap:Display(app.Main.Icon,iconIndex)
elseif type(iconIndex) == "string" then
data.IconMap:DisplayByKey(app.Main.Icon,iconIndex)
end
elseif type(iconIndex) == "string" then
app.Main.Icon.Image = iconIndex
else
app.Main.Icon.Image = ""
end

local function updateState()


app.Main.BackgroundTransparency = data.Open and 0 or
(Lib.CheckMouseInGui(app.Main) and 0 or 1)
app.Main.Highlight.Visible = data.Open
end

local function enable(silent)


if data.Open then return end
data.Open = true
updateState()
if not silent then
if data.Window then data.Window:Show() end
if data.OnClick then data.OnClick(data.Open) end
end
end
local function disable(silent)
if not data.Open then return end
data.Open = false
updateState()
if not silent then
if data.Window then data.Window:Hide() end
if data.OnClick then data.OnClick(data.Open) end
end
end

updateState()

local ySize =
service.TextService:GetTextSize(data.Name,14,Enum.Font.SourceSans,Vector2.new(62,99
9999)).Y
app.Main.Size = UDim2.new(1,0,0,math.clamp(46+ySize,60,74))
app.Main.AppName.Text = data.Name

app.Main.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
app.Main.BackgroundTransparency = 0
app.Main.BackgroundColor3 = Settings.Theme.ButtonHover
end
end)

app.Main.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then
app.Main.BackgroundTransparency = data.Open and 0 or 1
app.Main.BackgroundColor3 = Settings.Theme.Button
end
end)

app.Main.MouseButton1Click:Connect(function()
if data.Open then disable() else enable() end
end)

local window = data.Window


if window then
window.OnActivate:Connect(function() enable(true) end)
window.OnDeactivate:Connect(function() disable(true) end)
end

app.Visible = true
app.Parent = Main.AppsContainer
Main.AppsFrame.CanvasSize =
UDim2.new(0,0,0,Main.AppsContainerGrid.AbsoluteCellCount.Y*82 + 8)

control.Enable = enable
control.Disable = disable
Main.MenuApps[data.Name] = control
return control
end

Main.SetMainGuiOpen = function(val)
Main.MainGuiOpen = val

Main.MainGui.OpenButton.Text = val and "X" or "Dex"


if val then Main.MainGui.OpenButton.MainFrame.Visible = true end
Main.MainGui.OpenButton.MainFrame:TweenSize(val and
UDim2.new(0,224,0,200) or
UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.2,true)
--Main.MainGui.OpenButton.BackgroundTransparency = val and 0 or
(Lib.CheckMouseInGui(Main.MainGui.OpenButton) and 0 or 0.2)

service.TweenService:Create(Main.MainGui.OpenButton,TweenInfo.new(0.2,Enum.EasingSt
yle.Quad,Enum.EasingDirection.Out),{BackgroundTransparency = val and 0 or
(Lib.CheckMouseInGui(Main.MainGui.OpenButton) and 0 or 0.2)}):Play()

if Main.MainGuiMouseEvent then Main.MainGuiMouseEvent:Disconnect() end

if not val then


local startTime = tick()
Main.MainGuiCloseTime = startTime
coroutine.wrap(function()
Lib.FastWait(0.2)
if not Main.MainGuiOpen and startTime ==
Main.MainGuiCloseTime then Main.MainGui.OpenButton.MainFrame.Visible = false end
end)()
else
Main.MainGuiMouseEvent =
service.UserInputService.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1
and not Lib.CheckMouseInGui(Main.MainGui.OpenButton) and not
Lib.CheckMouseInGui(Main.MainGui.OpenButton.MainFrame) then
Main.SetMainGuiOpen(false)
end
end)
end
end

Main.CreateMainGui = function()
local gui = create({
{1,"ScreenGui",{IgnoreGuiInset=true,Name="MainMenu",}},
{2,"TextButton",
{AnchorPoint=Vector2.new(0.5,0),AutoButtonColor=false,BackgroundColor3=Color3.new(0
.17647059261799,0.17647059261799,0.17647059261799),BorderSizePixel=0,Font=4,Name="O
penButton",Parent={1},Position=UDim2.new(0.5,0,0,2),Size=UDim2.new(0,32,0,32),Text=
"Dex",TextColor3=Color3.new(1,1,1),TextSize=16,TextTransparency=0.20000000298023,}}
,
{3,"UICorner",{CornerRadius=UDim.new(0,4),Parent={2},}},
{4,"Frame",
{AnchorPoint=Vector2.new(0.5,0),BackgroundColor3=Color3.new(0.17647059261799,0.1764
7059261799,0.17647059261799),ClipsDescendants=true,Name="MainFrame",Parent={2},Posi
tion=UDim2.new(0.5,0,1,-4),Size=UDim2.new(0,224,0,200),}},
{5,"UICorner",{CornerRadius=UDim.new(0,4),Parent={4},}},
{6,"Frame",
{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),Na
me="BottomFrame",Parent={4},Position=UDim2.new(0,0,1,-
24),Size=UDim2.new(1,0,0,24),}},
{7,"UICorner",{CornerRadius=UDim.new(0,4),Parent={6},}},
{8,"Frame",
{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),Bo
rderSizePixel=0,Name="CoverFrame",Parent={6},Size=UDim2.new(1,0,0,4),}},
{9,"Frame",
{BackgroundColor3=Color3.new(0.1294117718935,0.1294117718935,0.1294117718935),Borde
rSizePixel=0,Name="Line",Parent={8},Position=UDim2.new(0,0,0,-
1),Size=UDim2.new(1,0,0,1),}},
{10,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Settings"
,Parent={6},Position=UDim2.new(1,-
48,0,0),Size=UDim2.new(0,24,1,0),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,}
},
{11,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
6578871732",ImageTransparency=0.20000000298023,Name="Icon",Parent={10},Position=UDi
m2.new(0,4,0,4),Size=UDim2.new(0,16,0,16),}},
{12,"TextButton",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Informati
on",Parent={6},Position=UDim2.new(1,-
24,0,0),Size=UDim2.new(0,24,1,0),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,}
},
{13,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
6578933307",ImageTransparency=0.20000000298023,Name="Icon",Parent={12},Position=UDi
m2.new(0,4,0,4),Size=UDim2.new(0,16,0,16),}},
{14,"ScrollingFrame",
{Active=true,AnchorPoint=Vector2.new(0.5,0),BackgroundColor3=Color3.new(1,1,1),Back
groundTransparency=1,BorderColor3=Color3.new(0.1294117718935,0.1294117718935,0.1294
117718935),BorderSizePixel=0,Name="AppsFrame",Parent={4},Position=UDim2.new(0.5,0,0
,0),ScrollBarImageColor3=Color3.new(0,0,0),ScrollBarThickness=4,Size=UDim2.new(0,22
2,1,-25),}},
{15,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="Container",Paren
t={14},Position=UDim2.new(0,7,0,8),Size=UDim2.new(1,-14,0,2),}},
{16,"UIGridLayout",
{CellSize=UDim2.new(0,66,0,74),Parent={15},SortOrder=2,}},
{17,"Frame",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="App",Parent={1},
Size=UDim2.new(0,100,0,100),Visible=false,}},
{18,"TextButton",
{AutoButtonColor=false,BackgroundColor3=Color3.new(0.2352941185236,0.2352941185236,
0.2352941185236),BorderSizePixel=0,Font=3,Name="Main",Parent={17},Size=UDim2.new(1,
0,0,60),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}},
{19,"ImageLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Image="rbxassetid://
6579106223",ImageRectSize=Vector2.new(32,32),Name="Icon",Parent={18},Position=UDim2
.new(0.5,-16,0,4),ScaleType=4,Size=UDim2.new(0,32,0,32),}},
{20,"TextLabel",
{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Font
=3,Name="AppName",Parent={18},Position=UDim2.new(0,2,0,38),Size=UDim2.new(1,-4,1,-
40),Text="Explorer",TextColor3=Color3.new(1,1,1),TextSize=14,TextTransparency=0.100
00000149012,TextTruncate=1,TextWrapped=true,TextYAlignment=0,}},
{21,"Frame",
{BackgroundColor3=Color3.new(0,0.66666668653488,1),BorderSizePixel=0,Name="Highligh
t",Parent={18},Position=UDim2.new(0,0,1,-2),Size=UDim2.new(1,0,0,2),}},
})
Main.MainGui = gui
Main.AppsFrame = gui.OpenButton.MainFrame.AppsFrame
Main.AppsContainer = Main.AppsFrame.Container
Main.AppsContainerGrid = Main.AppsContainer.UIGridLayout
Main.AppTemplate = gui.App
Main.MainGuiOpen = false

local openButton = gui.OpenButton


openButton.BackgroundTransparency = 0.2
openButton.MainFrame.Size = UDim2.new(0,0,0,0)
openButton.MainFrame.Visible = false
openButton.MouseButton1Click:Connect(function()
Main.SetMainGuiOpen(not Main.MainGuiOpen)
end)

openButton.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then

service.TweenService:Create(Main.MainGui.OpenButton,TweenInfo.new(0,Enum.EasingStyl
e.Quad,Enum.EasingDirection.Out),{BackgroundTransparency = 0}):Play()
end
end)

openButton.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement then

service.TweenService:Create(Main.MainGui.OpenButton,TweenInfo.new(0,Enum.EasingStyl
e.Quad,Enum.EasingDirection.Out),{BackgroundTransparency = Main.MainGuiOpen and 0
or 0.2}):Play()
end
end)

-- Create Main Apps


Main.CreateApp({Name = "Explorer", IconMap = Main.LargeIcons, Icon =
"Explorer", Open = true, Window = Explorer.Window})

Main.CreateApp({Name = "Properties", IconMap = Main.LargeIcons, Icon =


"Properties", Open = true, Window = Properties.Window})

Main.CreateApp({Name = "Script Viewer", IconMap = Main.LargeIcons, Icon


= "Script_Viewer", Window = ScriptViewer.Window})

local cptsOnMouseClick = nil


Main.CreateApp({Name = "Click part to select", IconMap =
Main.LargeIcons, Icon = 6, OnClick = function(callback)
if callback then
local mouse = Main.Mouse
cptsOnMouseClick = mouse.Button1Down:Connect(function()
pcall(function()
local object = mouse.Target
if nodes[object] then
selection:Set(nodes[object])
Explorer.ViewNode(nodes[object])
end
end)
end)
else if cptsOnMouseClick ~= nil then
cptsOnMouseClick:Disconnect() cptsOnMouseClick = nil end end
end})

Lib.ShowGui(gui)
end

Main.SetupFilesystem = function()
if not env.writefile or not env.makefolder then return end
local writefile, makefolder = env.writefile, env.makefolder
makefolder("dex")
makefolder("dex/assets")
makefolder("dex/saved")
makefolder("dex/plugins")
makefolder("dex/ModuleCache")
end

Main.LocalDepsUpToDate = function()
return Main.DepsVersionData and Main.ClientVersion ==
Main.DepsVersionData[1]
end

Main.Init = function()
Main.Elevated = pcall(function() local a =
clonerefs(game:GetService("CoreGui")):GetFullName() end)
Main.InitEnv()
Main.LoadSettings()
Main.SetupFilesystem()

-- Load Lib
local intro = Main.CreateIntro("Initializing Library")
Lib = Main.LoadModule("Lib")
Lib.FastWait()

-- Init other stuff


--Main.IncompatibleTest()

-- Init icons
Main.MiscIcons =
Lib.IconMap.new("rbxassetid://6511490623",256,256,16,16)
Main.MiscIcons:SetDict({
Reference = 0, Cut = 1,
Cut_Disabled = 2, Copy = 3, Copy_Disabled = 4, Paste = 5,
Paste_Disabled = 6,
Delete = 7, Delete_Disabled = 8, Group
= 9, Group_Disabled = 10, Ungroup = 11, Ungroup_Disabled =
12, TeleportTo = 13,
Rename = 14, JumpToParent = 15,
ExploreData = 16, Save = 17, CallFunction = 18, CallRemote =
19, Undo = 20,
Undo_Disabled = 21, Redo = 22,
Redo_Disabled = 23, Expand_Over = 24, Expand = 25, Collapse_Over
= 26, Collapse = 27,
SelectChildren = 28, SelectChildren_Disabled = 29,
InsertObject = 30, ViewScript = 31, AddStar = 32, RemoveStar =
33, Script_Disabled = 34,
LocalScript_Disabled = 35, Play = 36, Pause
= 37, Rename_Disabled = 38
})
Main.LargeIcons =
Lib.IconMap.new("rbxassetid://6579106223",256,256,32,32)
Main.LargeIcons:SetDict({
Explorer = 0, Properties = 1, Script_Viewer = 2,
})

-- Fetch version if needed


intro.SetProgress("Fetching Roblox Version",0.2)
if Main.Elevated then
local fileVer = Lib.ReadFile("dex/deps_version.dat")
Main.ClientVersion = Version()
if fileVer then
Main.DepsVersionData = string.split(fileVer,"\n")
if Main.LocalDepsUpToDate() then
Main.RobloxVersion = Main.DepsVersionData[2]
end
end
Main.RobloxVersion = Main.RobloxVersion or
game:HttpGet("http://setup.roblox.com/versionQTStudio")
end

-- Fetch external deps


intro.SetProgress("Fetching API",0.35)
API = Main.FetchAPI()
Lib.FastWait()
intro.SetProgress("Fetching RMD",0.5)
RMD = Main.FetchRMD()
Lib.FastWait()

-- Save external deps locally if needed


if Main.Elevated and env.writefile and not Main.LocalDepsUpToDate()
then
env.writefile("dex/deps_version.dat",Main.ClientVersion.."\
n"..Main.RobloxVersion)
env.writefile("dex/rbx_api.dat",Main.RawAPI)
env.writefile("dex/rbx_rmd.dat",Main.RawRMD)
end

-- Load other modules


intro.SetProgress("Loading Modules",0.75)
Main.AppControls.Lib.InitDeps(Main.GetInitDeps()) -- Missing deps now
available
Main.LoadModules()
Lib.FastWait()

-- Init other modules


intro.SetProgress("Initializing Modules",0.9)
Explorer.Init()
Properties.Init()
ScriptViewer.Init()
Lib.FastWait()

-- Done
intro.SetProgress("Complete",1)
coroutine.wrap(function()
Lib.FastWait(1.25)
intro.Close()
end)()

-- Init window system, create main menu, show explorer and properties
Lib.Window.Init()
Main.CreateMainGui()
Explorer.Window:Show({Align = "right", Pos = 1, Size = 0.5, Silent =
true})
Properties.Window:Show({Align = "right", Pos = 2, Size = 0.5, Silent =
true})
Lib.DeferFunc(function() Lib.Window.ToggleSide("right") end)
end
return Main
end)()

-- Start
Main.Init()

You might also like