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 nodes,tree,listEntries,explorerOrders,searchResults,specResults = {},{},{},{},{},{} local expanded local entryTemplate,treeFrame,toolBar,descendantAddedCon,descendantRemovingCon,itemChangedCon 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,selection,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),BorderColor3=Color3.new(0.062745101749897,0.51764708757401,1),BorderMode=2,ClearTextOnFocus=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,200,0,16),Text="",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=0,Visible=false,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=UDim2.new(1,0,0,1),ZIndex=2,}}, {3,"Frame",{BackgroundColor3=Color3.new(1,1,1),BorderSizePixel=0,Name="Line",Parent={1},Position=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=UDim2.new(0,1,1,0),ZIndex=2,}}, {5,"Frame",{BackgroundColor3=Color3.new(1,1,1),BorderSizePixel=0,Name="Line",Parent={1},Position=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 = game:GetService("UserInputService").InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then releaseEvent:Disconnect() mouseEvent:Disconnect() end end) mouseEvent = 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["Player"] then context:AddRegistered("SELECT_CHARACTER") 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}) context:Register("COPY_PATH",{Name = "Copy Path", OnClick = function() local sList = selection.List if #sList == 1 then env.setclipboard(Explorer.GetInstancePath(sList[1].Obj)) elseif #sList > 1 then local resList = {"{"} local count = 2 for i = 1,#sList do local path = "\t"..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("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("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 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),BackgroundTransparency=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),Name="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,16,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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=0,Name="ToolBar",Parent={1},Size=UDim2.new(1,0,0,22),}}, {3,"Frame",{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),BorderColor3=Color3.new(0.1176470592618,0.1176470592618,0.1176470592618),BorderSizePixel=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.12549020349979,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.39215686917305),Parent={6},Size=UDim2.new(0,16,0,16),}}, {8,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.12549020349979,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),BorderSizePixel=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 -- TODO: Remove when open source if gethsfuncs then _G.moduleData = {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main} else return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main} end 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('?)([^<]*)', 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.35294118523598,0.35294118523598,0.35294118523598),BackgroundTransparency=0,BorderColor3=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,Visible=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,BorderSizePixel=0,Name="Main",Parent={1},Position=UDim2.new(0.40000000596046,0,0.40000000596046,0),Size=UDim2.new(0,300,0,300),}}, {3,"Frame",{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),BorderSizePixel=0,Name="Content",Parent={2},Position=UDim2.new(0,0,0,20),Size=UDim2.new(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),BorderSizePixel=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",Parent={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.12549020349979,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.12549020349979,0.12549020349979),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="Minimize",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,Image="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=UDim2.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.27450981736183,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.27450981736183,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.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="NorthEast",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.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="East",Parent={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.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="West",Parent={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.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="SouthEast",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.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="NorthWest",Parent={14},Size=UDim2.new(0,5,0,5),Text="",TextColor3=Color3.new(0,0,0),TextSize=14,}}, {22,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.27450981736183,0.27450981736183,0.27450981736183),BackgroundTransparency=1,BorderSizePixel=0,Font=3,Name="SouthWest",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 = 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 = 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.EasingStyle.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.EasingStyle.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.EasingStyle.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.EasingStyle.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.Quart,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.17647059261799,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),BorderSizePixel=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),BorderSizePixel=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.17647059261799,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),BorderSizePixel=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),BorderSizePixel=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.20392157137394,0.20392157137394),BorderColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),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.14117647707462),BorderColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),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),Name="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.20392157137394),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),BorderSizePixel=0,Name="SearchFrame",Parent={4},Size=UDim2.new(1,0,0,24),Visible=false,}}, {9,"Frame",{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),BorderColor3=Color3.new(0.1176470592618,0.1176470592618,0.1176470592618),BorderSizePixel=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.39215689897537),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),BorderSizePixel=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.20392157137394,0.20392157137394),BackgroundTransparency=1,BorderColor3=Color3.new(0.33725491166115,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.86274516582489),TextSize=14,TextXAlignment=1,}}, {16,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,ImageRectOffset=Vector2.new(304,0),ImageRectSize=Vector2.new(16,16),Name="Icon",Parent={13},Position=UDim2.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),BackgroundTransparency=1,BorderSizePixel=0,Name="Divider",Parent={1},Position=UDim2.new(0,0,0,20),Size=UDim2.new(1,0,0,7),Visible=false,}}, {19,"Frame",{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BorderSizePixel=0,Name="Line",Parent={18},Position=UDim2.new(0,0,0.5,0),Size=UDim2.new(1,0,0,1),}}, {20,"TextLabel",{AnchorPoint=Vector2.new(0,0.5),BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=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.60000002384186,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 = { ["'"] = "'", ["\""] = """, ["<"] = "<", [">"] = ">", ["&"] = "&" } 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 = 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),BorderSizePixel = 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.EasingDirection.Out),{BackgroundTransparency = 1}) lineTweens.Vis = tweenService:Create(cursor,TweenInfo.new(0.2,Enum.EasingStyle.Quart,Enum.EasingDirection.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),BorderSizePixel=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 .. "") 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 .. "") or lastText) end if self.Lines[relaY] then lineNumberStr = lineNumberStr .. (relaY == self.CursorY and (""..relaY.."\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] = (''):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),BorderSizePixel=0,Name="outline",Parent={1},Size=UDim2.new(0,16,0,16),}}, {4,"Frame",{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderSizePixel=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),BorderSizePixel=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.90196084976196,0.90196084976196),BorderSizePixel=0,Name="bottom",Parent={4},Position=UDim2.new(0,0,0,14),Size=UDim2.new(0,16,0,0),}}, {7,"Frame",{BackgroundColor3=Color3.new(0.90196084976196,0.90196084976196,0.90196084976196),BorderSizePixel=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.90196084976196,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),BackgroundTransparency=1,BorderSizePixel=0,ClipsDescendants=true,Name="checkmark",Parent={4},Position=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),BackgroundTransparency=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),BackgroundTransparency=1,Image="rbxassetid://6401617475",ImageColor3=Color3.new(0.20784313976765,0.69803923368454,0.98431372642517),Name="checkmark2",Parent={4},Position=UDim2.new(0.5,0,0.5,0),Size=UDim2.new(0,12,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.17647059261799),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),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.21568627655506),BorderSizePixel=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,Image="rbxassetid://1281023007",ImageColor3=Color3.new(0.33333334326744,0.33333334326744,0.49803924560547),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),BorderSizePixel=0,ClipsDescendants=true,Name="Content",Position=UDim2.new(0,0,0,20),Size=UDim2.new(1,0,1,-20),}}, {2,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="BasicColors",Parent={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",Parent={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),TextSize=14,TextXAlignment=0,}}, {4,"Frame",{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),BorderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Blue",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),BackgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.37647062540054),Font=3,Name="Input",Parent={4},Position=UDim2.new(0,2,0,0),Size=UDim2.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="",TextSize=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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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=UDim2.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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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",Parent={4},Position=UDim2.new(0,-40,0,0),Size=UDim2.new(0,34,1,0),Text="Blue:",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}}, {18,"Frame",{BackgroundColor3=Color3.new(0.21568627655506,0.21568627655506,0.21568627655506),BorderSizePixel=0,ClipsDescendants=true,Name="ColorSpaceFrame",Parent={1},Position=UDim2.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.37647062540054,0.37647062540054),BorderSizePixel=0,Image="rbxassetid://1072518406",Name="ColorSpace",Parent={18},Position=UDim2.new(0,1,0,1),Size=UDim2.new(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},Position=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},Position=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",Parent={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",Parent={23},Size=UDim2.new(1,0,0,20),Text="Custom Colors (RC = Set)",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=0,}}, {25,"Frame",{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),BorderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Green",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),BackgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.37647062540054),Font=3,Name="Input",Parent={25},Position=UDim2.new(0,2,0,0),Size=UDim2.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="",TextSize=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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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=UDim2.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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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",Parent={25},Position=UDim2.new(0,-40,0,0),Size=UDim2.new(0,34,1,0),Text="Green:",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}}, {39,"Frame",{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),BorderColor3=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),BackgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.37647062540054),Font=3,Name="Input",Parent={39},Position=UDim2.new(0,2,0,0),Size=UDim2.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="",TextSize=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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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=UDim2.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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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",Parent={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.21568627655506,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),BorderColor3=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),BackgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.37647062540054),Font=3,Name="Input",Parent={54},Position=UDim2.new(0,2,0,0),Size=UDim2.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="",TextSize=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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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=UDim2.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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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",Parent={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),BorderColor3=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),BackgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.37647062540054),Font=3,Name="Input",Parent={68},Position=UDim2.new(0,2,0,0),Size=UDim2.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="",TextSize=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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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=UDim2.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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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",Parent={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),BorderColor3=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),BackgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.37647062540054),Font=3,Name="Input",Parent={82},Position=UDim2.new(0,2,0,0),Size=UDim2.new(0,50,0,16),Text="255",TextColor3=Color3.new(0.86274516582489,0.86274516582489,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="",TextSize=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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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=UDim2.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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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",Parent={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.21568627655506),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.21568627655506),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.86274516582489,0.86274516582489),TextSize=14,}}, {98,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,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),BackgroundTransparency=1,BorderSizePixel=0,Name="ArrowFrame",Parent={1},Position=UDim2.new(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.new(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.new(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.new(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.new(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.new(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 = game:GetService("UserInputService") local mouse = 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.66666668653488,1,0),Color3.new(0,0,0.49803924560547),Color3.new(0.66666668653488,0,0.49803924560547),Color3.new(0,0.33333334326744,0.49803924560547),Color3.new(0.66666668653488,0.33333334326744,0.49803924560547),Color3.new(0,0.66666668653488,0.49803924560547),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.66666668653488,0.33333334326744,1),Color3.new(0,0.66666668653488,1),Color3.new(0.66666668653488,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.33333334326744,0),Color3.new(1,0.33333334326744,0),Color3.new(0.33333334326744,0.66666668653488,0),Color3.new(1,0.66666668653488,0),Color3.new(0.33333334326744,1,0),Color3.new(1,1,0),Color3.new(0.33333334326744,0,0.49803924560547),Color3.new(1,0,0.49803924560547),Color3.new(0.33333334326744,0.33333334326744,0.49803924560547),Color3.new(1,0.33333334326744,0.49803924560547),Color3.new(0.33333334326744,0.66666668653488,0.49803924560547),Color3.new(1,0.66666668653488,0.49803924560547),Color3.new(0.33333334326744,1,0.49803924560547),Color3.new(1,1,0.49803924560547),Color3.new(0.33333334326744,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),Color3.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),BorderSizePixel=0,ClipsDescendants=true,Name="Content",Position=UDim2.new(0,0,0,20),Size=UDim2.new(1,0,1,-20),}}, {2,"Frame",{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),BorderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Time",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),BackgroundTransparency=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.86274516582489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=0,}}, {4,"TextLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Parent={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.21568627655506),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.86274516582489,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.21568627655506),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.86274516582489,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.21568627655506),Font=3,Name="Delete",Parent={1},Position=UDim2.new(0,380,0,210),Size=UDim2.new(0,80,0,20),Text="Delete",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.86274516582489),TextSize=14,}}, {8,"Frame",{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.21568627655506),Name="NumberLineOutlines",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),BackgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.37647062540054),Name="NumberLine",Parent={1},Position=UDim2.new(0,10,0,20),Size=UDim2.new(1,-20,0,170),}}, {10,"Frame",{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),BorderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Value",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",Parent={10},Position=UDim2.new(0,-40,0,0),Size=UDim2.new(0,34,1,0),Text="Value",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=1,}}, {12,"TextBox",{BackgroundColor3=Color3.new(0.25098040699959,0.25098040699959,0.25098040699959),BackgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.37647062540054),ClipsDescendants=true,Font=3,Name="Input",Parent={10},Position=UDim2.new(0,2,0,0),Size=UDim2.new(0,58,0,20),Text="0",TextColor3=Color3.new(0.86274516582489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=0,}}, {13,"Frame",{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),BorderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Envelope",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),BackgroundTransparency=1,BorderColor3=Color3.new(0.37647062540054,0.37647062540054,0.37647062540054),ClipsDescendants=true,Font=3,Name="Input",Parent={13},Position=UDim2.new(0,2,0,0),Size=UDim2.new(0,58,0,20),Text="0",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="Title",Parent={13},Position=UDim2.new(0,-40,0,0),Size=UDim2.new(0,34,1,0),Text="Envelope",TextColor3=Color3.new(0.86274516582489,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 = game:GetService("UserInputService") local mouse = 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),BorderSizePixel=0,ClipsDescendants=true,Name="Content",Position=UDim2.new(0,0,0,20),Size=UDim2.new(1,0,1,-20),}}, {2,"Frame",{BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),BorderColor3=Color3.new(0.21568627655506,0.21568627655506,0.21568627655506),Name="ColorLine",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},Size=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,Name="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),BorderColor3=Color3.new(0.12549020349979,0.12549020349979,0.12549020349979),Name="Time",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),BackgroundTransparency=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.86274516582489,0.86274516582489,0.86274516582489),TextSize=14,TextXAlignment=0,}}, {9,"TextLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Title",Parent={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.21568627655506,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",Parent={10},Position=UDim2.new(0,-40,0,0),Size=UDim2.new(0,34,1,0),Text="Color",TextColor3=Color3.new(0.86274516582489,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.21568627655506),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.86274516582489,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.21568627655506),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.86274516582489,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.21568627655506),BorderSizePixel=0,Font=3,Name="Delete",Parent={1},Position=UDim2.new(0,280,0,95),Size=UDim2.new(0,80,0,20),Text="Delete",TextColor3=Color3.new(0.86274516582489,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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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 = game:GetService("UserInputService") local mouse = 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 = 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(999999999,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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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 -- TODO: Remove when open source if gethsfuncs then _G.moduleData = {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main} else return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main} end 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","Vector3","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 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.huge,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,Properties.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 "" 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),BorderSizePixel=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),BackgroundTransparency=1,BorderColor3=Color3.new(0.062745101749897,0.51764708757401,1),BorderSizePixel=0,ClearTextOnFocus=false,Font=3,Parent={1},PlaceholderColor3=Color3.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.17647059261799,0.17647059261799),BorderColor3=Color3.new(0.1294117718935,0.1294117718935,0.1294117718935),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),BackgroundTransparency=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),Name="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,Visible=false,}}, {7,"Frame",{BackgroundColor3=Color3.new(0.04313725605607,0.35294118523598,0.68627452850342),BackgroundTransparency=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),BorderColor3=Color3.new(0.33725491166115,0.49019610881805,0.73725491762161),BorderSizePixel=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=Color3.new(1,1,1),TextSize=14,Visible=false,}}, {10,"Frame",{BackgroundColor3=Color3.new(1,1,1),BorderColor3=Color3.new(0,0,0),Name="ColorPreview",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),BorderSizePixel=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),BorderSizePixel=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),BorderSizePixel=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.10000000149012,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",Parent={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=Color3.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),Name="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),BorderSizePixel=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),BorderColor3=Color3.new(0.1294117718935,0.1294117718935,0.1294117718935),Name="Slider",Parent={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=UDim2.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.new(1,0,1,0),Text="Add Attribute",TextColor3=Color3.new(1,1,1),TextSize=14,TextTransparency=0.10000000149012,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),BorderSizePixel=0,Name="ToolBar",Parent={1},Size=UDim2.new(1,0,0,22),}}, {3,"Frame",{BackgroundColor3=Color3.new(0.14901961386204,0.14901961386204,0.14901961386204),BorderColor3=Color3.new(0.1176470592618,0.1176470592618,0.1176470592618),BorderSizePixel=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.12549020349979,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.39215686917305),Parent={6},Size=UDim2.new(0,16,0,16),}}, {8,"TextButton",{AutoButtonColor=false,BackgroundColor3=Color3.new(0.12549020349979,0.12549020349979,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),BorderSizePixel=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 -- TODO: Remove when open source if gethsfuncs then _G.moduleData = {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main} else return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main} end 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 ScriptViewer.ViewScript = function(scr) local s,source = pcall(env.decompile or function() end,scr) if not s or not source then source = "local test = 5\n\nlocal c = test + tick()\ngame.Workspace.Board:Destroy()\nstring.match('wow\\'f',\"yes\",3.4e-5,true)\ngame. Workspace.Wow\nfunction bar() print(54) end\n string . match() string 4 .match()" source = source.."\n"..[==[ function a.sad() end function a.b:sad() end function 4.why() end function a b() end function string.match() end function string.match.why() end function local() end function local.thing() end string . "sad" match ().magnitude = 3 a..b a..b() a...b a...b() a....b a....b() string..match() string....match() ]==] 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.5,0,0,0) save.Size = UDim2.new(0.5,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) end return ScriptViewer end -- TODO: Remove when open source if gethsfuncs then _G.moduleData = {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main} else return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main} end end, } --[[ New Dex Final Version Developed by Moon 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.gg/zinnia Note that very limited to no support will be provided. ]] -- 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 = 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.GitRepoName = "LorekeeperZinnia/Dex" 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]() -- TODO: Remove when open source if gethsfuncs then control = _G.moduleData end if not control then Main.Error("Missing Embedded Module: "..name) end elseif _G.DebugLoadModel then -- Load Debug Model File local model = Main.DebugModel if not model then model = game:GetObjects(getsynasset("AfterModules.rbxm"))[1] end control = loadstring(model.Modules[name].Source)() print("Locally Loaded Module",name,control) else -- Get hash data local hashs = Main.ModuleHashData if not hashs then local s,hashDataStr = pcall(game.HttpGet, game, "https://api.github.com/repos/"..Main.GitRepoName.."/ModuleHashs.dat") if not s then Main.Error("Failed to get module hashs") end local s,hashData = pcall(service.HttpService.JSONDecode,service.HttpService,hashDataStr) if not s then Main.Error("Failed to decode module hash JSON") end hashs = hashData Main.ModuleHashData = hashs end -- Check if local copy exists with matching hashs local hashfunc = (syn and syn.crypt.hash) or function() return "" end local filePath = "dex/ModuleCache/"..name..".lua" local s,moduleStr = pcall(env.readfile,filePath) if s and hashfunc(moduleStr) == hashs[name] then control = loadstring(moduleStr)() else -- Download and cache local s,moduleStr = pcall(game.HttpGet, game, "https://api.github.com/repos/"..Main.GitRepoName.."/Modules/"..name..".lua") if not s then Main.Error("Failed to get external module data of "..name) end env.writefile(filePath,moduleStr) control = loadstring(moduleStr)() 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.IncompatibleTest = function() local function incompatibleMessage(reason) local msg = Instance.new("ScreenGui") local t = Instance.new("TextLabel",msg) t.BackgroundColor3 = Color3.fromRGB(50,50,50) t.Position = UDim2.new(0,0,0,-36) t.Size = UDim2.new(1,0,1,36) t.TextColor3 = Color3.new(1,1,1) t.TextWrapped = true t.TextScaled = true t.Text = "\n\n\n\n\n\n\n\nHello Skidsploit user,\nZinnia and the Secret Service does not approve of Dex being used on your skidsploit.\nPlease consider getting something better.\n\nIncompatible Reason: "..reason.."\n\n\n\n\n\n\n\n" local sound = Instance.new("Sound",msg) sound.SoundId = "rbxassetid://175964948" sound.Volume = 1 sound.Looped = true sound.Playing = true Lib.ShowGui(msg) if os and os.execute then pcall(os.execute,'explorer "https://x.synapse.to/"') end while wait() do end end local t = {} t[1] = t local x = unpack(t) or incompatibleMessage("WRAPPER FAILED TO CYCLIC #1") if x[1] ~= t then incompatibleMessage("WRAPPER FAILED TO CYCLIC #2") end if game ~= workspace.Parent then incompatibleMessage("WRAPPER NO CACHE") end if Main.Elevated and not loadstring("for i = 1,1 do continue end") then incompatibleMessage("CAN'T CONTINUE OR NO LOADSTRING") end local obj = newproxy(true) local mt = getmetatable(obj) mt.__index = function() incompatibleMessage("CAN'T NAMECALL") end mt.__namecall = function() end obj:No() local fEnv = setmetatable({zin = 5},{__index = getfenv()}) local caller = function(f) f() end setfenv(caller,fEnv) caller(function() if not getfenv(2).zin then incompatibleMessage("RERU WILL BE FILING A LAWSUIT AGAINST YOU SOON") end end) local second = false coroutine.wrap(function() local start = tick() wait(5) if tick() - start < 0.1 or not second then incompatibleMessage("SKIDDED YIELDING") end end)() second = true 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.20392157137394),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),BorderSizePixel=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",Parent={3},Position=UDim2.new(0,-190,0,15),Size=UDim2.new(0,100,0,50),Text="Dex",TextColor3=Color3.new(1,1,1),TextSize=50,TextTransparency=1,}}, {6,"TextLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Desc",Parent={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="StatusText",Parent={3},Position=UDim2.new(0,20,0,110),Size=UDim2.new(0,180,0,25),Text="Fetching API",TextColor3=Color3.new(1,1,1),TextSize=14,TextTransparency=1,}}, {8,"Frame",{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BorderSizePixel=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),BorderSizePixel=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.17647059261799),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),NumberSequenceKeypoint.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="Beta 1.0.0",TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=1,}}, {14,"UIGradient",{Parent={13},Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenceKeypoint.new(1,1,0),}),}}, {15,"ImageLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Image="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=UDim2.new(0,20,0,20),}}, {16,"UIGradient",{Parent={15},Rotation=-30,Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenceKeypoint.new(1,1,0),}),}}, {17,"UIGradient",{Parent={2},Rotation=-30,Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenceKeypoint.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),function(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,999999)).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.EasingStyle.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="OpenButton",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.17647059261799,0.17647059261799),ClipsDescendants=true,Name="MainFrame",Parent={2},Position=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),Name="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),BorderSizePixel=0,Name="CoverFrame",Parent={6},Size=UDim2.new(1,0,0,4),}}, {9,"Frame",{BackgroundColor3=Color3.new(0.1294117718935,0.1294117718935,0.1294117718935),BorderSizePixel=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=UDim2.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="Information",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=UDim2.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),BackgroundTransparency=1,BorderColor3=Color3.new(0.1294117718935,0.1294117718935,0.1294117718935),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,222,1,-25),}}, {15,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="Container",Parent={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.10000000149012,TextTruncate=1,TextWrapped=true,TextYAlignment=0,}}, {21,"Frame",{BackgroundColor3=Color3.new(0,0.66666668653488,1),BorderSizePixel=0,Name="Highlight",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.EasingStyle.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.EasingStyle.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}) 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 = 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() --for i,v in pairs(Main.MissingEnv) do print(i,v) end