· last year · Jan 28, 2024, 07:30 AM
1-- https://github.com/LorekeeperZinnia/Dex
2
3--[[
4 New Dex
5 Final Version
6 Developed by Moon
7 Modified for Infinite Yield
8
9 Dex is a debugging suite designed to help the user debug games and find any potential vulnerabilities.
10
11 This is the final version of this script.
12 You are encouraged to edit, fork, do whatever with this. I pretty much won't be updating it anymore.
13 Though I would appreciate it if you kept the credits in the script if you enjoy this hard work.
14
15 If you want more info, you can join the server: https://discord.io/zinnia
16 Note that very limited to no support will be provided.
17]]
18
19local nodes = {}
20local selection
21local clonerefs = cloneref or function(...) return ... end
22
23local EmbeddedModules = {
24Explorer = function()
25--[[
26 Explorer App Module
27
28 The main explorer interface
29]]
30
31-- Common Locals
32local Main,Lib,Apps,Settings -- Main Containers
33local Explorer, Properties, ScriptViewer, Notebook -- Major Apps
34local API,RMD,env,service,plr,create,createSimple -- Main Locals
35
36local function initDeps(data)
37 Main = data.Main
38 Lib = data.Lib
39 Apps = data.Apps
40 Settings = data.Settings
41
42 API = data.API
43 RMD = data.RMD
44 env = data.env
45 service = data.service
46 plr = data.plr
47 create = data.create
48 createSimple = data.createSimple
49end
50
51local function initAfterMain()
52 Explorer = Apps.Explorer
53 Properties = Apps.Properties
54 ScriptViewer = Apps.ScriptViewer
55 Notebook = Apps.Notebook
56end
57
58local function main()
59 local Explorer = {}
60 local tree,listEntries,explorerOrders,searchResults,specResults = {},{},{},{},{}
61 local expanded
62 local entryTemplate,treeFrame,toolBar,descendantAddedCon,descendantRemovingCon,itemChangedCon
63 local ffa = game.FindFirstAncestorWhichIsA
64 local getDescendants = game.GetDescendants
65 local getTextSize = service.TextService.GetTextSize
66 local updateDebounce,refreshDebounce = false,false
67 local nilNode = {Obj = Instance.new("Folder")}
68 local idCounter = 0
69 local scrollV,scrollH,clipboard
70 local renameBox,renamingNode,searchFunc
71 local sortingEnabled,autoUpdateSearch
72 local table,math = table,math
73 local nilMap,nilCons = {},{}
74 local connectSignal = game.DescendantAdded.Connect
75 local addObject,removeObject,moveObject = nil,nil,nil
76
77 addObject = function(root)
78 if nodes[root] then return end
79
80 local isNil = false
81 local rootParObj = ffa(root,"Instance")
82 local par = nodes[rootParObj]
83
84 -- Nil Handling
85 if not par then
86 if nilMap[root] then
87 nilCons[root] = nilCons[root] or {
88 connectSignal(root.ChildAdded,addObject),
89 connectSignal(root.AncestryChanged,moveObject),
90 }
91 par = nilNode
92 isNil = true
93 else
94 return
95 end
96 elseif nilMap[rootParObj] or par == nilNode then
97 nilMap[root] = true
98 nilCons[root] = nilCons[root] or {
99 connectSignal(root.ChildAdded,addObject),
100 connectSignal(root.AncestryChanged,moveObject),
101 }
102 isNil = true
103 end
104
105 local newNode = {Obj = root, Parent = par}
106 nodes[root] = newNode
107
108 -- Automatic sorting if expanded
109 if sortingEnabled and expanded[par] and par.Sorted then
110 local left,right = 1,#par
111 local floor = math.floor
112 local sorter = Explorer.NodeSorter
113 local pos = (right == 0 and 1)
114
115 if not pos then
116 while true do
117 if left >= right then
118 if sorter(newNode,par[left]) then
119 pos = left
120 else
121 pos = left+1
122 end
123 break
124 end
125
126 local mid = floor((left+right)/2)
127 if sorter(newNode,par[mid]) then
128 right = mid-1
129 else
130 left = mid+1
131 end
132 end
133 end
134
135 table.insert(par,pos,newNode)
136 else
137 par[#par+1] = newNode
138 par.Sorted = nil
139 end
140
141 local insts = getDescendants(root)
142 for i = 1,#insts do
143 local obj = insts[i]
144 if nodes[obj] then continue end -- Deferred
145
146 local par = nodes[ffa(obj,"Instance")]
147 if not par then continue end
148 local newNode = {Obj = obj, Parent = par}
149 nodes[obj] = newNode
150 par[#par+1] = newNode
151
152 -- Nil Handling
153 if isNil then
154 nilMap[obj] = true
155 nilCons[obj] = nilCons[obj] or {
156 connectSignal(obj.ChildAdded,addObject),
157 connectSignal(obj.AncestryChanged,moveObject),
158 }
159 end
160 end
161
162 if searchFunc and autoUpdateSearch then
163 searchFunc({newNode})
164 end
165
166 if not updateDebounce and Explorer.IsNodeVisible(par) then
167 if expanded[par] then
168 Explorer.PerformUpdate()
169 elseif not refreshDebounce then
170 Explorer.PerformRefresh()
171 end
172 end
173 end
174
175 removeObject = function(root)
176 local node = nodes[root]
177 if not node then return end
178
179 -- Nil Handling
180 if nilMap[node.Obj] then
181 moveObject(node.Obj)
182 return
183 end
184
185 local par = node.Parent
186 if par then
187 par.HasDel = true
188 end
189
190 local function recur(root)
191 for i = 1,#root do
192 local node = root[i]
193 if not node.Del then
194 nodes[node.Obj] = nil
195 if #node > 0 then recur(node) end
196 end
197 end
198 end
199 recur(node)
200 node.Del = true
201 nodes[root] = nil
202
203 if par and not updateDebounce and Explorer.IsNodeVisible(par) then
204 if expanded[par] then
205 Explorer.PerformUpdate()
206 elseif not refreshDebounce then
207 Explorer.PerformRefresh()
208 end
209 end
210 end
211
212 moveObject = function(obj)
213 local node = nodes[obj]
214 if not node then return end
215
216 local oldPar = node.Parent
217 local newPar = nodes[ffa(obj,"Instance")]
218 if oldPar == newPar then return end
219
220 -- Nil Handling
221 if not newPar then
222 if nilMap[obj] then
223 newPar = nilNode
224 else
225 return
226 end
227 elseif nilMap[newPar.Obj] or newPar == nilNode then
228 nilMap[obj] = true
229 nilCons[obj] = nilCons[obj] or {
230 connectSignal(obj.ChildAdded,addObject),
231 connectSignal(obj.AncestryChanged,moveObject),
232 }
233 end
234
235 if oldPar then
236 local parPos = table.find(oldPar,node)
237 if parPos then table.remove(oldPar,parPos) end
238 end
239
240 node.Id = nil
241 node.Parent = newPar
242
243 if sortingEnabled and expanded[newPar] and newPar.Sorted then
244 local left,right = 1,#newPar
245 local floor = math.floor
246 local sorter = Explorer.NodeSorter
247 local pos = (right == 0 and 1)
248
249 if not pos then
250 while true do
251 if left >= right then
252 if sorter(node,newPar[left]) then
253 pos = left
254 else
255 pos = left+1
256 end
257 break
258 end
259
260 local mid = floor((left+right)/2)
261 if sorter(node,newPar[mid]) then
262 right = mid-1
263 else
264 left = mid+1
265 end
266 end
267 end
268
269 table.insert(newPar,pos,node)
270 else
271 newPar[#newPar+1] = node
272 newPar.Sorted = nil
273 end
274
275 if searchFunc and searchResults[node] then
276 local currentNode = node.Parent
277 while currentNode and (not searchResults[currentNode] or expanded[currentNode] == 0) do
278 expanded[currentNode] = true
279 searchResults[currentNode] = true
280 currentNode = currentNode.Parent
281 end
282 end
283
284 if not updateDebounce and (Explorer.IsNodeVisible(newPar) or Explorer.IsNodeVisible(oldPar)) then
285 if expanded[newPar] or expanded[oldPar] then
286 Explorer.PerformUpdate()
287 elseif not refreshDebounce then
288 Explorer.PerformRefresh()
289 end
290 end
291 end
292
293 Explorer.ViewWidth = 0
294 Explorer.Index = 0
295 Explorer.EntryIndent = 20
296 Explorer.FreeWidth = 32
297 Explorer.GuiElems = {}
298
299 Explorer.InitRenameBox = function()
300 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}}})
301
302 renameBox.Parent = Explorer.Window.GuiElems.Content.List
303
304 renameBox.FocusLost:Connect(function()
305 if not renamingNode then return end
306
307 pcall(function() renamingNode.Obj.Name = renameBox.Text end)
308 renamingNode = nil
309 Explorer.Refresh()
310 end)
311
312 renameBox.Focused:Connect(function()
313 renameBox.SelectionStart = 1
314 renameBox.CursorPosition = #renameBox.Text + 1
315 end)
316 end
317
318 Explorer.SetRenamingNode = function(node)
319 renamingNode = node
320 renameBox.Text = tostring(node.Obj)
321 renameBox:CaptureFocus()
322 Explorer.Refresh()
323 end
324
325 Explorer.SetSortingEnabled = function(val)
326 sortingEnabled = val
327 Settings.Explorer.Sorting = val
328 end
329
330 Explorer.UpdateView = function()
331 local maxNodes = math.ceil(treeFrame.AbsoluteSize.Y / 20)
332 local maxX = treeFrame.AbsoluteSize.X
333 local totalWidth = Explorer.ViewWidth + Explorer.FreeWidth
334
335 scrollV.VisibleSpace = maxNodes
336 scrollV.TotalSpace = #tree + 1
337 scrollH.VisibleSpace = maxX
338 scrollH.TotalSpace = totalWidth
339
340 scrollV.Gui.Visible = #tree + 1 > maxNodes
341 scrollH.Gui.Visible = totalWidth > maxX
342
343 local oldSize = treeFrame.Size
344 treeFrame.Size = UDim2.new(1,(scrollV.Gui.Visible and -16 or 0),1,(scrollH.Gui.Visible and -39 or -23))
345 if oldSize ~= treeFrame.Size then
346 Explorer.UpdateView()
347 else
348 scrollV:Update()
349 scrollH:Update()
350
351 renameBox.Size = UDim2.new(0,maxX-100,0,16)
352
353 if scrollV.Gui.Visible and scrollH.Gui.Visible then
354 scrollV.Gui.Size = UDim2.new(0,16,1,-39)
355 scrollH.Gui.Size = UDim2.new(1,-16,0,16)
356 Explorer.Window.GuiElems.Content.ScrollCorner.Visible = true
357 else
358 scrollV.Gui.Size = UDim2.new(0,16,1,-23)
359 scrollH.Gui.Size = UDim2.new(1,0,0,16)
360 Explorer.Window.GuiElems.Content.ScrollCorner.Visible = false
361 end
362
363 Explorer.Index = scrollV.Index
364 end
365 end
366
367 Explorer.NodeSorter = function(a,b)
368 if a.Del or b.Del then return false end -- Ghost node
369
370 local aClass = a.Class
371 local bClass = b.Class
372 if not aClass then aClass = a.Obj.ClassName a.Class = aClass end
373 if not bClass then bClass = b.Obj.ClassName b.Class = bClass end
374
375 local aOrder = explorerOrders[aClass]
376 local bOrder = explorerOrders[bClass]
377 if not aOrder then aOrder = RMD.Classes[aClass] and tonumber(RMD.Classes[aClass].ExplorerOrder) or 9999 explorerOrders[aClass] = aOrder end
378 if not bOrder then bOrder = RMD.Classes[bClass] and tonumber(RMD.Classes[bClass].ExplorerOrder) or 9999 explorerOrders[bClass] = bOrder end
379
380 if aOrder ~= bOrder then
381 return aOrder < bOrder
382 else
383 local aName,bName = tostring(a.Obj),tostring(b.Obj)
384 if aName ~= bName then
385 return aName < bName
386 elseif aClass ~= bClass then
387 return aClass < bClass
388 else
389 local aId = a.Id if not aId then aId = idCounter idCounter = (idCounter+0.001)%999999999 a.Id = aId end
390 local bId = b.Id if not bId then bId = idCounter idCounter = (idCounter+0.001)%999999999 b.Id = bId end
391 return aId < bId
392 end
393 end
394 end
395
396 Explorer.Update = function()
397 table.clear(tree)
398 local maxNameWidth,maxDepth,count = 0,1,1
399 local nameCache = {}
400 local font = Enum.Font.SourceSans
401 local size = Vector2.new(math.huge,20)
402 local useNameWidth = Settings.Explorer.UseNameWidth
403 local tSort = table.sort
404 local sortFunc = Explorer.NodeSorter
405 local isSearching = (expanded == Explorer.SearchExpanded)
406 local textServ = service.TextService
407
408 local function recur(root,depth)
409 if depth > maxDepth then maxDepth = depth end
410 depth = depth + 1
411 if sortingEnabled and not root.Sorted then
412 tSort(root,sortFunc)
413 root.Sorted = true
414 end
415 for i = 1,#root do
416 local n = root[i]
417
418 if (isSearching and not searchResults[n]) or n.Del then continue end
419
420 if useNameWidth then
421 local nameWidth = n.NameWidth
422 if not nameWidth then
423 local objName = tostring(n.Obj)
424 nameWidth = nameCache[objName]
425 if not nameWidth then
426 nameWidth = getTextSize(textServ,objName,14,font,size).X
427 nameCache[objName] = nameWidth
428 end
429 n.NameWidth = nameWidth
430 end
431 if nameWidth > maxNameWidth then
432 maxNameWidth = nameWidth
433 end
434 end
435
436 tree[count] = n
437 count = count + 1
438 if expanded[n] and #n > 0 then
439 recur(n,depth)
440 end
441 end
442 end
443
444 recur(nodes[game],1)
445
446 -- Nil Instances
447 if env.getnilinstances then
448 if not (isSearching and not searchResults[nilNode]) then
449 tree[count] = nilNode
450 count = count + 1
451 if expanded[nilNode] then
452 recur(nilNode,2)
453 end
454 end
455 end
456
457 Explorer.MaxNameWidth = maxNameWidth
458 Explorer.MaxDepth = maxDepth
459 Explorer.ViewWidth = useNameWidth and Explorer.EntryIndent*maxDepth + maxNameWidth + 26 or Explorer.EntryIndent*maxDepth + 226
460 Explorer.UpdateView()
461 end
462
463 Explorer.StartDrag = function(offX,offY)
464 if Explorer.Dragging then return end
465 Explorer.Dragging = true
466
467 local dragTree = treeFrame:Clone()
468 dragTree:ClearAllChildren()
469
470 for i,v in pairs(listEntries) do
471 local node = tree[i + Explorer.Index]
472 if node and selection.Map[node] then
473 local clone = v:Clone()
474 clone.Active = false
475 clone.Indent.Expand.Visible = false
476 clone.Parent = dragTree
477 end
478 end
479
480 local newGui = Instance.new("ScreenGui")
481 newGui.DisplayOrder = Main.DisplayOrders.Menu
482 dragTree.Parent = newGui
483 Lib.ShowGui(newGui)
484
485 local dragOutline = create({
486 {1,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="DragSelect",Size=UDim2.new(1,0,1,0),}},
487 {2,"Frame",{BackgroundColor3=Color3.new(1,1,1),BorderSizePixel=0,Name="Line",Parent={1},Size=UDim2.new(1,0,0,1),ZIndex=2,}},
488 {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,}},
489 {4,"Frame",{BackgroundColor3=Color3.new(1,1,1),BorderSizePixel=0,Name="Line",Parent={1},Size=UDim2.new(0,1,1,0),ZIndex=2,}},
490 {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,}},
491 })
492 dragOutline.Parent = treeFrame
493
494
495 local mouse = Main.Mouse or service.Players.LocalPlayer:GetMouse()
496local input = service.UserInputService
497local isMobile = input.TouchEnabled
498
499local function move()
500 local posX, posY
501
502 if isMobile then
503 posX, posY = input.Touches[1].Position.X, input.Touches[1].Position.Y
504 else
505 posX = mouse.X - offX
506 posY = mouse.Y - offY
507 end
508
509 dragTree.Position = UDim2.new(0, posX, 0, posY)
510
511 for i = 1, #listEntries do
512 local entry = listEntries[i]
513 if (isMobile and Lib.CheckTouchInGui(entry)) or (not isMobile and Lib.CheckMouseInGui(entry)) then
514 dragOutline.Position = UDim2.new(0, entry.Indent.Position.X.Offset - scrollH.Index, 0, entry.Position.Y.Offset)
515 dragOutline.Size = UDim2.new(0, entry.Size.X.Offset - entry.Indent.Position.X.Offset, 0, 20)
516 dragOutline.Visible = true
517 return
518 end
519 end
520 dragOutline.Visible = false
521end
522move()
523
524local mouseEvent, releaseEvent
525
526mouseEvent = input.InputChanged:Connect(function(input)
527 if (isMobile and input.UserInputType == Enum.UserInputType.Touch) or
528 (not isMobile and input.UserInputType == Enum.UserInputType.MouseMovement) then
529 move()
530 end
531end)
532
533releaseEvent = input.InputEnded:Connect(function(input)
534 if (isMobile and input.UserInputType == Enum.UserInputType.Touch) or
535 (not isMobile and input.UserInputType == Enum.UserInputType.MouseButton1) then
536 releaseEvent:Disconnect()
537 mouseEvent:Disconnect()
538 newGui:Destroy()
539 dragOutline:Destroy()
540 Explorer.Dragging = false
541
542 for i = 1, #listEntries do
543 if (isMobile and Lib.CheckTouchInGui(listEntries[i])) or
544 (not isMobile and Lib.CheckMouseInGui(listEntries[i])) then
545 local node = tree[i + Explorer.Index]
546 if node then
547 if selection.Map[node] then return end
548 local newPar = node.Obj
549 local sList = selection.List
550 for i = 1, #sList do
551 local n = sList[i]
552 pcall(function() n.Obj.Parent = newPar end)
553 end
554 Explorer.ViewNode(sList[1])
555 end
556 break
557 end
558 end
559 end
560end)
561
562 Explorer.NewListEntry = function(index)
563 local newEntry = entryTemplate:Clone()
564 newEntry.Position = UDim2.new(0,0,0,20*(index-1))
565
566 local isRenaming = false
567
568 newEntry.InputBegan:Connect(function(input)
569 local node = tree[index + Explorer.Index]
570 if not node or selection.Map[node] or input.UserInputType ~= Enum.UserInputType.MouseMovement then return end
571
572 newEntry.Indent.BackgroundColor3 = Settings.Theme.Button
573 newEntry.Indent.BorderSizePixel = 0
574 newEntry.Indent.BackgroundTransparency = 0
575 end)
576
577 newEntry.InputEnded:Connect(function(input)
578 local node = tree[index + Explorer.Index]
579 if not node or selection.Map[node] or input.UserInputType ~= Enum.UserInputType.MouseMovement then return end
580
581 newEntry.Indent.BackgroundTransparency = 1
582 end)
583
584 newEntry.MouseButton1Down:Connect(function()
585
586 end)
587
588 newEntry.MouseButton1Up:Connect(function()
589
590 end)
591
592 newEntry.InputBegan:Connect(function(input)
593 if input.UserInputType == Enum.UserInputType.MouseButton1 then
594 local releaseEvent,mouseEvent
595
596 local mouse = Main.Mouse or plr:GetMouse()
597 local startX = mouse.X
598 local startY = mouse.Y
599
600 local listOffsetX = startX - treeFrame.AbsolutePosition.X
601 local listOffsetY = startY - treeFrame.AbsolutePosition.Y
602
603 releaseEvent = clonerefs(game:GetService("UserInputService")).InputEnded:Connect(function(input)
604 if input.UserInputType == Enum.UserInputType.MouseButton1 then
605 releaseEvent:Disconnect()
606 mouseEvent:Disconnect()
607 end
608 end)
609
610 mouseEvent = clonerefs(game:GetService("UserInputService")).InputChanged:Connect(function(input)
611 if input.UserInputType == Enum.UserInputType.MouseMovement then
612 local deltaX = mouse.X - startX
613 local deltaY = mouse.Y - startY
614 local dist = math.sqrt(deltaX^2 + deltaY^2)
615
616 if dist > 5 then
617 releaseEvent:Disconnect()
618 mouseEvent:Disconnect()
619 isRenaming = false
620 Explorer.StartDrag(listOffsetX,listOffsetY)
621 end
622 end
623 end)
624 end
625 end)
626
627 newEntry.MouseButton2Down:Connect(function()
628
629 end)
630
631 newEntry.Indent.Expand.InputBegan:Connect(function(input)
632 local node = tree[index + Explorer.Index]
633 if not node or input.UserInputType ~= Enum.UserInputType.MouseMovement then return end
634
635 Explorer.MiscIcons:DisplayByKey(newEntry.Indent.Expand.Icon, expanded[node] and "Collapse_Over" or "Expand_Over")
636 end)
637
638 newEntry.Indent.Expand.InputEnded:Connect(function(input)
639 local node = tree[index + Explorer.Index]
640 if not node or input.UserInputType ~= Enum.UserInputType.MouseMovement then return end
641
642 Explorer.MiscIcons:DisplayByKey(newEntry.Indent.Expand.Icon, expanded[node] and "Collapse" or "Expand")
643 end)
644
645 newEntry.Indent.Expand.MouseButton1Down:Connect(function()
646 local node = tree[index + Explorer.Index]
647 if not node or #node == 0 then return end
648
649 expanded[node] = not expanded[node]
650 Explorer.Update()
651 Explorer.Refresh()
652 end)
653
654 newEntry.Parent = treeFrame
655 return newEntry
656 end
657
658 Explorer.Refresh = function()
659 local maxNodes = math.max(math.ceil((treeFrame.AbsoluteSize.Y) / 20),0)
660 local renameNodeVisible = false
661 local isa = game.IsA
662
663 for i = 1,maxNodes do
664 local entry = listEntries[i]
665 if not listEntries[i] then entry = Explorer.NewListEntry(i) listEntries[i] = entry Explorer.ClickSystem:Add(entry) end
666
667 local node = tree[i + Explorer.Index]
668 if node then
669 local obj = node.Obj
670 local depth = Explorer.EntryIndent*Explorer.NodeDepth(node)
671
672 entry.Visible = true
673 entry.Position = UDim2.new(0,-scrollH.Index,0,entry.Position.Y.Offset)
674 entry.Size = UDim2.new(0,Explorer.ViewWidth,0,20)
675 entry.Indent.EntryName.Text = tostring(node.Obj)
676 entry.Indent.Position = UDim2.new(0,depth,0,0)
677 entry.Indent.Size = UDim2.new(1,-depth,1,0)
678
679 entry.Indent.EntryName.TextTruncate = (Settings.Explorer.UseNameWidth and Enum.TextTruncate.None or Enum.TextTruncate.AtEnd)
680
681 if (isa(obj,"LocalScript") or isa(obj,"Script")) and obj.Disabled then
682 Explorer.MiscIcons:DisplayByKey(entry.Indent.Icon, isa(obj,"LocalScript") and "LocalScript_Disabled" or "Script_Disabled")
683 else
684 local rmdEntry = RMD.Classes[obj.ClassName]
685 Explorer.ClassIcons:Display(entry.Indent.Icon, rmdEntry and rmdEntry.ExplorerImageIndex or 0)
686 end
687
688 if selection.Map[node] then
689 entry.Indent.BackgroundColor3 = Settings.Theme.ListSelection
690 entry.Indent.BorderSizePixel = 0
691 entry.Indent.BackgroundTransparency = 0
692 else
693 if Lib.CheckMouseInGui(entry) then
694 entry.Indent.BackgroundColor3 = Settings.Theme.Button
695 else
696 entry.Indent.BackgroundTransparency = 1
697 end
698 end
699
700 if node == renamingNode then
701 renameNodeVisible = true
702 renameBox.Position = UDim2.new(0,depth+25-scrollH.Index,0,entry.Position.Y.Offset+2)
703 renameBox.Visible = true
704 end
705
706 if #node > 0 and expanded[node] ~= 0 then
707 if Lib.CheckMouseInGui(entry.Indent.Expand) then
708 Explorer.MiscIcons:DisplayByKey(entry.Indent.Expand.Icon, expanded[node] and "Collapse_Over" or "Expand_Over")
709 else
710 Explorer.MiscIcons:DisplayByKey(entry.Indent.Expand.Icon, expanded[node] and "Collapse" or "Expand")
711 end
712 entry.Indent.Expand.Visible = true
713 else
714 entry.Indent.Expand.Visible = false
715 end
716 else
717 entry.Visible = false
718 end
719 end
720
721 if not renameNodeVisible then
722 renameBox.Visible = false
723 end
724
725 for i = maxNodes+1, #listEntries do
726 Explorer.ClickSystem:Remove(listEntries[i])
727 listEntries[i]:Destroy()
728 listEntries[i] = nil
729 end
730 end
731
732 Explorer.PerformUpdate = function(instant)
733 updateDebounce = true
734 Lib.FastWait(not instant and 0.1)
735 if not updateDebounce then return end
736 updateDebounce = false
737 if not Explorer.Window:IsVisible() then return end
738 Explorer.Update()
739 Explorer.Refresh()
740 end
741
742 Explorer.ForceUpdate = function(norefresh)
743 updateDebounce = false
744 Explorer.Update()
745 if not norefresh then Explorer.Refresh() end
746 end
747
748 Explorer.PerformRefresh = function()
749 refreshDebounce = true
750 Lib.FastWait(0.1)
751 refreshDebounce = false
752 if updateDebounce or not Explorer.Window:IsVisible() then return end
753 Explorer.Refresh()
754 end
755
756 Explorer.IsNodeVisible = function(node)
757 if not node then return end
758
759 local curNode = node.Parent
760 while curNode do
761 if not expanded[curNode] then return false end
762 curNode = curNode.Parent
763 end
764 return true
765 end
766
767 Explorer.NodeDepth = function(node)
768 local depth = 0
769
770 if node == nilNode then
771 return 1
772 end
773
774 local curNode = node.Parent
775 while curNode do
776 if curNode == nilNode then depth = depth + 1 end
777 curNode = curNode.Parent
778 depth = depth + 1
779 end
780 return depth
781 end
782
783 Explorer.SetupConnections = function()
784 if descendantAddedCon then descendantAddedCon:Disconnect() end
785 if descendantRemovingCon then descendantRemovingCon:Disconnect() end
786 if itemChangedCon then itemChangedCon:Disconnect() end
787
788 if Main.Elevated then
789 descendantAddedCon = game.DescendantAdded:Connect(addObject)
790 descendantRemovingCon = game.DescendantRemoving:Connect(removeObject)
791 else
792 descendantAddedCon = game.DescendantAdded:Connect(function(obj) pcall(addObject,obj) end)
793 descendantRemovingCon = game.DescendantRemoving:Connect(function(obj) pcall(removeObject,obj) end)
794 end
795
796 if Settings.Explorer.UseNameWidth then
797 itemChangedCon = game.ItemChanged:Connect(function(obj,prop)
798 if prop == "Parent" and nodes[obj] then
799 moveObject(obj)
800 elseif prop == "Name" and nodes[obj] then
801 nodes[obj].NameWidth = nil
802 end
803 end)
804 else
805 itemChangedCon = game.ItemChanged:Connect(function(obj,prop)
806 if prop == "Parent" and nodes[obj] then
807 moveObject(obj)
808 end
809 end)
810 end
811 end
812
813 Explorer.ViewNode = function(node)
814 if not node then return end
815
816 Explorer.MakeNodeVisible(node)
817 Explorer.ForceUpdate(true)
818 local visibleSpace = scrollV.VisibleSpace
819
820 for i,v in next,tree do
821 if v == node then
822 local relative = i - 1
823 if Explorer.Index > relative then
824 scrollV.Index = relative
825 elseif Explorer.Index + visibleSpace - 1 <= relative then
826 scrollV.Index = relative - visibleSpace + 2
827 end
828 end
829 end
830
831 scrollV:Update() Explorer.Index = scrollV.Index
832 Explorer.Refresh()
833 end
834
835 Explorer.ViewObj = function(obj)
836 Explorer.ViewNode(nodes[obj])
837 end
838
839 Explorer.MakeNodeVisible = function(node,expandRoot)
840 if not node then return end
841
842 local hasExpanded = false
843
844 if expandRoot and not expanded[node] then
845 expanded[node] = true
846 hasExpanded = true
847 end
848
849 local currentNode = node.Parent
850 while currentNode do
851 hasExpanded = true
852 expanded[currentNode] = true
853 currentNode = currentNode.Parent
854 end
855
856 if hasExpanded and not updateDebounce then
857 coroutine.wrap(Explorer.PerformUpdate)(true)
858 end
859 end
860
861 Explorer.ShowRightClick = function()
862 local context = Explorer.RightClickContext
863 context:Clear()
864
865 local sList = selection.List
866 local sMap = selection.Map
867 local emptyClipboard = #clipboard == 0
868 local presentClasses = {}
869 local apiClasses = API.Classes
870
871 for i = 1, #sList do
872 local node = sList[i]
873 local class = node.Class
874 if not class then class = node.Obj.ClassName node.Class = class end
875 local curClass = apiClasses[class]
876 while curClass and not presentClasses[curClass.Name] do
877 presentClasses[curClass.Name] = true
878 curClass = curClass.Superclass
879 end
880 end
881
882 context:AddRegistered("CUT")
883 context:AddRegistered("COPY")
884 context:AddRegistered("PASTE", emptyClipboard)
885 context:AddRegistered("DUPLICATE")
886 context:AddRegistered("DELETE")
887 context:AddRegistered("RENAME", #sList ~= 1)
888
889 context:AddDivider()
890 context:AddRegistered("GROUP")
891 context:AddRegistered("UNGROUP")
892 context:AddRegistered("SELECT_CHILDREN")
893 context:AddRegistered("JUMP_TO_PARENT")
894 context:AddRegistered("EXPAND_ALL")
895 context:AddRegistered("COLLAPSE_ALL")
896
897 context:AddDivider()
898 if expanded == Explorer.SearchExpanded then context:AddRegistered("CLEAR_SEARCH_AND_JUMP_TO") end
899 if env.setclipboard then context:AddRegistered("COPY_PATH") end
900 context:AddRegistered("INSERT_OBJECT")
901 context:AddRegistered("SAVE_INST")
902 context:AddRegistered("CALL_FUNCTION")
903 context:AddRegistered("VIEW_CONNECTIONS")
904 context:AddRegistered("GET_REFERENCES")
905 context:AddRegistered("VIEW_API")
906
907 context:QueueDivider()
908
909 if presentClasses["BasePart"] or presentClasses["Model"] then
910 context:AddRegistered("TELEPORT_TO")
911 context:AddRegistered("VIEW_OBJECT")
912 end
913
914 if presentClasses["TouchTransmitter"] then context:AddRegistered("FIRE_TOUCHTRANSMITTER", firetouchinterest == nil) end
915 if presentClasses["ClickDetector"] then context:AddRegistered("FIRE_CLICKDETECTOR", fireclickdetector == nil) end
916 if presentClasses["ProximityPrompt"] then context:AddRegistered("FIRE_PROXIMITYPROMPT", fireproximityprompt == nil) end
917 if presentClasses["Player"] then context:AddRegistered("SELECT_CHARACTER") end
918 if presentClasses["Players"] then context:AddRegistered("SELECT_LOCAL_PLAYER") end
919 if presentClasses["LuaSourceContainer"] then context:AddRegistered("VIEW_SCRIPT") end
920
921 if sMap[nilNode] then
922 context:AddRegistered("REFRESH_NIL")
923 context:AddRegistered("HIDE_NIL")
924 end
925
926 Explorer.LastRightClickX, Explorer.LastRightClickY = Main.Mouse.X, Main.Mouse.Y
927 context:Show()
928 end
929
930 Explorer.InitRightClick = function()
931 local context = Lib.ContextMenu.new()
932
933 context:Register("CUT",{Name = "Cut", IconMap = Explorer.MiscIcons, Icon = "Cut", DisabledIcon = "Cut_Disabled", Shortcut = "Ctrl+Z", OnClick = function()
934 local destroy,clone = game.Destroy,game.Clone
935 local sList,newClipboard = selection.List,{}
936 local count = 1
937 for i = 1,#sList do
938 local inst = sList[i].Obj
939 local s,cloned = pcall(clone,inst)
940 if s and cloned then
941 newClipboard[count] = cloned
942 count = count + 1
943 end
944 pcall(destroy,inst)
945 end
946 clipboard = newClipboard
947 selection:Clear()
948 end})
949
950 context:Register("COPY",{Name = "Copy", IconMap = Explorer.MiscIcons, Icon = "Copy", DisabledIcon = "Copy_Disabled", Shortcut = "Ctrl+C", OnClick = function()
951 local clone = game.Clone
952 local sList,newClipboard = selection.List,{}
953 local count = 1
954 for i = 1,#sList do
955 local inst = sList[i].Obj
956 local s,cloned = pcall(clone,inst)
957 if s and cloned then
958 newClipboard[count] = cloned
959 count = count + 1
960 end
961 end
962 clipboard = newClipboard
963 end})
964
965 context:Register("PASTE",{Name = "Paste Into", IconMap = Explorer.MiscIcons, Icon = "Paste", DisabledIcon = "Paste_Disabled", Shortcut = "Ctrl+Shift+V", OnClick = function()
966 local sList = selection.List
967 local newSelection = {}
968 local count = 1
969 for i = 1,#sList do
970 local node = sList[i]
971 local inst = node.Obj
972 Explorer.MakeNodeVisible(node,true)
973 for c = 1,#clipboard do
974 local cloned = clipboard[c]:Clone()
975 if cloned then
976 cloned.Parent = inst
977 local clonedNode = nodes[cloned]
978 if clonedNode then newSelection[count] = clonedNode count = count + 1 end
979 end
980 end
981 end
982 selection:SetTable(newSelection)
983
984 if #newSelection > 0 then
985 Explorer.ViewNode(newSelection[1])
986 end
987 end})
988
989 context:Register("DUPLICATE",{Name = "Duplicate", IconMap = Explorer.MiscIcons, Icon = "Copy", DisabledIcon = "Copy_Disabled", Shortcut = "Ctrl+D", OnClick = function()
990 local clone = game.Clone
991 local sList = selection.List
992 local newSelection = {}
993 local count = 1
994 for i = 1,#sList do
995 local node = sList[i]
996 local inst = node.Obj
997 local instPar = node.Parent and node.Parent.Obj
998 Explorer.MakeNodeVisible(node)
999 local s,cloned = pcall(clone,inst)
1000 if s and cloned then
1001 cloned.Parent = instPar
1002 local clonedNode = nodes[cloned]
1003 if clonedNode then newSelection[count] = clonedNode count = count + 1 end
1004 end
1005 end
1006
1007 selection:SetTable(newSelection)
1008 if #newSelection > 0 then
1009 Explorer.ViewNode(newSelection[1])
1010 end
1011 end})
1012
1013 context:Register("DELETE",{Name = "Delete", IconMap = Explorer.MiscIcons, Icon = "Delete", DisabledIcon = "Delete_Disabled", Shortcut = "Del", OnClick = function()
1014 local destroy = game.Destroy
1015 local sList = selection.List
1016 for i = 1,#sList do
1017 pcall(destroy,sList[i].Obj)
1018 end
1019 selection:Clear()
1020 end})
1021
1022 context:Register("RENAME",{Name = "Rename", IconMap = Explorer.MiscIcons, Icon = "Rename", DisabledIcon = "Rename_Disabled", Shortcut = "F2", OnClick = function()
1023 local sList = selection.List
1024 if sList[1] then
1025 Explorer.SetRenamingNode(sList[1])
1026 end
1027 end})
1028
1029 context:Register("GROUP",{Name = "Group", IconMap = Explorer.MiscIcons, Icon = "Group", DisabledIcon = "Group_Disabled", Shortcut = "Ctrl+G", OnClick = function()
1030 local sList = selection.List
1031 if #sList == 0 then return end
1032
1033 local model = Instance.new("Model",sList[#sList].Obj.Parent)
1034 for i = 1,#sList do
1035 pcall(function() sList[i].Obj.Parent = model end)
1036 end
1037
1038 if nodes[model] then
1039 selection:Set(nodes[model])
1040 Explorer.ViewNode(nodes[model])
1041 end
1042 end})
1043
1044 context:Register("UNGROUP",{Name = "Ungroup", IconMap = Explorer.MiscIcons, Icon = "Ungroup", DisabledIcon = "Ungroup_Disabled", Shortcut = "Ctrl+U", OnClick = function()
1045 local newSelection = {}
1046 local count = 1
1047 local isa = game.IsA
1048
1049 local function ungroup(node)
1050 local par = node.Parent.Obj
1051 local ch = {}
1052 local chCount = 1
1053
1054 for i = 1,#node do
1055 local n = node[i]
1056 newSelection[count] = n
1057 ch[chCount] = n
1058 count = count + 1
1059 chCount = chCount + 1
1060 end
1061
1062 for i = 1,#ch do
1063 pcall(function() ch[i].Obj.Parent = par end)
1064 end
1065
1066 node.Obj:Destroy()
1067 end
1068
1069 for i,v in next,selection.List do
1070 if isa(v.Obj,"Model") then
1071 ungroup(v)
1072 end
1073 end
1074
1075 selection:SetTable(newSelection)
1076 if #newSelection > 0 then
1077 Explorer.ViewNode(newSelection[1])
1078 end
1079 end})
1080
1081 context:Register("SELECT_CHILDREN",{Name = "Select Children", IconMap = Explorer.MiscIcons, Icon = "SelectChildren", DisabledIcon = "SelectChildren_Disabled", OnClick = function()
1082 local newSelection = {}
1083 local count = 1
1084 local sList = selection.List
1085
1086 for i = 1,#sList do
1087 local node = sList[i]
1088 for ind = 1,#node do
1089 local cNode = node[ind]
1090 if ind == 1 then Explorer.MakeNodeVisible(cNode) end
1091
1092 newSelection[count] = cNode
1093 count = count + 1
1094 end
1095 end
1096
1097 selection:SetTable(newSelection)
1098 if #newSelection > 0 then
1099 Explorer.ViewNode(newSelection[1])
1100 else
1101 Explorer.Refresh()
1102 end
1103 end})
1104
1105 context:Register("JUMP_TO_PARENT",{Name = "Jump to Parent", IconMap = Explorer.MiscIcons, Icon = "JumpToParent", OnClick = function()
1106 local newSelection = {}
1107 local count = 1
1108 local sList = selection.List
1109
1110 for i = 1,#sList do
1111 local node = sList[i]
1112 if node.Parent then
1113 newSelection[count] = node.Parent
1114 count = count + 1
1115 end
1116 end
1117
1118 selection:SetTable(newSelection)
1119 if #newSelection > 0 then
1120 Explorer.ViewNode(newSelection[1])
1121 else
1122 Explorer.Refresh()
1123 end
1124 end})
1125
1126 context:Register("TELEPORT_TO",{Name = "Teleport To", IconMap = Explorer.MiscIcons, Icon = "TeleportTo", OnClick = function()
1127 local sList = selection.List
1128 local isa = game.IsA
1129
1130 local hrp = plr.Character and plr.Character:FindFirstChild("HumanoidRootPart")
1131 if not hrp then return end
1132
1133 for i = 1,#sList do
1134 local node = sList[i]
1135
1136 if isa(node.Obj,"BasePart") then
1137 hrp.CFrame = node.Obj.CFrame + Settings.Explorer.TeleportToOffset
1138 break
1139 elseif isa(node.Obj,"Model") then
1140 if node.Obj.PrimaryPart then
1141 hrp.CFrame = node.Obj.PrimaryPart.CFrame + Settings.Explorer.TeleportToOffset
1142 break
1143 else
1144 local part = node.Obj:FindFirstChildWhichIsA("BasePart",true)
1145 if part and nodes[part] then
1146 hrp.CFrame = nodes[part].Obj.CFrame + Settings.Explorer.TeleportToOffset
1147 end
1148 end
1149 end
1150 end
1151 end})
1152
1153 context:Register("EXPAND_ALL",{Name = "Expand All", OnClick = function()
1154 local sList = selection.List
1155
1156 local function expand(node)
1157 expanded[node] = true
1158 for i = 1,#node do
1159 if #node[i] > 0 then
1160 expand(node[i])
1161 end
1162 end
1163 end
1164
1165 for i = 1,#sList do
1166 expand(sList[i])
1167 end
1168
1169 Explorer.ForceUpdate()
1170 end})
1171
1172 context:Register("COLLAPSE_ALL",{Name = "Collapse All", OnClick = function()
1173 local sList = selection.List
1174
1175 local function expand(node)
1176 expanded[node] = nil
1177 for i = 1,#node do
1178 if #node[i] > 0 then
1179 expand(node[i])
1180 end
1181 end
1182 end
1183
1184 for i = 1,#sList do
1185 expand(sList[i])
1186 end
1187
1188 Explorer.ForceUpdate()
1189 end})
1190
1191 context:Register("CLEAR_SEARCH_AND_JUMP_TO",{Name = "Clear Search and Jump to", OnClick = function()
1192 local newSelection = {}
1193 local count = 1
1194 local sList = selection.List
1195
1196 for i = 1,#sList do
1197 newSelection[count] = sList[i]
1198 count = count + 1
1199 end
1200
1201 selection:SetTable(newSelection)
1202 Explorer.ClearSearch()
1203 if #newSelection > 0 then
1204 Explorer.ViewNode(newSelection[1])
1205 end
1206 end})
1207
1208 local clth = function(str)
1209 if str:sub(1, 28) == "game:GetService(\"Workspace\")" then str = str:gsub("game:GetService%(\"Workspace\"%)", "workspace", 1) end
1210 if str:sub(1, 27 + #plr.Name) == "game:GetService(\"Players\")." .. plr.Name then str = str:gsub("game:GetService%(\"Players\"%)." .. plr.Name, "game:GetService(\"Players\").LocalPlayer", 1) end
1211 return str
1212 end
1213
1214 context:Register("COPY_PATH",{Name = "Copy Path", OnClick = function()
1215 local sList = selection.List
1216 if #sList == 1 then
1217 env.setclipboard(clth(Explorer.GetInstancePath(sList[1].Obj)))
1218 elseif #sList > 1 then
1219 local resList = {"{"}
1220 local count = 2
1221 for i = 1,#sList do
1222 local path = "\t"..clth(Explorer.GetInstancePath(sList[i].Obj))..","
1223 if #path > 0 then
1224 resList[count] = path
1225 count = count+1
1226 end
1227 end
1228 resList[count] = "}"
1229 env.setclipboard(table.concat(resList,"\n"))
1230 end
1231 end})
1232
1233 context:Register("INSERT_OBJECT",{Name = "Insert Object", IconMap = Explorer.MiscIcons, Icon = "InsertObject", OnClick = function()
1234 local mouse = Main.Mouse
1235 local x,y = Explorer.LastRightClickX or mouse.X, Explorer.LastRightClickY or mouse.Y
1236 Explorer.InsertObjectContext:Show(x,y)
1237 end})
1238
1239 context:Register("CALL_FUNCTION",{Name = "Call Function", IconMap = Explorer.ClassIcons, Icon = 66, OnClick = function()
1240
1241 end})
1242
1243 context:Register("GET_REFERENCES",{Name = "Get Lua References", IconMap = Explorer.ClassIcons, Icon = 34, OnClick = function()
1244
1245 end})
1246
1247 context:Register("SAVE_INST",{Name = "Save to File", IconMap = Explorer.MiscIcons, Icon = "Save", OnClick = function()
1248
1249 end})
1250
1251 context:Register("VIEW_CONNECTIONS",{Name = "View Connections", OnClick = function()
1252
1253 end})
1254
1255 context:Register("VIEW_API",{Name = "View API Page", IconMap = Explorer.MiscIcons, Icon = "Reference", OnClick = function()
1256
1257 end})
1258
1259 context:Register("VIEW_OBJECT",{Name = "View Object (Right click to reset)", IconMap = Explorer.ClassIcons, Icon = 5, OnClick = function()
1260 local sList = selection.List
1261 local isa = game.IsA
1262
1263 for i = 1,#sList do
1264 local node = sList[i]
1265
1266 if isa(node.Obj,"BasePart") or isa(node.Obj,"Model") then
1267 workspace.CurrentCamera.CameraSubject = node.Obj
1268 break
1269 end
1270 end
1271 end, OnRightClick = function()
1272 workspace.CurrentCamera.CameraSubject = plr.Character
1273 end})
1274
1275 context:Register("FIRE_TOUCHTRANSMITTER",{Name = "Fire TouchTransmitter", IconMap = Explorer.ClassIcons, Icon = 37, OnClick = function()
1276 local hrp = plr.Character and plr.Character:FindFirstChild("HumanoidRootPart")
1277 if not hrp then return end
1278 for _, v in ipairs(selection.List) do if v.Obj and v.Obj:IsA("TouchTransmitter") then firetouchinterest(hrp, v.Obj.Parent, 0) end end
1279 end})
1280
1281 context:Register("FIRE_CLICKDETECTOR",{Name = "Fire ClickDetector", IconMap = Explorer.ClassIcons, Icon = 41, OnClick = function()
1282 local hrp = plr.Character and plr.Character:FindFirstChild("HumanoidRootPart")
1283 if not hrp then return end
1284 for _, v in ipairs(selection.List) do if v.Obj and v.Obj:IsA("ClickDetector") then fireclickdetector(v.Obj) end end
1285 end})
1286
1287 context:Register("FIRE_PROXIMITYPROMPT",{Name = "Fire ProximityPrompt", IconMap = Explorer.ClassIcons, Icon = 124, OnClick = function()
1288 local hrp = plr.Character and plr.Character:FindFirstChild("HumanoidRootPart")
1289 if not hrp then return end
1290 for _, v in ipairs(selection.List) do if v.Obj and v.Obj:IsA("ProximityPrompt") then fireproximityprompt(v.Obj) end end
1291 end})
1292
1293 context:Register("VIEW_SCRIPT",{Name = "View Script", IconMap = Explorer.MiscIcons, Icon = "ViewScript", OnClick = function()
1294 local scr = selection.List[1] and selection.List[1].Obj
1295 if scr then ScriptViewer.ViewScript(scr) end
1296 end})
1297
1298 context:Register("SELECT_CHARACTER",{Name = "Select Character", IconMap = Explorer.ClassIcons, Icon = 9, OnClick = function()
1299 local newSelection = {}
1300 local count = 1
1301 local sList = selection.List
1302 local isa = game.IsA
1303
1304 for i = 1,#sList do
1305 local node = sList[i]
1306 if isa(node.Obj,"Player") and nodes[node.Obj.Character] then
1307 newSelection[count] = nodes[node.Obj.Character]
1308 count = count + 1
1309 end
1310 end
1311
1312 selection:SetTable(newSelection)
1313 if #newSelection > 0 then
1314 Explorer.ViewNode(newSelection[1])
1315 else
1316 Explorer.Refresh()
1317 end
1318 end})
1319
1320 context:Register("SELECT_LOCAL_PLAYER",{Name = "Select Local Player", IconMap = Explorer.ClassIcons, Icon = 9, OnClick = function()
1321 pcall(function() if nodes[plr] then selection:Set(nodes[plr]) Explorer.ViewNode(nodes[plr]) end end)
1322 end})
1323
1324 context:Register("REFRESH_NIL",{Name = "Refresh Nil Instances", OnClick = function()
1325 Explorer.RefreshNilInstances()
1326 end})
1327
1328 context:Register("HIDE_NIL",{Name = "Hide Nil Instances", OnClick = function()
1329 Explorer.HideNilInstances()
1330 end})
1331
1332 Explorer.RightClickContext = context
1333 end
1334
1335 Explorer.HideNilInstances = function()
1336 table.clear(nilMap)
1337
1338 local disconnectCon = Instance.new("Folder").ChildAdded:Connect(function() end).Disconnect
1339 for i,v in next,nilCons do
1340 disconnectCon(v[1])
1341 disconnectCon(v[2])
1342 end
1343 table.clear(nilCons)
1344
1345 for i = 1,#nilNode do
1346 coroutine.wrap(removeObject)(nilNode[i].Obj)
1347 end
1348
1349 Explorer.Update()
1350 Explorer.Refresh()
1351 end
1352
1353 Explorer.RefreshNilInstances = function()
1354 if not env.getnilinstances then return end
1355
1356 local nilInsts = env.getnilinstances()
1357 local game = game
1358 local getDescs = game.GetDescendants
1359 --local newNilMap = {}
1360 --local newNilRoots = {}
1361 --local nilRoots = Explorer.NilRoots
1362 --local connect = game.DescendantAdded.Connect
1363 --local disconnect
1364 --if not nilRoots then nilRoots = {} Explorer.NilRoots = nilRoots end
1365
1366 for i = 1,#nilInsts do
1367 local obj = nilInsts[i]
1368 if obj ~= game then
1369 nilMap[obj] = true
1370 --newNilRoots[obj] = true
1371
1372 local descs = getDescs(obj)
1373 for j = 1,#descs do
1374 nilMap[descs[j]] = true
1375 end
1376 end
1377 end
1378
1379 -- Remove unmapped nil nodes
1380 --[[for i = 1,#nilNode do
1381 local node = nilNode[i]
1382 if not newNilMap[node.Obj] then
1383 nilMap[node.Obj] = nil
1384 coroutine.wrap(removeObject)(node)
1385 end
1386 end]]
1387
1388 --nilMap = newNilMap
1389
1390 for i = 1,#nilInsts do
1391 local obj = nilInsts[i]
1392 local node = nodes[obj]
1393 if not node then coroutine.wrap(addObject)(obj) end
1394 end
1395
1396 --[[
1397 -- Remove old root connections
1398 for obj in next,nilRoots do
1399 if not newNilRoots[obj] then
1400 if not disconnect then disconnect = obj[1].Disconnect end
1401 disconnect(obj[1])
1402 disconnect(obj[2])
1403 end
1404 end
1405
1406 for obj in next,newNilRoots do
1407 if not nilRoots[obj] then
1408 nilRoots[obj] = {
1409 connect(obj.DescendantAdded,addObject),
1410 connect(obj.DescendantRemoving,removeObject)
1411 }
1412 end
1413 end]]
1414
1415 --nilMap = newNilMap
1416 --Explorer.NilRoots = newNilRoots
1417
1418 Explorer.Update()
1419 Explorer.Refresh()
1420 end
1421
1422 Explorer.GetInstancePath = function(obj)
1423 local ffc = game.FindFirstChild
1424 local getCh = game.GetChildren
1425 local path = ""
1426 local curObj = obj
1427 local ts = tostring
1428 local match = string.match
1429 local gsub = string.gsub
1430 local tableFind = table.find
1431 local useGetCh = Settings.Explorer.CopyPathUseGetChildren
1432 local formatLuaString = Lib.FormatLuaString
1433
1434 while curObj do
1435 if curObj == game then
1436 path = "game"..path
1437 break
1438 end
1439
1440 local className = curObj.ClassName
1441 local curName = ts(curObj)
1442 local indexName
1443 if match(curName,"^[%a_][%w_]*$") then
1444 indexName = "."..curName
1445 else
1446 local cleanName = formatLuaString(curName)
1447 indexName = '["'..cleanName..'"]'
1448 end
1449
1450 local parObj = curObj.Parent
1451 if parObj then
1452 local fc = ffc(parObj,curName)
1453 if useGetCh and fc and fc ~= curObj then
1454 local parCh = getCh(parObj)
1455 local fcInd = tableFind(parCh,curObj)
1456 indexName = ":GetChildren()["..fcInd.."]"
1457 elseif parObj == game and API.Classes[className] and API.Classes[className].Tags.Service then
1458 indexName = ':GetService("'..className..'")'
1459 end
1460 elseif parObj == nil then
1461 local getnil = "local getNil = function(name, class) for _, v in next, getnilinstances() do if v.ClassName == class and v.Name == name then return v end end end"
1462 local gotnil = "\n\ngetNil(\"%s\", \"%s\")"
1463 indexName = getnil .. gotnil:format(curObj.Name, className)
1464 end
1465
1466 path = indexName..path
1467 curObj = parObj
1468 end
1469
1470 return path
1471 end
1472
1473 Explorer.InitInsertObject = function()
1474 local context = Lib.ContextMenu.new()
1475 context.SearchEnabled = true
1476 context.MaxHeight = 400
1477 context:ApplyTheme({
1478 ContentColor = Settings.Theme.Main2,
1479 OutlineColor = Settings.Theme.Outline1,
1480 DividerColor = Settings.Theme.Outline1,
1481 TextColor = Settings.Theme.Text,
1482 HighlightColor = Settings.Theme.ButtonHover
1483 })
1484
1485 local classes = {}
1486 for i,class in next,API.Classes do
1487 local tags = class.Tags
1488 if not tags.NotCreatable and not tags.Service then
1489 local rmdEntry = RMD.Classes[class.Name]
1490 classes[#classes+1] = {class,rmdEntry and rmdEntry.ClassCategory or "Uncategorized"}
1491 end
1492 end
1493 table.sort(classes,function(a,b)
1494 if a[2] ~= b[2] then
1495 return a[2] < b[2]
1496 else
1497 return a[1].Name < b[1].Name
1498 end
1499 end)
1500
1501 local function onClick(className)
1502 local sList = selection.List
1503 local instNew = Instance.new
1504 for i = 1,#sList do
1505 local node = sList[i]
1506 local obj = node.Obj
1507 Explorer.MakeNodeVisible(node,true)
1508 pcall(instNew,className,obj)
1509 end
1510 end
1511
1512 local lastCategory = ""
1513 for i = 1,#classes do
1514 local class = classes[i][1]
1515 local rmdEntry = RMD.Classes[class.Name]
1516 local iconInd = rmdEntry and tonumber(rmdEntry.ExplorerImageIndex) or 0
1517 local category = classes[i][2]
1518
1519 if lastCategory ~= category then
1520 context:AddDivider(category)
1521 lastCategory = category
1522 end
1523 context:Add({Name = class.Name, IconMap = Explorer.ClassIcons, Icon = iconInd, OnClick = onClick})
1524 end
1525
1526 Explorer.InsertObjectContext = context
1527 end
1528
1529 --[[
1530 Headers, Setups, Predicate, ObjectDefs
1531 ]]
1532 Explorer.SearchFilters = { -- TODO: Use data table (so we can disable some if funcs don't exist)
1533 Comparison = {
1534 ["isa"] = function(argString)
1535 local lower = string.lower
1536 local find = string.find
1537 local classQuery = string.split(argString)[1]
1538 if not classQuery then return end
1539 classQuery = lower(classQuery)
1540
1541 local className
1542 for class,_ in pairs(API.Classes) do
1543 local cName = lower(class)
1544 if cName == classQuery then
1545 className = class
1546 break
1547 elseif find(cName,classQuery,1,true) then
1548 className = class
1549 end
1550 end
1551 if not className then return end
1552
1553 return {
1554 Headers = {"local isa = game.IsA"},
1555 Predicate = "isa(obj,'"..className.."')"
1556 }
1557 end,
1558 ["remotes"] = function(argString)
1559 return {
1560 Headers = {"local isa = game.IsA"},
1561 Predicate = "isa(obj,'RemoteEvent') or isa(obj,'RemoteFunction')"
1562 }
1563 end,
1564 ["bindables"] = function(argString)
1565 return {
1566 Headers = {"local isa = game.IsA"},
1567 Predicate = "isa(obj,'BindableEvent') or isa(obj,'BindableFunction')"
1568 }
1569 end,
1570 ["rad"] = function(argString)
1571 local num = tonumber(argString)
1572 if not num then return end
1573
1574 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
1575
1576 return {
1577 Headers = {"local isa = game.IsA", "local hrp = service.Players.LocalPlayer.Character.HumanoidRootPart"},
1578 Setups = {"local hrpPos = hrp.Position"},
1579 ObjectDefs = {"local isBasePart = isa(obj,'BasePart')"},
1580 Predicate = "(isBasePart and (obj.Position-hrpPos).Magnitude <= "..num..")"
1581 }
1582 end,
1583 },
1584 Specific = {
1585 ["players"] = function()
1586 return function() return service.Players:GetPlayers() end
1587 end,
1588 ["loadedmodules"] = function()
1589 return env.getloadedmodules
1590 end,
1591 },
1592 Default = function(argString,caseSensitive)
1593 local cleanString = argString:gsub("\"","\\\""):gsub("\n","\\n")
1594 if caseSensitive then
1595 return {
1596 Headers = {"local find = string.find"},
1597 ObjectDefs = {"local objName = tostring(obj)"},
1598 Predicate = "find(objName,\"" .. cleanString .. "\",1,true)"
1599 }
1600 else
1601 return {
1602 Headers = {"local lower = string.lower","local find = string.find","local tostring = tostring"},
1603 ObjectDefs = {"local lowerName = lower(tostring(obj))"},
1604 Predicate = "find(lowerName,\"" .. cleanString:lower() .. "\",1,true)"
1605 }
1606 end
1607 end,
1608 SpecificDefault = function(n)
1609 return {
1610 Headers = {},
1611 ObjectDefs = {"local isSpec"..n.." = specResults["..n.."][node]"},
1612 Predicate = "isSpec"..n
1613 }
1614 end,
1615 }
1616
1617 Explorer.BuildSearchFunc = function(query)
1618 local specFilterList,specMap = {},{}
1619 local finalPredicate = ""
1620 local rep = string.rep
1621 local formatQuery = query:gsub("\\."," "):gsub('".-"',function(str) return rep(" ",#str) end)
1622 local headers = {}
1623 local objectDefs = {}
1624 local setups = {}
1625 local find = string.find
1626 local sub = string.sub
1627 local lower = string.lower
1628 local match = string.match
1629 local ops = {
1630 ["("] = "(",
1631 [")"] = ")",
1632 ["||"] = " or ",
1633 ["&&"] = " and "
1634 }
1635 local filterCount = 0
1636 local compFilters = Explorer.SearchFilters.Comparison
1637 local specFilters = Explorer.SearchFilters.Specific
1638 local init = 1
1639 local lastOp = nil
1640
1641 local function processFilter(dat)
1642 if dat.Headers then
1643 local t = dat.Headers
1644 for i = 1,#t do
1645 headers[t[i]] = true
1646 end
1647 end
1648
1649 if dat.ObjectDefs then
1650 local t = dat.ObjectDefs
1651 for i = 1,#t do
1652 objectDefs[t[i]] = true
1653 end
1654 end
1655
1656 if dat.Setups then
1657 local t = dat.Setups
1658 for i = 1,#t do
1659 setups[t[i]] = true
1660 end
1661 end
1662
1663 finalPredicate = finalPredicate..dat.Predicate
1664 end
1665
1666 local found = {}
1667 local foundData = {}
1668 local find = string.find
1669 local sub = string.sub
1670
1671 local function findAll(str,pattern)
1672 local count = #found+1
1673 local init = 1
1674 local sz = #pattern
1675 local x,y,extra = find(str,pattern,init,true)
1676 while x do
1677 found[count] = x
1678 foundData[x] = {sz,pattern}
1679
1680 count = count+1
1681 init = y+1
1682 x,y,extra = find(str,pattern,init,true)
1683 end
1684 end
1685 local start = tick()
1686 findAll(formatQuery,'&&')
1687 findAll(formatQuery,"||")
1688 findAll(formatQuery,"(")
1689 findAll(formatQuery,")")
1690 table.sort(found)
1691 table.insert(found,#formatQuery+1)
1692
1693 local function inQuotes(str)
1694 local len = #str
1695 if sub(str,1,1) == '"' and sub(str,len,len) == '"' then
1696 return sub(str,2,len-1)
1697 end
1698 end
1699
1700 for i = 1,#found do
1701 local nextInd = found[i]
1702 local nextData = foundData[nextInd] or {1}
1703 local op = ops[nextData[2]]
1704 local term = sub(query,init,nextInd-1)
1705 term = match(term,"^%s*(.-)%s*$") or "" -- Trim
1706
1707 if #term > 0 then
1708 if sub(term,1,1) == "!" then
1709 term = sub(term,2)
1710 finalPredicate = finalPredicate.."not "
1711 end
1712
1713 local qTerm = inQuotes(term)
1714 if qTerm then
1715 processFilter(Explorer.SearchFilters.Default(qTerm,true))
1716 else
1717 local x,y = find(term,"%S+")
1718 if x then
1719 local first = sub(term,x,y)
1720 local specifier = sub(first,1,1) == "/" and lower(sub(first,2))
1721 local compFunc = specifier and compFilters[specifier]
1722 local specFunc = specifier and specFilters[specifier]
1723
1724 if compFunc then
1725 local argStr = sub(term,y+2)
1726 local ret = compFunc(inQuotes(argStr) or argStr)
1727 if ret then
1728 processFilter(ret)
1729 else
1730 finalPredicate = finalPredicate.."false"
1731 end
1732 elseif specFunc then
1733 local argStr = sub(term,y+2)
1734 local ret = specFunc(inQuotes(argStr) or argStr)
1735 if ret then
1736 if not specMap[term] then
1737 specFilterList[#specFilterList + 1] = ret
1738 specMap[term] = #specFilterList
1739 end
1740 processFilter(Explorer.SearchFilters.SpecificDefault(specMap[term]))
1741 else
1742 finalPredicate = finalPredicate.."false"
1743 end
1744 else
1745 processFilter(Explorer.SearchFilters.Default(term))
1746 end
1747 end
1748 end
1749 end
1750
1751 if op then
1752 finalPredicate = finalPredicate..op
1753 if op == "(" and (#term > 0 or lastOp == ")") then -- Handle bracket glitch
1754 return
1755 else
1756 lastOp = op
1757 end
1758 end
1759 init = nextInd+nextData[1]
1760 end
1761
1762 local finalSetups = ""
1763 local finalHeaders = ""
1764 local finalObjectDefs = ""
1765
1766 for setup,_ in next,setups do finalSetups = finalSetups..setup.."\n" end
1767 for header,_ in next,headers do finalHeaders = finalHeaders..header.."\n" end
1768 for oDef,_ in next,objectDefs do finalObjectDefs = finalObjectDefs..oDef.."\n" end
1769
1770 local template = [==[
1771local searchResults = searchResults
1772local nodes = nodes
1773local expandTable = Explorer.SearchExpanded
1774local specResults = specResults
1775local service = service
1776
1777%s
1778local function search(root)
1779%s
1780
1781 local expandedpar = false
1782 for i = 1,#root do
1783 local node = root[i]
1784 local obj = node.Obj
1785
1786%s
1787
1788 if %s then
1789 expandTable[node] = 0
1790 searchResults[node] = true
1791 if not expandedpar then
1792 local parnode = node.Parent
1793 while parnode and (not searchResults[parnode] or expandTable[parnode] == 0) do
1794 expandTable[parnode] = true
1795 searchResults[parnode] = true
1796 parnode = parnode.Parent
1797 end
1798 expandedpar = true
1799 end
1800 end
1801
1802 if #node > 0 then search(node) end
1803 end
1804end
1805return search]==]
1806
1807 local funcStr = template:format(finalHeaders,finalSetups,finalObjectDefs,finalPredicate)
1808 local s,func = pcall(loadstring,funcStr)
1809 if not s or not func then return nil,specFilterList end
1810
1811 local env = setmetatable({["searchResults"] = searchResults, ["nodes"] = nodes, ["Explorer"] = Explorer, ["specResults"] = specResults,
1812 ["service"] = service},{__index = getfenv()})
1813 setfenv(func,env)
1814
1815 return func(),specFilterList
1816 end
1817
1818 Explorer.DoSearch = function(query)
1819 table.clear(Explorer.SearchExpanded)
1820 table.clear(searchResults)
1821 expanded = (#query == 0 and Explorer.Expanded or Explorer.SearchExpanded)
1822 searchFunc = nil
1823
1824 if #query > 0 then
1825 local expandTable = Explorer.SearchExpanded
1826 local specFilters
1827
1828 local lower = string.lower
1829 local find = string.find
1830 local tostring = tostring
1831
1832 local lowerQuery = lower(query)
1833
1834 local function defaultSearch(root)
1835 local expandedpar = false
1836 for i = 1,#root do
1837 local node = root[i]
1838 local obj = node.Obj
1839
1840 if find(lower(tostring(obj)),lowerQuery,1,true) then
1841 expandTable[node] = 0
1842 searchResults[node] = true
1843 if not expandedpar then
1844 local parnode = node.Parent
1845 while parnode and (not searchResults[parnode] or expandTable[parnode] == 0) do
1846 expanded[parnode] = true
1847 searchResults[parnode] = true
1848 parnode = parnode.Parent
1849 end
1850 expandedpar = true
1851 end
1852 end
1853
1854 if #node > 0 then defaultSearch(node) end
1855 end
1856 end
1857
1858 if Main.Elevated then
1859 local start = tick()
1860 searchFunc,specFilters = Explorer.BuildSearchFunc(query)
1861 --print("BUILD SEARCH",tick()-start)
1862 else
1863 searchFunc = defaultSearch
1864 end
1865
1866 if specFilters then
1867 table.clear(specResults)
1868 for i = 1,#specFilters do -- Specific search filers that returns list of matches
1869 local resMap = {}
1870 specResults[i] = resMap
1871 local objs = specFilters[i]()
1872 for c = 1,#objs do
1873 local node = nodes[objs[c]]
1874 if node then
1875 resMap[node] = true
1876 end
1877 end
1878 end
1879 end
1880
1881 if searchFunc then
1882 local start = tick()
1883 searchFunc(nodes[game])
1884 searchFunc(nilNode)
1885 --warn(tick()-start)
1886 end
1887 end
1888
1889 Explorer.ForceUpdate()
1890 end
1891
1892 Explorer.ClearSearch = function()
1893 Explorer.GuiElems.SearchBar.Text = ""
1894 expanded = Explorer.Expanded
1895 searchFunc = nil
1896 end
1897
1898 Explorer.InitSearch = function()
1899 local searchBox = Explorer.GuiElems.ToolBar.SearchFrame.SearchBox
1900 Explorer.GuiElems.SearchBar = searchBox
1901
1902 Lib.ViewportTextBox.convert(searchBox)
1903
1904 searchBox.FocusLost:Connect(function()
1905 Explorer.DoSearch(searchBox.Text)
1906 end)
1907 end
1908
1909 Explorer.InitEntryTemplate = function()
1910 entryTemplate = create({
1911 {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,}},
1912 {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),}},
1913 {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,}},
1914 {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,}},
1915 {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),}},
1916 {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),}},
1917 })
1918
1919 local sys = Lib.ClickSystem.new()
1920 sys.AllowedButtons = {1,2}
1921 sys.OnDown:Connect(function(item,combo,button)
1922 local ind = table.find(listEntries,item)
1923 if not ind then return end
1924 local node = tree[ind + Explorer.Index]
1925 if not node then return end
1926
1927 local entry = listEntries[ind]
1928
1929 if button == 1 then
1930 if combo == 2 then
1931 if node.Obj:IsA("LuaSourceContainer") then
1932 ScriptViewer.ViewScript(node.Obj)
1933 elseif #node > 0 and expanded[node] ~= 0 then
1934 expanded[node] = not expanded[node]
1935 Explorer.Update()
1936 end
1937 end
1938
1939 if Properties.SelectObject(node.Obj) then
1940 sys.IsRenaming = false
1941 return
1942 end
1943
1944 sys.IsRenaming = selection.Map[node]
1945
1946 if Lib.IsShiftDown() then
1947 if not selection.Piviot then return end
1948
1949 local fromIndex = table.find(tree,selection.Piviot)
1950 local toIndex = table.find(tree,node)
1951 if not fromIndex or not toIndex then return end
1952 fromIndex,toIndex = math.min(fromIndex,toIndex),math.max(fromIndex,toIndex)
1953
1954 local sList = selection.List
1955 for i = #sList,1,-1 do
1956 local elem = sList[i]
1957 if selection.ShiftSet[elem] then
1958 selection.Map[elem] = nil
1959 table.remove(sList,i)
1960 end
1961 end
1962 selection.ShiftSet = {}
1963 for i = fromIndex,toIndex do
1964 local elem = tree[i]
1965 if not selection.Map[elem] then
1966 selection.ShiftSet[elem] = true
1967 selection.Map[elem] = true
1968 sList[#sList+1] = elem
1969 end
1970 end
1971 selection.Changed:Fire()
1972 elseif Lib.IsCtrlDown() then
1973 selection.ShiftSet = {}
1974 if selection.Map[node] then selection:Remove(node) else selection:Add(node) end
1975 selection.Piviot = node
1976 sys.IsRenaming = false
1977 elseif not selection.Map[node] then
1978 selection.ShiftSet = {}
1979 selection:Set(node)
1980 selection.Piviot = node
1981 end
1982 elseif button == 2 then
1983 if Properties.SelectObject(node.Obj) then
1984 return
1985 end
1986
1987 if not Lib.IsCtrlDown() and not selection.Map[node] then
1988 selection.ShiftSet = {}
1989 selection:Set(node)
1990 selection.Piviot = node
1991 Explorer.Refresh()
1992 end
1993 end
1994
1995 Explorer.Refresh()
1996 end)
1997
1998 sys.OnRelease:Connect(function(item,combo,button)
1999 local ind = table.find(listEntries,item)
2000 if not ind then return end
2001 local node = tree[ind + Explorer.Index]
2002 if not node then return end
2003
2004 if button == 1 then
2005 if selection.Map[node] and not Lib.IsShiftDown() and not Lib.IsCtrlDown() then
2006 selection.ShiftSet = {}
2007 selection:Set(node)
2008 selection.Piviot = node
2009 Explorer.Refresh()
2010 end
2011
2012 local id = sys.ClickId
2013 Lib.FastWait(sys.ComboTime)
2014 if combo == 1 and id == sys.ClickId and sys.IsRenaming and selection.Map[node] then
2015 Explorer.SetRenamingNode(node)
2016 end
2017 elseif button == 2 then
2018 Explorer.ShowRightClick()
2019 end
2020 end)
2021 Explorer.ClickSystem = sys
2022 end
2023
2024 Explorer.InitDelCleaner = function()
2025 coroutine.wrap(function()
2026 local fw = Lib.FastWait
2027 while true do
2028 local processed = false
2029 local c = 0
2030 for _,node in next,nodes do
2031 if node.HasDel then
2032 local delInd
2033 for i = 1,#node do
2034 if node[i].Del then
2035 delInd = i
2036 break
2037 end
2038 end
2039 if delInd then
2040 for i = delInd+1,#node do
2041 local cn = node[i]
2042 if not cn.Del then
2043 node[delInd] = cn
2044 delInd = delInd+1
2045 end
2046 end
2047 for i = delInd,#node do
2048 node[i] = nil
2049 end
2050 end
2051 node.HasDel = false
2052 processed = true
2053 fw()
2054 end
2055 c = c + 1
2056 if c > 10000 then
2057 c = 0
2058 fw()
2059 end
2060 end
2061 if processed and not refreshDebounce then Explorer.PerformRefresh() end
2062 fw(0.5)
2063 end
2064 end)()
2065 end
2066
2067 Explorer.UpdateSelectionVisuals = function()
2068 local holder = Explorer.SelectionVisualsHolder
2069 local isa = game.IsA
2070 local clone = game.Clone
2071 if not holder then
2072 holder = Instance.new("ScreenGui")
2073 holder.Name = "ExplorerSelections"
2074 holder.DisplayOrder = Main.DisplayOrders.Core
2075 Lib.ShowGui(holder)
2076 Explorer.SelectionVisualsHolder = holder
2077 Explorer.SelectionVisualCons = {}
2078
2079 local guiTemplate = create({
2080 {1,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Size=UDim2.new(0,100,0,100),}},
2081 {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),}},
2082 {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),}},
2083 {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),}},
2084 {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),}},
2085 })
2086 Explorer.SelectionVisualGui = guiTemplate
2087
2088 local boxTemplate = Instance.new("SelectionBox")
2089 boxTemplate.LineThickness = 0.03
2090 boxTemplate.Color3 = Color3.fromRGB(0, 170, 255)
2091 Explorer.SelectionVisualBox = boxTemplate
2092 end
2093 holder:ClearAllChildren()
2094
2095 -- Updates theme
2096 for i,v in pairs(Explorer.SelectionVisualGui:GetChildren()) do
2097 v.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
2098 end
2099
2100 local attachCons = Explorer.SelectionVisualCons
2101 for i = 1,#attachCons do
2102 attachCons[i].Destroy()
2103 end
2104 table.clear(attachCons)
2105
2106 local partEnabled = Settings.Explorer.PartSelectionBox
2107 local guiEnabled = Settings.Explorer.GuiSelectionBox
2108 if not partEnabled and not guiEnabled then return end
2109
2110 local svg = Explorer.SelectionVisualGui
2111 local svb = Explorer.SelectionVisualBox
2112 local attachTo = Lib.AttachTo
2113 local sList = selection.List
2114 local count = 1
2115 local boxCount = 0
2116 local workspaceNode = nodes[workspace]
2117 for i = 1,#sList do
2118 if boxCount > 1000 then break end
2119 local node = sList[i]
2120 local obj = node.Obj
2121
2122 if node ~= workspaceNode then
2123 if isa(obj,"GuiObject") and guiEnabled then
2124 local newVisual = clone(svg)
2125 attachCons[count] = attachTo(newVisual,{Target = obj, Resize = true})
2126 count = count + 1
2127 newVisual.Parent = holder
2128 boxCount = boxCount + 1
2129 elseif isa(obj,"PVInstance") and partEnabled then
2130 local newBox = clone(svb)
2131 newBox.Adornee = obj
2132 newBox.Parent = holder
2133 boxCount = boxCount + 1
2134 end
2135 end
2136 end
2137 end
2138
2139 Explorer.Init = function()
2140 Explorer.ClassIcons = Lib.IconMap.newLinear("rbxasset://textures/ClassImages.png",16,16)
2141 Explorer.MiscIcons = Main.MiscIcons
2142
2143 clipboard = {}
2144
2145 selection = Lib.Set.new()
2146 selection.ShiftSet = {}
2147 selection.Changed:Connect(Properties.ShowExplorerProps)
2148 Explorer.Selection = selection
2149
2150 Explorer.InitRightClick()
2151 Explorer.InitInsertObject()
2152 Explorer.SetSortingEnabled(Settings.Explorer.Sorting)
2153 Explorer.Expanded = setmetatable({},{__mode = "k"})
2154 Explorer.SearchExpanded = setmetatable({},{__mode = "k"})
2155 expanded = Explorer.Expanded
2156
2157 nilNode.Obj.Name = "Nil Instances"
2158 nilNode.Locked = true
2159
2160 local explorerItems = create({
2161 {1,"Folder",{Name="ExplorerItems",}},
2162 {2,"Frame",{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BorderSizePixel=0,Name="ToolBar",Parent={1},Size=UDim2.new(1,0,0,22),}},
2163 {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),}},
2164 {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,}},
2165 {5,"UICorner",{CornerRadius=UDim.new(0,2),Parent={3},}},
2166 {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,}},
2167 {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),}},
2168 {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,}},
2169 {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),}},
2170 {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,}},
2171 {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),}},
2172 })
2173
2174 toolBar = explorerItems.ToolBar
2175 treeFrame = explorerItems.List
2176
2177 Explorer.GuiElems.ToolBar = toolBar
2178 Explorer.GuiElems.TreeFrame = treeFrame
2179
2180 scrollV = Lib.ScrollBar.new()
2181 scrollV.WheelIncrement = 3
2182 scrollV.Gui.Position = UDim2.new(1,-16,0,23)
2183 scrollV:SetScrollFrame(treeFrame)
2184 scrollV.Scrolled:Connect(function()
2185 Explorer.Index = scrollV.Index
2186 Explorer.Refresh()
2187 end)
2188
2189 scrollH = Lib.ScrollBar.new(true)
2190 scrollH.Increment = 5
2191 scrollH.WheelIncrement = Explorer.EntryIndent
2192 scrollH.Gui.Position = UDim2.new(0,0,1,-16)
2193 scrollH.Scrolled:Connect(function()
2194 Explorer.Refresh()
2195 end)
2196
2197 local window = Lib.Window.new()
2198 Explorer.Window = window
2199 window:SetTitle("Explorer")
2200 window.GuiElems.Line.Position = UDim2.new(0,0,0,22)
2201
2202 Explorer.InitEntryTemplate()
2203 toolBar.Parent = window.GuiElems.Content
2204 treeFrame.Parent = window.GuiElems.Content
2205 explorerItems.ScrollCorner.Parent = window.GuiElems.Content
2206 scrollV.Gui.Parent = window.GuiElems.Content
2207 scrollH.Gui.Parent = window.GuiElems.Content
2208
2209 -- Init stuff that requires the window
2210 Explorer.InitRenameBox()
2211 Explorer.InitSearch()
2212 Explorer.InitDelCleaner()
2213 selection.Changed:Connect(Explorer.UpdateSelectionVisuals)
2214
2215 -- Window events
2216 window.GuiElems.Main:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
2217 if Explorer.Active then
2218 Explorer.UpdateView()
2219 Explorer.Refresh()
2220 end
2221 end)
2222 window.OnActivate:Connect(function()
2223 Explorer.Active = true
2224 Explorer.UpdateView()
2225 Explorer.Update()
2226 Explorer.Refresh()
2227 end)
2228 window.OnRestore:Connect(function()
2229 Explorer.Active = true
2230 Explorer.UpdateView()
2231 Explorer.Update()
2232 Explorer.Refresh()
2233 end)
2234 window.OnDeactivate:Connect(function() Explorer.Active = false end)
2235 window.OnMinimize:Connect(function() Explorer.Active = false end)
2236
2237 -- Settings
2238 autoUpdateSearch = Settings.Explorer.AutoUpdateSearch
2239
2240
2241 -- Fill in nodes
2242 nodes[game] = {Obj = game}
2243 expanded[nodes[game]] = true
2244
2245 -- Nil Instances
2246 if env.getnilinstances then
2247 nodes[nilNode.Obj] = nilNode
2248 end
2249
2250 Explorer.SetupConnections()
2251
2252 local insts = getDescendants(game)
2253 if Main.Elevated then
2254 for i = 1,#insts do
2255 local obj = insts[i]
2256 local par = nodes[ffa(obj,"Instance")]
2257 if not par then continue end
2258 local newNode = {
2259 Obj = obj,
2260 Parent = par,
2261 }
2262 nodes[obj] = newNode
2263 par[#par+1] = newNode
2264 end
2265 else
2266 for i = 1,#insts do
2267 local obj = insts[i]
2268 local s,parObj = pcall(ffa,obj,"Instance")
2269 local par = nodes[parObj]
2270 if not par then continue end
2271 local newNode = {
2272 Obj = obj,
2273 Parent = par,
2274 }
2275 nodes[obj] = newNode
2276 par[#par+1] = newNode
2277 end
2278 end
2279 end
2280
2281 return Explorer
2282end
2283
2284return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main}
2285end,
2286Properties = function()
2287--[[
2288 Properties App Module
2289
2290 The main properties interface
2291]]
2292
2293-- Common Locals
2294local Main,Lib,Apps,Settings -- Main Containers
2295local Explorer, Properties, ScriptViewer, Notebook -- Major Apps
2296local API,RMD,env,service,plr,create,createSimple -- Main Locals
2297
2298local function initDeps(data)
2299 Main = data.Main
2300 Lib = data.Lib
2301 Apps = data.Apps
2302 Settings = data.Settings
2303
2304 API = data.API
2305 RMD = data.RMD
2306 env = data.env
2307 service = data.service
2308 plr = data.plr
2309 create = data.create
2310 createSimple = data.createSimple
2311end
2312
2313local function initAfterMain()
2314 Explorer = Apps.Explorer
2315 Properties = Apps.Properties
2316 ScriptViewer = Apps.ScriptViewer
2317 Notebook = Apps.Notebook
2318end
2319
2320local function main()
2321 local Properties = {}
2322
2323 local window, toolBar, propsFrame
2324 local scrollV, scrollH
2325 local categoryOrder
2326 local props,viewList,expanded,indexableProps,propEntries,autoUpdateObjs = {},{},{},{},{},{}
2327 local inputBox,inputTextBox,inputProp
2328 local checkboxes,propCons = {},{}
2329 local table,string = table,string
2330 local getPropChangedSignal = game.GetPropertyChangedSignal
2331 local getAttributeChangedSignal = game.GetAttributeChangedSignal
2332 local isa = game.IsA
2333 local getAttribute = game.GetAttribute
2334 local setAttribute = game.SetAttribute
2335
2336 Properties.GuiElems = {}
2337 Properties.Index = 0
2338 Properties.ViewWidth = 0
2339 Properties.MinInputWidth = 100
2340 Properties.EntryIndent = 16
2341 Properties.EntryOffset = 4
2342 Properties.NameWidthCache = {}
2343 Properties.SubPropCache = {}
2344 Properties.ClassLists = {}
2345 Properties.SearchText = ""
2346
2347 Properties.AddAttributeProp = {Category = "Attributes", Class = "", Name = "", SpecialRow = "AddAttribute", Tags = {}}
2348 Properties.SoundPreviewProp = {Category = "Data", ValueType = {Name = "SoundPlayer"}, Class = "Sound", Name = "Preview", Tags = {}}
2349
2350 Properties.IgnoreProps = {
2351 ["DataModel"] = {
2352 ["PrivateServerId"] = true,
2353 ["PrivateServerOwnerId"] = true,
2354 ["VIPServerId"] = true,
2355 ["VIPServerOwnerId"] = true
2356 }
2357 }
2358
2359 Properties.ExpandableTypes = {
2360 ["Vector2"] = true,
2361 ["Vector3"] = true,
2362 ["UDim"] = true,
2363 ["UDim2"] = true,
2364 ["CFrame"] = true,
2365 ["Rect"] = true,
2366 ["PhysicalProperties"] = true,
2367 ["Ray"] = true,
2368 ["NumberRange"] = true,
2369 ["Faces"] = true,
2370 ["Axes"] = true,
2371 }
2372
2373 Properties.ExpandableProps = {
2374 ["Sound.SoundId"] = true
2375 }
2376
2377 Properties.CollapsedCategories = {
2378 ["Surface Inputs"] = true,
2379 ["Surface"] = true
2380 }
2381
2382 Properties.ConflictSubProps = {
2383 ["Vector2"] = {"X","Y"},
2384 ["Vector3"] = {"X","Y","Z"},
2385 ["UDim"] = {"Scale","Offset"},
2386 ["UDim2"] = {"X","X.Scale","X.Offset","Y","Y.Scale","Y.Offset"},
2387 ["CFrame"] = {"Position","Position.X","Position.Y","Position.Z",
2388 "RightVector","RightVector.X","RightVector.Y","RightVector.Z",
2389 "UpVector","UpVector.X","UpVector.Y","UpVector.Z",
2390 "LookVector","LookVector.X","LookVector.Y","LookVector.Z"},
2391 ["Rect"] = {"Min.X","Min.Y","Max.X","Max.Y"},
2392 ["PhysicalProperties"] = {"Density","Elasticity","ElasticityWeight","Friction","FrictionWeight"},
2393 ["Ray"] = {"Origin","Origin.X","Origin.Y","Origin.Z","Direction","Direction.X","Direction.Y","Direction.Z"},
2394 ["NumberRange"] = {"Min","Max"},
2395 ["Faces"] = {"Back","Bottom","Front","Left","Right","Top"},
2396 ["Axes"] = {"X","Y","Z"}
2397 }
2398
2399 Properties.ConflictIgnore = {
2400 ["BasePart"] = {
2401 ["ResizableFaces"] = true
2402 }
2403 }
2404
2405 Properties.RoundableTypes = {
2406 ["float"] = true,
2407 ["double"] = true,
2408 ["Color3"] = true,
2409 ["UDim"] = true,
2410 ["UDim2"] = true,
2411 ["Vector2"] = true,
2412 ["Vector3"] = true,
2413 ["NumberRange"] = true,
2414 ["Rect"] = true,
2415 ["NumberSequence"] = true,
2416 ["ColorSequence"] = true,
2417 ["Ray"] = true,
2418 ["CFrame"] = true
2419 }
2420
2421 Properties.TypeNameConvert = {
2422 ["number"] = "double",
2423 ["boolean"] = "bool"
2424 }
2425
2426 Properties.ToNumberTypes = {
2427 ["int"] = true,
2428 ["int64"] = true,
2429 ["float"] = true,
2430 ["double"] = true
2431 }
2432
2433 Properties.DefaultPropValue = {
2434 string = "",
2435 bool = false,
2436 double = 0,
2437 UDim = UDim.new(0,0),
2438 UDim2 = UDim2.new(0,0,0,0),
2439 BrickColor = BrickColor.new("Medium stone grey"),
2440 Color3 = Color3.new(1,1,1),
2441 Vector2 = Vector2.new(0,0),
2442 Vector3 = Vector3.new(0,0,0),
2443 NumberSequence = NumberSequence.new(1),
2444 ColorSequence = ColorSequence.new(Color3.new(1,1,1)),
2445 NumberRange = NumberRange.new(0),
2446 Rect = Rect.new(0,0,0,0)
2447 }
2448
2449 Properties.AllowedAttributeTypes = {"string","boolean","number","UDim","UDim2","BrickColor","Color3","Vector2","Vector3","NumberSequence","ColorSequence","NumberRange","Rect"}
2450
2451 Properties.StringToValue = function(prop,str)
2452 local typeData = prop.ValueType
2453 local typeName = typeData.Name
2454
2455 if typeName == "string" or typeName == "Content" then
2456 return str
2457 elseif Properties.ToNumberTypes[typeName] then
2458 return tonumber(str)
2459 elseif typeName == "Vector2" then
2460 local vals = str:split(",")
2461 local x,y = tonumber(vals[1]),tonumber(vals[2])
2462 if x and y and #vals >= 2 then return Vector2.new(x,y) end
2463 elseif typeName == "Vector3" then
2464 local vals = str:split(",")
2465 local x,y,z = tonumber(vals[1]),tonumber(vals[2]),tonumber(vals[3])
2466 if x and y and z and #vals >= 3 then return Vector3.new(x,y,z) end
2467 elseif typeName == "UDim" then
2468 local vals = str:split(",")
2469 local scale,offset = tonumber(vals[1]),tonumber(vals[2])
2470 if scale and offset and #vals >= 2 then return UDim.new(scale,offset) end
2471 elseif typeName == "UDim2" then
2472 local vals = str:gsub("[{}]",""):split(",")
2473 local xScale,xOffset,yScale,yOffset = tonumber(vals[1]),tonumber(vals[2]),tonumber(vals[3]),tonumber(vals[4])
2474 if xScale and xOffset and yScale and yOffset and #vals >= 4 then return UDim2.new(xScale,xOffset,yScale,yOffset) end
2475 elseif typeName == "CFrame" then
2476 local vals = str:split(",")
2477 local s,result = pcall(CFrame.new,unpack(vals))
2478 if s and #vals >= 12 then return result end
2479 elseif typeName == "Rect" then
2480 local vals = str:split(",")
2481 local s,result = pcall(Rect.new,unpack(vals))
2482 if s and #vals >= 4 then return result end
2483 elseif typeName == "Ray" then
2484 local vals = str:gsub("[{}]",""):split(",")
2485 local s,origin = pcall(Vector3.new,unpack(vals,1,3))
2486 local s2,direction = pcall(Vector3.new,unpack(vals,4,6))
2487 if s and s2 and #vals >= 6 then return Ray.new(origin,direction) end
2488 elseif typeName == "NumberRange" then
2489 local vals = str:split(",")
2490 local s,result = pcall(NumberRange.new,unpack(vals))
2491 if s and #vals >= 1 then return result end
2492 elseif typeName == "Color3" then
2493 local vals = str:gsub("[{}]",""):split(",")
2494 local s,result = pcall(Color3.fromRGB,unpack(vals))
2495 if s and #vals >= 3 then return result end
2496 end
2497
2498 return nil
2499 end
2500
2501 Properties.ValueToString = function(prop,val)
2502 local typeData = prop.ValueType
2503 local typeName = typeData.Name
2504
2505 if typeName == "Color3" then
2506 return Lib.ColorToBytes(val)
2507 elseif typeName == "NumberRange" then
2508 return val.Min..", "..val.Max
2509 end
2510
2511 return tostring(val)
2512 end
2513
2514 Properties.GetIndexableProps = function(obj,classData)
2515 if not Main.Elevated then
2516 if not pcall(function() return obj.ClassName end) then return nil end
2517 end
2518
2519 local ignoreProps = Properties.IgnoreProps[classData.Name] or {}
2520
2521 local result = {}
2522 local count = 1
2523 local props = classData.Properties
2524 for i = 1,#props do
2525 local prop = props[i]
2526 if not ignoreProps[prop.Name] then
2527 local s = pcall(function() return obj[prop.Name] end)
2528 if s then
2529 result[count] = prop
2530 count = count + 1
2531 end
2532 end
2533 end
2534
2535 return result
2536 end
2537
2538 Properties.FindFirstObjWhichIsA = function(class)
2539 local classList = Properties.ClassLists[class] or {}
2540 if classList and #classList > 0 then
2541 return classList[1]
2542 end
2543
2544 return nil
2545 end
2546
2547 Properties.ComputeConflicts = function(p)
2548 local maxConflictCheck = Settings.Properties.MaxConflictCheck
2549 local sList = Explorer.Selection.List
2550 local classLists = Properties.ClassLists
2551 local stringSplit = string.split
2552 local t_clear = table.clear
2553 local conflictIgnore = Properties.ConflictIgnore
2554 local conflictMap = {}
2555 local propList = p and {p} or props
2556
2557 if p then
2558 local gName = p.Class.."."..p.Name
2559 autoUpdateObjs[gName] = nil
2560 local subProps = Properties.ConflictSubProps[p.ValueType.Name] or {}
2561 for i = 1,#subProps do
2562 autoUpdateObjs[gName.."."..subProps[i]] = nil
2563 end
2564 else
2565 table.clear(autoUpdateObjs)
2566 end
2567
2568 if #sList > 0 then
2569 for i = 1,#propList do
2570 local prop = propList[i]
2571 local propName,propClass = prop.Name,prop.Class
2572 local typeData = prop.RootType or prop.ValueType
2573 local typeName = typeData.Name
2574 local attributeName = prop.AttributeName
2575 local gName = propClass.."."..propName
2576
2577 local checked = 0
2578 local subProps = Properties.ConflictSubProps[typeName] or {}
2579 local subPropCount = #subProps
2580 local toCheck = subPropCount + 1
2581 local conflictsFound = 0
2582 local indexNames = {}
2583 local ignored = conflictIgnore[propClass] and conflictIgnore[propClass][propName]
2584 local truthyCheck = (typeName == "PhysicalProperties")
2585 local isAttribute = prop.IsAttribute
2586 local isMultiType = prop.MultiType
2587
2588 t_clear(conflictMap)
2589
2590 if not isMultiType then
2591 local firstVal,firstObj,firstSet
2592 local classList = classLists[prop.Class] or {}
2593 for c = 1,#classList do
2594 local obj = classList[c]
2595 if not firstSet then
2596 if isAttribute then
2597 firstVal = getAttribute(obj,attributeName)
2598 if firstVal ~= nil then
2599 firstObj = obj
2600 firstSet = true
2601 end
2602 else
2603 firstVal = obj[propName]
2604 firstObj = obj
2605 firstSet = true
2606 end
2607 if ignored then break end
2608 else
2609 local propVal,skip
2610 if isAttribute then
2611 propVal = getAttribute(obj,attributeName)
2612 if propVal == nil then skip = true end
2613 else
2614 propVal = obj[propName]
2615 end
2616
2617 if not skip then
2618 if not conflictMap[1] then
2619 if truthyCheck then
2620 if (firstVal and true or false) ~= (propVal and true or false) then
2621 conflictMap[1] = true
2622 conflictsFound = conflictsFound + 1
2623 end
2624 elseif firstVal ~= propVal then
2625 conflictMap[1] = true
2626 conflictsFound = conflictsFound + 1
2627 end
2628 end
2629
2630 if subPropCount > 0 then
2631 for sPropInd = 1,subPropCount do
2632 local indexes = indexNames[sPropInd]
2633 if not indexes then indexes = stringSplit(subProps[sPropInd],".") indexNames[sPropInd] = indexes end
2634
2635 local firstValSub = firstVal
2636 local propValSub = propVal
2637
2638 for j = 1,#indexes do
2639 if not firstValSub or not propValSub then break end -- PhysicalProperties
2640 local indexName = indexes[j]
2641 firstValSub = firstValSub[indexName]
2642 propValSub = propValSub[indexName]
2643 end
2644
2645 local mapInd = sPropInd + 1
2646 if not conflictMap[mapInd] and firstValSub ~= propValSub then
2647 conflictMap[mapInd] = true
2648 conflictsFound = conflictsFound + 1
2649 end
2650 end
2651 end
2652
2653 if conflictsFound == toCheck then break end
2654 end
2655 end
2656
2657 checked = checked + 1
2658 if checked == maxConflictCheck then break end
2659 end
2660
2661 if not conflictMap[1] then autoUpdateObjs[gName] = firstObj end
2662 for sPropInd = 1,subPropCount do
2663 if not conflictMap[sPropInd+1] then
2664 autoUpdateObjs[gName.."."..subProps[sPropInd]] = firstObj
2665 end
2666 end
2667 end
2668 end
2669 end
2670
2671 if p then
2672 Properties.Refresh()
2673 end
2674 end
2675
2676 -- Fetches the properties to be displayed based on the explorer selection
2677 Settings.Properties.ShowAttributes = true -- im making it true anyway since its useful by default and people complain
2678 Properties.ShowExplorerProps = function()
2679 local maxConflictCheck = Settings.Properties.MaxConflictCheck
2680 local sList = Explorer.Selection.List
2681 local foundClasses = {}
2682 local propCount = 1
2683 local elevated = Main.Elevated
2684 local showDeprecated,showHidden = Settings.Properties.ShowDeprecated,Settings.Properties.ShowHidden
2685 local Classes = API.Classes
2686 local classLists = {}
2687 local lower = string.lower
2688 local RMDCustomOrders = RMD.PropertyOrders
2689 local getAttributes = game.GetAttributes
2690 local maxAttrs = Settings.Properties.MaxAttributes
2691 local showingAttrs = Settings.Properties.ShowAttributes
2692 local foundAttrs = {}
2693 local attrCount = 0
2694 local typeof = typeof
2695 local typeNameConvert = Properties.TypeNameConvert
2696
2697 table.clear(props)
2698
2699 for i = 1,#sList do
2700 local node = sList[i]
2701 local obj = node.Obj
2702 local class = node.Class
2703 if not class then class = obj.ClassName node.Class = class end
2704
2705 local apiClass = Classes[class]
2706 while apiClass do
2707 local APIClassName = apiClass.Name
2708 if not foundClasses[APIClassName] then
2709 local apiProps = indexableProps[APIClassName]
2710 if not apiProps then apiProps = Properties.GetIndexableProps(obj,apiClass) indexableProps[APIClassName] = apiProps end
2711
2712 for i = 1,#apiProps do
2713 local prop = apiProps[i]
2714 local tags = prop.Tags
2715 if (not tags.Deprecated or showDeprecated) and (not tags.Hidden or showHidden) then
2716 props[propCount] = prop
2717 propCount = propCount + 1
2718 end
2719 end
2720 foundClasses[APIClassName] = true
2721 end
2722
2723 local classList = classLists[APIClassName]
2724 if not classList then classList = {} classLists[APIClassName] = classList end
2725 classList[#classList+1] = obj
2726
2727 apiClass = apiClass.Superclass
2728 end
2729
2730 if showingAttrs and attrCount < maxAttrs then
2731 local attrs = getAttributes(obj)
2732 for name,val in pairs(attrs) do
2733 local typ = typeof(val)
2734 if not foundAttrs[name] then
2735 local category = (typ == "Instance" and "Class") or (typ == "EnumItem" and "Enum") or "Other"
2736 local valType = {Name = typeNameConvert[typ] or typ, Category = category}
2737 local attrProp = {IsAttribute = true, Name = "ATTR_"..name, AttributeName = name, DisplayName = name, Class = "Instance", ValueType = valType, Category = "Attributes", Tags = {}}
2738 props[propCount] = attrProp
2739 propCount = propCount + 1
2740 attrCount = attrCount + 1
2741 foundAttrs[name] = {typ,attrProp}
2742 if attrCount == maxAttrs then break end
2743 elseif foundAttrs[name][1] ~= typ then
2744 foundAttrs[name][2].MultiType = true
2745 foundAttrs[name][2].Tags.ReadOnly = true
2746 foundAttrs[name][2].ValueType = {Name = "string"}
2747 end
2748 end
2749 end
2750 end
2751
2752 table.sort(props,function(a,b)
2753 if a.Category ~= b.Category then
2754 return (categoryOrder[a.Category] or 9999) < (categoryOrder[b.Category] or 9999)
2755 else
2756 local aOrder = (RMDCustomOrders[a.Class] and RMDCustomOrders[a.Class][a.Name]) or 9999999
2757 local bOrder = (RMDCustomOrders[b.Class] and RMDCustomOrders[b.Class][b.Name]) or 9999999
2758 if aOrder ~= bOrder then
2759 return aOrder < bOrder
2760 else
2761 return lower(a.Name) < lower(b.Name)
2762 end
2763 end
2764 end)
2765
2766 -- Find conflicts and get auto-update instances
2767 Properties.ClassLists = classLists
2768 Properties.ComputeConflicts()
2769 --warn("CONFLICT",tick()-start)
2770 if #props > 0 then
2771 props[#props+1] = Properties.AddAttributeProp
2772 end
2773
2774 Properties.Update()
2775 Properties.Refresh()
2776 end
2777
2778 Properties.UpdateView = function()
2779 local maxEntries = math.ceil(propsFrame.AbsoluteSize.Y / 23)
2780 local maxX = propsFrame.AbsoluteSize.X
2781 local totalWidth = Properties.ViewWidth + Properties.MinInputWidth
2782
2783 scrollV.VisibleSpace = maxEntries
2784 scrollV.TotalSpace = #viewList + 1
2785 scrollH.VisibleSpace = maxX
2786 scrollH.TotalSpace = totalWidth
2787
2788 scrollV.Gui.Visible = #viewList + 1 > maxEntries
2789 scrollH.Gui.Visible = Settings.Properties.ScaleType == 0 and totalWidth > maxX
2790
2791 local oldSize = propsFrame.Size
2792 propsFrame.Size = UDim2.new(1,(scrollV.Gui.Visible and -16 or 0),1,(scrollH.Gui.Visible and -39 or -23))
2793 if oldSize ~= propsFrame.Size then
2794 Properties.UpdateView()
2795 else
2796 scrollV:Update()
2797 scrollH:Update()
2798
2799 if scrollV.Gui.Visible and scrollH.Gui.Visible then
2800 scrollV.Gui.Size = UDim2.new(0,16,1,-39)
2801 scrollH.Gui.Size = UDim2.new(1,-16,0,16)
2802 Properties.Window.GuiElems.Content.ScrollCorner.Visible = true
2803 else
2804 scrollV.Gui.Size = UDim2.new(0,16,1,-23)
2805 scrollH.Gui.Size = UDim2.new(1,0,0,16)
2806 Properties.Window.GuiElems.Content.ScrollCorner.Visible = false
2807 end
2808
2809 Properties.Index = scrollV.Index
2810 end
2811 end
2812
2813 Properties.MakeSubProp = function(prop,subName,valueType,displayName)
2814 local subProp = {}
2815 for i,v in pairs(prop) do
2816 subProp[i] = v
2817 end
2818 subProp.RootType = subProp.RootType or subProp.ValueType
2819 subProp.ValueType = valueType
2820 subProp.SubName = subProp.SubName and (subProp.SubName..subName) or subName
2821 subProp.DisplayName = displayName
2822
2823 return subProp
2824 end
2825
2826 Properties.GetExpandedProps = function(prop) -- TODO: Optimize using table
2827 local result = {}
2828 local typeData = prop.ValueType
2829 local typeName = typeData.Name
2830 local makeSubProp = Properties.MakeSubProp
2831
2832 if typeName == "Vector2" then
2833 result[1] = makeSubProp(prop,".X",{Name = "float"})
2834 result[2] = makeSubProp(prop,".Y",{Name = "float"})
2835 elseif typeName == "Vector3" then
2836 result[1] = makeSubProp(prop,".X",{Name = "float"})
2837 result[2] = makeSubProp(prop,".Y",{Name = "float"})
2838 result[3] = makeSubProp(prop,".Z",{Name = "float"})
2839 elseif typeName == "CFrame" then
2840 result[1] = makeSubProp(prop,".Position",{Name = "Vector3"})
2841 result[2] = makeSubProp(prop,".RightVector",{Name = "Vector3"})
2842 result[3] = makeSubProp(prop,".UpVector",{Name = "Vector3"})
2843 result[4] = makeSubProp(prop,".LookVector",{Name = "Vector3"})
2844 elseif typeName == "UDim" then
2845 result[1] = makeSubProp(prop,".Scale",{Name = "float"})
2846 result[2] = makeSubProp(prop,".Offset",{Name = "int"})
2847 elseif typeName == "UDim2" then
2848 result[1] = makeSubProp(prop,".X",{Name = "UDim"})
2849 result[2] = makeSubProp(prop,".Y",{Name = "UDim"})
2850 elseif typeName == "Rect" then
2851 result[1] = makeSubProp(prop,".Min.X",{Name = "float"},"X0")
2852 result[2] = makeSubProp(prop,".Min.Y",{Name = "float"},"Y0")
2853 result[3] = makeSubProp(prop,".Max.X",{Name = "float"},"X1")
2854 result[4] = makeSubProp(prop,".Max.Y",{Name = "float"},"Y1")
2855 elseif typeName == "PhysicalProperties" then
2856 result[1] = makeSubProp(prop,".Density",{Name = "float"})
2857 result[2] = makeSubProp(prop,".Elasticity",{Name = "float"})
2858 result[3] = makeSubProp(prop,".ElasticityWeight",{Name = "float"})
2859 result[4] = makeSubProp(prop,".Friction",{Name = "float"})
2860 result[5] = makeSubProp(prop,".FrictionWeight",{Name = "float"})
2861 elseif typeName == "Ray" then
2862 result[1] = makeSubProp(prop,".Origin",{Name = "Vector3"})
2863 result[2] = makeSubProp(prop,".Direction",{Name = "Vector3"})
2864 elseif typeName == "NumberRange" then
2865 result[1] = makeSubProp(prop,".Min",{Name = "float"})
2866 result[2] = makeSubProp(prop,".Max",{Name = "float"})
2867 elseif typeName == "Faces" then
2868 result[1] = makeSubProp(prop,".Back",{Name = "bool"})
2869 result[2] = makeSubProp(prop,".Bottom",{Name = "bool"})
2870 result[3] = makeSubProp(prop,".Front",{Name = "bool"})
2871 result[4] = makeSubProp(prop,".Left",{Name = "bool"})
2872 result[5] = makeSubProp(prop,".Right",{Name = "bool"})
2873 result[6] = makeSubProp(prop,".Top",{Name = "bool"})
2874 elseif typeName == "Axes" then
2875 result[1] = makeSubProp(prop,".X",{Name = "bool"})
2876 result[2] = makeSubProp(prop,".Y",{Name = "bool"})
2877 result[3] = makeSubProp(prop,".Z",{Name = "bool"})
2878 end
2879
2880 if prop.Name == "SoundId" and prop.Class == "Sound" then
2881 result[1] = Properties.SoundPreviewProp
2882 end
2883
2884 return result
2885 end
2886
2887 Properties.Update = function()
2888 table.clear(viewList)
2889
2890 local nameWidthCache = Properties.NameWidthCache
2891 local lastCategory
2892 local count = 1
2893 local maxWidth,maxDepth = 0,1
2894
2895 local textServ = service.TextService
2896 local getTextSize = textServ.GetTextSize
2897 local font = Enum.Font.SourceSans
2898 local size = Vector2.new(math.huge,20)
2899 local stringSplit = string.split
2900 local entryIndent = Properties.EntryIndent
2901 local isFirstScaleType = Settings.Properties.ScaleType == 0
2902 local find,lower = string.find,string.lower
2903 local searchText = (#Properties.SearchText > 0 and lower(Properties.SearchText))
2904
2905 local function recur(props,depth)
2906 for i = 1,#props do
2907 local prop = props[i]
2908 local propName = prop.Name
2909 local subName = prop.SubName
2910 local category = prop.Category
2911
2912 local visible
2913 if searchText and depth == 1 then
2914 if find(lower(propName),searchText,1,true) then
2915 visible = true
2916 end
2917 else
2918 visible = true
2919 end
2920
2921 if visible and lastCategory ~= category then
2922 viewList[count] = {CategoryName = category}
2923 count = count + 1
2924 lastCategory = category
2925 end
2926
2927 if (expanded["CAT_"..category] and visible) or prop.SpecialRow then
2928 if depth > 1 then prop.Depth = depth if depth > maxDepth then maxDepth = depth end end
2929
2930 if isFirstScaleType then
2931 local nameArr = subName and stringSplit(subName,".")
2932 local displayName = prop.DisplayName or (nameArr and nameArr[#nameArr]) or propName
2933
2934 local nameWidth = nameWidthCache[displayName]
2935 if not nameWidth then nameWidth = getTextSize(textServ,displayName,14,font,size).X nameWidthCache[displayName] = nameWidth end
2936
2937 local totalWidth = nameWidth + entryIndent*depth
2938 if totalWidth > maxWidth then
2939 maxWidth = totalWidth
2940 end
2941 end
2942
2943 viewList[count] = prop
2944 count = count + 1
2945
2946 local fullName = prop.Class.."."..prop.Name..(prop.SubName or "")
2947 if expanded[fullName] then
2948 local nextDepth = depth+1
2949 local expandedProps = Properties.GetExpandedProps(prop)
2950 if #expandedProps > 0 then
2951 recur(expandedProps,nextDepth)
2952 end
2953 end
2954 end
2955 end
2956 end
2957 recur(props,1)
2958
2959 inputProp = nil
2960 Properties.ViewWidth = maxWidth + 9 + Properties.EntryOffset
2961 Properties.UpdateView()
2962 end
2963
2964 Properties.NewPropEntry = function(index)
2965 local newEntry = Properties.EntryTemplate:Clone()
2966 local nameFrame = newEntry.NameFrame
2967 local valueFrame = newEntry.ValueFrame
2968 local newCheckbox = Lib.Checkbox.new(1)
2969 newCheckbox.Gui.Position = UDim2.new(0,3,0,3)
2970 newCheckbox.Gui.Parent = valueFrame
2971 newCheckbox.OnInput:Connect(function()
2972 local prop = viewList[index + Properties.Index]
2973 if not prop then return end
2974
2975 if prop.ValueType.Name == "PhysicalProperties" then
2976 Properties.SetProp(prop,newCheckbox.Toggled and true or nil)
2977 else
2978 Properties.SetProp(prop,newCheckbox.Toggled)
2979 end
2980 end)
2981 checkboxes[index] = newCheckbox
2982
2983 local iconFrame = Main.MiscIcons:GetLabel()
2984 iconFrame.Position = UDim2.new(0,2,0,3)
2985 iconFrame.Parent = newEntry.ValueFrame.RightButton
2986
2987 newEntry.Position = UDim2.new(0,0,0,23*(index-1))
2988
2989 nameFrame.Expand.InputBegan:Connect(function(input)
2990 local prop = viewList[index + Properties.Index]
2991 if not prop or input.UserInputType ~= Enum.UserInputType.MouseMovement then return end
2992
2993 local fullName = (prop.CategoryName and "CAT_"..prop.CategoryName) or prop.Class.."."..prop.Name..(prop.SubName or "")
2994
2995 Main.MiscIcons:DisplayByKey(newEntry.NameFrame.Expand.Icon, expanded[fullName] and "Collapse_Over" or "Expand_Over")
2996 end)
2997
2998 nameFrame.Expand.InputEnded:Connect(function(input)
2999 local prop = viewList[index + Properties.Index]
3000 if not prop or input.UserInputType ~= Enum.UserInputType.MouseMovement then return end
3001
3002 local fullName = (prop.CategoryName and "CAT_"..prop.CategoryName) or prop.Class.."."..prop.Name..(prop.SubName or "")
3003
3004 Main.MiscIcons:DisplayByKey(newEntry.NameFrame.Expand.Icon, expanded[fullName] and "Collapse" or "Expand")
3005 end)
3006
3007 nameFrame.Expand.MouseButton1Down:Connect(function()
3008 local prop = viewList[index + Properties.Index]
3009 if not prop then return end
3010
3011 local fullName = (prop.CategoryName and "CAT_"..prop.CategoryName) or prop.Class.."."..prop.Name..(prop.SubName or "")
3012 if not prop.CategoryName and not Properties.ExpandableTypes[prop.ValueType and prop.ValueType.Name] and not Properties.ExpandableProps[fullName] then return end
3013
3014 expanded[fullName] = not expanded[fullName]
3015 Properties.Update()
3016 Properties.Refresh()
3017 end)
3018
3019 nameFrame.PropName.InputBegan:Connect(function(input)
3020 local prop = viewList[index + Properties.Index]
3021 if not prop then return end
3022 if input.UserInputType == Enum.UserInputType.MouseMovement and not nameFrame.PropName.TextFits then
3023 local fullNameFrame = Properties.FullNameFrame
3024 local nameArr = string.split(prop.Class.."."..prop.Name..(prop.SubName or ""),".")
3025 local dispName = prop.DisplayName or nameArr[#nameArr]
3026 local sizeX = service.TextService:GetTextSize(dispName,14,Enum.Font.SourceSans,Vector2.new(math.huge,20)).X
3027
3028 fullNameFrame.TextLabel.Text = dispName
3029 --fullNameFrame.Position = UDim2.new(0,Properties.EntryIndent*(prop.Depth or 1) + Properties.EntryOffset,0,23*(index-1))
3030 fullNameFrame.Size = UDim2.new(0,sizeX + 4,0,22)
3031 fullNameFrame.Visible = true
3032 Properties.FullNameFrameIndex = index
3033 Properties.FullNameFrameAttach.SetData(fullNameFrame, {Target = nameFrame})
3034 Properties.FullNameFrameAttach.Enable()
3035 end
3036 end)
3037
3038 nameFrame.PropName.InputEnded:Connect(function(input)
3039 if input.UserInputType == Enum.UserInputType.MouseMovement and Properties.FullNameFrameIndex == index then
3040 Properties.FullNameFrame.Visible = false
3041 Properties.FullNameFrameAttach.Disable()
3042 end
3043 end)
3044
3045 valueFrame.ValueBox.MouseButton1Down:Connect(function()
3046 local prop = viewList[index + Properties.Index]
3047 if not prop then return end
3048
3049 Properties.SetInputProp(prop,index)
3050 end)
3051
3052 valueFrame.ColorButton.MouseButton1Down:Connect(function()
3053 local prop = viewList[index + Properties.Index]
3054 if not prop then return end
3055
3056 Properties.SetInputProp(prop,index,"color")
3057 end)
3058
3059 valueFrame.RightButton.MouseButton1Click:Connect(function()
3060 local prop = viewList[index + Properties.Index]
3061 if not prop then return end
3062
3063 local fullName = prop.Class.."."..prop.Name..(prop.SubName or "")
3064 local inputFullName = inputProp and (inputProp.Class.."."..inputProp.Name..(inputProp.SubName or ""))
3065
3066 if fullName == inputFullName and inputProp.ValueType.Category == "Class" then
3067 inputProp = nil
3068 Properties.SetProp(prop,nil)
3069 else
3070 Properties.SetInputProp(prop,index,"right")
3071 end
3072 end)
3073
3074 nameFrame.ToggleAttributes.MouseButton1Click:Connect(function()
3075 Settings.Properties.ShowAttributes = not Settings.Properties.ShowAttributes
3076 Properties.ShowExplorerProps()
3077 end)
3078
3079 newEntry.RowButton.MouseButton1Click:Connect(function()
3080 Properties.DisplayAddAttributeWindow()
3081 end)
3082
3083 newEntry.EditAttributeButton.MouseButton1Down:Connect(function()
3084 local prop = viewList[index + Properties.Index]
3085 if not prop then return end
3086
3087 Properties.DisplayAttributeContext(prop)
3088 end)
3089
3090 valueFrame.SoundPreview.ControlButton.MouseButton1Click:Connect(function()
3091 if Properties.PreviewSound and Properties.PreviewSound.Playing then
3092 Properties.SetSoundPreview(false)
3093 else
3094 local soundObj = Properties.FindFirstObjWhichIsA("Sound")
3095 if soundObj then Properties.SetSoundPreview(soundObj) end
3096 end
3097 end)
3098
3099 valueFrame.SoundPreview.InputBegan:Connect(function(input)
3100 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
3101
3102 local releaseEvent,mouseEvent
3103 releaseEvent = service.UserInputService.InputEnded:Connect(function(input)
3104 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
3105 releaseEvent:Disconnect()
3106 mouseEvent:Disconnect()
3107 end)
3108
3109 local timeLine = newEntry.ValueFrame.SoundPreview.TimeLine
3110 local soundObj = Properties.FindFirstObjWhichIsA("Sound")
3111 if soundObj then Properties.SetSoundPreview(soundObj,true) end
3112
3113 local function update(input)
3114 local sound = Properties.PreviewSound
3115 if not sound or sound.TimeLength == 0 then return end
3116
3117 local mouseX = input.Position.X
3118 local timeLineSize = timeLine.AbsoluteSize
3119 local relaX = mouseX - timeLine.AbsolutePosition.X
3120
3121 if timeLineSize.X <= 1 then return end
3122 if relaX < 0 then relaX = 0 elseif relaX >= timeLineSize.X then relaX = timeLineSize.X-1 end
3123
3124 local perc = (relaX/(timeLineSize.X-1))
3125 sound.TimePosition = perc*sound.TimeLength
3126 timeLine.Slider.Position = UDim2.new(perc,-4,0,-8)
3127 end
3128 update(input)
3129
3130 mouseEvent = service.UserInputService.InputChanged:Connect(function(input)
3131 if input.UserInputType == Enum.UserInputType.MouseMovement then
3132 update(input)
3133 end
3134 end)
3135 end)
3136
3137 newEntry.Parent = propsFrame
3138
3139 return {
3140 Gui = newEntry,
3141 GuiElems = {
3142 NameFrame = nameFrame,
3143 ValueFrame = valueFrame,
3144 PropName = nameFrame.PropName,
3145 ValueBox = valueFrame.ValueBox,
3146 Expand = nameFrame.Expand,
3147 ColorButton = valueFrame.ColorButton,
3148 ColorPreview = valueFrame.ColorButton.ColorPreview,
3149 Gradient = valueFrame.ColorButton.ColorPreview.UIGradient,
3150 EnumArrow = valueFrame.EnumArrow,
3151 Checkbox = valueFrame.Checkbox,
3152 RightButton = valueFrame.RightButton,
3153 RightButtonIcon = iconFrame,
3154 RowButton = newEntry.RowButton,
3155 EditAttributeButton = newEntry.EditAttributeButton,
3156 ToggleAttributes = nameFrame.ToggleAttributes,
3157 SoundPreview = valueFrame.SoundPreview,
3158 SoundPreviewSlider = valueFrame.SoundPreview.TimeLine.Slider
3159 }
3160 }
3161 end
3162
3163 Properties.GetSoundPreviewEntry = function()
3164 for i = 1,#viewList do
3165 if viewList[i] == Properties.SoundPreviewProp then
3166 return propEntries[i - Properties.Index]
3167 end
3168 end
3169 end
3170
3171 Properties.SetSoundPreview = function(soundObj,noplay)
3172 local sound = Properties.PreviewSound
3173 if not sound then
3174 sound = Instance.new("Sound")
3175 sound.Name = "Preview"
3176 sound.Paused:Connect(function()
3177 local entry = Properties.GetSoundPreviewEntry()
3178 if entry then Main.MiscIcons:DisplayByKey(entry.GuiElems.SoundPreview.ControlButton.Icon, "Play") end
3179 end)
3180 sound.Resumed:Connect(function() Properties.Refresh() end)
3181 sound.Ended:Connect(function()
3182 local entry = Properties.GetSoundPreviewEntry()
3183 if entry then entry.GuiElems.SoundPreviewSlider.Position = UDim2.new(0,-4,0,-8) end
3184 Properties.Refresh()
3185 end)
3186 sound.Parent = window.Gui
3187 Properties.PreviewSound = sound
3188 end
3189
3190 if not soundObj then
3191 sound:Pause()
3192 else
3193 local newId = sound.SoundId ~= soundObj.SoundId
3194 sound.SoundId = soundObj.SoundId
3195 sound.PlaybackSpeed = soundObj.PlaybackSpeed
3196 sound.Volume = soundObj.Volume
3197 if newId then sound.TimePosition = 0 end
3198 if not noplay then sound:Resume() end
3199
3200 coroutine.wrap(function()
3201 local previewTime = tick()
3202 Properties.SoundPreviewTime = previewTime
3203 while previewTime == Properties.SoundPreviewTime and sound.Playing do
3204 local entry = Properties.GetSoundPreviewEntry()
3205 if entry then
3206 local tl = sound.TimeLength
3207 local perc = sound.TimePosition/(tl == 0 and 1 or tl)
3208 entry.GuiElems.SoundPreviewSlider.Position = UDim2.new(perc,-4,0,-8)
3209 end
3210 Lib.FastWait()
3211 end
3212 end)()
3213 Properties.Refresh()
3214 end
3215 end
3216
3217 Properties.DisplayAttributeContext = function(prop)
3218 local context = Properties.AttributeContext
3219 if not context then
3220 context = Lib.ContextMenu.new()
3221 context.Iconless = true
3222 context.Width = 80
3223 end
3224 context:Clear()
3225
3226 context:Add({Name = "Edit", OnClick = function()
3227 Properties.DisplayAddAttributeWindow(prop)
3228 end})
3229 context:Add({Name = "Delete", OnClick = function()
3230 Properties.SetProp(prop,nil,true)
3231 Properties.ShowExplorerProps()
3232 end})
3233
3234 context:Show()
3235 end
3236
3237 Properties.DisplayAddAttributeWindow = function(editAttr)
3238 local win = Properties.AddAttributeWindow
3239 if not win then
3240 win = Lib.Window.new()
3241 win.Alignable = false
3242 win.Resizable = false
3243 win:SetTitle("Add Attribute")
3244 win:SetSize(200,130)
3245
3246 local saveButton = Lib.Button.new()
3247 local nameLabel = Lib.Label.new()
3248 nameLabel.Text = "Name"
3249 nameLabel.Position = UDim2.new(0,30,0,10)
3250 nameLabel.Size = UDim2.new(0,40,0,20)
3251 win:Add(nameLabel)
3252
3253 local nameBox = Lib.ViewportTextBox.new()
3254 nameBox.Position = UDim2.new(0,75,0,10)
3255 nameBox.Size = UDim2.new(0,120,0,20)
3256 win:Add(nameBox,"NameBox")
3257 nameBox.TextBox:GetPropertyChangedSignal("Text"):Connect(function()
3258 saveButton:SetDisabled(#nameBox:GetText() == 0)
3259 end)
3260
3261 local typeLabel = Lib.Label.new()
3262 typeLabel.Text = "Type"
3263 typeLabel.Position = UDim2.new(0,30,0,40)
3264 typeLabel.Size = UDim2.new(0,40,0,20)
3265 win:Add(typeLabel)
3266
3267 local typeChooser = Lib.DropDown.new()
3268 typeChooser.CanBeEmpty = false
3269 typeChooser.Position = UDim2.new(0,75,0,40)
3270 typeChooser.Size = UDim2.new(0,120,0,20)
3271 typeChooser:SetOptions(Properties.AllowedAttributeTypes)
3272 win:Add(typeChooser,"TypeChooser")
3273
3274 local errorLabel = Lib.Label.new()
3275 errorLabel.Text = ""
3276 errorLabel.Position = UDim2.new(0,5,1,-45)
3277 errorLabel.Size = UDim2.new(1,-10,0,20)
3278 errorLabel.TextColor3 = Settings.Theme.Important
3279 win.ErrorLabel = errorLabel
3280 win:Add(errorLabel,"Error")
3281
3282 local cancelButton = Lib.Button.new()
3283 cancelButton.Text = "Cancel"
3284 cancelButton.Position = UDim2.new(1,-97,1,-25)
3285 cancelButton.Size = UDim2.new(0,92,0,20)
3286 cancelButton.OnClick:Connect(function()
3287 win:Close()
3288 end)
3289 win:Add(cancelButton)
3290
3291 saveButton.Text = "Save"
3292 saveButton.Position = UDim2.new(0,5,1,-25)
3293 saveButton.Size = UDim2.new(0,92,0,20)
3294 saveButton.OnClick:Connect(function()
3295 local name = nameBox:GetText()
3296 if #name > 100 then
3297 errorLabel.Text = "Error: Name over 100 chars"
3298 return
3299 elseif name:sub(1,3) == "RBX" then
3300 errorLabel.Text = "Error: Name begins with 'RBX'"
3301 return
3302 end
3303
3304 local typ = typeChooser.Selected
3305 local valType = {Name = Properties.TypeNameConvert[typ] or typ, Category = "DataType"}
3306 local attrProp = {IsAttribute = true, Name = "ATTR_"..name, AttributeName = name, DisplayName = name, Class = "Instance", ValueType = valType, Category = "Attributes", Tags = {}}
3307
3308 Settings.Properties.ShowAttributes = true
3309 Properties.SetProp(attrProp,Properties.DefaultPropValue[valType.Name],true,Properties.EditingAttribute)
3310 Properties.ShowExplorerProps()
3311 win:Close()
3312 end)
3313 win:Add(saveButton,"SaveButton")
3314
3315 Properties.AddAttributeWindow = win
3316 end
3317
3318 Properties.EditingAttribute = editAttr
3319 win:SetTitle(editAttr and "Edit Attribute "..editAttr.AttributeName or "Add Attribute")
3320 win.Elements.Error.Text = ""
3321 win.Elements.NameBox:SetText("")
3322 win.Elements.SaveButton:SetDisabled(true)
3323 win.Elements.TypeChooser:SetSelected(1)
3324 win:Show()
3325 end
3326
3327 Properties.IsTextEditable = function(prop)
3328 local typeData = prop.ValueType
3329 local typeName = typeData.Name
3330
3331 return typeName ~= "bool" and typeData.Category ~= "Enum" and typeData.Category ~= "Class" and typeName ~= "BrickColor"
3332 end
3333
3334 Properties.DisplayEnumDropdown = function(entryIndex)
3335 local context = Properties.EnumContext
3336 if not context then
3337 context = Lib.ContextMenu.new()
3338 context.Iconless = true
3339 context.MaxHeight = 200
3340 context.ReverseYOffset = 22
3341 Properties.EnumDropdown = context
3342 end
3343
3344 if not inputProp or inputProp.ValueType.Category ~= "Enum" then return end
3345 local prop = inputProp
3346
3347 local entry = propEntries[entryIndex]
3348 local valueFrame = entry.GuiElems.ValueFrame
3349
3350 local enum = Enum[prop.ValueType.Name]
3351 if not enum then return end
3352
3353 local sorted = {}
3354 for name,enum in next,enum:GetEnumItems() do
3355 sorted[#sorted+1] = enum
3356 end
3357 table.sort(sorted,function(a,b) return a.Name < b.Name end)
3358
3359 context:Clear()
3360
3361 local function onClick(name)
3362 if prop ~= inputProp then return end
3363
3364 local enumItem = enum[name]
3365 inputProp = nil
3366 Properties.SetProp(prop,enumItem)
3367 end
3368
3369 for i = 1,#sorted do
3370 local enumItem = sorted[i]
3371 context:Add({Name = enumItem.Name, OnClick = onClick})
3372 end
3373
3374 context.Width = valueFrame.AbsoluteSize.X
3375 context:Show(valueFrame.AbsolutePosition.X, valueFrame.AbsolutePosition.Y + 22)
3376 end
3377
3378 Properties.DisplayBrickColorEditor = function(prop,entryIndex,col)
3379 local editor = Properties.BrickColorEditor
3380 if not editor then
3381 editor = Lib.BrickColorPicker.new()
3382 editor.Gui.DisplayOrder = Main.DisplayOrders.Menu
3383 editor.ReverseYOffset = 22
3384
3385 editor.OnSelect:Connect(function(col)
3386 if not editor.CurrentProp or editor.CurrentProp.ValueType.Name ~= "BrickColor" then return end
3387
3388 if editor.CurrentProp == inputProp then inputProp = nil end
3389 Properties.SetProp(editor.CurrentProp,BrickColor.new(col))
3390 end)
3391
3392 editor.OnMoreColors:Connect(function() -- TODO: Special Case BasePart.BrickColor to BasePart.Color
3393 editor:Close()
3394 local colProp
3395 for i,v in pairs(API.Classes.BasePart.Properties) do
3396 if v.Name == "Color" then
3397 colProp = v
3398 break
3399 end
3400 end
3401 Properties.DisplayColorEditor(colProp,editor.SavedColor.Color)
3402 end)
3403
3404 Properties.BrickColorEditor = editor
3405 end
3406
3407 local entry = propEntries[entryIndex]
3408 local valueFrame = entry.GuiElems.ValueFrame
3409
3410 editor.CurrentProp = prop
3411 editor.SavedColor = col
3412 if prop and prop.Class == "BasePart" and prop.Name == "BrickColor" then
3413 editor:SetMoreColorsVisible(true)
3414 else
3415 editor:SetMoreColorsVisible(false)
3416 end
3417 editor:Show(valueFrame.AbsolutePosition.X, valueFrame.AbsolutePosition.Y + 22)
3418 end
3419
3420 Properties.DisplayColorEditor = function(prop,col)
3421 local editor = Properties.ColorEditor
3422 if not editor then
3423 editor = Lib.ColorPicker.new()
3424
3425 editor.OnSelect:Connect(function(col)
3426 if not editor.CurrentProp then return end
3427 local typeName = editor.CurrentProp.ValueType.Name
3428 if typeName ~= "Color3" and typeName ~= "BrickColor" then return end
3429
3430 local colVal = (typeName == "Color3" and col or BrickColor.new(col))
3431
3432 if editor.CurrentProp == inputProp then inputProp = nil end
3433 Properties.SetProp(editor.CurrentProp,colVal)
3434 end)
3435
3436 Properties.ColorEditor = editor
3437 end
3438
3439 editor.CurrentProp = prop
3440 if col then
3441 editor:SetColor(col)
3442 else
3443 local firstVal = Properties.GetFirstPropVal(prop)
3444 if firstVal then editor:SetColor(firstVal) end
3445 end
3446 editor:Show()
3447 end
3448
3449 Properties.DisplayNumberSequenceEditor = function(prop,seq)
3450 local editor = Properties.NumberSequenceEditor
3451 if not editor then
3452 editor = Lib.NumberSequenceEditor.new()
3453
3454 editor.OnSelect:Connect(function(val)
3455 if not editor.CurrentProp or editor.CurrentProp.ValueType.Name ~= "NumberSequence" then return end
3456
3457 if editor.CurrentProp == inputProp then inputProp = nil end
3458 Properties.SetProp(editor.CurrentProp,val)
3459 end)
3460
3461 Properties.NumberSequenceEditor = editor
3462 end
3463
3464 editor.CurrentProp = prop
3465 if seq then
3466 editor:SetSequence(seq)
3467 else
3468 local firstVal = Properties.GetFirstPropVal(prop)
3469 if firstVal then editor:SetSequence(firstVal) end
3470 end
3471 editor:Show()
3472 end
3473
3474 Properties.DisplayColorSequenceEditor = function(prop,seq)
3475 local editor = Properties.ColorSequenceEditor
3476 if not editor then
3477 editor = Lib.ColorSequenceEditor.new()
3478
3479 editor.OnSelect:Connect(function(val)
3480 if not editor.CurrentProp or editor.CurrentProp.ValueType.Name ~= "ColorSequence" then return end
3481
3482 if editor.CurrentProp == inputProp then inputProp = nil end
3483 Properties.SetProp(editor.CurrentProp,val)
3484 end)
3485
3486 Properties.ColorSequenceEditor = editor
3487 end
3488
3489 editor.CurrentProp = prop
3490 if seq then
3491 editor:SetSequence(seq)
3492 else
3493 local firstVal = Properties.GetFirstPropVal(prop)
3494 if firstVal then editor:SetSequence(firstVal) end
3495 end
3496 editor:Show()
3497 end
3498
3499 Properties.GetFirstPropVal = function(prop)
3500 local first = Properties.FindFirstObjWhichIsA(prop.Class)
3501 if first then
3502 return Properties.GetPropVal(prop,first)
3503 end
3504 end
3505
3506 Properties.GetPropVal = function(prop,obj)
3507 if prop.MultiType then return "<Multiple Types>" end
3508 if not obj then return end
3509
3510 local propVal
3511 if prop.IsAttribute then
3512 propVal = getAttribute(obj,prop.AttributeName)
3513 if propVal == nil then return nil end
3514
3515 local typ = typeof(propVal)
3516 local currentType = Properties.TypeNameConvert[typ] or typ
3517 if prop.RootType then
3518 if prop.RootType.Name ~= currentType then
3519 return nil
3520 end
3521 elseif prop.ValueType.Name ~= currentType then
3522 return nil
3523 end
3524 else
3525 propVal = obj[prop.Name]
3526 end
3527 if prop.SubName then
3528 local indexes = string.split(prop.SubName,".")
3529 for i = 1,#indexes do
3530 local indexName = indexes[i]
3531 if #indexName > 0 and propVal then
3532 propVal = propVal[indexName]
3533 end
3534 end
3535 end
3536
3537 return propVal
3538 end
3539
3540 Properties.SelectObject = function(obj)
3541 if inputProp and inputProp.ValueType.Category == "Class" then
3542 local prop = inputProp
3543 inputProp = nil
3544
3545 if isa(obj,prop.ValueType.Name) then
3546 Properties.SetProp(prop,obj)
3547 else
3548 Properties.Refresh()
3549 end
3550
3551 return true
3552 end
3553
3554 return false
3555 end
3556
3557 Properties.DisplayProp = function(prop,entryIndex)
3558 local propName = prop.Name
3559 local typeData = prop.ValueType
3560 local typeName = typeData.Name
3561 local tags = prop.Tags
3562 local gName = prop.Class.."."..prop.Name..(prop.SubName or "")
3563 local propObj = autoUpdateObjs[gName]
3564 local entryData = propEntries[entryIndex]
3565 local UDim2 = UDim2
3566
3567 local guiElems = entryData.GuiElems
3568 local valueFrame = guiElems.ValueFrame
3569 local valueBox = guiElems.ValueBox
3570 local colorButton = guiElems.ColorButton
3571 local colorPreview = guiElems.ColorPreview
3572 local gradient = guiElems.Gradient
3573 local enumArrow = guiElems.EnumArrow
3574 local checkbox = guiElems.Checkbox
3575 local rightButton = guiElems.RightButton
3576 local soundPreview = guiElems.SoundPreview
3577
3578 local propVal = Properties.GetPropVal(prop,propObj)
3579 local inputFullName = inputProp and (inputProp.Class.."."..inputProp.Name..(inputProp.SubName or ""))
3580
3581 local offset = 4
3582 local endOffset = 6
3583
3584 -- Offsetting the ValueBox for ValueType specific buttons
3585 if (typeName == "Color3" or typeName == "BrickColor" or typeName == "ColorSequence") then
3586 colorButton.Visible = true
3587 enumArrow.Visible = false
3588 if propVal then
3589 gradient.Color = (typeName == "Color3" and ColorSequence.new(propVal)) or (typeName == "BrickColor" and ColorSequence.new(propVal.Color)) or propVal
3590 else
3591 gradient.Color = ColorSequence.new(Color3.new(1,1,1))
3592 end
3593 colorPreview.BorderColor3 = (typeName == "ColorSequence" and Color3.new(1,1,1) or Color3.new(0,0,0))
3594 offset = 22
3595 endOffset = 24 + (typeName == "ColorSequence" and 20 or 0)
3596 elseif typeData.Category == "Enum" then
3597 colorButton.Visible = false
3598 enumArrow.Visible = not prop.Tags.ReadOnly
3599 endOffset = 22
3600 elseif (gName == inputFullName and typeData.Category == "Class") or typeName == "NumberSequence" then
3601 colorButton.Visible = false
3602 enumArrow.Visible = false
3603 endOffset = 26
3604 else
3605 colorButton.Visible = false
3606 enumArrow.Visible = false
3607 end
3608
3609 valueBox.Position = UDim2.new(0,offset,0,0)
3610 valueBox.Size = UDim2.new(1,-endOffset,1,0)
3611
3612 -- Right button
3613 if inputFullName == gName and typeData.Category == "Class" then
3614 Main.MiscIcons:DisplayByKey(guiElems.RightButtonIcon, "Delete")
3615 guiElems.RightButtonIcon.Visible = true
3616 rightButton.Text = ""
3617 rightButton.Visible = true
3618 elseif typeName == "NumberSequence" or typeName == "ColorSequence" then
3619 guiElems.RightButtonIcon.Visible = false
3620 rightButton.Text = "..."
3621 rightButton.Visible = true
3622 else
3623 rightButton.Visible = false
3624 end
3625
3626 -- Displays the correct ValueBox for the ValueType, and sets it to the prop value
3627 if typeName == "bool" or typeName == "PhysicalProperties" then
3628 valueBox.Visible = false
3629 checkbox.Visible = true
3630 soundPreview.Visible = false
3631 checkboxes[entryIndex].Disabled = tags.ReadOnly
3632 if typeName == "PhysicalProperties" and autoUpdateObjs[gName] then
3633 checkboxes[entryIndex]:SetState(propVal and true or false)
3634 else
3635 checkboxes[entryIndex]:SetState(propVal)
3636 end
3637 elseif typeName == "SoundPlayer" then
3638 valueBox.Visible = false
3639 checkbox.Visible = false
3640 soundPreview.Visible = true
3641 local playing = Properties.PreviewSound and Properties.PreviewSound.Playing
3642 Main.MiscIcons:DisplayByKey(soundPreview.ControlButton.Icon, playing and "Pause" or "Play")
3643 else
3644 valueBox.Visible = true
3645 checkbox.Visible = false
3646 soundPreview.Visible = false
3647
3648 if propVal ~= nil then
3649 if typeName == "Color3" then
3650 valueBox.Text = "["..Lib.ColorToBytes(propVal).."]"
3651 elseif typeData.Category == "Enum" then
3652 valueBox.Text = propVal.Name
3653 elseif Properties.RoundableTypes[typeName] and Settings.Properties.NumberRounding then
3654 local rawStr = Properties.ValueToString(prop,propVal)
3655 valueBox.Text = rawStr:gsub("-?%d+%.%d+",function(num)
3656 return tostring(tonumber(("%."..Settings.Properties.NumberRounding.."f"):format(num)))
3657 end)
3658 else
3659 valueBox.Text = Properties.ValueToString(prop,propVal)
3660 end
3661 else
3662 valueBox.Text = ""
3663 end
3664
3665 valueBox.TextColor3 = tags.ReadOnly and Settings.Theme.PlaceholderText or Settings.Theme.Text
3666 end
3667 end
3668
3669 Properties.Refresh = function()
3670 local maxEntries = math.max(math.ceil((propsFrame.AbsoluteSize.Y) / 23),0)
3671 local maxX = propsFrame.AbsoluteSize.X
3672 local valueWidth = math.max(Properties.MinInputWidth,maxX-Properties.ViewWidth)
3673 local inputPropVisible = false
3674 local isa = game.IsA
3675 local UDim2 = UDim2
3676 local stringSplit = string.split
3677 local scaleType = Settings.Properties.ScaleType
3678
3679 -- Clear connections
3680 for i = 1,#propCons do
3681 propCons[i]:Disconnect()
3682 end
3683 table.clear(propCons)
3684
3685 -- Hide full name viewer
3686 Properties.FullNameFrame.Visible = false
3687 Properties.FullNameFrameAttach.Disable()
3688
3689 for i = 1,maxEntries do
3690 local entryData = propEntries[i]
3691 if not propEntries[i] then entryData = Properties.NewPropEntry(i) propEntries[i] = entryData end
3692
3693 local entry = entryData.Gui
3694 local guiElems = entryData.GuiElems
3695 local nameFrame = guiElems.NameFrame
3696 local propNameLabel = guiElems.PropName
3697 local valueFrame = guiElems.ValueFrame
3698 local expand = guiElems.Expand
3699 local valueBox = guiElems.ValueBox
3700 local propNameBox = guiElems.PropName
3701 local rightButton = guiElems.RightButton
3702 local editAttributeButton = guiElems.EditAttributeButton
3703 local toggleAttributes = guiElems.ToggleAttributes
3704
3705 local prop = viewList[i + Properties.Index]
3706 if prop then
3707 local entryXOffset = (scaleType == 0 and scrollH.Index or 0)
3708 entry.Visible = true
3709 entry.Position = UDim2.new(0,-entryXOffset,0,entry.Position.Y.Offset)
3710 entry.Size = UDim2.new(scaleType == 0 and 0 or 1, scaleType == 0 and Properties.ViewWidth + valueWidth or 0,0,22)
3711
3712 if prop.SpecialRow then
3713 if prop.SpecialRow == "AddAttribute" then
3714 nameFrame.Visible = false
3715 valueFrame.Visible = false
3716 guiElems.RowButton.Visible = true
3717 end
3718 else
3719 -- Revert special row stuff
3720 nameFrame.Visible = true
3721 guiElems.RowButton.Visible = false
3722
3723 local depth = Properties.EntryIndent*(prop.Depth or 1)
3724 local leftOffset = depth + Properties.EntryOffset
3725 nameFrame.Position = UDim2.new(0,leftOffset,0,0)
3726 propNameLabel.Size = UDim2.new(1,-2 - (scaleType == 0 and 0 or 6),1,0)
3727
3728 local gName = (prop.CategoryName and "CAT_"..prop.CategoryName) or prop.Class.."."..prop.Name..(prop.SubName or "")
3729
3730 if prop.CategoryName then
3731 entry.BackgroundColor3 = Settings.Theme.Main1
3732 valueFrame.Visible = false
3733
3734 propNameBox.Text = prop.CategoryName
3735 propNameBox.Font = Enum.Font.SourceSansBold
3736 expand.Visible = true
3737 propNameBox.TextColor3 = Settings.Theme.Text
3738 nameFrame.BackgroundTransparency = 1
3739 nameFrame.Size = UDim2.new(1,0,1,0)
3740 editAttributeButton.Visible = false
3741
3742 local showingAttrs = Settings.Properties.ShowAttributes
3743 toggleAttributes.Position = UDim2.new(1,-85-leftOffset,0,0)
3744 toggleAttributes.Text = (showingAttrs and "[Setting: ON]" or "[Setting: OFF]")
3745 toggleAttributes.TextColor3 = Settings.Theme.Text
3746 toggleAttributes.Visible = (prop.CategoryName == "Attributes")
3747 else
3748 local propName = prop.Name
3749 local typeData = prop.ValueType
3750 local typeName = typeData.Name
3751 local tags = prop.Tags
3752 local propObj = autoUpdateObjs[gName]
3753
3754 local attributeOffset = (prop.IsAttribute and 20 or 0)
3755 editAttributeButton.Visible = (prop.IsAttribute and not prop.RootType)
3756 toggleAttributes.Visible = false
3757
3758 -- Moving around the frames
3759 if scaleType == 0 then
3760 nameFrame.Size = UDim2.new(0,Properties.ViewWidth - leftOffset - 1,1,0)
3761 valueFrame.Position = UDim2.new(0,Properties.ViewWidth,0,0)
3762 valueFrame.Size = UDim2.new(0,valueWidth - attributeOffset,1,0)
3763 else
3764 nameFrame.Size = UDim2.new(0.5,-leftOffset - 1,1,0)
3765 valueFrame.Position = UDim2.new(0.5,0,0,0)
3766 valueFrame.Size = UDim2.new(0.5,-attributeOffset,1,0)
3767 end
3768
3769 local nameArr = stringSplit(gName,".")
3770 propNameBox.Text = prop.DisplayName or nameArr[#nameArr]
3771 propNameBox.Font = Enum.Font.SourceSans
3772 entry.BackgroundColor3 = Settings.Theme.Main2
3773 valueFrame.Visible = true
3774
3775 expand.Visible = typeData.Category == "DataType" and Properties.ExpandableTypes[typeName] or Properties.ExpandableProps[gName]
3776 propNameBox.TextColor3 = tags.ReadOnly and Settings.Theme.PlaceholderText or Settings.Theme.Text
3777
3778 -- Display property value
3779 Properties.DisplayProp(prop,i)
3780 if propObj then
3781 if prop.IsAttribute then
3782 propCons[#propCons+1] = getAttributeChangedSignal(propObj,prop.AttributeName):Connect(function()
3783 Properties.DisplayProp(prop,i)
3784 end)
3785 else
3786 propCons[#propCons+1] = getPropChangedSignal(propObj,propName):Connect(function()
3787 Properties.DisplayProp(prop,i)
3788 end)
3789 end
3790 end
3791
3792 -- Position and resize Input Box
3793 local beforeVisible = valueBox.Visible
3794 local inputFullName = inputProp and (inputProp.Class.."."..inputProp.Name..(inputProp.SubName or ""))
3795 if gName == inputFullName then
3796 nameFrame.BackgroundColor3 = Settings.Theme.ListSelection
3797 nameFrame.BackgroundTransparency = 0
3798 if typeData.Category == "Class" or typeData.Category == "Enum" or typeName == "BrickColor" then
3799 valueFrame.BackgroundColor3 = Settings.Theme.TextBox
3800 valueFrame.BackgroundTransparency = 0
3801 valueBox.Visible = true
3802 else
3803 inputPropVisible = true
3804 local scale = (scaleType == 0 and 0 or 0.5)
3805 local offset = (scaleType == 0 and Properties.ViewWidth-scrollH.Index or 0)
3806 local endOffset = 0
3807
3808 if typeName == "Color3" or typeName == "ColorSequence" then
3809 offset = offset + 22
3810 end
3811
3812 if typeName == "NumberSequence" or typeName == "ColorSequence" then
3813 endOffset = 20
3814 end
3815
3816 inputBox.Position = UDim2.new(scale,offset,0,entry.Position.Y.Offset)
3817 inputBox.Size = UDim2.new(1-scale,-offset-endOffset-attributeOffset,0,22)
3818 inputBox.Visible = true
3819 valueBox.Visible = false
3820 end
3821 else
3822 nameFrame.BackgroundColor3 = Settings.Theme.Main1
3823 nameFrame.BackgroundTransparency = 1
3824 valueFrame.BackgroundColor3 = Settings.Theme.Main1
3825 valueFrame.BackgroundTransparency = 1
3826 valueBox.Visible = beforeVisible
3827 end
3828 end
3829
3830 -- Expand
3831 if prop.CategoryName or Properties.ExpandableTypes[prop.ValueType and prop.ValueType.Name] or Properties.ExpandableProps[gName] then
3832 if Lib.CheckMouseInGui(expand) then
3833 Main.MiscIcons:DisplayByKey(expand.Icon, expanded[gName] and "Collapse_Over" or "Expand_Over")
3834 else
3835 Main.MiscIcons:DisplayByKey(expand.Icon, expanded[gName] and "Collapse" or "Expand")
3836 end
3837 expand.Visible = true
3838 else
3839 expand.Visible = false
3840 end
3841 end
3842 entry.Visible = true
3843 else
3844 entry.Visible = false
3845 end
3846 end
3847
3848 if not inputPropVisible then
3849 inputBox.Visible = false
3850 end
3851
3852 for i = maxEntries+1,#propEntries do
3853 propEntries[i].Gui:Destroy()
3854 propEntries[i] = nil
3855 checkboxes[i] = nil
3856 end
3857 end
3858
3859 Properties.SetProp = function(prop,val,noupdate,prevAttribute)
3860 local sList = Explorer.Selection.List
3861 local propName = prop.Name
3862 local subName = prop.SubName
3863 local propClass = prop.Class
3864 local typeData = prop.ValueType
3865 local typeName = typeData.Name
3866 local attributeName = prop.AttributeName
3867 local rootTypeData = prop.RootType
3868 local rootTypeName = rootTypeData and rootTypeData.Name
3869 local fullName = prop.Class.."."..prop.Name..(prop.SubName or "")
3870 local Vector3 = Vector3
3871
3872 for i = 1,#sList do
3873 local node = sList[i]
3874 local obj = node.Obj
3875
3876 if isa(obj,propClass) then
3877 pcall(function()
3878 local setVal = val
3879 local root
3880 if prop.IsAttribute then
3881 root = getAttribute(obj,attributeName)
3882 else
3883 root = obj[propName]
3884 end
3885
3886 if prevAttribute then
3887 if prevAttribute.ValueType.Name == typeName then
3888 setVal = getAttribute(obj,prevAttribute.AttributeName) or setVal
3889 end
3890 setAttribute(obj,prevAttribute.AttributeName,nil)
3891 end
3892
3893 if rootTypeName then
3894 if rootTypeName == "Vector2" then
3895 setVal = Vector2.new((subName == ".X" and setVal) or root.X, (subName == ".Y" and setVal) or root.Y)
3896 elseif rootTypeName == "Vector3" then
3897 setVal = Vector3.new((subName == ".X" and setVal) or root.X, (subName == ".Y" and setVal) or root.Y, (subName == ".Z" and setVal) or root.Z)
3898 elseif rootTypeName == "UDim" then
3899 setVal = UDim.new((subName == ".Scale" and setVal) or root.Scale, (subName == ".Offset" and setVal) or root.Offset)
3900 elseif rootTypeName == "UDim2" then
3901 local rootX,rootY = root.X,root.Y
3902 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)
3903 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)
3904 setVal = UDim2.new(X_UDim,Y_UDim)
3905 elseif rootTypeName == "CFrame" then
3906 local rootPos,rootRight,rootUp,rootLook = root.Position,root.RightVector,root.UpVector,root.LookVector
3907 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)
3908 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)
3909 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)
3910 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)
3911 setVal = CFrame.fromMatrix(pos,rightV,upV,-lookV)
3912 elseif rootTypeName == "Rect" then
3913 local rootMin,rootMax = root.Min,root.Max
3914 local min = Vector2.new((subName == ".Min.X" and setVal) or rootMin.X, (subName == ".Min.Y" and setVal) or rootMin.Y)
3915 local max = Vector2.new((subName == ".Max.X" and setVal) or rootMax.X, (subName == ".Max.Y" and setVal) or rootMax.Y)
3916 setVal = Rect.new(min,max)
3917 elseif rootTypeName == "PhysicalProperties" then
3918 local rootProps = PhysicalProperties.new(obj.Material)
3919 local density = (subName == ".Density" and setVal) or (root and root.Density) or rootProps.Density
3920 local friction = (subName == ".Friction" and setVal) or (root and root.Friction) or rootProps.Friction
3921 local elasticity = (subName == ".Elasticity" and setVal) or (root and root.Elasticity) or rootProps.Elasticity
3922 local frictionWeight = (subName == ".FrictionWeight" and setVal) or (root and root.FrictionWeight) or rootProps.FrictionWeight
3923 local elasticityWeight = (subName == ".ElasticityWeight" and setVal) or (root and root.ElasticityWeight) or rootProps.ElasticityWeight
3924 setVal = PhysicalProperties.new(density,friction,elasticity,frictionWeight,elasticityWeight)
3925 elseif rootTypeName == "Ray" then
3926 local rootOrigin,rootDirection = root.Origin,root.Direction
3927 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)
3928 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)
3929 setVal = Ray.new(origin,direction)
3930 elseif rootTypeName == "Faces" then
3931 local faces = {}
3932 local faceList = {"Back","Bottom","Front","Left","Right","Top"}
3933 for _,face in pairs(faceList) do
3934 local val
3935 if subName == "."..face then
3936 val = setVal
3937 else
3938 val = root[face]
3939 end
3940 if val then faces[#faces+1] = Enum.NormalId[face] end
3941 end
3942 setVal = Faces.new(unpack(faces))
3943 elseif rootTypeName == "Axes" then
3944 local axes = {}
3945 local axesList = {"X","Y","Z"}
3946 for _,axe in pairs(axesList) do
3947 local val
3948 if subName == "."..axe then
3949 val = setVal
3950 else
3951 val = root[axe]
3952 end
3953 if val then axes[#axes+1] = Enum.Axis[axe] end
3954 end
3955 setVal = Axes.new(unpack(axes))
3956 elseif rootTypeName == "NumberRange" then
3957 setVal = NumberRange.new(subName == ".Min" and setVal or root.Min, subName == ".Max" and setVal or root.Max)
3958 end
3959 end
3960
3961 if typeName == "PhysicalProperties" and setVal then
3962 setVal = root or PhysicalProperties.new(obj.Material)
3963 end
3964
3965 if prop.IsAttribute then
3966 setAttribute(obj,attributeName,setVal)
3967 else
3968 obj[propName] = setVal
3969 end
3970 end)
3971 end
3972 end
3973
3974 if not noupdate then
3975 Properties.ComputeConflicts(prop)
3976 end
3977 end
3978
3979 Properties.InitInputBox = function()
3980 inputBox = create({
3981 {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,}},
3982 {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,}},
3983 })
3984 inputTextBox = inputBox.TextBox
3985 inputBox.BackgroundColor3 = Settings.Theme.TextBox
3986 inputBox.Parent = Properties.Window.GuiElems.Content.List
3987
3988 inputTextBox.FocusLost:Connect(function()
3989 if not inputProp then return end
3990
3991 local prop = inputProp
3992 inputProp = nil
3993 local val = Properties.StringToValue(prop,inputTextBox.Text)
3994 if val then Properties.SetProp(prop,val) else Properties.Refresh() end
3995 end)
3996
3997 inputTextBox.Focused:Connect(function()
3998 inputTextBox.SelectionStart = 1
3999 inputTextBox.CursorPosition = #inputTextBox.Text + 1
4000 end)
4001
4002 Lib.ViewportTextBox.convert(inputTextBox)
4003 end
4004
4005 Properties.SetInputProp = function(prop,entryIndex,special)
4006 local typeData = prop.ValueType
4007 local typeName = typeData.Name
4008 local fullName = prop.Class.."."..prop.Name..(prop.SubName or "")
4009 local propObj = autoUpdateObjs[fullName]
4010 local propVal = Properties.GetPropVal(prop,propObj)
4011
4012 if prop.Tags.ReadOnly then return end
4013
4014 inputProp = prop
4015 if special then
4016 if special == "color" then
4017 if typeName == "Color3" then
4018 inputTextBox.Text = propVal and Properties.ValueToString(prop,propVal) or ""
4019 Properties.DisplayColorEditor(prop,propVal)
4020 elseif typeName == "BrickColor" then
4021 Properties.DisplayBrickColorEditor(prop,entryIndex,propVal)
4022 elseif typeName == "ColorSequence" then
4023 inputTextBox.Text = propVal and Properties.ValueToString(prop,propVal) or ""
4024 Properties.DisplayColorSequenceEditor(prop,propVal)
4025 end
4026 elseif special == "right" then
4027 if typeName == "NumberSequence" then
4028 inputTextBox.Text = propVal and Properties.ValueToString(prop,propVal) or ""
4029 Properties.DisplayNumberSequenceEditor(prop,propVal)
4030 elseif typeName == "ColorSequence" then
4031 inputTextBox.Text = propVal and Properties.ValueToString(prop,propVal) or ""
4032 Properties.DisplayColorSequenceEditor(prop,propVal)
4033 end
4034 end
4035 else
4036 if Properties.IsTextEditable(prop) then
4037 inputTextBox.Text = propVal and Properties.ValueToString(prop,propVal) or ""
4038 inputTextBox:CaptureFocus()
4039 elseif typeData.Category == "Enum" then
4040 Properties.DisplayEnumDropdown(entryIndex)
4041 elseif typeName == "BrickColor" then
4042 Properties.DisplayBrickColorEditor(prop,entryIndex,propVal)
4043 end
4044 end
4045 Properties.Refresh()
4046 end
4047
4048 Properties.InitSearch = function()
4049 local searchBox = Properties.GuiElems.ToolBar.SearchFrame.SearchBox
4050
4051 Lib.ViewportTextBox.convert(searchBox)
4052
4053 searchBox:GetPropertyChangedSignal("Text"):Connect(function()
4054 Properties.SearchText = searchBox.Text
4055 Properties.Update()
4056 Properties.Refresh()
4057 end)
4058 end
4059
4060 Properties.InitEntryStuff = function()
4061 Properties.EntryTemplate = create({
4062 {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,}},
4063 {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),}},
4064 {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,}},
4065 {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,}},
4066 {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),}},
4067 {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,}},
4068 {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),}},
4069 {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),}},
4070 {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,}},
4071 {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),}},
4072 {11,"UIGradient",{Parent={10},}},
4073 {12,"Frame",{BackgroundTransparency=1,Name="EnumArrow",Parent={7},Position=UDim2.new(1,-16,0,3),Size=UDim2.new(0,16,0,16),Visible=false,}},
4074 {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),}},
4075 {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),}},
4076 {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),}},
4077 {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,}},
4078 {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,}},
4079 {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,}},
4080 {19,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="SoundPreview",Parent={7},Size=UDim2.new(1,0,1,0),Visible=false,}},
4081 {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,}},
4082 {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),}},
4083 {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),}},
4084 {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),}},
4085 {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,}},
4086 {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),}},
4087 {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,}},
4088 })
4089
4090 local fullNameFrame = Lib.Frame.new()
4091 local label = Lib.Label.new()
4092 label.Parent = fullNameFrame.Gui
4093 label.Position = UDim2.new(0,2,0,0)
4094 label.Size = UDim2.new(1,-4,1,0)
4095 fullNameFrame.Visible = false
4096 fullNameFrame.Parent = window.Gui
4097
4098 Properties.FullNameFrame = fullNameFrame
4099 Properties.FullNameFrameAttach = Lib.AttachTo(fullNameFrame)
4100 end
4101
4102 Properties.Init = function() -- TODO: MAKE BETTER
4103 local guiItems = create({
4104 {1,"Folder",{Name="Items",}},
4105 {2,"Frame",{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BorderSizePixel=0,Name="ToolBar",Parent={1},Size=UDim2.new(1,0,0,22),}},
4106 {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),}},
4107 {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,}},
4108 {5,"UICorner",{CornerRadius=UDim.new(0,2),Parent={3},}},
4109 {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,}},
4110 {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),}},
4111 {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,}},
4112 {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),}},
4113 {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,}},
4114 {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),}},
4115 })
4116
4117 -- Vars
4118 categoryOrder = API.CategoryOrder
4119 for category,_ in next,categoryOrder do
4120 if not Properties.CollapsedCategories[category] then
4121 expanded["CAT_"..category] = true
4122 end
4123 end
4124 expanded["Sound.SoundId"] = true
4125
4126 -- Init window
4127 window = Lib.Window.new()
4128 Properties.Window = window
4129 window:SetTitle("Properties")
4130
4131 toolBar = guiItems.ToolBar
4132 propsFrame = guiItems.List
4133
4134 Properties.GuiElems.ToolBar = toolBar
4135 Properties.GuiElems.PropsFrame = propsFrame
4136
4137 Properties.InitEntryStuff()
4138
4139 -- Window events
4140 window.GuiElems.Main:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
4141 if Properties.Window:IsContentVisible() then
4142 Properties.UpdateView()
4143 Properties.Refresh()
4144 end
4145 end)
4146 window.OnActivate:Connect(function()
4147 Properties.UpdateView()
4148 Properties.Update()
4149 Properties.Refresh()
4150 end)
4151 window.OnRestore:Connect(function()
4152 Properties.UpdateView()
4153 Properties.Update()
4154 Properties.Refresh()
4155 end)
4156
4157 -- Init scrollbars
4158 scrollV = Lib.ScrollBar.new()
4159 scrollV.WheelIncrement = 3
4160 scrollV.Gui.Position = UDim2.new(1,-16,0,23)
4161 scrollV:SetScrollFrame(propsFrame)
4162 scrollV.Scrolled:Connect(function()
4163 Properties.Index = scrollV.Index
4164 Properties.Refresh()
4165 end)
4166
4167 scrollH = Lib.ScrollBar.new(true)
4168 scrollH.Increment = 5
4169 scrollH.WheelIncrement = 20
4170 scrollH.Gui.Position = UDim2.new(0,0,1,-16)
4171 scrollH.Scrolled:Connect(function()
4172 Properties.Refresh()
4173 end)
4174
4175 -- Setup Gui
4176 window.GuiElems.Line.Position = UDim2.new(0,0,0,22)
4177 toolBar.Parent = window.GuiElems.Content
4178 propsFrame.Parent = window.GuiElems.Content
4179 guiItems.ScrollCorner.Parent = window.GuiElems.Content
4180 scrollV.Gui.Parent = window.GuiElems.Content
4181 scrollH.Gui.Parent = window.GuiElems.Content
4182 Properties.InitInputBox()
4183 Properties.InitSearch()
4184 end
4185
4186 return Properties
4187end
4188
4189return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main}
4190end,
4191ScriptViewer = function()
4192--[[
4193 Script Viewer App Module
4194
4195 A script viewer that is basically a notepad
4196]]
4197
4198-- Common Locals
4199local Main,Lib,Apps,Settings -- Main Containers
4200local Explorer, Properties, ScriptViewer, Notebook -- Major Apps
4201local API,RMD,env,service,plr,create,createSimple -- Main Locals
4202
4203local function initDeps(data)
4204 Main = data.Main
4205 Lib = data.Lib
4206 Apps = data.Apps
4207 Settings = data.Settings
4208
4209 API = data.API
4210 RMD = data.RMD
4211 env = data.env
4212 service = data.service
4213 plr = data.plr
4214 create = data.create
4215 createSimple = data.createSimple
4216end
4217
4218local function initAfterMain()
4219 Explorer = Apps.Explorer
4220 Properties = Apps.Properties
4221 ScriptViewer = Apps.ScriptViewer
4222 Notebook = Apps.Notebook
4223end
4224
4225local function main()
4226 local ScriptViewer = {}
4227 local window, codeFrame
4228 local PreviousScr = nil
4229
4230 ScriptViewer.ViewScript = function(scr)
4231 local success, source = pcall(env.decompile or function() end, scr)
4232 if not success or not source then source, PreviousScr = "-- DEX - Source failed to decompile", nil else PreviousScr = scr end
4233 codeFrame:SetText(source)
4234 window:Show()
4235 end
4236
4237 ScriptViewer.Init = function()
4238 window = Lib.Window.new()
4239 window:SetTitle("Script Viewer")
4240 window:Resize(500,400)
4241 ScriptViewer.Window = window
4242
4243 codeFrame = Lib.CodeFrame.new()
4244 codeFrame.Frame.Position = UDim2.new(0,0,0,20)
4245 codeFrame.Frame.Size = UDim2.new(1,0,1,-20)
4246 codeFrame.Frame.Parent = window.GuiElems.Content
4247
4248 -- TODO: REMOVE AND MAKE BETTER
4249 local copy = Instance.new("TextButton",window.GuiElems.Content)
4250 copy.BackgroundTransparency = 1
4251 copy.Size = UDim2.new(0.5,0,0,20)
4252 copy.Text = "Copy to Clipboard"
4253 copy.TextColor3 = Color3.new(1,1,1)
4254
4255 copy.MouseButton1Click:Connect(function()
4256 local source = codeFrame:GetText()
4257 setclipboard(source)
4258 end)
4259
4260 local save = Instance.new("TextButton",window.GuiElems.Content)
4261 save.BackgroundTransparency = 1
4262 save.Position = UDim2.new(0.35,0,0,0)
4263 save.Size = UDim2.new(0.3,0,0,20)
4264 save.Text = "Save to File"
4265 save.TextColor3 = Color3.new(1,1,1)
4266
4267 save.MouseButton1Click:Connect(function()
4268 local source = codeFrame:GetText()
4269 local filename = "Place_"..game.PlaceId.."_Script_"..os.time()..".txt"
4270
4271 writefile(filename,source)
4272 if movefileas then -- TODO: USE ENV
4273 movefileas(filename,".txt")
4274 end
4275 end)
4276
4277 local dumpbtn = Instance.new("TextButton",window.GuiElems.Content)
4278 dumpbtn.BackgroundTransparency = 1
4279 dumpbtn.Position = UDim2.new(0.7,0,0,0)
4280 dumpbtn.Size = UDim2.new(0.3,0,0,20)
4281 dumpbtn.Text = "Dump Functions"
4282 dumpbtn.TextColor3 = Color3.new(1,1,1)
4283
4284 dumpbtn.MouseButton1Click:Connect(function()
4285 if PreviousScr ~= nil then
4286 pcall(function()
4287 -- thanks King.Kevin#6025 you'll obviously be credited (no discord tag since that can easily be impersonated)
4288 local getgc = getgc or get_gc_objects
4289 local getupvalues = (debug and debug.getupvalues) or getupvalues or getupvals
4290 local getconstants = (debug and debug.getconstants) or getconstants or getconsts
4291 local getinfo = (debug and (debug.getinfo or debug.info)) or getinfo
4292 local original = ("\n-- // Function Dumper made by King.Kevin\n-- // Script Path: %s\n\n--[["):format(PreviousScr:GetFullName())
4293 local dump = original
4294 local functions, function_count, data_base = {}, 0, {}
4295 function functions:add_to_dump(str, indentation, new_line)
4296 local new_line = new_line or true
4297 dump = dump .. ("%s%s%s"):format(string.rep(" ", indentation), tostring(str), new_line and "\n" or "")
4298 end
4299 function functions:get_function_name(func)
4300 local n = getinfo(func).name
4301 return n ~= "" and n or "Unknown Name"
4302 end
4303 function functions:dump_table(input, indent, index)
4304 local indent = indent < 0 and 0 or indent
4305 functions:add_to_dump(("%s [%s] %s"):format(tostring(index), tostring(typeof(input)), tostring(input)), indent - 1)
4306 local count = 0
4307 for index, value in pairs(input) do
4308 count = count + 1
4309 if type(value) == "function" then
4310 functions:add_to_dump(("%d [function] = %s"):format(count, functions:get_function_name(value)), indent)
4311 elseif type(value) == "table" then
4312 if not data_base[value] then
4313 data_base[value] = true
4314 functions:add_to_dump(("%d [table]:"):format(count), indent)
4315 functions:dump_table(value, indent + 1, index)
4316 else
4317 functions:add_to_dump(("%d [table] (Recursive table detected)"):format(count), indent)
4318 end
4319 else
4320 functions:add_to_dump(("%d [%s] = %s"):format(count, tostring(typeof(value)), tostring(value)), indent)
4321 end
4322 end
4323 end
4324 function functions:dump_function(input, indent)
4325 functions:add_to_dump(("\nFunction Dump: %s"):format(functions:get_function_name(input)), indent)
4326 functions:add_to_dump(("\nFunction Upvalues: %s"):format(functions:get_function_name(input)), indent)
4327 for index, upvalue in pairs(getupvalues(input)) do
4328 if type(upvalue) == "function" then
4329 functions:add_to_dump(("%d [function] = %s"):format(index, functions:get_function_name(upvalue)), indent + 1)
4330 elseif type(upvalue) == "table" then
4331 if not data_base[upvalue] then
4332 data_base[upvalue] = true
4333 functions:add_to_dump(("%d [table]:"):format(index), indent + 1)
4334 functions:dump_table(upvalue, indent + 2, index)
4335 else
4336 functions:add_to_dump(("%d [table] (Recursive table detected)"):format(index), indent + 1)
4337 end
4338 else
4339 functions:add_to_dump(("%d [%s] = %s"):format(index, tostring(typeof(upvalue)), tostring(upvalue)), indent + 1)
4340 end
4341 end
4342 functions:add_to_dump(("\nFunction Constants: %s"):format(functions:get_function_name(input)), indent)
4343 for index, constant in pairs(getconstants(input)) do
4344 if type(constant) == "function" then
4345 functions:add_to_dump(("%d [function] = %s"):format(index, functions:get_function_name(constant)), indent + 1)
4346 elseif type(constant) == "table" then
4347 if not data_base[constant] then
4348 data_base[constant] = true
4349 functions:add_to_dump(("%d [table]:"):format(index), indent + 1)
4350 functions:dump_table(constant, indent + 2, index)
4351 else
4352 functions:add_to_dump(("%d [table] (Recursive table detected)"):format(index), indent + 1)
4353 end
4354 else
4355 functions:add_to_dump(("%d [%s] = %s"):format(index, tostring(typeof(constant)), tostring(constant)), indent + 1)
4356 end
4357 end
4358 end
4359 for _, _function in pairs(getgc()) do
4360 if typeof(_function) == "function" and getfenv(_function).script and getfenv(_function).script == PreviousScr then
4361 functions:dump_function(_function, 0)
4362 functions:add_to_dump("\n" .. ("="):rep(100), 0, false)
4363 end
4364 end
4365 local source = codeFrame:GetText()
4366 if dump ~= original then source = source .. dump .. "]]" end
4367 codeFrame:SetText(source)
4368 end)
4369 end
4370 end)
4371 end
4372
4373 return ScriptViewer
4374end
4375
4376return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main}
4377end,
4378Lib = function()
4379--[[
4380 Lib Module
4381
4382 Container for functions and classes
4383]]
4384
4385-- Common Locals
4386local Main,Lib,Apps,Settings -- Main Containers
4387local Explorer, Properties, ScriptViewer, Notebook -- Major Apps
4388local API,RMD,env,service,plr,create,createSimple -- Main Locals
4389
4390local function initDeps(data)
4391 Main = data.Main
4392 Lib = data.Lib
4393 Apps = data.Apps
4394 Settings = data.Settings
4395
4396 API = data.API
4397 RMD = data.RMD
4398 env = data.env
4399 service = data.service
4400 plr = data.plr
4401 create = data.create
4402 createSimple = data.createSimple
4403end
4404
4405local function initAfterMain()
4406 Explorer = Apps.Explorer
4407 Properties = Apps.Properties
4408 ScriptViewer = Apps.ScriptViewer
4409 Notebook = Apps.Notebook
4410end
4411
4412local function main()
4413 local Lib = {}
4414
4415 local renderStepped = service.RunService.RenderStepped
4416 local signalWait = renderStepped.wait
4417 local PH = newproxy() -- Placeholder, must be replaced in constructor
4418 local SIGNAL = newproxy()
4419
4420 -- Usually for classes that work with a Roblox Object
4421 local function initObj(props,mt)
4422 local type = type
4423 local function copy(t)
4424 local res = {}
4425 for i,v in pairs(t) do
4426 if v == SIGNAL then
4427 res[i] = Lib.Signal.new()
4428 elseif type(v) == "table" then
4429 res[i] = copy(v)
4430 else
4431 res[i] = v
4432 end
4433 end
4434 return res
4435 end
4436
4437 local newObj = copy(props)
4438 return setmetatable(newObj,mt)
4439 end
4440
4441 local function getGuiMT(props,funcs)
4442 return {__index = function(self,ind) if not props[ind] then return funcs[ind] or self.Gui[ind] end end,
4443 __newindex = function(self,ind,val) if not props[ind] then self.Gui[ind] = val else rawset(self,ind,val) end end}
4444 end
4445
4446 -- Functions
4447
4448 Lib.FormatLuaString = (function()
4449 local string = string
4450 local gsub = string.gsub
4451 local format = string.format
4452 local char = string.char
4453 local cleanTable = {['"'] = '\\"', ['\\'] = '\\\\'}
4454 for i = 0,31 do
4455 cleanTable[char(i)] = "\\"..format("%03d",i)
4456 end
4457 for i = 127,255 do
4458 cleanTable[char(i)] = "\\"..format("%03d",i)
4459 end
4460
4461 return function(str)
4462 return gsub(str,"[\"\\\0-\31\127-\255]",cleanTable)
4463 end
4464 end)()
4465
4466 Lib.CheckMouseInGui = function(gui)
4467 if gui == nil then return false end
4468 local mouse = Main.Mouse
4469 local guiPosition = gui.AbsolutePosition
4470 local guiSize = gui.AbsoluteSize
4471
4472 return mouse.X >= guiPosition.X and mouse.X < guiPosition.X + guiSize.X and mouse.Y >= guiPosition.Y and mouse.Y < guiPosition.Y + guiSize.Y
4473 end
4474
4475 Lib.IsShiftDown = function()
4476 return service.UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or service.UserInputService:IsKeyDown(Enum.KeyCode.RightShift)
4477 end
4478
4479 Lib.IsCtrlDown = function()
4480 return service.UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or service.UserInputService:IsKeyDown(Enum.KeyCode.RightControl)
4481 end
4482
4483 Lib.CreateArrow = function(size,num,dir)
4484 local max = num
4485 local arrowFrame = createSimple("Frame",{
4486 BackgroundTransparency = 1,
4487 Name = "Arrow",
4488 Size = UDim2.new(0,size,0,size)
4489 })
4490 if dir == "up" then
4491 for i = 1,num do
4492 local newLine = createSimple("Frame",{
4493 BackgroundColor3 = Color3.new(220/255,220/255,220/255),
4494 BorderSizePixel = 0,
4495 Position = UDim2.new(0,math.floor(size/2)-(i-1),0,math.floor(size/2)+i-math.floor(max/2)-1),
4496 Size = UDim2.new(0,i+(i-1),0,1),
4497 Parent = arrowFrame
4498 })
4499 end
4500 return arrowFrame
4501 elseif dir == "down" then
4502 for i = 1,num do
4503 local newLine = createSimple("Frame",{
4504 BackgroundColor3 = Color3.new(220/255,220/255,220/255),
4505 BorderSizePixel = 0,
4506 Position = UDim2.new(0,math.floor(size/2)-(i-1),0,math.floor(size/2)-i+math.floor(max/2)+1),
4507 Size = UDim2.new(0,i+(i-1),0,1),
4508 Parent = arrowFrame
4509 })
4510 end
4511 return arrowFrame
4512 elseif dir == "left" then
4513 for i = 1,num do
4514 local newLine = createSimple("Frame",{
4515 BackgroundColor3 = Color3.new(220/255,220/255,220/255),
4516 BorderSizePixel = 0,
4517 Position = UDim2.new(0,math.floor(size/2)+i-math.floor(max/2)-1,0,math.floor(size/2)-(i-1)),
4518 Size = UDim2.new(0,1,0,i+(i-1)),
4519 Parent = arrowFrame
4520 })
4521 end
4522 return arrowFrame
4523 elseif dir == "right" then
4524 for i = 1,num do
4525 local newLine = createSimple("Frame",{
4526 BackgroundColor3 = Color3.new(220/255,220/255,220/255),
4527 BorderSizePixel = 0,
4528 Position = UDim2.new(0,math.floor(size/2)-i+math.floor(max/2)+1,0,math.floor(size/2)-(i-1)),
4529 Size = UDim2.new(0,1,0,i+(i-1)),
4530 Parent = arrowFrame
4531 })
4532 end
4533 return arrowFrame
4534 end
4535 error("r u ok")
4536 end
4537
4538 Lib.ParseXML = (function()
4539 local func = function()
4540 -- Only exists to parse RMD
4541 -- from https://github.com/jonathanpoelen/xmlparser
4542
4543 local string, print, pairs = string, print, pairs
4544
4545 -- http://lua-users.org/wiki/StringTrim
4546 local trim = function(s)
4547 local from = s:match"^%s*()"
4548 return from > #s and "" or s:match(".*%S", from)
4549 end
4550
4551 local gtchar = string.byte('>', 1)
4552 local slashchar = string.byte('/', 1)
4553 local D = string.byte('D', 1)
4554 local E = string.byte('E', 1)
4555
4556 function parse(s, evalEntities)
4557 -- remove comments
4558 s = s:gsub('<!%-%-(.-)%-%->', '')
4559
4560 local entities, tentities = {}
4561
4562 if evalEntities then
4563 local pos = s:find('<[_%w]')
4564 if pos then
4565 s:sub(1, pos):gsub('<!ENTITY%s+([_%w]+)%s+(.)(.-)%2', function(name, q, entity)
4566 entities[#entities+1] = {name=name, value=entity}
4567 end)
4568 tentities = createEntityTable(entities)
4569 s = replaceEntities(s:sub(pos), tentities)
4570 end
4571 end
4572
4573 local t, l = {}, {}
4574
4575 local addtext = function(txt)
4576 txt = txt:match'^%s*(.*%S)' or ''
4577 if #txt ~= 0 then
4578 t[#t+1] = {text=txt}
4579 end
4580 end
4581
4582 s:gsub('<([?!/]?)([-:_%w]+)%s*(/?>?)([^<]*)', function(type, name, closed, txt)
4583 -- open
4584 if #type == 0 then
4585 local a = {}
4586 if #closed == 0 then
4587 local len = 0
4588 for all,aname,_,value,starttxt in string.gmatch(txt, "(.-([-_%w]+)%s*=%s*(.)(.-)%3%s*(/?>?))") do
4589 len = len + #all
4590 a[aname] = value
4591 if #starttxt ~= 0 then
4592 txt = txt:sub(len+1)
4593 closed = starttxt
4594 break
4595 end
4596 end
4597 end
4598 t[#t+1] = {tag=name, attrs=a, children={}}
4599
4600 if closed:byte(1) ~= slashchar then
4601 l[#l+1] = t
4602 t = t[#t].children
4603 end
4604
4605 addtext(txt)
4606 -- close
4607 elseif '/' == type then
4608 t = l[#l]
4609 l[#l] = nil
4610
4611 addtext(txt)
4612 -- ENTITY
4613 elseif '!' == type then
4614 if E == name:byte(1) then
4615 txt:gsub('([_%w]+)%s+(.)(.-)%2', function(name, q, entity)
4616 entities[#entities+1] = {name=name, value=entity}
4617 end, 1)
4618 end
4619 -- elseif '?' == type then
4620 -- print('? ' .. name .. ' // ' .. attrs .. '$$')
4621 -- elseif '-' == type then
4622 -- print('comment ' .. name .. ' // ' .. attrs .. '$$')
4623 -- else
4624 -- print('o ' .. #p .. ' // ' .. name .. ' // ' .. attrs .. '$$')
4625 end
4626 end)
4627
4628 return {children=t, entities=entities, tentities=tentities}
4629 end
4630
4631 function parseText(txt)
4632 return parse(txt)
4633 end
4634
4635 function defaultEntityTable()
4636 return { quot='"', apos='\'', lt='<', gt='>', amp='&', tab='\t', nbsp=' ', }
4637 end
4638
4639 function replaceEntities(s, entities)
4640 return s:gsub('&([^;]+);', entities)
4641 end
4642
4643 function createEntityTable(docEntities, resultEntities)
4644 entities = resultEntities or defaultEntityTable()
4645 for _,e in pairs(docEntities) do
4646 e.value = replaceEntities(e.value, entities)
4647 entities[e.name] = e.value
4648 end
4649 return entities
4650 end
4651
4652 return parseText
4653 end
4654 local newEnv = setmetatable({},{__index = getfenv()})
4655 setfenv(func,newEnv)
4656 return func()
4657 end)()
4658
4659 Lib.FastWait = function(s)
4660 if not s then return signalWait(renderStepped) end
4661 local start = tick()
4662 while tick() - start < s do signalWait(renderStepped) end
4663 end
4664
4665 Lib.ButtonAnim = function(button,data)
4666 local holding = false
4667 local disabled = false
4668 local mode = data and data.Mode or 1
4669 local control = {}
4670
4671 if mode == 2 then
4672 local lerpTo = data.LerpTo or Color3.new(0,0,0)
4673 local delta = data.LerpDelta or 0.2
4674 control.StartColor = data.StartColor or button.BackgroundColor3
4675 control.PressColor = data.PressColor or control.StartColor:lerp(lerpTo,delta)
4676 control.HoverColor = data.HoverColor or control.StartColor:lerp(control.PressColor,0.6)
4677 control.OutlineColor = data.OutlineColor
4678 end
4679
4680 button.InputBegan:Connect(function(input)
4681 if disabled then return end
4682 if input.UserInputType == Enum.UserInputType.MouseMovement and not holding then
4683 if mode == 1 then
4684 button.BackgroundTransparency = 0.4
4685 elseif mode == 2 then
4686 button.BackgroundColor3 = control.HoverColor
4687 end
4688 elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
4689 holding = true
4690 if mode == 1 then
4691 button.BackgroundTransparency = 0
4692 elseif mode == 2 then
4693 button.BackgroundColor3 = control.PressColor
4694 if control.OutlineColor then button.BorderColor3 = control.PressColor end
4695 end
4696 end
4697 end)
4698
4699 button.InputEnded:Connect(function(input)
4700 if disabled then return end
4701 if input.UserInputType == Enum.UserInputType.MouseMovement and not holding then
4702 if mode == 1 then
4703 button.BackgroundTransparency = 1
4704 elseif mode == 2 then
4705 button.BackgroundColor3 = control.StartColor
4706 end
4707 elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
4708 holding = false
4709 if mode == 1 then
4710 button.BackgroundTransparency = Lib.CheckMouseInGui(button) and 0.4 or 1
4711 elseif mode == 2 then
4712 button.BackgroundColor3 = Lib.CheckMouseInGui(button) and control.HoverColor or control.StartColor
4713 if control.OutlineColor then button.BorderColor3 = control.OutlineColor end
4714 end
4715 end
4716 end)
4717
4718 control.Disable = function()
4719 disabled = true
4720 holding = false
4721
4722 if mode == 1 then
4723 button.BackgroundTransparency = 1
4724 elseif mode == 2 then
4725 button.BackgroundColor3 = control.StartColor
4726 end
4727 end
4728
4729 control.Enable = function()
4730 disabled = false
4731 end
4732
4733 return control
4734 end
4735
4736 Lib.FindAndRemove = function(t,item)
4737 local pos = table.find(t,item)
4738 if pos then table.remove(t,pos) end
4739 end
4740
4741 Lib.AttachTo = function(obj,data)
4742 local target,posOffX,posOffY,sizeOffX,sizeOffY,resize,con
4743 local disabled = false
4744
4745 local function update()
4746 if not obj or not target then return end
4747
4748 local targetPos = target.AbsolutePosition
4749 local targetSize = target.AbsoluteSize
4750 obj.Position = UDim2.new(0,targetPos.X + posOffX,0,targetPos.Y + posOffY)
4751 if resize then obj.Size = UDim2.new(0,targetSize.X + sizeOffX,0,targetSize.Y + sizeOffY) end
4752 end
4753
4754 local function setup(o,data)
4755 obj = o
4756 data = data or {}
4757 target = data.Target
4758 posOffX = data.PosOffX or 0
4759 posOffY = data.PosOffY or 0
4760 sizeOffX = data.SizeOffX or 0
4761 sizeOffY = data.SizeOffY or 0
4762 resize = data.Resize or false
4763
4764 if con then con:Disconnect() con = nil end
4765 if target then
4766 con = target.Changed:Connect(function(prop)
4767 if not disabled and prop == "AbsolutePosition" or prop == "AbsoluteSize" then
4768 update()
4769 end
4770 end)
4771 end
4772
4773 update()
4774 end
4775 setup(obj,data)
4776
4777 return {
4778 SetData = function(obj,data)
4779 setup(obj,data)
4780 end,
4781 Enable = function()
4782 disabled = false
4783 update()
4784 end,
4785 Disable = function()
4786 disabled = true
4787 end,
4788 Destroy = function()
4789 con:Disconnect()
4790 con = nil
4791 end,
4792 }
4793 end
4794
4795 Lib.ProtectedGuis = {}
4796
4797 Lib.ShowGui = function(gui)
4798 if env.protectgui then
4799 env.protectgui(gui)
4800 end
4801 gui.Parent = Main.GuiHolder
4802 end
4803
4804 Lib.ColorToBytes = function(col)
4805 local round = math.round
4806 return string.format("%d, %d, %d",round(col.r*255),round(col.g*255),round(col.b*255))
4807 end
4808
4809 Lib.ReadFile = function(filename)
4810 if not env.readfile then return end
4811
4812 local s,contents = pcall(env.readfile,filename)
4813 if s and contents then return contents end
4814 end
4815
4816 Lib.DeferFunc = function(f,...)
4817 signalWait(renderStepped)
4818 return f(...)
4819 end
4820
4821 Lib.LoadCustomAsset = function(filepath)
4822 if not env.getcustomasset or not env.isfile or not env.isfile(filepath) then return end
4823
4824 return env.getcustomasset(filepath)
4825 end
4826
4827 Lib.FetchCustomAsset = function(url,filepath)
4828 if not env.writefile then return end
4829
4830 local s,data = pcall(game.HttpGet,game,url)
4831 if not s then return end
4832
4833 env.writefile(filepath,data)
4834 return Lib.LoadCustomAsset(filepath)
4835 end
4836
4837 -- Classes
4838
4839 Lib.Signal = (function()
4840 local funcs = {}
4841
4842 local disconnect = function(con)
4843 local pos = table.find(con.Signal.Connections,con)
4844 if pos then table.remove(con.Signal.Connections,pos) end
4845 end
4846
4847 funcs.Connect = function(self,func)
4848 if type(func) ~= "function" then error("Attempt to connect a non-function") end
4849 local con = {
4850 Signal = self,
4851 Func = func,
4852 Disconnect = disconnect
4853 }
4854 self.Connections[#self.Connections+1] = con
4855 return con
4856 end
4857
4858 funcs.Fire = function(self,...)
4859 for i,v in next,self.Connections do
4860 xpcall(coroutine.wrap(v.Func),function(e) warn(e.."\n"..debug.traceback()) end,...)
4861 end
4862 end
4863
4864 local mt = {
4865 __index = funcs,
4866 __tostring = function(self)
4867 return "Signal: " .. tostring(#self.Connections) .. " Connections"
4868 end
4869 }
4870
4871 local function new()
4872 local obj = {}
4873 obj.Connections = {}
4874
4875 return setmetatable(obj,mt)
4876 end
4877
4878 return {new = new}
4879 end)()
4880
4881 Lib.Set = (function()
4882 local funcs = {}
4883
4884 funcs.Add = function(self,obj)
4885 if self.Map[obj] then return end
4886
4887 local list = self.List
4888 list[#list+1] = obj
4889 self.Map[obj] = true
4890 self.Changed:Fire()
4891 end
4892
4893 funcs.AddTable = function(self,t)
4894 local changed
4895 local list,map = self.List,self.Map
4896 for i = 1,#t do
4897 local elem = t[i]
4898 if not map[elem] then
4899 list[#list+1] = elem
4900 map[elem] = true
4901 changed = true
4902 end
4903 end
4904 if changed then self.Changed:Fire() end
4905 end
4906
4907 funcs.Remove = function(self,obj)
4908 if not self.Map[obj] then return end
4909
4910 local list = self.List
4911 local pos = table.find(list,obj)
4912 if pos then table.remove(list,pos) end
4913 self.Map[obj] = nil
4914 self.Changed:Fire()
4915 end
4916
4917 funcs.RemoveTable = function(self,t)
4918 local changed
4919 local list,map = self.List,self.Map
4920 local removeSet = {}
4921 for i = 1,#t do
4922 local elem = t[i]
4923 map[elem] = nil
4924 removeSet[elem] = true
4925 end
4926
4927 for i = #list,1,-1 do
4928 local elem = list[i]
4929 if removeSet[elem] then
4930 table.remove(list,i)
4931 changed = true
4932 end
4933 end
4934 if changed then self.Changed:Fire() end
4935 end
4936
4937 funcs.Set = function(self,obj)
4938 if #self.List == 1 and self.List[1] == obj then return end
4939
4940 self.List = {obj}
4941 self.Map = {[obj] = true}
4942 self.Changed:Fire()
4943 end
4944
4945 funcs.SetTable = function(self,t)
4946 local newList,newMap = {},{}
4947 self.List,self.Map = newList,newMap
4948 table.move(t,1,#t,1,newList)
4949 for i = 1,#t do
4950 newMap[t[i]] = true
4951 end
4952 self.Changed:Fire()
4953 end
4954
4955 funcs.Clear = function(self)
4956 if #self.List == 0 then return end
4957 self.List = {}
4958 self.Map = {}
4959 self.Changed:Fire()
4960 end
4961
4962 local mt = {__index = funcs}
4963
4964 local function new()
4965 local obj = setmetatable({
4966 List = {},
4967 Map = {},
4968 Changed = Lib.Signal.new()
4969 },mt)
4970
4971 return obj
4972 end
4973
4974 return {new = new}
4975 end)()
4976
4977 Lib.IconMap = (function()
4978 local funcs = {}
4979
4980 funcs.GetLabel = function(self)
4981 local label = Instance.new("ImageLabel")
4982 self:SetupLabel(label)
4983 return label
4984 end
4985
4986 funcs.SetupLabel = function(self,obj)
4987 obj.BackgroundTransparency = 1
4988 obj.ImageRectOffset = Vector2.new(0,0)
4989 obj.ImageRectSize = Vector2.new(self.IconSizeX,self.IconSizeY)
4990 obj.ScaleType = Enum.ScaleType.Crop
4991 obj.Size = UDim2.new(0,self.IconSizeX,0,self.IconSizeY)
4992 end
4993
4994 funcs.Display = function(self,obj,index)
4995 obj.Image = self.MapId
4996 if not self.NumX then
4997 obj.ImageRectOffset = Vector2.new(self.IconSizeX*index, 0)
4998 else
4999 obj.ImageRectOffset = Vector2.new(self.IconSizeX*(index % self.NumX), self.IconSizeY*math.floor(index / self.NumX))
5000 end
5001 end
5002
5003 funcs.DisplayByKey = function(self,obj,key)
5004 if self.IndexDict[key] then
5005 self:Display(obj,self.IndexDict[key])
5006 end
5007 end
5008
5009 funcs.SetDict = function(self,dict)
5010 self.IndexDict = dict
5011 end
5012
5013 local mt = {}
5014 mt.__index = funcs
5015
5016 local function new(mapId,mapSizeX,mapSizeY,iconSizeX,iconSizeY)
5017 local obj = setmetatable({
5018 MapId = mapId,
5019 MapSizeX = mapSizeX,
5020 MapSizeY = mapSizeY,
5021 IconSizeX = iconSizeX,
5022 IconSizeY = iconSizeY,
5023 NumX = mapSizeX/iconSizeX,
5024 IndexDict = {}
5025 },mt)
5026 return obj
5027 end
5028
5029 local function newLinear(mapId,iconSizeX,iconSizeY)
5030 local obj = setmetatable({
5031 MapId = mapId,
5032 IconSizeX = iconSizeX,
5033 IconSizeY = iconSizeY,
5034 IndexDict = {}
5035 },mt)
5036 return obj
5037 end
5038
5039 return {new = new, newLinear = newLinear}
5040 end)()
5041
5042 Lib.ScrollBar = (function()
5043 local funcs = {}
5044 local user = service.UserInputService
5045 local mouse = plr:GetMouse()
5046 local checkMouseInGui = Lib.CheckMouseInGui
5047 local createArrow = Lib.CreateArrow
5048
5049 local function drawThumb(self)
5050 local total = self.TotalSpace
5051 local visible = self.VisibleSpace
5052 local index = self.Index
5053 local scrollThumb = self.GuiElems.ScrollThumb
5054 local scrollThumbFrame = self.GuiElems.ScrollThumbFrame
5055
5056 if not (self:CanScrollUp() or self:CanScrollDown()) then
5057 scrollThumb.Visible = false
5058 else
5059 scrollThumb.Visible = true
5060 end
5061
5062 if self.Horizontal then
5063 scrollThumb.Size = UDim2.new(visible/total,0,1,0)
5064 if scrollThumb.AbsoluteSize.X < 16 then
5065 scrollThumb.Size = UDim2.new(0,16,1,0)
5066 end
5067 local fs = scrollThumbFrame.AbsoluteSize.X
5068 local bs = scrollThumb.AbsoluteSize.X
5069 scrollThumb.Position = UDim2.new(self:GetScrollPercent()*(fs-bs)/fs,0,0,0)
5070 else
5071 scrollThumb.Size = UDim2.new(1,0,visible/total,0)
5072 if scrollThumb.AbsoluteSize.Y < 16 then
5073 scrollThumb.Size = UDim2.new(1,0,0,16)
5074 end
5075 local fs = scrollThumbFrame.AbsoluteSize.Y
5076 local bs = scrollThumb.AbsoluteSize.Y
5077 scrollThumb.Position = UDim2.new(0,0,self:GetScrollPercent()*(fs-bs)/fs,0)
5078 end
5079 end
5080
5081 local function createFrame(self)
5082 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",})
5083 local button1 = nil
5084 local button2 = nil
5085
5086 if self.Horizontal then
5087 newFrame.Size = UDim2.new(1,0,0,16)
5088 button1 = createSimple("ImageButton",{
5089 Parent = newFrame,
5090 Name = "Left",
5091 Size = UDim2.new(0,16,0,16),
5092 BackgroundTransparency = 1,
5093 BorderSizePixel = 0,
5094 AutoButtonColor = false
5095 })
5096 createArrow(16,4,"left").Parent = button1
5097 button2 = createSimple("ImageButton",{
5098 Parent = newFrame,
5099 Name = "Right",
5100 Position = UDim2.new(1,-16,0,0),
5101 Size = UDim2.new(0,16,0,16),
5102 BackgroundTransparency = 1,
5103 BorderSizePixel = 0,
5104 AutoButtonColor = false
5105 })
5106 createArrow(16,4,"right").Parent = button2
5107 else
5108 newFrame.Size = UDim2.new(0,16,1,0)
5109 button1 = createSimple("ImageButton",{
5110 Parent = newFrame,
5111 Name = "Up",
5112 Size = UDim2.new(0,16,0,16),
5113 BackgroundTransparency = 1,
5114 BorderSizePixel = 0,
5115 AutoButtonColor = false
5116 })
5117 createArrow(16,4,"up").Parent = button1
5118 button2 = createSimple("ImageButton",{
5119 Parent = newFrame,
5120 Name = "Down",
5121 Position = UDim2.new(0,0,1,-16),
5122 Size = UDim2.new(0,16,0,16),
5123 BackgroundTransparency = 1,
5124 BorderSizePixel = 0,
5125 AutoButtonColor = false
5126 })
5127 createArrow(16,4,"down").Parent = button2
5128 end
5129
5130 local scrollThumbFrame = createSimple("Frame",{
5131 BackgroundTransparency = 1,
5132 Parent = newFrame
5133 })
5134 if self.Horizontal then
5135 scrollThumbFrame.Position = UDim2.new(0,16,0,0)
5136 scrollThumbFrame.Size = UDim2.new(1,-32,1,0)
5137 else
5138 scrollThumbFrame.Position = UDim2.new(0,0,0,16)
5139 scrollThumbFrame.Size = UDim2.new(1,0,1,-32)
5140 end
5141
5142 local scrollThumb = createSimple("Frame",{
5143 BackgroundColor3 = Color3.new(120/255,120/255,120/255),
5144 BorderSizePixel = 0,
5145 Parent = scrollThumbFrame
5146 })
5147
5148 local markerFrame = createSimple("Frame",{
5149 BackgroundTransparency = 1,
5150 Name = "Markers",
5151 Size = UDim2.new(1,0,1,0),
5152 Parent = scrollThumbFrame
5153 })
5154
5155 local buttonPress = false
5156 local thumbPress = false
5157 local thumbFramePress = false
5158
5159 --local thumbColor = Color3.new(120/255,120/255,120/255)
5160 --local thumbSelectColor = Color3.new(140/255,140/255,140/255)
5161 button1.InputBegan:Connect(function(input)
5162 if input.UserInputType == Enum.UserInputType.MouseMovement and not buttonPress and self:CanScrollUp() then button1.BackgroundTransparency = 0.8 end
5163 if input.UserInputType ~= Enum.UserInputType.MouseButton1 or not self:CanScrollUp() then return end
5164 buttonPress = true
5165 button1.BackgroundTransparency = 0.5
5166 if self:CanScrollUp() then self:ScrollUp() self.Scrolled:Fire() end
5167 local buttonTick = tick()
5168 local releaseEvent
5169 releaseEvent = user.InputEnded:Connect(function(input)
5170 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
5171 releaseEvent:Disconnect()
5172 if checkMouseInGui(button1) and self:CanScrollUp() then button1.BackgroundTransparency = 0.8 else button1.BackgroundTransparency = 1 end
5173 buttonPress = false
5174 end)
5175 while buttonPress do
5176 if tick() - buttonTick >= 0.3 and self:CanScrollUp() then
5177 self:ScrollUp()
5178 self.Scrolled:Fire()
5179 end
5180 wait()
5181 end
5182 end)
5183 button1.InputEnded:Connect(function(input)
5184 if input.UserInputType == Enum.UserInputType.MouseMovement and not buttonPress then button1.BackgroundTransparency = 1 end
5185 end)
5186 button2.InputBegan:Connect(function(input)
5187 if input.UserInputType == Enum.UserInputType.MouseMovement and not buttonPress and self:CanScrollDown() then button2.BackgroundTransparency = 0.8 end
5188 if input.UserInputType ~= Enum.UserInputType.MouseButton1 or not self:CanScrollDown() then return end
5189 buttonPress = true
5190 button2.BackgroundTransparency = 0.5
5191 if self:CanScrollDown() then self:ScrollDown() self.Scrolled:Fire() end
5192 local buttonTick = tick()
5193 local releaseEvent
5194 releaseEvent = user.InputEnded:Connect(function(input)
5195 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
5196 releaseEvent:Disconnect()
5197 if checkMouseInGui(button2) and self:CanScrollDown() then button2.BackgroundTransparency = 0.8 else button2.BackgroundTransparency = 1 end
5198 buttonPress = false
5199 end)
5200 while buttonPress do
5201 if tick() - buttonTick >= 0.3 and self:CanScrollDown() then
5202 self:ScrollDown()
5203 self.Scrolled:Fire()
5204 end
5205 wait()
5206 end
5207 end)
5208 button2.InputEnded:Connect(function(input)
5209 if input.UserInputType == Enum.UserInputType.MouseMovement and not buttonPress then button2.BackgroundTransparency = 1 end
5210 end)
5211
5212 scrollThumb.InputBegan:Connect(function(input)
5213 if input.UserInputType == Enum.UserInputType.MouseMovement and not thumbPress then scrollThumb.BackgroundTransparency = 0.2 scrollThumb.BackgroundColor3 = self.ThumbSelectColor end
5214 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
5215
5216 local dir = self.Horizontal and "X" or "Y"
5217 local lastThumbPos = nil
5218
5219 buttonPress = false
5220 thumbFramePress = false
5221 thumbPress = true
5222 scrollThumb.BackgroundTransparency = 0
5223 local mouseOffset = mouse[dir] - scrollThumb.AbsolutePosition[dir]
5224 local mouseStart = mouse[dir]
5225 local releaseEvent
5226 local mouseEvent
5227 releaseEvent = user.InputEnded:Connect(function(input)
5228 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
5229 releaseEvent:Disconnect()
5230 if mouseEvent then mouseEvent:Disconnect() end
5231 if checkMouseInGui(scrollThumb) then scrollThumb.BackgroundTransparency = 0.2 else scrollThumb.BackgroundTransparency = 0 scrollThumb.BackgroundColor3 = self.ThumbColor end
5232 thumbPress = false
5233 end)
5234 self:Update()
5235
5236 mouseEvent = user.InputChanged:Connect(function(input)
5237 if input.UserInputType == Enum.UserInputType.MouseMovement and thumbPress and releaseEvent.Connected then
5238 local thumbFrameSize = scrollThumbFrame.AbsoluteSize[dir]-scrollThumb.AbsoluteSize[dir]
5239 local pos = mouse[dir] - scrollThumbFrame.AbsolutePosition[dir] - mouseOffset
5240 if pos > thumbFrameSize then
5241 pos = thumbFrameSize
5242 elseif pos < 0 then
5243 pos = 0
5244 end
5245 if lastThumbPos ~= pos then
5246 lastThumbPos = pos
5247 self:ScrollTo(math.floor(0.5+pos/thumbFrameSize*(self.TotalSpace-self.VisibleSpace)))
5248 end
5249 wait()
5250 end
5251 end)
5252 end)
5253 scrollThumb.InputEnded:Connect(function(input)
5254 if input.UserInputType == Enum.UserInputType.MouseMovement and not thumbPress then scrollThumb.BackgroundTransparency = 0 scrollThumb.BackgroundColor3 = self.ThumbColor end
5255 end)
5256 scrollThumbFrame.InputBegan:Connect(function(input)
5257 if input.UserInputType ~= Enum.UserInputType.MouseButton1 or checkMouseInGui(scrollThumb) then return end
5258
5259 local dir = self.Horizontal and "X" or "Y"
5260 local scrollDir = 0
5261 if mouse[dir] >= scrollThumb.AbsolutePosition[dir] + scrollThumb.AbsoluteSize[dir] then
5262 scrollDir = 1
5263 end
5264
5265 local function doTick()
5266 local scrollSize = self.VisibleSpace - 1
5267 if scrollDir == 0 and mouse[dir] < scrollThumb.AbsolutePosition[dir] then
5268 self:ScrollTo(self.Index - scrollSize)
5269 elseif scrollDir == 1 and mouse[dir] >= scrollThumb.AbsolutePosition[dir] + scrollThumb.AbsoluteSize[dir] then
5270 self:ScrollTo(self.Index + scrollSize)
5271 end
5272 end
5273
5274 thumbPress = false
5275 thumbFramePress = true
5276 doTick()
5277 local thumbFrameTick = tick()
5278 local releaseEvent
5279 releaseEvent = user.InputEnded:Connect(function(input)
5280 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
5281 releaseEvent:Disconnect()
5282 thumbFramePress = false
5283 end)
5284 while thumbFramePress do
5285 if tick() - thumbFrameTick >= 0.3 and checkMouseInGui(scrollThumbFrame) then
5286 doTick()
5287 end
5288 wait()
5289 end
5290 end)
5291
5292 newFrame.MouseWheelForward:Connect(function()
5293 self:ScrollTo(self.Index - self.WheelIncrement)
5294 end)
5295
5296 newFrame.MouseWheelBackward:Connect(function()
5297 self:ScrollTo(self.Index + self.WheelIncrement)
5298 end)
5299
5300 self.GuiElems.ScrollThumb = scrollThumb
5301 self.GuiElems.ScrollThumbFrame = scrollThumbFrame
5302 self.GuiElems.Button1 = button1
5303 self.GuiElems.Button2 = button2
5304 self.GuiElems.MarkerFrame = markerFrame
5305
5306 return newFrame
5307 end
5308
5309 funcs.Update = function(self,nocallback)
5310 local total = self.TotalSpace
5311 local visible = self.VisibleSpace
5312 local index = self.Index
5313 local button1 = self.GuiElems.Button1
5314 local button2 = self.GuiElems.Button2
5315
5316 self.Index = math.clamp(self.Index,0,math.max(0,total-visible))
5317
5318 if self.LastTotalSpace ~= self.TotalSpace then
5319 self.LastTotalSpace = self.TotalSpace
5320 self:UpdateMarkers()
5321 end
5322
5323 if self:CanScrollUp() then
5324 for i,v in pairs(button1.Arrow:GetChildren()) do
5325 v.BackgroundTransparency = 0
5326 end
5327 else
5328 button1.BackgroundTransparency = 1
5329 for i,v in pairs(button1.Arrow:GetChildren()) do
5330 v.BackgroundTransparency = 0.5
5331 end
5332 end
5333 if self:CanScrollDown() then
5334 for i,v in pairs(button2.Arrow:GetChildren()) do
5335 v.BackgroundTransparency = 0
5336 end
5337 else
5338 button2.BackgroundTransparency = 1
5339 for i,v in pairs(button2.Arrow:GetChildren()) do
5340 v.BackgroundTransparency = 0.5
5341 end
5342 end
5343
5344 drawThumb(self)
5345 end
5346
5347 funcs.UpdateMarkers = function(self)
5348 local markerFrame = self.GuiElems.MarkerFrame
5349 markerFrame:ClearAllChildren()
5350
5351 for i,v in pairs(self.Markers) do
5352 if i < self.TotalSpace then
5353 createSimple("Frame",{
5354 BackgroundTransparency = 0,
5355 BackgroundColor3 = v,
5356 BorderSizePixel = 0,
5357 Position = self.Horizontal and UDim2.new(i/self.TotalSpace,0,1,-6) or UDim2.new(1,-6,i/self.TotalSpace,0),
5358 Size = self.Horizontal and UDim2.new(0,1,0,6) or UDim2.new(0,6,0,1),
5359 Name = "Marker"..tostring(i),
5360 Parent = markerFrame
5361 })
5362 end
5363 end
5364 end
5365
5366 funcs.AddMarker = function(self,ind,color)
5367 self.Markers[ind] = color or Color3.new(0,0,0)
5368 end
5369 funcs.ScrollTo = function(self,ind,nocallback)
5370 self.Index = ind
5371 self:Update()
5372 if not nocallback then
5373 self.Scrolled:Fire()
5374 end
5375 end
5376 funcs.ScrollUp = function(self)
5377 self.Index = self.Index - self.Increment
5378 self:Update()
5379 end
5380 funcs.ScrollDown = function(self)
5381 self.Index = self.Index + self.Increment
5382 self:Update()
5383 end
5384 funcs.CanScrollUp = function(self)
5385 return self.Index > 0
5386 end
5387 funcs.CanScrollDown = function(self)
5388 return self.Index + self.VisibleSpace < self.TotalSpace
5389 end
5390 funcs.GetScrollPercent = function(self)
5391 return self.Index/(self.TotalSpace-self.VisibleSpace)
5392 end
5393 funcs.SetScrollPercent = function(self,perc)
5394 self.Index = math.floor(perc*(self.TotalSpace-self.VisibleSpace))
5395 self:Update()
5396 end
5397
5398 funcs.Texture = function(self,data)
5399 self.ThumbColor = data.ThumbColor or Color3.new(0,0,0)
5400 self.ThumbSelectColor = data.ThumbSelectColor or Color3.new(0,0,0)
5401 self.GuiElems.ScrollThumb.BackgroundColor3 = data.ThumbColor or Color3.new(0,0,0)
5402 self.Gui.BackgroundColor3 = data.FrameColor or Color3.new(0,0,0)
5403 self.GuiElems.Button1.BackgroundColor3 = data.ButtonColor or Color3.new(0,0,0)
5404 self.GuiElems.Button2.BackgroundColor3 = data.ButtonColor or Color3.new(0,0,0)
5405 for i,v in pairs(self.GuiElems.Button1.Arrow:GetChildren()) do
5406 v.BackgroundColor3 = data.ArrowColor or Color3.new(0,0,0)
5407 end
5408 for i,v in pairs(self.GuiElems.Button2.Arrow:GetChildren()) do
5409 v.BackgroundColor3 = data.ArrowColor or Color3.new(0,0,0)
5410 end
5411 end
5412
5413 funcs.SetScrollFrame = function(self,frame)
5414 if self.ScrollUpEvent then self.ScrollUpEvent:Disconnect() self.ScrollUpEvent = nil end
5415 if self.ScrollDownEvent then self.ScrollDownEvent:Disconnect() self.ScrollDownEvent = nil end
5416 self.ScrollUpEvent = frame.MouseWheelForward:Connect(function() self:ScrollTo(self.Index - self.WheelIncrement) end)
5417 self.ScrollDownEvent = frame.MouseWheelBackward:Connect(function() self:ScrollTo(self.Index + self.WheelIncrement) end)
5418 end
5419
5420 local mt = {}
5421 mt.__index = funcs
5422
5423 local function new(hor)
5424 local obj = setmetatable({
5425 Index = 0,
5426 VisibleSpace = 0,
5427 TotalSpace = 0,
5428 Increment = 1,
5429 WheelIncrement = 1,
5430 Markers = {},
5431 GuiElems = {},
5432 Horizontal = hor,
5433 LastTotalSpace = 0,
5434 Scrolled = Lib.Signal.new()
5435 },mt)
5436 obj.Gui = createFrame(obj)
5437 obj:Texture({
5438 ThumbColor = Color3.fromRGB(60,60,60),
5439 ThumbSelectColor = Color3.fromRGB(75,75,75),
5440 ArrowColor = Color3.new(1,1,1),
5441 FrameColor = Color3.fromRGB(40,40,40),
5442 ButtonColor = Color3.fromRGB(75,75,75)
5443 })
5444 return obj
5445 end
5446
5447 return {new = new}
5448 end)()
5449
5450 Lib.Window = (function()
5451 local funcs = {}
5452 local static = {MinWidth = 200, FreeWidth = 200}
5453 local mouse = plr:GetMouse()
5454 local sidesGui,alignIndicator
5455 local visibleWindows = {}
5456 local leftSide = {Width = 300, Windows = {}, ResizeCons = {}, Hidden = true}
5457 local rightSide = {Width = 300, Windows = {}, ResizeCons = {}, Hidden = true}
5458
5459 local displayOrderStart
5460 local sideDisplayOrder
5461 local sideTweenInfo = TweenInfo.new(0.3,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
5462 local tweens = {}
5463 local isA = game.IsA
5464
5465 local theme = {
5466 MainColor1 = Color3.fromRGB(52,52,52),
5467 MainColor2 = Color3.fromRGB(45,45,45),
5468 Button = Color3.fromRGB(60,60,60)
5469 }
5470
5471 local function stopTweens()
5472 for i = 1,#tweens do
5473 tweens[i]:Cancel()
5474 end
5475 tweens = {}
5476 end
5477
5478 local function resizeHook(self,resizer,dir)
5479 local guiMain = self.GuiElems.Main
5480 resizer.InputBegan:Connect(function(input)
5481 if not self.Dragging and not self.Resizing and self.Resizable and self.ResizableInternal then
5482 local isH = dir:find("[WE]") and true
5483 local isV = dir:find("[NS]") and true
5484 local signX = dir:find("W",1,true) and -1 or 1
5485 local signY = dir:find("N",1,true) and -1 or 1
5486
5487 if self.Minimized and isV then return end
5488
5489 if input.UserInputType == Enum.UserInputType.MouseMovement then
5490 resizer.BackgroundTransparency = 0.5
5491 elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
5492 local releaseEvent,mouseEvent
5493
5494 local offX = mouse.X - resizer.AbsolutePosition.X
5495 local offY = mouse.Y - resizer.AbsolutePosition.Y
5496
5497 self.Resizing = resizer
5498 resizer.BackgroundTransparency = 1
5499
5500 releaseEvent = service.UserInputService.InputEnded:Connect(function(input)
5501 if input.UserInputType == Enum.UserInputType.MouseButton1 then
5502 releaseEvent:Disconnect()
5503 mouseEvent:Disconnect()
5504 self.Resizing = false
5505 resizer.BackgroundTransparency = 1
5506 end
5507 end)
5508
5509 mouseEvent = service.UserInputService.InputChanged:Connect(function(input)
5510 if self.Resizable and self.ResizableInternal and input.UserInputType == Enum.UserInputType.MouseMovement then
5511 self:StopTweens()
5512 local deltaX = input.Position.X - resizer.AbsolutePosition.X - offX
5513 local deltaY = input.Position.Y - resizer.AbsolutePosition.Y - offY
5514
5515 if guiMain.AbsoluteSize.X + deltaX*signX < self.MinX then deltaX = signX*(self.MinX - guiMain.AbsoluteSize.X) end
5516 if guiMain.AbsoluteSize.Y + deltaY*signY < self.MinY then deltaY = signY*(self.MinY - guiMain.AbsoluteSize.Y) end
5517 if signY < 0 and guiMain.AbsolutePosition.Y + deltaY < 0 then deltaY = -guiMain.AbsolutePosition.Y end
5518
5519 guiMain.Position = guiMain.Position + UDim2.new(0,(signX < 0 and deltaX or 0),0,(signY < 0 and deltaY or 0))
5520 self.SizeX = self.SizeX + (isH and deltaX*signX or 0)
5521 self.SizeY = self.SizeY + (isV and deltaY*signY or 0)
5522 guiMain.Size = UDim2.new(0,self.SizeX,0,self.Minimized and 20 or self.SizeY)
5523
5524 --if isH then self.SizeX = guiMain.AbsoluteSize.X end
5525 --if isV then self.SizeY = guiMain.AbsoluteSize.Y end
5526 end
5527 end)
5528 end
5529 end
5530 end)
5531
5532 resizer.InputEnded:Connect(function(input)
5533 if input.UserInputType == Enum.UserInputType.MouseMovement and self.Resizing ~= resizer then
5534 resizer.BackgroundTransparency = 1
5535 end
5536 end)
5537 end
5538
5539 local updateWindows
5540
5541 local function moveToTop(window)
5542 local found = table.find(visibleWindows,window)
5543 if found then
5544 table.remove(visibleWindows,found)
5545 table.insert(visibleWindows,1,window)
5546 updateWindows()
5547 end
5548 end
5549
5550 local function sideHasRoom(side,neededSize)
5551 local maxY = sidesGui.AbsoluteSize.Y - (math.max(0,#side.Windows - 1) * 4)
5552 local inc = 0
5553 for i,v in pairs(side.Windows) do
5554 inc = inc + (v.MinY or 100)
5555 if inc > maxY - neededSize then return false end
5556 end
5557
5558 return true
5559 end
5560
5561 local function getSideInsertPos(side,curY)
5562 local pos = #side.Windows + 1
5563 local range = {0,sidesGui.AbsoluteSize.Y}
5564
5565 for i,v in pairs(side.Windows) do
5566 local midPos = v.PosY + v.SizeY/2
5567 if curY <= midPos then
5568 pos = i
5569 range[2] = midPos
5570 break
5571 else
5572 range[1] = midPos
5573 end
5574 end
5575
5576 return pos,range
5577 end
5578
5579 local function focusInput(self,obj)
5580 if isA(obj,"GuiButton") then
5581 obj.MouseButton1Down:Connect(function()
5582 moveToTop(self)
5583 end)
5584 elseif isA(obj,"TextBox") then
5585 obj.Focused:Connect(function()
5586 moveToTop(self)
5587 end)
5588 end
5589 end
5590
5591 local createGui = function(self)
5592 local gui = create({
5593 {1,"ScreenGui",{Name="Window",}},
5594 {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),}},
5595 {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}},
5596 {4,"Frame",{BackgroundColor3=Color3.fromRGB(33,33,33),BorderSizePixel=0,Name="Line",Parent={3},Size=UDim2.new(1,0,0,1),}},
5597 {5,"Frame",{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BorderSizePixel=0,Name="TopBar",Parent={2},Size=UDim2.new(1,0,0,20),}},
5598 {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,}},
5599 {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,}},
5600 {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),}},
5601 {9,"UICorner",{CornerRadius=UDim.new(0,4),Parent={7},}},
5602 {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,}},
5603 {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),}},
5604 {12,"UICorner",{CornerRadius=UDim.new(0,4),Parent={10},}},
5605 {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),}},
5606 {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),}},
5607 {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,}},
5608 {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,}},
5609 {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,}},
5610 {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,}},
5611 {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,}},
5612 {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,}},
5613 {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,}},
5614 {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,}},
5615 })
5616
5617 local guiMain = gui.Main
5618 local guiTopBar = guiMain.TopBar
5619 local guiResizeControls = guiMain.ResizeControls
5620
5621 self.GuiElems.Main = guiMain
5622 self.GuiElems.TopBar = guiMain.TopBar
5623 self.GuiElems.Content = guiMain.Content
5624 self.GuiElems.Line = guiMain.Content.Line
5625 self.GuiElems.Outlines = guiMain.Outlines
5626 self.GuiElems.Title = guiTopBar.Title
5627 self.GuiElems.Close = guiTopBar.Close
5628 self.GuiElems.Minimize = guiTopBar.Minimize
5629 self.GuiElems.ResizeControls = guiResizeControls
5630 self.ContentPane = guiMain.Content
5631
5632 guiTopBar.InputBegan:Connect(function(input)
5633 if input.UserInputType == Enum.UserInputType.MouseButton1 and self.Draggable then
5634 local releaseEvent,mouseEvent
5635
5636 local maxX = sidesGui.AbsoluteSize.X
5637 local initX = guiMain.AbsolutePosition.X
5638 local initY = guiMain.AbsolutePosition.Y
5639 local offX = mouse.X - initX
5640 local offY = mouse.Y - initY
5641
5642 local alignInsertPos,alignInsertSide
5643
5644 guiDragging = true
5645
5646 releaseEvent = clonerefs(game:GetService("UserInputService")).InputEnded:Connect(function(input)
5647 if input.UserInputType == Enum.UserInputType.MouseButton1 then
5648 releaseEvent:Disconnect()
5649 mouseEvent:Disconnect()
5650 guiDragging = false
5651 alignIndicator.Parent = nil
5652 if alignInsertSide then
5653 local targetSide = (alignInsertSide == "left" and leftSide) or (alignInsertSide == "right" and rightSide)
5654 self:AlignTo(targetSide,alignInsertPos)
5655 end
5656 end
5657 end)
5658
5659 mouseEvent = clonerefs(game:GetService("UserInputService")).InputChanged:Connect(function(input)
5660 if input.UserInputType == Enum.UserInputType.MouseMovement and self.Draggable and not self.Closed then
5661 if self.Aligned then
5662 if leftSide.Resizing or rightSide.Resizing then return end
5663 local posX,posY = input.Position.X-offX,input.Position.Y-offY
5664 local delta = math.sqrt((posX-initX)^2 + (posY-initY)^2)
5665 if delta >= 5 then
5666 self:SetAligned(false)
5667 end
5668 else
5669 local inputX,inputY = input.Position.X,input.Position.Y
5670 local posX,posY = inputX-offX,inputY-offY
5671 if posY < 0 then posY = 0 end
5672 guiMain.Position = UDim2.new(0,posX,0,posY)
5673
5674 if self.Resizable and self.Alignable then
5675 if inputX < 25 then
5676 if sideHasRoom(leftSide,self.MinY or 100) then
5677 local insertPos,range = getSideInsertPos(leftSide,inputY)
5678 alignIndicator.Indicator.Position = UDim2.new(0,-15,0,range[1])
5679 alignIndicator.Indicator.Size = UDim2.new(0,40,0,range[2]-range[1])
5680 Lib.ShowGui(alignIndicator)
5681 alignInsertPos = insertPos
5682 alignInsertSide = "left"
5683 return
5684 end
5685 elseif inputX >= maxX - 25 then
5686 if sideHasRoom(rightSide,self.MinY or 100) then
5687 local insertPos,range = getSideInsertPos(rightSide,inputY)
5688 alignIndicator.Indicator.Position = UDim2.new(0,maxX-25,0,range[1])
5689 alignIndicator.Indicator.Size = UDim2.new(0,40,0,range[2]-range[1])
5690 Lib.ShowGui(alignIndicator)
5691 alignInsertPos = insertPos
5692 alignInsertSide = "right"
5693 return
5694 end
5695 end
5696 end
5697 alignIndicator.Parent = nil
5698 alignInsertPos = nil
5699 alignInsertSide = nil
5700 end
5701 end
5702 end)
5703 end
5704 end)
5705
5706 guiTopBar.Close.MouseButton1Click:Connect(function()
5707 if self.Closed then return end
5708 self:Close()
5709 end)
5710
5711 guiTopBar.Minimize.MouseButton1Click:Connect(function()
5712 if self.Closed then return end
5713 if self.Aligned then
5714 self:SetAligned(false)
5715 else
5716 self:SetMinimized()
5717 end
5718 end)
5719
5720 guiTopBar.Minimize.MouseButton2Click:Connect(function()
5721 if self.Closed then return end
5722 if not self.Aligned then
5723 self:SetMinimized(nil,2)
5724 guiTopBar.Minimize.BackgroundTransparency = 1
5725 end
5726 end)
5727
5728 guiMain.InputBegan:Connect(function(input)
5729 if input.UserInputType == Enum.UserInputType.MouseButton1 and not self.Aligned and not self.Closed then
5730 moveToTop(self)
5731 end
5732 end)
5733
5734 guiMain:GetPropertyChangedSignal("AbsolutePosition"):Connect(function()
5735 local absPos = guiMain.AbsolutePosition
5736 self.PosX = absPos.X
5737 self.PosY = absPos.Y
5738 end)
5739
5740 resizeHook(self,guiResizeControls.North,"N")
5741 resizeHook(self,guiResizeControls.NorthEast,"NE")
5742 resizeHook(self,guiResizeControls.East,"E")
5743 resizeHook(self,guiResizeControls.SouthEast,"SE")
5744 resizeHook(self,guiResizeControls.South,"S")
5745 resizeHook(self,guiResizeControls.SouthWest,"SW")
5746 resizeHook(self,guiResizeControls.West,"W")
5747 resizeHook(self,guiResizeControls.NorthWest,"NW")
5748
5749 guiMain.Size = UDim2.new(0,self.SizeX,0,self.SizeY)
5750
5751 gui.DescendantAdded:Connect(function(obj) focusInput(self,obj) end)
5752 local descs = gui:GetDescendants()
5753 for i = 1,#descs do
5754 focusInput(self,descs[i])
5755 end
5756
5757 self.MinimizeAnim = Lib.ButtonAnim(guiTopBar.Minimize)
5758 self.CloseAnim = Lib.ButtonAnim(guiTopBar.Close)
5759
5760 return gui
5761 end
5762
5763 local function updateSideFrames(noTween)
5764 stopTweens()
5765 leftSide.Frame.Size = UDim2.new(0,leftSide.Width,1,0)
5766 rightSide.Frame.Size = UDim2.new(0,rightSide.Width,1,0)
5767 leftSide.Frame.Resizer.Position = UDim2.new(0,leftSide.Width,0,0)
5768 rightSide.Frame.Resizer.Position = UDim2.new(0,-5,0,0)
5769
5770 --leftSide.Frame.Visible = (#leftSide.Windows > 0)
5771 --rightSide.Frame.Visible = (#rightSide.Windows > 0)
5772
5773 --[[if #leftSide.Windows > 0 and leftSide.Frame.Position == UDim2.new(0,-leftSide.Width-5,0,0) then
5774 leftSide.Frame:TweenPosition(UDim2.new(0,0,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)
5775 elseif #leftSide.Windows == 0 and leftSide.Frame.Position == UDim2.new(0,0,0,0) then
5776 leftSide.Frame:TweenPosition(UDim2.new(0,-leftSide.Width-5,0,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)
5777 end
5778 local rightTweenPos = (#rightSide.Windows == 0 and UDim2.new(1,5,0,0) or UDim2.new(1,-rightSide.Width,0,0))
5779 rightSide.Frame:TweenPosition(rightTweenPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)]]
5780 local leftHidden = #leftSide.Windows == 0 or leftSide.Hidden
5781 local rightHidden = #rightSide.Windows == 0 or rightSide.Hidden
5782 local leftPos = (leftHidden and UDim2.new(0,-leftSide.Width-10,0,0) or UDim2.new(0,0,0,0))
5783 local rightPos = (rightHidden and UDim2.new(1,10,0,0) or UDim2.new(1,-rightSide.Width,0,0))
5784
5785 sidesGui.LeftToggle.Text = leftHidden and ">" or "<"
5786 sidesGui.RightToggle.Text = rightHidden and "<" or ">"
5787
5788 if not noTween then
5789 local function insertTween(...)
5790 local tween = service.TweenService:Create(...)
5791 tweens[#tweens+1] = tween
5792 tween:Play()
5793 end
5794 insertTween(leftSide.Frame,sideTweenInfo,{Position = leftPos})
5795 insertTween(rightSide.Frame,sideTweenInfo,{Position = rightPos})
5796 insertTween(sidesGui.LeftToggle,sideTweenInfo,{Position = UDim2.new(0,#leftSide.Windows == 0 and -16 or 0,0,-36)})
5797 insertTween(sidesGui.RightToggle,sideTweenInfo,{Position = UDim2.new(1,#rightSide.Windows == 0 and 0 or -16,0,-36)})
5798 else
5799 leftSide.Frame.Position = leftPos
5800 rightSide.Frame.Position = rightPos
5801 sidesGui.LeftToggle.Position = UDim2.new(0,#leftSide.Windows == 0 and -16 or 0,0,-36)
5802 sidesGui.RightToggle.Position = UDim2.new(1,#rightSide.Windows == 0 and 0 or -16,0,-36)
5803 end
5804 end
5805
5806 local function getSideFramePos(side)
5807 local leftHidden = #leftSide.Windows == 0 or leftSide.Hidden
5808 local rightHidden = #rightSide.Windows == 0 or rightSide.Hidden
5809 if side == leftSide then
5810 return (leftHidden and UDim2.new(0,-leftSide.Width-10,0,0) or UDim2.new(0,0,0,0))
5811 else
5812 return (rightHidden and UDim2.new(1,10,0,0) or UDim2.new(1,-rightSide.Width,0,0))
5813 end
5814 end
5815
5816 local function sideResized(side)
5817 local currentPos = 0
5818 local sideFramePos = getSideFramePos(side)
5819 for i,v in pairs(side.Windows) do
5820 v.SizeX = side.Width
5821 v.GuiElems.Main.Size = UDim2.new(0,side.Width,0,v.SizeY)
5822 v.GuiElems.Main.Position = UDim2.new(sideFramePos.X.Scale,sideFramePos.X.Offset,0,currentPos)
5823 currentPos = currentPos + v.SizeY+4
5824 end
5825 end
5826
5827 local function sideResizerHook(resizer,dir,side,pos)
5828 local mouse = Main.Mouse
5829 local windows = side.Windows
5830
5831 resizer.InputBegan:Connect(function(input)
5832 if not side.Resizing then
5833 if input.UserInputType == Enum.UserInputType.MouseMovement then
5834 resizer.BackgroundColor3 = theme.MainColor2
5835 elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
5836 local releaseEvent,mouseEvent
5837
5838 local offX = mouse.X - resizer.AbsolutePosition.X
5839 local offY = mouse.Y - resizer.AbsolutePosition.Y
5840
5841 side.Resizing = resizer
5842 resizer.BackgroundColor3 = theme.MainColor2
5843
5844 releaseEvent = service.UserInputService.InputEnded:Connect(function(input)
5845 if input.UserInputType == Enum.UserInputType.MouseButton1 then
5846 releaseEvent:Disconnect()
5847 mouseEvent:Disconnect()
5848 side.Resizing = false
5849 resizer.BackgroundColor3 = theme.Button
5850 end
5851 end)
5852
5853 mouseEvent = service.UserInputService.InputChanged:Connect(function(input)
5854 if not resizer.Parent then
5855 releaseEvent:Disconnect()
5856 mouseEvent:Disconnect()
5857 side.Resizing = false
5858 return
5859 end
5860 if input.UserInputType == Enum.UserInputType.MouseMovement then
5861 if dir == "V" then
5862 local delta = input.Position.Y - resizer.AbsolutePosition.Y - offY
5863
5864 if delta > 0 then
5865 local neededSize = delta
5866 for i = pos+1,#windows do
5867 local window = windows[i]
5868 local newSize = math.max(window.SizeY-neededSize,(window.MinY or 100))
5869 neededSize = neededSize - (window.SizeY - newSize)
5870 window.SizeY = newSize
5871 end
5872 windows[pos].SizeY = windows[pos].SizeY + math.max(0,delta-neededSize)
5873 else
5874 local neededSize = -delta
5875 for i = pos,1,-1 do
5876 local window = windows[i]
5877 local newSize = math.max(window.SizeY-neededSize,(window.MinY or 100))
5878 neededSize = neededSize - (window.SizeY - newSize)
5879 window.SizeY = newSize
5880 end
5881 windows[pos+1].SizeY = windows[pos+1].SizeY + math.max(0,-delta-neededSize)
5882 end
5883
5884 updateSideFrames()
5885 sideResized(side)
5886 elseif dir == "H" then
5887 local maxWidth = math.max(300,sidesGui.AbsoluteSize.X-static.FreeWidth)
5888 local otherSide = (side == leftSide and rightSide or leftSide)
5889 local delta = input.Position.X - resizer.AbsolutePosition.X - offX
5890 delta = (side == leftSide and delta or -delta)
5891
5892 local proposedSize = math.max(static.MinWidth,side.Width + delta)
5893 if proposedSize + otherSide.Width <= maxWidth then
5894 side.Width = proposedSize
5895 else
5896 local newOtherSize = maxWidth - proposedSize
5897 if newOtherSize >= static.MinWidth then
5898 side.Width = proposedSize
5899 otherSide.Width = newOtherSize
5900 else
5901 side.Width = maxWidth - static.MinWidth
5902 otherSide.Width = static.MinWidth
5903 end
5904 end
5905
5906 updateSideFrames(true)
5907 sideResized(side)
5908 sideResized(otherSide)
5909 end
5910 end
5911 end)
5912 end
5913 end
5914 end)
5915
5916 resizer.InputEnded:Connect(function(input)
5917 if input.UserInputType == Enum.UserInputType.MouseMovement and side.Resizing ~= resizer then
5918 resizer.BackgroundColor3 = theme.Button
5919 end
5920 end)
5921 end
5922
5923 local function renderSide(side,noTween) -- TODO: Use existing resizers
5924 local currentPos = 0
5925 local sideFramePos = getSideFramePos(side)
5926 local template = side.WindowResizer:Clone()
5927 for i,v in pairs(side.ResizeCons) do v:Disconnect() end
5928 for i,v in pairs(side.Frame:GetChildren()) do if v.Name == "WindowResizer" then v:Destroy() end end
5929 side.ResizeCons = {}
5930 side.Resizing = nil
5931
5932 for i,v in pairs(side.Windows) do
5933 v.SidePos = i
5934 local isEnd = i == #side.Windows
5935 local size = UDim2.new(0,side.Width,0,v.SizeY)
5936 local pos = UDim2.new(sideFramePos.X.Scale,sideFramePos.X.Offset,0,currentPos)
5937 Lib.ShowGui(v.Gui)
5938 --v.GuiElems.Main:TweenSizeAndPosition(size,pos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)
5939 if noTween then
5940 v.GuiElems.Main.Size = size
5941 v.GuiElems.Main.Position = pos
5942 else
5943 local tween = service.TweenService:Create(v.GuiElems.Main,sideTweenInfo,{Size = size, Position = pos})
5944 tweens[#tweens+1] = tween
5945 tween:Play()
5946 end
5947 currentPos = currentPos + v.SizeY+4
5948
5949 if not isEnd then
5950 local newTemplate = template:Clone()
5951 newTemplate.Position = UDim2.new(1,-side.Width,0,currentPos-4)
5952 side.ResizeCons[#side.ResizeCons+1] = v.Gui.Main:GetPropertyChangedSignal("Size"):Connect(function()
5953 newTemplate.Position = UDim2.new(1,-side.Width,0, v.GuiElems.Main.Position.Y.Offset + v.GuiElems.Main.Size.Y.Offset)
5954 end)
5955 side.ResizeCons[#side.ResizeCons+1] = v.Gui.Main:GetPropertyChangedSignal("Position"):Connect(function()
5956 newTemplate.Position = UDim2.new(1,-side.Width,0, v.GuiElems.Main.Position.Y.Offset + v.GuiElems.Main.Size.Y.Offset)
5957 end)
5958 sideResizerHook(newTemplate,"V",side,i)
5959 newTemplate.Parent = side.Frame
5960 end
5961 end
5962
5963 --side.Frame.Back.Position = UDim2.new(0,0,0,0)
5964 --side.Frame.Back.Size = UDim2.new(0,side.Width,1,0)
5965 end
5966
5967 local function updateSide(side,noTween)
5968 local oldHeight = 0
5969 local currentPos = 0
5970 local neededSize = 0
5971 local windows = side.Windows
5972 local height = sidesGui.AbsoluteSize.Y - (math.max(0,#windows - 1) * 4)
5973
5974 for i,v in pairs(windows) do oldHeight = oldHeight + v.SizeY end
5975 for i,v in pairs(windows) do
5976 if i == #windows then
5977 v.SizeY = height-currentPos
5978 neededSize = math.max(0,(v.MinY or 100)-v.SizeY)
5979 else
5980 v.SizeY = math.max(math.floor(v.SizeY/oldHeight*height),v.MinY or 100)
5981 end
5982 currentPos = currentPos + v.SizeY
5983 end
5984
5985 if neededSize > 0 then
5986 for i = #windows-1,1,-1 do
5987 local window = windows[i]
5988 local newSize = math.max(window.SizeY-neededSize,(window.MinY or 100))
5989 neededSize = neededSize - (window.SizeY - newSize)
5990 window.SizeY = newSize
5991 end
5992 local lastWindow = windows[#windows]
5993 lastWindow.SizeY = (lastWindow.MinY or 100)-neededSize
5994 end
5995 renderSide(side,noTween)
5996 end
5997
5998 updateWindows = function(noTween)
5999 updateSideFrames(noTween)
6000 updateSide(leftSide,noTween)
6001 updateSide(rightSide,noTween)
6002 local count = 0
6003 for i = #visibleWindows,1,-1 do
6004 visibleWindows[i].Gui.DisplayOrder = displayOrderStart + count
6005 Lib.ShowGui(visibleWindows[i].Gui)
6006 count = count + 1
6007 end
6008
6009 --[[local leftTweenPos = (#leftSide.Windows == 0 and UDim2.new(0,-leftSide.Width-5,0,0) or UDim2.new(0,0,0,0))
6010 leftSide.Frame:TweenPosition(leftTweenPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)
6011 local rightTweenPos = (#rightSide.Windows == 0 and UDim2.new(1,5,0,0) or UDim2.new(1,-rightSide.Width,0,0))
6012 rightSide.Frame:TweenPosition(rightTweenPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,0.3,true)]]
6013 end
6014
6015 funcs.SetMinimized = function(self,set,mode)
6016 local oldVal = self.Minimized
6017 local newVal
6018 if set == nil then newVal = not self.Minimized else newVal = set end
6019 self.Minimized = newVal
6020 if not mode then mode = 1 end
6021
6022 local resizeControls = self.GuiElems.ResizeControls
6023 local minimizeControls = {"North","NorthEast","NorthWest","South","SouthEast","SouthWest"}
6024 for i = 1,#minimizeControls do
6025 local control = resizeControls:FindFirstChild(minimizeControls[i])
6026 if control then control.Visible = not newVal end
6027 end
6028
6029 if mode == 1 or mode == 2 then
6030 self:StopTweens()
6031 if mode == 1 then
6032 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)
6033 else
6034 local maxY = sidesGui.AbsoluteSize.Y
6035 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))
6036
6037 self.GuiElems.Main:TweenPosition(newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.25,true)
6038 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)
6039 end
6040 self.GuiElems.Minimize.ImageLabel.Image = newVal and "rbxassetid://5060023708" or "rbxassetid://5034768003"
6041 end
6042
6043 if oldVal ~= newVal then
6044 if newVal then
6045 self.OnMinimize:Fire()
6046 else
6047 self.OnRestore:Fire()
6048 end
6049 end
6050 end
6051
6052 funcs.Resize = function(self,sizeX,sizeY)
6053 self.SizeX = sizeX or self.SizeX
6054 self.SizeY = sizeY or self.SizeY
6055 self.GuiElems.Main.Size = UDim2.new(0,self.SizeX,0,self.SizeY)
6056 end
6057
6058 funcs.SetSize = funcs.Resize
6059
6060 funcs.SetTitle = function(self,title)
6061 self.GuiElems.Title.Text = title
6062 end
6063
6064 funcs.SetResizable = function(self,val)
6065 self.Resizable = val
6066 self.GuiElems.ResizeControls.Visible = self.Resizable and self.ResizableInternal
6067 end
6068
6069 funcs.SetResizableInternal = function(self,val)
6070 self.ResizableInternal = val
6071 self.GuiElems.ResizeControls.Visible = self.Resizable and self.ResizableInternal
6072 end
6073
6074 funcs.SetAligned = function(self,val)
6075 self.Aligned = val
6076 self:SetResizableInternal(not val)
6077 self.GuiElems.Main.Active = not val
6078 self.GuiElems.Main.Outlines.Visible = not val
6079 if not val then
6080 for i,v in pairs(leftSide.Windows) do if v == self then table.remove(leftSide.Windows,i) break end end
6081 for i,v in pairs(rightSide.Windows) do if v == self then table.remove(rightSide.Windows,i) break end end
6082 if not table.find(visibleWindows,self) then table.insert(visibleWindows,1,self) end
6083 self.GuiElems.Minimize.ImageLabel.Image = "rbxassetid://5034768003"
6084 self.Side = nil
6085 updateWindows()
6086 else
6087 self:SetMinimized(false,3)
6088 for i,v in pairs(visibleWindows) do if v == self then table.remove(visibleWindows,i) break end end
6089 self.GuiElems.Minimize.ImageLabel.Image = "rbxassetid://5448127505"
6090 end
6091 end
6092
6093 funcs.Add = function(self,obj,name)
6094 if type(obj) == "table" and obj.Gui and obj.Gui:IsA("GuiObject") then
6095 obj.Gui.Parent = self.ContentPane
6096 else
6097 obj.Parent = self.ContentPane
6098 end
6099 if name then self.Elements[name] = obj end
6100 end
6101
6102 funcs.GetElement = function(self,obj,name)
6103 return self.Elements[name]
6104 end
6105
6106 funcs.AlignTo = function(self,side,pos,size,silent)
6107 if table.find(side.Windows,self) or self.Closed then return end
6108
6109 size = size or self.SizeY
6110 if size > 0 and size <= 1 then
6111 local totalSideHeight = 0
6112 for i,v in pairs(side.Windows) do totalSideHeight = totalSideHeight + v.SizeY end
6113 self.SizeY = (totalSideHeight > 0 and totalSideHeight * size * 2) or size
6114 else
6115 self.SizeY = (size > 0 and size or 100)
6116 end
6117
6118 self:SetAligned(true)
6119 self.Side = side
6120 self.SizeX = side.Width
6121 self.Gui.DisplayOrder = sideDisplayOrder + 1
6122 for i,v in pairs(side.Windows) do v.Gui.DisplayOrder = sideDisplayOrder end
6123 pos = math.min(#side.Windows+1, pos or 1)
6124 self.SidePos = pos
6125 table.insert(side.Windows, pos, self)
6126
6127 if not silent then
6128 side.Hidden = false
6129 end
6130 -- updateWindows(silent)
6131 end
6132
6133 funcs.Close = function(self)
6134 self.Closed = true
6135 self:SetResizableInternal(false)
6136
6137 Lib.FindAndRemove(leftSide.Windows,self)
6138 Lib.FindAndRemove(rightSide.Windows,self)
6139 Lib.FindAndRemove(visibleWindows,self)
6140
6141 self.MinimizeAnim.Disable()
6142 self.CloseAnim.Disable()
6143 self.ClosedSide = self.Side
6144 self.Side = nil
6145 self.OnDeactivate:Fire()
6146
6147 if not self.Aligned then
6148 self:StopTweens()
6149 local ti = TweenInfo.new(0.2,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
6150
6151 local closeTime = tick()
6152 self.LastClose = closeTime
6153
6154 self:DoTween(self.GuiElems.Main,ti,{Size = UDim2.new(0,self.SizeX,0,20)})
6155 self:DoTween(self.GuiElems.Title,ti,{TextTransparency = 1})
6156 self:DoTween(self.GuiElems.Minimize.ImageLabel,ti,{ImageTransparency = 1})
6157 self:DoTween(self.GuiElems.Close.ImageLabel,ti,{ImageTransparency = 1})
6158 Lib.FastWait(0.2)
6159 if closeTime ~= self.LastClose then return end
6160
6161 self:DoTween(self.GuiElems.TopBar,ti,{BackgroundTransparency = 1})
6162 self:DoTween(self.GuiElems.Outlines,ti,{ImageTransparency = 1})
6163 Lib.FastWait(0.2)
6164 if closeTime ~= self.LastClose then return end
6165 end
6166
6167 self.Aligned = false
6168 self.Gui.Parent = nil
6169 updateWindows(true)
6170 end
6171
6172 funcs.Hide = funcs.Close
6173
6174 funcs.IsVisible = function(self)
6175 return not self.Closed and ((self.Side and not self.Side.Hidden) or not self.Side)
6176 end
6177
6178 funcs.IsContentVisible = function(self)
6179 return self:IsVisible() and not self.Minimized
6180 end
6181
6182 funcs.Focus = function(self)
6183 moveToTop(self)
6184 end
6185
6186 funcs.MoveInBoundary = function(self)
6187 local posX,posY = self.PosX,self.PosY
6188 local maxX,maxY = sidesGui.AbsoluteSize.X,sidesGui.AbsoluteSize.Y
6189 posX = math.min(posX,maxX-self.SizeX)
6190 posY = math.min(posY,maxY-20)
6191 self.GuiElems.Main.Position = UDim2.new(0,posX,0,posY)
6192 end
6193
6194 funcs.DoTween = function(self,...)
6195 local tween = service.TweenService:Create(...)
6196 self.Tweens[#self.Tweens+1] = tween
6197 tween:Play()
6198 end
6199
6200 funcs.StopTweens = function(self)
6201 for i,v in pairs(self.Tweens) do
6202 v:Cancel()
6203 end
6204 self.Tweens = {}
6205 end
6206
6207 funcs.Show = function(self,data)
6208 return static.ShowWindow(self,data)
6209 end
6210
6211 funcs.ShowAndFocus = function(self,data)
6212 static.ShowWindow(self,data)
6213 service.RunService.RenderStepped:wait()
6214 self:Focus()
6215 end
6216
6217 static.ShowWindow = function(window,data)
6218 data = data or {}
6219 local align = data.Align
6220 local pos = data.Pos
6221 local size = data.Size
6222 local targetSide = (align == "left" and leftSide) or (align == "right" and rightSide)
6223
6224 if not window.Closed then
6225 if not window.Aligned then
6226 window:SetMinimized(false)
6227 elseif window.Side and not data.Silent then
6228 static.SetSideVisible(window.Side,true)
6229 end
6230 return
6231 end
6232
6233 window.Closed = false
6234 window.LastClose = tick()
6235 window.GuiElems.Title.TextTransparency = 0
6236 window.GuiElems.Minimize.ImageLabel.ImageTransparency = 0
6237 window.GuiElems.Close.ImageLabel.ImageTransparency = 0
6238 window.GuiElems.TopBar.BackgroundTransparency = 0
6239 window.GuiElems.Outlines.ImageTransparency = 0
6240 window.GuiElems.Minimize.ImageLabel.Image = "rbxassetid://5034768003"
6241 window.GuiElems.Main.Active = true
6242 window.GuiElems.Main.Outlines.Visible = true
6243 window:SetMinimized(false,3)
6244 window:SetResizableInternal(true)
6245 window.MinimizeAnim.Enable()
6246 window.CloseAnim.Enable()
6247
6248 if align then
6249 window:AlignTo(targetSide,pos,size,data.Silent)
6250 else
6251 if align == nil and window.ClosedSide then -- Regular open
6252 window:AlignTo(window.ClosedSide,window.SidePos,size,true)
6253 static.SetSideVisible(window.ClosedSide,true)
6254 else
6255 if table.find(visibleWindows,window) then return end
6256
6257 -- TODO: make better
6258 window.GuiElems.Main.Size = UDim2.new(0,window.SizeX,0,20)
6259 local ti = TweenInfo.new(0.2,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
6260 window:StopTweens()
6261 window:DoTween(window.GuiElems.Main,ti,{Size = UDim2.new(0,window.SizeX,0,window.SizeY)})
6262
6263 window.SizeY = size or window.SizeY
6264 table.insert(visibleWindows,1,window)
6265 updateWindows()
6266 end
6267 end
6268
6269 window.ClosedSide = nil
6270 window.OnActivate:Fire()
6271 end
6272
6273 static.ToggleSide = function(name)
6274 local side = (name == "left" and leftSide or rightSide)
6275 side.Hidden = not side.Hidden
6276 for i,v in pairs(side.Windows) do
6277 if side.Hidden then
6278 v.OnDeactivate:Fire()
6279 else
6280 v.OnActivate:Fire()
6281 end
6282 end
6283 updateWindows()
6284 end
6285
6286 static.SetSideVisible = function(s,vis)
6287 local side = (type(s) == "table" and s) or (s == "left" and leftSide or rightSide)
6288 side.Hidden = not vis
6289 for i,v in pairs(side.Windows) do
6290 if side.Hidden then
6291 v.OnDeactivate:Fire()
6292 else
6293 v.OnActivate:Fire()
6294 end
6295 end
6296 updateWindows()
6297 end
6298
6299 static.Init = function()
6300 displayOrderStart = Main.DisplayOrders.Window
6301 sideDisplayOrder = Main.DisplayOrders.SideWindow
6302
6303 sidesGui = Instance.new("ScreenGui")
6304 local leftFrame = create({
6305 {1,"Frame",{Active=true,Name="LeftSide",BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),BorderSizePixel=0,}},
6306 {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,}},
6307 {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),}},
6308 {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,}},
6309 {5,"Frame",{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderSizePixel=0,Name="Line",Parent={4},Size=UDim2.new(1,0,0,1),}},
6310 })
6311 leftSide.Frame = leftFrame
6312 leftFrame.Position = UDim2.new(0,-leftSide.Width-10,0,0)
6313 leftSide.WindowResizer = leftFrame.WindowResizer
6314 leftFrame.WindowResizer.Parent = nil
6315 leftFrame.Parent = sidesGui
6316
6317 local rightFrame = create({
6318 {1,"Frame",{Active=true,Name="RightSide",BackgroundColor3=Color3.new(0.17647059261799,0.17647059261799,0.17647059261799),BorderSizePixel=0,}},
6319 {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,}},
6320 {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),}},
6321 {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,}},
6322 {5,"Frame",{BackgroundColor3=Color3.new(0.14117647707462,0.14117647707462,0.14117647707462),BorderSizePixel=0,Name="Line",Parent={4},Size=UDim2.new(1,0,0,1),}},
6323 })
6324 rightSide.Frame = rightFrame
6325 rightFrame.Position = UDim2.new(1,10,0,0)
6326 rightSide.WindowResizer = rightFrame.WindowResizer
6327 rightFrame.WindowResizer.Parent = nil
6328 rightFrame.Parent = sidesGui
6329
6330 sideResizerHook(leftFrame.Resizer,"H",leftSide)
6331 sideResizerHook(rightFrame.Resizer,"H",rightSide)
6332
6333 alignIndicator = Instance.new("ScreenGui")
6334 alignIndicator.DisplayOrder = Main.DisplayOrders.Core
6335 local indicator = Instance.new("Frame",alignIndicator)
6336 indicator.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
6337 indicator.BorderSizePixel = 0
6338 indicator.BackgroundTransparency = 0.8
6339 indicator.Name = "Indicator"
6340 local corner = Instance.new("UICorner",indicator)
6341 corner.CornerRadius = UDim.new(0,10)
6342
6343 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,}}})
6344 local rightToggle = leftToggle:Clone()
6345 rightToggle.Name = "RightToggle"
6346 rightToggle.Position = UDim2.new(1,-16,0,-36)
6347 Lib.ButtonAnim(leftToggle,{Mode = 2,PressColor = Color3.fromRGB(32,32,32)})
6348 Lib.ButtonAnim(rightToggle,{Mode = 2,PressColor = Color3.fromRGB(32,32,32)})
6349
6350 leftToggle.MouseButton1Click:Connect(function()
6351 static.ToggleSide("left")
6352 end)
6353
6354 rightToggle.MouseButton1Click:Connect(function()
6355 static.ToggleSide("right")
6356 end)
6357
6358 leftToggle.Parent = sidesGui
6359 rightToggle.Parent = sidesGui
6360
6361 sidesGui:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
6362 local maxWidth = math.max(300,sidesGui.AbsoluteSize.X-static.FreeWidth)
6363 leftSide.Width = math.max(static.MinWidth,math.min(leftSide.Width,maxWidth-rightSide.Width))
6364 rightSide.Width = math.max(static.MinWidth,math.min(rightSide.Width,maxWidth-leftSide.Width))
6365 for i = 1,#visibleWindows do
6366 visibleWindows[i]:MoveInBoundary()
6367 end
6368 updateWindows(true)
6369 end)
6370
6371 sidesGui.DisplayOrder = sideDisplayOrder - 1
6372 Lib.ShowGui(sidesGui)
6373 updateSideFrames()
6374 end
6375
6376 local mt = {__index = funcs}
6377 static.new = function()
6378 local obj = setmetatable({
6379 Minimized = false,
6380 Dragging = false,
6381 Resizing = false,
6382 Aligned = false,
6383 Draggable = true,
6384 Resizable = true,
6385 ResizableInternal = true,
6386 Alignable = true,
6387 Closed = true,
6388 SizeX = 300,
6389 SizeY = 300,
6390 MinX = 200,
6391 MinY = 200,
6392 PosX = 0,
6393 PosY = 0,
6394 GuiElems = {},
6395 Tweens = {},
6396 Elements = {},
6397 OnActivate = Lib.Signal.new(),
6398 OnDeactivate = Lib.Signal.new(),
6399 OnMinimize = Lib.Signal.new(),
6400 OnRestore = Lib.Signal.new()
6401 },mt)
6402 obj.Gui = createGui(obj)
6403 return obj
6404 end
6405
6406 return static
6407 end)()
6408
6409 Lib.ContextMenu = (function()
6410 local funcs = {}
6411 local mouse
6412
6413 local function createGui(self)
6414 local contextGui = create({
6415 {1,"ScreenGui",{DisplayOrder=1000000,Name="Context",ZIndexBehavior=1,}},
6416 {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),}},
6417 {3,"UICorner",{CornerRadius=UDim.new(0,4),Parent={2},}},
6418 {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),}},
6419 {5,"UICorner",{CornerRadius=UDim.new(0,4),Parent={4},}},
6420 {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,}},
6421 {7,"UIListLayout",{Parent={6},SortOrder=2,}},
6422 {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,}},
6423 {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),}},
6424 {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,}},
6425 {11,"UICorner",{CornerRadius=UDim.new(0,2),Parent={9},}},
6426 {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),}},
6427 {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,}},
6428 {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,}},
6429 {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,}},
6430 {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),}},
6431 {17,"UICorner",{CornerRadius=UDim.new(0,4),Parent={13},}},
6432 {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,}},
6433 {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),}},
6434 {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,}},
6435 })
6436 self.GuiElems.Main = contextGui.Main
6437 self.GuiElems.List = contextGui.Main.Container.List
6438 self.GuiElems.Entry = contextGui.Entry
6439 self.GuiElems.Divider = contextGui.Divider
6440 self.GuiElems.SearchFrame = contextGui.Main.Container.SearchFrame
6441 self.GuiElems.SearchBar = self.GuiElems.SearchFrame.SearchContainer.SearchBox
6442 Lib.ViewportTextBox.convert(self.GuiElems.SearchBar)
6443
6444 self.GuiElems.SearchBar:GetPropertyChangedSignal("Text"):Connect(function()
6445 local lower,find = string.lower,string.find
6446 local searchText = lower(self.GuiElems.SearchBar.Text)
6447 local items = self.Items
6448 local map = self.ItemToEntryMap
6449
6450 if searchText ~= "" then
6451 local results = {}
6452 local count = 1
6453 for i = 1,#items do
6454 local item = items[i]
6455 local entry = map[item]
6456 if entry then
6457 if not item.Divider and find(lower(item.Name),searchText,1,true) then
6458 results[count] = item
6459 count = count + 1
6460 else
6461 entry.Visible = false
6462 end
6463 end
6464 end
6465 table.sort(results,function(a,b) return a.Name < b.Name end)
6466 for i = 1,#results do
6467 local entry = map[results[i]]
6468 entry.LayoutOrder = i
6469 entry.Visible = true
6470 end
6471 else
6472 for i = 1,#items do
6473 local entry = map[items[i]]
6474 if entry then entry.LayoutOrder = i entry.Visible = true end
6475 end
6476 end
6477
6478 local toSize = self.GuiElems.List.UIListLayout.AbsoluteContentSize.Y + 6
6479 self.GuiElems.List.CanvasSize = UDim2.new(0,0,0,toSize-6)
6480 end)
6481
6482 return contextGui
6483 end
6484
6485 funcs.Add = function(self,item)
6486 local newItem = {
6487 Name = item.Name or "Item",
6488 Icon = item.Icon or "",
6489 Shortcut = item.Shortcut or "",
6490 OnClick = item.OnClick,
6491 OnHover = item.OnHover,
6492 Disabled = item.Disabled or false,
6493 DisabledIcon = item.DisabledIcon or "",
6494 IconMap = item.IconMap,
6495 OnRightClick = item.OnRightClick
6496 }
6497 if self.QueuedDivider then
6498 local text = self.QueuedDividerText and #self.QueuedDividerText > 0 and self.QueuedDividerText
6499 self:AddDivider(text)
6500 end
6501 self.Items[#self.Items+1] = newItem
6502 self.Updated = nil
6503 end
6504
6505 funcs.AddRegistered = function(self,name,disabled)
6506 if not self.Registered[name] then error(name.." is not registered") end
6507
6508 if self.QueuedDivider then
6509 local text = self.QueuedDividerText and #self.QueuedDividerText > 0 and self.QueuedDividerText
6510 self:AddDivider(text)
6511 end
6512 self.Registered[name].Disabled = disabled
6513 self.Items[#self.Items+1] = self.Registered[name]
6514 self.Updated = nil
6515 end
6516
6517 funcs.Register = function(self,name,item)
6518 self.Registered[name] = {
6519 Name = item.Name or "Item",
6520 Icon = item.Icon or "",
6521 Shortcut = item.Shortcut or "",
6522 OnClick = item.OnClick,
6523 OnHover = item.OnHover,
6524 DisabledIcon = item.DisabledIcon or "",
6525 IconMap = item.IconMap,
6526 OnRightClick = item.OnRightClick
6527 }
6528 end
6529
6530 funcs.UnRegister = function(self,name)
6531 self.Registered[name] = nil
6532 end
6533
6534 funcs.AddDivider = function(self,text)
6535 self.QueuedDivider = false
6536 local textWidth = text and service.TextService:GetTextSize(text,14,Enum.Font.SourceSans,Vector2.new(999999999,20)).X or nil
6537 table.insert(self.Items,{Divider = true, Text = text, TextSize = textWidth and textWidth+4})
6538 self.Updated = nil
6539 end
6540
6541 funcs.QueueDivider = function(self,text)
6542 self.QueuedDivider = true
6543 self.QueuedDividerText = text or ""
6544 end
6545
6546 funcs.Clear = function(self)
6547 self.Items = {}
6548 self.Updated = nil
6549 end
6550
6551 funcs.Refresh = function(self)
6552 for i,v in pairs(self.GuiElems.List:GetChildren()) do
6553 if not v:IsA("UIListLayout") then
6554 v:Destroy()
6555 end
6556 end
6557 local map = {}
6558 self.ItemToEntryMap = map
6559
6560 local dividerFrame = self.GuiElems.Divider
6561 local contextList = self.GuiElems.List
6562 local entryFrame = self.GuiElems.Entry
6563 local items = self.Items
6564
6565 for i = 1,#items do
6566 local item = items[i]
6567 if item.Divider then
6568 local newDivider = dividerFrame:Clone()
6569 newDivider.Line.BackgroundColor3 = self.Theme.DividerColor
6570 if item.Text then
6571 newDivider.Size = UDim2.new(1,0,0,20)
6572 newDivider.Line.Position = UDim2.new(0,item.TextSize,0.5,0)
6573 newDivider.Line.Size = UDim2.new(1,-item.TextSize,0,1)
6574 newDivider.DividerName.TextColor3 = self.Theme.TextColor
6575 newDivider.DividerName.Text = item.Text
6576 newDivider.DividerName.Visible = true
6577 end
6578 newDivider.Visible = true
6579 map[item] = newDivider
6580 newDivider.Parent = contextList
6581 else
6582 local newEntry = entryFrame:Clone()
6583 newEntry.BackgroundColor3 = self.Theme.HighlightColor
6584 newEntry.EntryName.TextColor3 = self.Theme.TextColor
6585 newEntry.EntryName.Text = item.Name
6586 newEntry.Shortcut.Text = item.Shortcut
6587 if item.Disabled then
6588 newEntry.EntryName.TextColor3 = Color3.new(150/255,150/255,150/255)
6589 newEntry.Shortcut.TextColor3 = Color3.new(150/255,150/255,150/255)
6590 end
6591
6592 if self.Iconless then
6593 newEntry.EntryName.Position = UDim2.new(0,2,0,0)
6594 newEntry.EntryName.Size = UDim2.new(1,-4,0,20)
6595 newEntry.Icon.Visible = false
6596 else
6597 local iconIndex = item.Disabled and item.DisabledIcon or item.Icon
6598 if item.IconMap then
6599 if type(iconIndex) == "number" then
6600 item.IconMap:Display(newEntry.Icon,iconIndex)
6601 elseif type(iconIndex) == "string" then
6602 item.IconMap:DisplayByKey(newEntry.Icon,iconIndex)
6603 end
6604 elseif type(iconIndex) == "string" then
6605 newEntry.Icon.Image = iconIndex
6606 end
6607 end
6608
6609 if not item.Disabled then
6610 if item.OnClick then
6611 newEntry.MouseButton1Click:Connect(function()
6612 item.OnClick(item.Name)
6613 if not item.NoHide then
6614 self:Hide()
6615 end
6616 end)
6617 end
6618
6619 if item.OnRightClick then
6620 newEntry.MouseButton2Click:Connect(function()
6621 item.OnRightClick(item.Name)
6622 if not item.NoHide then
6623 self:Hide()
6624 end
6625 end)
6626 end
6627 end
6628
6629 newEntry.InputBegan:Connect(function(input)
6630 if input.UserInputType == Enum.UserInputType.MouseMovement then
6631 newEntry.BackgroundTransparency = 0
6632 end
6633 end)
6634
6635 newEntry.InputEnded:Connect(function(input)
6636 if input.UserInputType == Enum.UserInputType.MouseMovement then
6637 newEntry.BackgroundTransparency = 1
6638 end
6639 end)
6640
6641 newEntry.Visible = true
6642 map[item] = newEntry
6643 newEntry.Parent = contextList
6644 end
6645 end
6646 self.Updated = true
6647 end
6648
6649 funcs.Show = function(self,x,y)
6650 -- Initialize Gui
6651 local elems = self.GuiElems
6652 elems.SearchFrame.Visible = self.SearchEnabled
6653 elems.List.Position = UDim2.new(0,2,0,2 + (self.SearchEnabled and 24 or 0))
6654 elems.List.Size = UDim2.new(1,-4,1,-4 - (self.SearchEnabled and 24 or 0))
6655 if self.SearchEnabled and self.ClearSearchOnShow then elems.SearchBar.Text = "" end
6656 self.GuiElems.List.CanvasPosition = Vector2.new(0,0)
6657
6658 if not self.Updated then
6659 self:Refresh() -- Create entries
6660 end
6661
6662 -- Vars
6663 local reverseY = false
6664 local x,y = x or mouse.X, y or mouse.Y
6665 local maxX,maxY = mouse.ViewSizeX,mouse.ViewSizeY
6666
6667 -- Position and show
6668 if x + self.Width > maxX then
6669 x = self.ReverseX and x - self.Width or maxX - self.Width
6670 end
6671 elems.Main.Position = UDim2.new(0,x,0,y)
6672 elems.Main.Size = UDim2.new(0,self.Width,0,0)
6673 self.Gui.DisplayOrder = Main.DisplayOrders.Menu
6674 Lib.ShowGui(self.Gui)
6675
6676 -- Size adjustment
6677 local toSize = elems.List.UIListLayout.AbsoluteContentSize.Y + 6 -- Padding
6678 if self.MaxHeight and toSize > self.MaxHeight then
6679 elems.List.CanvasSize = UDim2.new(0,0,0,toSize-6)
6680 toSize = self.MaxHeight
6681 else
6682 elems.List.CanvasSize = UDim2.new(0,0,0,0)
6683 end
6684 if y + toSize > maxY then reverseY = true end
6685
6686 -- Close event
6687 local closable
6688 if self.CloseEvent then self.CloseEvent:Disconnect() end
6689 self.CloseEvent = service.UserInputService.InputBegan:Connect(function(input)
6690 if not closable or input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
6691
6692 if not Lib.CheckMouseInGui(elems.Main) then
6693 self.CloseEvent:Disconnect()
6694 self:Hide()
6695 end
6696 end)
6697
6698 -- Resize
6699 if reverseY then
6700 elems.Main.Position = UDim2.new(0,x,0,y-(self.ReverseYOffset or 0))
6701 local newY = y - toSize - (self.ReverseYOffset or 0)
6702 y = newY >= 0 and newY or 0
6703 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)
6704 else
6705 elems.Main:TweenSize(UDim2.new(0,self.Width,0,toSize),Enum.EasingDirection.Out,Enum.EasingStyle.Quart,0.2,true)
6706 end
6707
6708 -- Close debounce
6709 Lib.FastWait()
6710 if self.SearchEnabled and self.FocusSearchOnShow then elems.SearchBar:CaptureFocus() end
6711 closable = true
6712 end
6713
6714 funcs.Hide = function(self)
6715 self.Gui.Parent = nil
6716 end
6717
6718 funcs.ApplyTheme = function(self,data)
6719 local theme = self.Theme
6720 theme.ContentColor = data.ContentColor or Settings.Theme.Menu
6721 theme.OutlineColor = data.OutlineColor or Settings.Theme.Menu
6722 theme.DividerColor = data.DividerColor or Settings.Theme.Outline2
6723 theme.TextColor = data.TextColor or Settings.Theme.Text
6724 theme.HighlightColor = data.HighlightColor or Settings.Theme.Main1
6725
6726 self.GuiElems.Main.BackgroundColor3 = theme.OutlineColor
6727 self.GuiElems.Main.Container.BackgroundColor3 = theme.ContentColor
6728 end
6729
6730 local mt = {__index = funcs}
6731 local function new()
6732 if not mouse then mouse = Main.Mouse or service.Players.LocalPlayer:GetMouse() end
6733
6734 local obj = setmetatable({
6735 Width = 200,
6736 MaxHeight = nil,
6737 Iconless = false,
6738 SearchEnabled = false,
6739 ClearSearchOnShow = true,
6740 FocusSearchOnShow = true,
6741 Updated = false,
6742 QueuedDivider = false,
6743 QueuedDividerText = "",
6744 Items = {},
6745 Registered = {},
6746 GuiElems = {},
6747 Theme = {}
6748 },mt)
6749 obj.Gui = createGui(obj)
6750 obj:ApplyTheme({})
6751 return obj
6752 end
6753
6754 return {new = new}
6755 end)()
6756
6757 Lib.CodeFrame = (function()
6758 local funcs = {}
6759
6760 local typeMap = {
6761 [1] = "String",
6762 [2] = "String",
6763 [3] = "String",
6764 [4] = "Comment",
6765 [5] = "Operator",
6766 [6] = "Number",
6767 [7] = "Keyword",
6768 [8] = "BuiltIn",
6769 [9] = "LocalMethod",
6770 [10] = "LocalProperty",
6771 [11] = "Nil",
6772 [12] = "Bool",
6773 [13] = "Function",
6774 [14] = "Local",
6775 [15] = "Self",
6776 [16] = "FunctionName",
6777 [17] = "Bracket"
6778 }
6779
6780 local specialKeywordsTypes = {
6781 ["nil"] = 11,
6782 ["true"] = 12,
6783 ["false"] = 12,
6784 ["function"] = 13,
6785 ["local"] = 14,
6786 ["self"] = 15
6787 }
6788
6789 local keywords = {
6790 ["and"] = true,
6791 ["break"] = true,
6792 ["do"] = true,
6793 ["else"] = true,
6794 ["elseif"] = true,
6795 ["end"] = true,
6796 ["false"] = true,
6797 ["for"] = true,
6798 ["function"] = true,
6799 ["if"] = true,
6800 ["in"] = true,
6801 ["local"] = true,
6802 ["nil"] = true,
6803 ["not"] = true,
6804 ["or"] = true,
6805 ["repeat"] = true,
6806 ["return"] = true,
6807 ["then"] = true,
6808 ["true"] = true,
6809 ["until"] = true,
6810 ["while"] = true,
6811 ["plugin"] = true
6812 }
6813
6814 local builtIns = {
6815 ["delay"] = true,
6816 ["elapsedTime"] = true,
6817 ["require"] = true,
6818 ["spawn"] = true,
6819 ["tick"] = true,
6820 ["time"] = true,
6821 ["typeof"] = true,
6822 ["UserSettings"] = true,
6823 ["wait"] = true,
6824 ["warn"] = true,
6825 ["game"] = true,
6826 ["shared"] = true,
6827 ["script"] = true,
6828 ["workspace"] = true,
6829 ["assert"] = true,
6830 ["collectgarbage"] = true,
6831 ["error"] = true,
6832 ["getfenv"] = true,
6833 ["getmetatable"] = true,
6834 ["ipairs"] = true,
6835 ["loadstring"] = true,
6836 ["newproxy"] = true,
6837 ["next"] = true,
6838 ["pairs"] = true,
6839 ["pcall"] = true,
6840 ["print"] = true,
6841 ["rawequal"] = true,
6842 ["rawget"] = true,
6843 ["rawset"] = true,
6844 ["select"] = true,
6845 ["setfenv"] = true,
6846 ["setmetatable"] = true,
6847 ["tonumber"] = true,
6848 ["tostring"] = true,
6849 ["type"] = true,
6850 ["unpack"] = true,
6851 ["xpcall"] = true,
6852 ["_G"] = true,
6853 ["_VERSION"] = true,
6854 ["coroutine"] = true,
6855 ["debug"] = true,
6856 ["math"] = true,
6857 ["os"] = true,
6858 ["string"] = true,
6859 ["table"] = true,
6860 ["bit32"] = true,
6861 ["utf8"] = true,
6862 ["Axes"] = true,
6863 ["BrickColor"] = true,
6864 ["CFrame"] = true,
6865 ["Color3"] = true,
6866 ["ColorSequence"] = true,
6867 ["ColorSequenceKeypoint"] = true,
6868 ["DockWidgetPluginGuiInfo"] = true,
6869 ["Enum"] = true,
6870 ["Faces"] = true,
6871 ["Instance"] = true,
6872 ["NumberRange"] = true,
6873 ["NumberSequence"] = true,
6874 ["NumberSequenceKeypoint"] = true,
6875 ["PathWaypoint"] = true,
6876 ["PhysicalProperties"] = true,
6877 ["Random"] = true,
6878 ["Ray"] = true,
6879 ["Rect"] = true,
6880 ["Region3"] = true,
6881 ["Region3int16"] = true,
6882 ["TweenInfo"] = true,
6883 ["UDim"] = true,
6884 ["UDim2"] = true,
6885 ["Vector2"] = true,
6886 ["Vector2int16"] = true,
6887 ["Vector3"] = true,
6888 ["Vector3int16"] = true
6889 }
6890
6891 local builtInInited = false
6892
6893 local richReplace = {
6894 ["'"] = "'",
6895 ["\""] = """,
6896 ["<"] = "<",
6897 [">"] = ">",
6898 ["&"] = "&"
6899 }
6900
6901 local tabSub = "\205"
6902 local tabReplacement = (" %s%s "):format(tabSub,tabSub)
6903
6904 local tabJumps = {
6905 [("[^%s] %s"):format(tabSub,tabSub)] = 0,
6906 [(" %s%s"):format(tabSub,tabSub)] = -1,
6907 [("%s%s "):format(tabSub,tabSub)] = 2,
6908 [("%s [^%s]"):format(tabSub,tabSub)] = 1,
6909 }
6910
6911 local tweenService = service.TweenService
6912 local lineTweens = {}
6913
6914 local function initBuiltIn()
6915 local env = getfenv()
6916 local type = type
6917 local tostring = tostring
6918 for name,_ in next,builtIns do
6919 local envVal = env[name]
6920 if type(envVal) == "table" then
6921 local items = {}
6922 for i,v in next,envVal do
6923 items[i] = true
6924 end
6925 builtIns[name] = items
6926 end
6927 end
6928
6929 local enumEntries = {}
6930 local enums = Enum:GetEnums()
6931 for i = 1,#enums do
6932 enumEntries[tostring(enums[i])] = true
6933 end
6934 builtIns["Enum"] = enumEntries
6935
6936 builtInInited = true
6937 end
6938
6939 local function setupEditBox(obj)
6940 local editBox = obj.GuiElems.EditBox
6941
6942 editBox.Focused:Connect(function()
6943 obj:ConnectEditBoxEvent()
6944 obj.Editing = true
6945 end)
6946
6947 editBox.FocusLost:Connect(function()
6948 obj:DisconnectEditBoxEvent()
6949 obj.Editing = false
6950 end)
6951
6952 editBox:GetPropertyChangedSignal("Text"):Connect(function()
6953 local text = editBox.Text
6954 if #text == 0 or obj.EditBoxCopying then return end
6955 editBox.Text = ""
6956 obj:AppendText(text)
6957 end)
6958 end
6959
6960 local function setupMouseSelection(obj)
6961 local mouse = plr:GetMouse()
6962 local codeFrame = obj.GuiElems.LinesFrame
6963 local lines = obj.Lines
6964
6965 codeFrame.InputBegan:Connect(function(input)
6966 if input.UserInputType == Enum.UserInputType.MouseButton1 then
6967 local fontSizeX,fontSizeY = math.ceil(obj.FontSize/2),obj.FontSize
6968
6969 local relX = mouse.X - codeFrame.AbsolutePosition.X
6970 local relY = mouse.Y - codeFrame.AbsolutePosition.Y
6971 local selX = math.round(relX / fontSizeX) + obj.ViewX
6972 local selY = math.floor(relY / fontSizeY) + obj.ViewY
6973 local releaseEvent,mouseEvent,scrollEvent
6974 local scrollPowerV,scrollPowerH = 0,0
6975 selY = math.min(#lines-1,selY)
6976 local relativeLine = lines[selY+1] or ""
6977 selX = math.min(#relativeLine, selX + obj:TabAdjust(selX,selY))
6978
6979 obj.SelectionRange = {{-1,-1},{-1,-1}}
6980 obj:MoveCursor(selX,selY)
6981 obj.FloatCursorX = selX
6982
6983 local function updateSelection()
6984 local relX = mouse.X - codeFrame.AbsolutePosition.X
6985 local relY = mouse.Y - codeFrame.AbsolutePosition.Y
6986 local sel2X = math.max(0,math.round(relX / fontSizeX) + obj.ViewX)
6987 local sel2Y = math.max(0,math.floor(relY / fontSizeY) + obj.ViewY)
6988
6989 sel2Y = math.min(#lines-1,sel2Y)
6990 local relativeLine = lines[sel2Y+1] or ""
6991 sel2X = math.min(#relativeLine, sel2X + obj:TabAdjust(sel2X,sel2Y))
6992
6993 if sel2Y < selY or (sel2Y == selY and sel2X < selX) then
6994 obj.SelectionRange = {{sel2X,sel2Y},{selX,selY}}
6995 else
6996 obj.SelectionRange = {{selX,selY},{sel2X,sel2Y}}
6997 end
6998
6999 obj:MoveCursor(sel2X,sel2Y)
7000 obj.FloatCursorX = sel2X
7001 obj:Refresh()
7002 end
7003
7004 releaseEvent = service.UserInputService.InputEnded:Connect(function(input)
7005 if input.UserInputType == Enum.UserInputType.MouseButton1 then
7006 releaseEvent:Disconnect()
7007 mouseEvent:Disconnect()
7008 scrollEvent:Disconnect()
7009 obj:SetCopyableSelection()
7010 --updateSelection()
7011 end
7012 end)
7013
7014 mouseEvent = service.UserInputService.InputChanged:Connect(function(input)
7015 if input.UserInputType == Enum.UserInputType.MouseMovement then
7016 local upDelta = mouse.Y - codeFrame.AbsolutePosition.Y
7017 local downDelta = mouse.Y - codeFrame.AbsolutePosition.Y - codeFrame.AbsoluteSize.Y
7018 local leftDelta = mouse.X - codeFrame.AbsolutePosition.X
7019 local rightDelta = mouse.X - codeFrame.AbsolutePosition.X - codeFrame.AbsoluteSize.X
7020 scrollPowerV = 0
7021 scrollPowerH = 0
7022 if downDelta > 0 then
7023 scrollPowerV = math.floor(downDelta*0.05) + 1
7024 elseif upDelta < 0 then
7025 scrollPowerV = math.ceil(upDelta*0.05) - 1
7026 end
7027 if rightDelta > 0 then
7028 scrollPowerH = math.floor(rightDelta*0.05) + 1
7029 elseif leftDelta < 0 then
7030 scrollPowerH = math.ceil(leftDelta*0.05) - 1
7031 end
7032 updateSelection()
7033 end
7034 end)
7035
7036 scrollEvent = clonerefs(game:GetService("RunService")).RenderStepped:Connect(function()
7037 if scrollPowerV ~= 0 or scrollPowerH ~= 0 then
7038 obj:ScrollDelta(scrollPowerH,scrollPowerV)
7039 updateSelection()
7040 end
7041 end)
7042
7043 obj:Refresh()
7044 end
7045 end)
7046 end
7047
7048 local function makeFrame(obj)
7049 local frame = create({
7050 {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),}},
7051 })
7052 local elems = {}
7053
7054 local linesFrame = Instance.new("Frame")
7055 linesFrame.Name = "Lines"
7056 linesFrame.BackgroundTransparency = 1
7057 linesFrame.Size = UDim2.new(1,0,1,0)
7058 linesFrame.ClipsDescendants = true
7059 linesFrame.Parent = frame
7060
7061 local lineNumbersLabel = Instance.new("TextLabel")
7062 lineNumbersLabel.Name = "LineNumbers"
7063 lineNumbersLabel.BackgroundTransparency = 1
7064 lineNumbersLabel.Font = Enum.Font.Code
7065 lineNumbersLabel.TextXAlignment = Enum.TextXAlignment.Right
7066 lineNumbersLabel.TextYAlignment = Enum.TextYAlignment.Top
7067 lineNumbersLabel.ClipsDescendants = true
7068 lineNumbersLabel.RichText = true
7069 lineNumbersLabel.Parent = frame
7070
7071 local cursor = Instance.new("Frame")
7072 cursor.Name = "Cursor"
7073 cursor.BackgroundColor3 = Color3.fromRGB(220,220,220)
7074 cursor.BorderSizePixel = 0
7075 cursor.Parent = frame
7076
7077 local editBox = Instance.new("TextBox")
7078 editBox.Name = "EditBox"
7079 editBox.MultiLine = true
7080 editBox.Visible = false
7081 editBox.Parent = frame
7082
7083 lineTweens.Invis = tweenService:Create(cursor,TweenInfo.new(0.4,Enum.EasingStyle.Quart,Enum.EasingDirection.Out),{BackgroundTransparency = 1})
7084 lineTweens.Vis = tweenService:Create(cursor,TweenInfo.new(0.2,Enum.EasingStyle.Quart,Enum.EasingDirection.Out),{BackgroundTransparency = 0})
7085
7086 elems.LinesFrame = linesFrame
7087 elems.LineNumbersLabel = lineNumbersLabel
7088 elems.Cursor = cursor
7089 elems.EditBox = editBox
7090 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,}}})
7091
7092 elems.ScrollCorner.Parent = frame
7093 linesFrame.InputBegan:Connect(function(input)
7094 if input.UserInputType == Enum.UserInputType.MouseButton1 then
7095 obj:SetEditing(true,input)
7096 end
7097 end)
7098
7099 obj.Frame = frame
7100 obj.Gui = frame
7101 obj.GuiElems = elems
7102 setupEditBox(obj)
7103 setupMouseSelection(obj)
7104
7105 return frame
7106 end
7107
7108 funcs.GetSelectionText = function(self)
7109 if not self:IsValidRange() then return "" end
7110
7111 local selectionRange = self.SelectionRange
7112 local selX,selY = selectionRange[1][1], selectionRange[1][2]
7113 local sel2X,sel2Y = selectionRange[2][1], selectionRange[2][2]
7114 local deltaLines = sel2Y-selY
7115 local lines = self.Lines
7116
7117 if not lines[selY+1] or not lines[sel2Y+1] then return "" end
7118
7119 if deltaLines == 0 then
7120 return self:ConvertText(lines[selY+1]:sub(selX+1,sel2X), false)
7121 end
7122
7123 local leftSub = lines[selY+1]:sub(selX+1)
7124 local rightSub = lines[sel2Y+1]:sub(1,sel2X)
7125
7126 local result = leftSub.."\n"
7127 for i = selY+1,sel2Y-1 do
7128 result = result..lines[i+1].."\n"
7129 end
7130 result = result..rightSub
7131
7132 return self:ConvertText(result,false)
7133 end
7134
7135 funcs.SetCopyableSelection = function(self)
7136 local text = self:GetSelectionText()
7137 local editBox = self.GuiElems.EditBox
7138
7139 self.EditBoxCopying = true
7140 editBox.Text = text
7141 editBox.SelectionStart = 1
7142 editBox.CursorPosition = #editBox.Text + 1
7143 self.EditBoxCopying = false
7144 end
7145
7146 funcs.ConnectEditBoxEvent = function(self)
7147 if self.EditBoxEvent then
7148 self.EditBoxEvent:Disconnect()
7149 end
7150
7151 self.EditBoxEvent = service.UserInputService.InputBegan:Connect(function(input)
7152 if input.UserInputType ~= Enum.UserInputType.Keyboard then return end
7153
7154 local keycodes = Enum.KeyCode
7155 local keycode = input.KeyCode
7156
7157 local function setupMove(key,func)
7158 local endCon,finished
7159 endCon = service.UserInputService.InputEnded:Connect(function(input)
7160 if input.KeyCode ~= key then return end
7161 endCon:Disconnect()
7162 finished = true
7163 end)
7164 func()
7165 Lib.FastWait(0.5)
7166 while not finished do func() Lib.FastWait(0.03) end
7167 end
7168
7169 if keycode == keycodes.Down then
7170 setupMove(keycodes.Down,function()
7171 self.CursorX = self.FloatCursorX
7172 self.CursorY = self.CursorY + 1
7173 self:UpdateCursor()
7174 self:JumpToCursor()
7175 end)
7176 elseif keycode == keycodes.Up then
7177 setupMove(keycodes.Up,function()
7178 self.CursorX = self.FloatCursorX
7179 self.CursorY = self.CursorY - 1
7180 self:UpdateCursor()
7181 self:JumpToCursor()
7182 end)
7183 elseif keycode == keycodes.Left then
7184 setupMove(keycodes.Left,function()
7185 local line = self.Lines[self.CursorY+1] or ""
7186 self.CursorX = self.CursorX - 1 - (line:sub(self.CursorX-3,self.CursorX) == tabReplacement and 3 or 0)
7187 if self.CursorX < 0 then
7188 self.CursorY = self.CursorY - 1
7189 local line2 = self.Lines[self.CursorY+1] or ""
7190 self.CursorX = #line2
7191 end
7192 self.FloatCursorX = self.CursorX
7193 self:UpdateCursor()
7194 self:JumpToCursor()
7195 end)
7196 elseif keycode == keycodes.Right then
7197 setupMove(keycodes.Right,function()
7198 local line = self.Lines[self.CursorY+1] or ""
7199 self.CursorX = self.CursorX + 1 + (line:sub(self.CursorX+1,self.CursorX+4) == tabReplacement and 3 or 0)
7200 if self.CursorX > #line then
7201 self.CursorY = self.CursorY + 1
7202 self.CursorX = 0
7203 end
7204 self.FloatCursorX = self.CursorX
7205 self:UpdateCursor()
7206 self:JumpToCursor()
7207 end)
7208 elseif keycode == keycodes.Backspace then
7209 setupMove(keycodes.Backspace,function()
7210 local startRange,endRange
7211 if self:IsValidRange() then
7212 startRange = self.SelectionRange[1]
7213 endRange = self.SelectionRange[2]
7214 else
7215 endRange = {self.CursorX,self.CursorY}
7216 end
7217
7218 if not startRange then
7219 local line = self.Lines[self.CursorY+1] or ""
7220 self.CursorX = self.CursorX - 1 - (line:sub(self.CursorX-3,self.CursorX) == tabReplacement and 3 or 0)
7221 if self.CursorX < 0 then
7222 self.CursorY = self.CursorY - 1
7223 local line2 = self.Lines[self.CursorY+1] or ""
7224 self.CursorX = #line2
7225 end
7226 self.FloatCursorX = self.CursorX
7227 self:UpdateCursor()
7228
7229 startRange = startRange or {self.CursorX,self.CursorY}
7230 end
7231
7232 self:DeleteRange({startRange,endRange},false,true)
7233 self:ResetSelection(true)
7234 self:JumpToCursor()
7235 end)
7236 elseif keycode == keycodes.Delete then
7237 setupMove(keycodes.Delete,function()
7238 local startRange,endRange
7239 if self:IsValidRange() then
7240 startRange = self.SelectionRange[1]
7241 endRange = self.SelectionRange[2]
7242 else
7243 startRange = {self.CursorX,self.CursorY}
7244 end
7245
7246 if not endRange then
7247 local line = self.Lines[self.CursorY+1] or ""
7248 local endCursorX = self.CursorX + 1 + (line:sub(self.CursorX+1,self.CursorX+4) == tabReplacement and 3 or 0)
7249 local endCursorY = self.CursorY
7250 if endCursorX > #line then
7251 endCursorY = endCursorY + 1
7252 endCursorX = 0
7253 end
7254 self:UpdateCursor()
7255
7256 endRange = endRange or {endCursorX,endCursorY}
7257 end
7258
7259 self:DeleteRange({startRange,endRange},false,true)
7260 self:ResetSelection(true)
7261 self:JumpToCursor()
7262 end)
7263 elseif service.UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) then
7264 if keycode == keycodes.A then
7265 self.SelectionRange = {{0,0},{#self.Lines[#self.Lines],#self.Lines-1}}
7266 self:SetCopyableSelection()
7267 self:Refresh()
7268 end
7269 end
7270 end)
7271 end
7272
7273 funcs.DisconnectEditBoxEvent = function(self)
7274 if self.EditBoxEvent then
7275 self.EditBoxEvent:Disconnect()
7276 end
7277 end
7278
7279 funcs.ResetSelection = function(self,norefresh)
7280 self.SelectionRange = {{-1,-1},{-1,-1}}
7281 if not norefresh then self:Refresh() end
7282 end
7283
7284 funcs.IsValidRange = function(self,range)
7285 local selectionRange = range or self.SelectionRange
7286 local selX,selY = selectionRange[1][1], selectionRange[1][2]
7287 local sel2X,sel2Y = selectionRange[2][1], selectionRange[2][2]
7288
7289 if selX == -1 or (selX == sel2X and selY == sel2Y) then return false end
7290
7291 return true
7292 end
7293
7294 funcs.DeleteRange = function(self,range,noprocess,updatemouse)
7295 range = range or self.SelectionRange
7296 if not self:IsValidRange(range) then return end
7297
7298 local lines = self.Lines
7299 local selX,selY = range[1][1], range[1][2]
7300 local sel2X,sel2Y = range[2][1], range[2][2]
7301 local deltaLines = sel2Y-selY
7302
7303 if not lines[selY+1] or not lines[sel2Y+1] then return end
7304
7305 local leftSub = lines[selY+1]:sub(1,selX)
7306 local rightSub = lines[sel2Y+1]:sub(sel2X+1)
7307 lines[selY+1] = leftSub..rightSub
7308
7309 local remove = table.remove
7310 for i = 1,deltaLines do
7311 remove(lines,selY+2)
7312 end
7313
7314 if range == self.SelectionRange then self.SelectionRange = {{-1,-1},{-1,-1}} end
7315 if updatemouse then
7316 self.CursorX = selX
7317 self.CursorY = selY
7318 self:UpdateCursor()
7319 end
7320
7321 if not noprocess then
7322 self:ProcessTextChange()
7323 end
7324 end
7325
7326 funcs.AppendText = function(self,text)
7327 self:DeleteRange(nil,true,true)
7328 local lines,cursorX,cursorY = self.Lines,self.CursorX,self.CursorY
7329 local line = lines[cursorY+1]
7330 local before = line:sub(1,cursorX)
7331 local after = line:sub(cursorX+1)
7332
7333 text = text:gsub("\r\n","\n")
7334 text = self:ConvertText(text,true) -- Tab Convert
7335
7336 local textLines = text:split("\n")
7337 local insert = table.insert
7338
7339 for i = 1,#textLines do
7340 local linePos = cursorY+i
7341 if i > 1 then insert(lines,linePos,"") end
7342
7343 local textLine = textLines[i]
7344 local newBefore = (i == 1 and before or "")
7345 local newAfter = (i == #textLines and after or "")
7346
7347 lines[linePos] = newBefore..textLine..newAfter
7348 end
7349
7350 if #textLines > 1 then cursorX = 0 end
7351
7352 self:ProcessTextChange()
7353 self.CursorX = cursorX + #textLines[#textLines]
7354 self.CursorY = cursorY + #textLines-1
7355 self:UpdateCursor()
7356 end
7357
7358 funcs.ScrollDelta = function(self,x,y)
7359 self.ScrollV:ScrollTo(self.ScrollV.Index + y)
7360 self.ScrollH:ScrollTo(self.ScrollH.Index + x)
7361 end
7362
7363 -- x and y starts at 0
7364 funcs.TabAdjust = function(self,x,y)
7365 local lines = self.Lines
7366 local line = lines[y+1]
7367 x=x+1
7368
7369 if line then
7370 local left = line:sub(x-1,x-1)
7371 local middle = line:sub(x,x)
7372 local right = line:sub(x+1,x+1)
7373 local selRange = (#left > 0 and left or " ") .. (#middle > 0 and middle or " ") .. (#right > 0 and right or " ")
7374
7375 for i,v in pairs(tabJumps) do
7376 if selRange:find(i) then
7377 return v
7378 end
7379 end
7380 end
7381 return 0
7382 end
7383
7384 funcs.SetEditing = function(self,on,input)
7385 self:UpdateCursor(input)
7386
7387 if on then
7388 if self.Editable then
7389 self.GuiElems.EditBox.Text = ""
7390 self.GuiElems.EditBox:CaptureFocus()
7391 end
7392 else
7393 self.GuiElems.EditBox:ReleaseFocus()
7394 end
7395 end
7396
7397 funcs.CursorAnim = function(self,on)
7398 local cursor = self.GuiElems.Cursor
7399 local animTime = tick()
7400 self.LastAnimTime = animTime
7401
7402 if not on then return end
7403
7404 lineTweens.Invis:Cancel()
7405 lineTweens.Vis:Cancel()
7406 cursor.BackgroundTransparency = 0
7407
7408 coroutine.wrap(function()
7409 while self.Editable do
7410 Lib.FastWait(0.5)
7411 if self.LastAnimTime ~= animTime then return end
7412 lineTweens.Invis:Play()
7413 Lib.FastWait(0.4)
7414 if self.LastAnimTime ~= animTime then return end
7415 lineTweens.Vis:Play()
7416 Lib.FastWait(0.2)
7417 end
7418 end)()
7419 end
7420
7421 funcs.MoveCursor = function(self,x,y)
7422 self.CursorX = x
7423 self.CursorY = y
7424 self:UpdateCursor()
7425 self:JumpToCursor()
7426 end
7427
7428 funcs.JumpToCursor = function(self)
7429 self:Refresh()
7430 end
7431
7432 funcs.UpdateCursor = function(self,input)
7433 local linesFrame = self.GuiElems.LinesFrame
7434 local cursor = self.GuiElems.Cursor
7435 local hSize = math.max(0,linesFrame.AbsoluteSize.X)
7436 local vSize = math.max(0,linesFrame.AbsoluteSize.Y)
7437 local maxLines = math.ceil(vSize / self.FontSize)
7438 local maxCols = math.ceil(hSize / math.ceil(self.FontSize/2))
7439 local viewX,viewY = self.ViewX,self.ViewY
7440 local totalLinesStr = tostring(#self.Lines)
7441 local fontWidth = math.ceil(self.FontSize / 2)
7442 local linesOffset = #totalLinesStr*fontWidth + 4*fontWidth
7443
7444 if input then
7445 local linesFrame = self.GuiElems.LinesFrame
7446 local frameX,frameY = linesFrame.AbsolutePosition.X,linesFrame.AbsolutePosition.Y
7447 local mouseX,mouseY = input.Position.X,input.Position.Y
7448 local fontSizeX,fontSizeY = math.ceil(self.FontSize/2),self.FontSize
7449
7450 self.CursorX = self.ViewX + math.round((mouseX - frameX) / fontSizeX)
7451 self.CursorY = self.ViewY + math.floor((mouseY - frameY) / fontSizeY)
7452 end
7453
7454 local cursorX,cursorY = self.CursorX,self.CursorY
7455
7456 local line = self.Lines[cursorY+1] or ""
7457 if cursorX > #line then cursorX = #line
7458 elseif cursorX < 0 then cursorX = 0 end
7459
7460 if cursorY >= #self.Lines then
7461 cursorY = math.max(0,#self.Lines-1)
7462 elseif cursorY < 0 then
7463 cursorY = 0
7464 end
7465
7466 cursorX = cursorX + self:TabAdjust(cursorX,cursorY)
7467
7468 -- Update modified
7469 self.CursorX = cursorX
7470 self.CursorY = cursorY
7471
7472 local cursorVisible = (cursorX >= viewX) and (cursorY >= viewY) and (cursorX <= viewX + maxCols) and (cursorY <= viewY + maxLines)
7473 if cursorVisible then
7474 local offX = (cursorX - viewX)
7475 local offY = (cursorY - viewY)
7476 cursor.Position = UDim2.new(0,linesOffset + offX*math.ceil(self.FontSize/2) - 1,0,offY*self.FontSize)
7477 cursor.Size = UDim2.new(0,1,0,self.FontSize+2)
7478 cursor.Visible = true
7479 self:CursorAnim(true)
7480 else
7481 cursor.Visible = false
7482 end
7483 end
7484
7485 funcs.MapNewLines = function(self)
7486 local newLines = {}
7487 local count = 1
7488 local text = self.Text
7489 local find = string.find
7490 local init = 1
7491
7492 local pos = find(text,"\n",init,true)
7493 while pos do
7494 newLines[count] = pos
7495 count = count + 1
7496 init = pos + 1
7497 pos = find(text,"\n",init,true)
7498 end
7499
7500 self.NewLines = newLines
7501 end
7502
7503 funcs.PreHighlight = function(self)
7504 local start = tick()
7505 local text = self.Text:gsub("\\\\"," ")
7506 --print("BACKSLASH SUB",tick()-start)
7507 local textLen = #text
7508 local found = {}
7509 local foundMap = {}
7510 local extras = {}
7511 local find = string.find
7512 local sub = string.sub
7513 self.ColoredLines = {}
7514
7515 local function findAll(str,pattern,typ,raw)
7516 local count = #found+1
7517 local init = 1
7518 local x,y,extra = find(str,pattern,init,raw)
7519 while x do
7520 found[count] = x
7521 foundMap[x] = typ
7522 if extra then
7523 extras[x] = extra
7524 end
7525
7526 count = count+1
7527 init = y+1
7528 x,y,extra = find(str,pattern,init,raw)
7529 end
7530 end
7531 local start = tick()
7532 findAll(text,'"',1,true)
7533 findAll(text,"'",2,true)
7534 findAll(text,"%[(=*)%[",3)
7535 findAll(text,"--",4,true)
7536 table.sort(found)
7537
7538 local newLines = self.NewLines
7539 local curLine = 0
7540 local lineTableCount = 1
7541 local lineStart = 0
7542 local lineEnd = 0
7543 local lastEnding = 0
7544 local foundHighlights = {}
7545
7546 for i = 1,#found do
7547 local pos = found[i]
7548 if pos <= lastEnding then continue end
7549
7550 local ending = pos
7551 local typ = foundMap[pos]
7552 if typ == 1 then
7553 ending = find(text,'"',pos+1,true)
7554 while ending and sub(text,ending-1,ending-1) == "\\" do
7555 ending = find(text,'"',ending+1,true)
7556 end
7557 if not ending then ending = textLen end
7558 elseif typ == 2 then
7559 ending = find(text,"'",pos+1,true)
7560 while ending and sub(text,ending-1,ending-1) == "\\" do
7561 ending = find(text,"'",ending+1,true)
7562 end
7563 if not ending then ending = textLen end
7564 elseif typ == 3 then
7565 _,ending = find(text,"]"..extras[pos].."]",pos+1,true)
7566 if not ending then ending = textLen end
7567 elseif typ == 4 then
7568 local ahead = foundMap[pos+2]
7569
7570 if ahead == 3 then
7571 _,ending = find(text,"]"..extras[pos+2].."]",pos+1,true)
7572 if not ending then ending = textLen end
7573 else
7574 ending = find(text,"\n",pos+1,true) or textLen
7575 end
7576 end
7577
7578 while pos > lineEnd do
7579 curLine = curLine + 1
7580 --lineTableCount = 1
7581 lineEnd = newLines[curLine] or textLen+1
7582 end
7583 while true do
7584 local lineTable = foundHighlights[curLine]
7585 if not lineTable then lineTable = {} foundHighlights[curLine] = lineTable end
7586 lineTable[pos] = {typ,ending}
7587 --lineTableCount = lineTableCount + 1
7588
7589 if ending > lineEnd then
7590 curLine = curLine + 1
7591 lineEnd = newLines[curLine] or textLen+1
7592 else
7593 break
7594 end
7595 end
7596
7597 lastEnding = ending
7598 --if i < 200 then print(curLine) end
7599 end
7600 self.PreHighlights = foundHighlights
7601 --print(tick()-start)
7602 --print(#found,curLine)
7603 end
7604
7605 funcs.HighlightLine = function(self,line)
7606 local cached = self.ColoredLines[line]
7607 if cached then return cached end
7608
7609 local sub = string.sub
7610 local find = string.find
7611 local match = string.match
7612 local highlights = {}
7613 local preHighlights = self.PreHighlights[line] or {}
7614 local lineText = self.Lines[line] or ""
7615 local lineLen = #lineText
7616 local lastEnding = 0
7617 local currentType = 0
7618 local lastWord = nil
7619 local wordBeginsDotted = false
7620 local funcStatus = 0
7621 local lineStart = self.NewLines[line-1] or 0
7622
7623 local preHighlightMap = {}
7624 for pos,data in next,preHighlights do
7625 local relativePos = pos-lineStart
7626 if relativePos < 1 then
7627 currentType = data[1]
7628 lastEnding = data[2] - lineStart
7629 --warn(pos,data[2])
7630 else
7631 preHighlightMap[relativePos] = {data[1],data[2]-lineStart}
7632 end
7633 end
7634
7635 for col = 1,#lineText do
7636 if col <= lastEnding then highlights[col] = currentType continue end
7637
7638 local pre = preHighlightMap[col]
7639 if pre then
7640 currentType = pre[1]
7641 lastEnding = pre[2]
7642 highlights[col] = currentType
7643 wordBeginsDotted = false
7644 lastWord = nil
7645 funcStatus = 0
7646 else
7647 local char = sub(lineText,col,col)
7648 if find(char,"[%a_]") then
7649 local word = match(lineText,"[%a%d_]+",col)
7650 local wordType = (keywords[word] and 7) or (builtIns[word] and 8)
7651
7652 lastEnding = col+#word-1
7653
7654 if wordType ~= 7 then
7655 if wordBeginsDotted then
7656 local prevBuiltIn = lastWord and builtIns[lastWord]
7657 wordType = (prevBuiltIn and type(prevBuiltIn) == "table" and prevBuiltIn[word] and 8) or 10
7658 end
7659
7660 if wordType ~= 8 then
7661 local x,y,br = find(lineText,"^%s*([%({\"'])",lastEnding+1)
7662 if x then
7663 wordType = (funcStatus > 0 and br == "(" and 16) or 9
7664 funcStatus = 0
7665 end
7666 end
7667 else
7668 wordType = specialKeywordsTypes[word] or wordType
7669 funcStatus = (word == "function" and 1 or 0)
7670 end
7671
7672 lastWord = word
7673 wordBeginsDotted = false
7674 if funcStatus > 0 then funcStatus = 1 end
7675
7676 if wordType then
7677 currentType = wordType
7678 highlights[col] = currentType
7679 else
7680 currentType = nil
7681 end
7682 elseif find(char,"%p") then
7683 local isDot = (char == ".")
7684 local isNum = isDot and find(sub(lineText,col+1,col+1),"%d")
7685 highlights[col] = (isNum and 6 or 5)
7686
7687 if not isNum then
7688 local dotStr = isDot and match(lineText,"%.%.?%.?",col)
7689 if dotStr and #dotStr > 1 then
7690 currentType = 5
7691 lastEnding = col+#dotStr-1
7692 wordBeginsDotted = false
7693 lastWord = nil
7694 funcStatus = 0
7695 else
7696 if isDot then
7697 if wordBeginsDotted then
7698 lastWord = nil
7699 else
7700 wordBeginsDotted = true
7701 end
7702 else
7703 wordBeginsDotted = false
7704 lastWord = nil
7705 end
7706
7707 funcStatus = ((isDot or char == ":") and funcStatus == 1 and 2) or 0
7708 end
7709 end
7710 elseif find(char,"%d") then
7711 local _,endPos = find(lineText,"%x+",col)
7712 local endPart = sub(lineText,endPos,endPos+1)
7713 if (endPart == "e+" or endPart == "e-") and find(sub(lineText,endPos+2,endPos+2),"%d") then
7714 endPos = endPos + 1
7715 end
7716 currentType = 6
7717 lastEnding = endPos
7718 highlights[col] = 6
7719 wordBeginsDotted = false
7720 lastWord = nil
7721 funcStatus = 0
7722 else
7723 highlights[col] = currentType
7724 local _,endPos = find(lineText,"%s+",col)
7725 if endPos then
7726 lastEnding = endPos
7727 end
7728 end
7729 end
7730 end
7731
7732 self.ColoredLines[line] = highlights
7733 return highlights
7734 end
7735
7736 funcs.Refresh = function(self)
7737 local start = tick()
7738
7739 local linesFrame = self.Frame.Lines
7740 local hSize = math.max(0,linesFrame.AbsoluteSize.X)
7741 local vSize = math.max(0,linesFrame.AbsoluteSize.Y)
7742 local maxLines = math.ceil(vSize / self.FontSize)
7743 local maxCols = math.ceil(hSize / math.ceil(self.FontSize/2))
7744 local gsub = string.gsub
7745 local sub = string.sub
7746
7747 local viewX,viewY = self.ViewX,self.ViewY
7748
7749 local lineNumberStr = ""
7750
7751 for row = 1,maxLines do
7752 local lineFrame = self.LineFrames[row]
7753 if not lineFrame then
7754 lineFrame = Instance.new("Frame")
7755 lineFrame.Name = "Line"
7756 lineFrame.Position = UDim2.new(0,0,0,(row-1)*self.FontSize)
7757 lineFrame.Size = UDim2.new(1,0,0,self.FontSize)
7758 lineFrame.BorderSizePixel = 0
7759 lineFrame.BackgroundTransparency = 1
7760
7761 local selectionHighlight = Instance.new("Frame")
7762 selectionHighlight.Name = "SelectionHighlight"
7763 selectionHighlight.BorderSizePixel = 0
7764 selectionHighlight.BackgroundColor3 = Settings.Theme.Syntax.SelectionBack
7765 selectionHighlight.Parent = lineFrame
7766
7767 local label = Instance.new("TextLabel")
7768 label.Name = "Label"
7769 label.BackgroundTransparency = 1
7770 label.Font = Enum.Font.Code
7771 label.TextSize = self.FontSize
7772 label.Size = UDim2.new(1,0,0,self.FontSize)
7773 label.RichText = true
7774 label.TextXAlignment = Enum.TextXAlignment.Left
7775 label.TextColor3 = self.Colors.Text
7776 label.ZIndex = 2
7777 label.Parent = lineFrame
7778
7779 lineFrame.Parent = linesFrame
7780 self.LineFrames[row] = lineFrame
7781 end
7782
7783 local relaY = viewY + row
7784 local lineText = self.Lines[relaY] or ""
7785 local resText = ""
7786 local highlights = self:HighlightLine(relaY)
7787 local colStart = viewX + 1
7788
7789 local richTemplates = self.RichTemplates
7790 local textTemplate = richTemplates.Text
7791 local selectionTemplate = richTemplates.Selection
7792 local curType = highlights[colStart]
7793 local curTemplate = richTemplates[typeMap[curType]] or textTemplate
7794
7795 -- Selection Highlight
7796 local selectionRange = self.SelectionRange
7797 local selPos1 = selectionRange[1]
7798 local selPos2 = selectionRange[2]
7799 local selRow,selColumn = selPos1[2],selPos1[1]
7800 local sel2Row,sel2Column = selPos2[2],selPos2[1]
7801 local selRelaX,selRelaY = viewX,relaY-1
7802
7803 if selRelaY >= selPos1[2] and selRelaY <= selPos2[2] then
7804 local fontSizeX = math.ceil(self.FontSize/2)
7805 local posX = (selRelaY == selPos1[2] and selPos1[1] or 0) - viewX
7806 local sizeX = (selRelaY == selPos2[2] and selPos2[1]-posX-viewX or maxCols+viewX)
7807
7808 lineFrame.SelectionHighlight.Position = UDim2.new(0,posX*fontSizeX,0,0)
7809 lineFrame.SelectionHighlight.Size = UDim2.new(0,sizeX*fontSizeX,1,0)
7810 lineFrame.SelectionHighlight.Visible = true
7811 else
7812 lineFrame.SelectionHighlight.Visible = false
7813 end
7814
7815 -- Selection Text Color for first char
7816 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)
7817 if inSelection then
7818 curType = -999
7819 curTemplate = selectionTemplate
7820 end
7821
7822 for col = 2,maxCols do
7823 local relaX = viewX + col
7824 local selRelaX = relaX-1
7825 local posType = highlights[relaX]
7826
7827 -- Selection Text Color
7828 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)
7829 if inSelection then
7830 posType = -999
7831 end
7832
7833 if posType ~= curType then
7834 local template = (inSelection and selectionTemplate) or richTemplates[typeMap[posType]] or textTemplate
7835
7836 if template ~= curTemplate then
7837 local nextText = gsub(sub(lineText,colStart,relaX-1),"['\"<>&]",richReplace)
7838 resText = resText .. (curTemplate ~= textTemplate and (curTemplate .. nextText .. "</font>") or nextText)
7839 colStart = relaX
7840 curTemplate = template
7841 end
7842 curType = posType
7843 end
7844 end
7845
7846 local lastText = gsub(sub(lineText,colStart,viewX+maxCols),"['\"<>&]",richReplace)
7847 --warn("SUB",colStart,viewX+maxCols-1)
7848 if #lastText > 0 then
7849 resText = resText .. (curTemplate ~= textTemplate and (curTemplate .. lastText .. "</font>") or lastText)
7850 end
7851
7852 if self.Lines[relaY] then
7853 lineNumberStr = lineNumberStr .. (relaY == self.CursorY and ("<b>"..relaY.."</b>\n") or relaY .. "\n")
7854 end
7855
7856 lineFrame.Label.Text = resText
7857 end
7858
7859 for i = maxLines+1,#self.LineFrames do
7860 self.LineFrames[i]:Destroy()
7861 self.LineFrames[i] = nil
7862 end
7863
7864 self.Frame.LineNumbers.Text = lineNumberStr
7865 self:UpdateCursor()
7866
7867 --print("REFRESH TIME",tick()-start)
7868 end
7869
7870 funcs.UpdateView = function(self)
7871 local totalLinesStr = tostring(#self.Lines)
7872 local fontWidth = math.ceil(self.FontSize / 2)
7873 local linesOffset = #totalLinesStr*fontWidth + 4*fontWidth
7874
7875 local linesFrame = self.Frame.Lines
7876 local hSize = linesFrame.AbsoluteSize.X
7877 local vSize = linesFrame.AbsoluteSize.Y
7878 local maxLines = math.ceil(vSize / self.FontSize)
7879 local totalWidth = self.MaxTextCols*fontWidth
7880 local scrollV = self.ScrollV
7881 local scrollH = self.ScrollH
7882
7883 scrollV.VisibleSpace = maxLines
7884 scrollV.TotalSpace = #self.Lines + 1
7885 scrollH.VisibleSpace = math.ceil(hSize/fontWidth)
7886 scrollH.TotalSpace = self.MaxTextCols + 1
7887
7888 scrollV.Gui.Visible = #self.Lines + 1 > maxLines
7889 scrollH.Gui.Visible = totalWidth > hSize
7890
7891 local oldOffsets = self.FrameOffsets
7892 self.FrameOffsets = Vector2.new(scrollV.Gui.Visible and -16 or 0, scrollH.Gui.Visible and -16 or 0)
7893 if oldOffsets ~= self.FrameOffsets then
7894 self:UpdateView()
7895 else
7896 scrollV:ScrollTo(self.ViewY,true)
7897 scrollH:ScrollTo(self.ViewX,true)
7898
7899 if scrollV.Gui.Visible and scrollH.Gui.Visible then
7900 scrollV.Gui.Size = UDim2.new(0,16,1,-16)
7901 scrollH.Gui.Size = UDim2.new(1,-16,0,16)
7902 self.GuiElems.ScrollCorner.Visible = true
7903 else
7904 scrollV.Gui.Size = UDim2.new(0,16,1,0)
7905 scrollH.Gui.Size = UDim2.new(1,0,0,16)
7906 self.GuiElems.ScrollCorner.Visible = false
7907 end
7908
7909 self.ViewY = scrollV.Index
7910 self.ViewX = scrollH.Index
7911 self.Frame.Lines.Position = UDim2.new(0,linesOffset,0,0)
7912 self.Frame.Lines.Size = UDim2.new(1,-linesOffset+oldOffsets.X,1,oldOffsets.Y)
7913 self.Frame.LineNumbers.Position = UDim2.new(0,fontWidth,0,0)
7914 self.Frame.LineNumbers.Size = UDim2.new(0,#totalLinesStr*fontWidth,1,oldOffsets.Y)
7915 self.Frame.LineNumbers.TextSize = self.FontSize
7916 end
7917 end
7918
7919 funcs.ProcessTextChange = function(self)
7920 local maxCols = 0
7921 local lines = self.Lines
7922
7923 for i = 1,#lines do
7924 local lineLen = #lines[i]
7925 if lineLen > maxCols then
7926 maxCols = lineLen
7927 end
7928 end
7929
7930 self.MaxTextCols = maxCols
7931 self:UpdateView()
7932 self.Text = table.concat(self.Lines,"\n")
7933 self:MapNewLines()
7934 self:PreHighlight()
7935 self:Refresh()
7936 --self.TextChanged:Fire()
7937 end
7938
7939 funcs.ConvertText = function(self,text,toEditor)
7940 if toEditor then
7941 return text:gsub("\t",(" %s%s "):format(tabSub,tabSub))
7942 else
7943 return text:gsub((" %s%s "):format(tabSub,tabSub),"\t")
7944 end
7945 end
7946
7947 funcs.GetText = function(self) -- TODO: better (use new tab format)
7948 local source = table.concat(self.Lines,"\n")
7949 return self:ConvertText(source,false) -- Tab Convert
7950 end
7951
7952 funcs.SetText = function(self,txt)
7953 txt = self:ConvertText(txt,true) -- Tab Convert
7954 local lines = self.Lines
7955 table.clear(lines)
7956 local count = 1
7957
7958 for line in txt:gmatch("([^\n\r]*)[\n\r]?") do
7959 local len = #line
7960 lines[count] = line
7961 count = count + 1
7962 end
7963
7964 self:ProcessTextChange()
7965 end
7966
7967 funcs.MakeRichTemplates = function(self)
7968 local floor = math.floor
7969 local templates = {}
7970
7971 for name,color in pairs(self.Colors) do
7972 templates[name] = ('<font color="rgb(%s,%s,%s)">'):format(floor(color.r*255),floor(color.g*255),floor(color.b*255))
7973 end
7974
7975 self.RichTemplates = templates
7976 end
7977
7978 funcs.ApplyTheme = function(self)
7979 local colors = Settings.Theme.Syntax
7980 self.Colors = colors
7981 self.Frame.LineNumbers.TextColor3 = colors.Text
7982 self.Frame.BackgroundColor3 = colors.Background
7983 end
7984
7985 local mt = {__index = funcs}
7986
7987 local function new()
7988 if not builtInInited then initBuiltIn() end
7989
7990 local scrollV = Lib.ScrollBar.new()
7991 local scrollH = Lib.ScrollBar.new(true)
7992 scrollH.Gui.Position = UDim2.new(0,0,1,-16)
7993 local obj = setmetatable({
7994 FontSize = 15,
7995 ViewX = 0,
7996 ViewY = 0,
7997 Colors = Settings.Theme.Syntax,
7998 ColoredLines = {},
7999 Lines = {""},
8000 LineFrames = {},
8001 Editable = true,
8002 Editing = false,
8003 CursorX = 0,
8004 CursorY = 0,
8005 FloatCursorX = 0,
8006 Text = "",
8007 PreHighlights = {},
8008 SelectionRange = {{-1,-1},{-1,-1}},
8009 NewLines = {},
8010 FrameOffsets = Vector2.new(0,0),
8011 MaxTextCols = 0,
8012 ScrollV = scrollV,
8013 ScrollH = scrollH
8014 },mt)
8015
8016 scrollV.WheelIncrement = 3
8017 scrollH.Increment = 2
8018 scrollH.WheelIncrement = 7
8019
8020 scrollV.Scrolled:Connect(function()
8021 obj.ViewY = scrollV.Index
8022 obj:Refresh()
8023 end)
8024
8025 scrollH.Scrolled:Connect(function()
8026 obj.ViewX = scrollH.Index
8027 obj:Refresh()
8028 end)
8029
8030 makeFrame(obj)
8031 obj:MakeRichTemplates()
8032 obj:ApplyTheme()
8033 scrollV:SetScrollFrame(obj.Frame.Lines)
8034 scrollV.Gui.Parent = obj.Frame
8035 scrollH.Gui.Parent = obj.Frame
8036
8037 obj:UpdateView()
8038 obj.Frame:GetPropertyChangedSignal("AbsoluteSize"):Connect(function()
8039 obj:UpdateView()
8040 obj:Refresh()
8041 end)
8042
8043 return obj
8044 end
8045
8046 return {new = new}
8047 end)()
8048
8049 Lib.Checkbox = (function()
8050 local funcs = {}
8051 local c3 = Color3.fromRGB
8052 local v2 = Vector2.new
8053 local ud2s = UDim2.fromScale
8054 local ud2o = UDim2.fromOffset
8055 local ud = UDim.new
8056 local max = math.max
8057 local new = Instance.new
8058 local TweenSize = new("Frame").TweenSize
8059 local ti = TweenInfo.new
8060 local delay = delay
8061
8062 local function ripple(object, color)
8063 local circle = new('Frame')
8064 circle.BackgroundColor3 = color
8065 circle.BackgroundTransparency = 0.75
8066 circle.BorderSizePixel = 0
8067 circle.AnchorPoint = v2(0.5, 0.5)
8068 circle.Size = ud2o()
8069 circle.Position = ud2s(0.5, 0.5)
8070 circle.Parent = object
8071 local rounding = new('UICorner')
8072 rounding.CornerRadius = ud(1)
8073 rounding.Parent = circle
8074
8075 local abssz = object.AbsoluteSize
8076 local size = max(abssz.X, abssz.Y) * 5/3
8077
8078 TweenSize(circle, ud2o(size, size), "Out", "Quart", 0.4)
8079 service.TweenService:Create(circle, ti(0.4, Enum.EasingStyle.Quart, Enum.EasingDirection.In), {BackgroundTransparency = 1}):Play()
8080
8081 service.Debris:AddItem(circle, 0.4)
8082 end
8083
8084 local function initGui(self,frame)
8085 local checkbox = frame or create({
8086 {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),}},
8087 {2,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,BorderSizePixel=0,Name="ripples",Parent={1},Size=UDim2.new(1,0,1,0),}},
8088 {3,"Frame",{BackgroundColor3=Color3.new(0.10196078568697,0.10196078568697,0.10196078568697),BorderSizePixel=0,Name="outline",Parent={1},Size=UDim2.new(0,16,0,16),}},
8089 {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),}},
8090 {5,"Frame",{BackgroundColor3=Color3.new(0.90196084976196,0.90196084976196,0.90196084976196),BorderSizePixel=0,Name="top",Parent={4},Size=UDim2.new(0,16,0,0),}},
8091 {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),}},
8092 {7,"Frame",{BackgroundColor3=Color3.new(0.90196084976196,0.90196084976196,0.90196084976196),BorderSizePixel=0,Name="left",Parent={4},Size=UDim2.new(0,0,0,16),}},
8093 {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),}},
8094 {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),}},
8095 {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),}},
8096 {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,}},
8097 {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,}},
8098 {13,"UICorner",{CornerRadius=UDim.new(0,2),Parent={3},}},
8099 })
8100 local outline = checkbox.outline
8101 local filler = outline.filler
8102 local checkmark = filler.checkmark
8103 local ripples_container = checkbox.ripples
8104
8105 -- walls
8106 local top, bottom, left, right = filler.top, filler.bottom, filler.left, filler.right
8107
8108 self.Gui = checkbox
8109 self.GuiElems = {
8110 Top = top,
8111 Bottom = bottom,
8112 Left = left,
8113 Right = right,
8114 Outline = outline,
8115 Filler = filler,
8116 Checkmark = checkmark,
8117 Checkmark2 = filler.checkmark2,
8118 Middle = filler.middle
8119 }
8120
8121 checkbox.InputBegan:Connect(function(i)
8122 if i.UserInputType == Enum.UserInputType.MouseButton1 then
8123 local release
8124 release = service.UserInputService.InputEnded:Connect(function(input)
8125 if input.UserInputType == Enum.UserInputType.MouseButton1 then
8126 release:Disconnect()
8127
8128 if Lib.CheckMouseInGui(checkbox) then
8129 if self.Style == 0 then
8130 ripple(ripples_container, self.Disabled and self.Colors.Disabled or self.Colors.Primary)
8131 end
8132
8133 if not self.Disabled then
8134 self:SetState(not self.Toggled,true)
8135 else
8136 self:Paint()
8137 end
8138
8139 self.OnInput:Fire()
8140 end
8141 end
8142 end)
8143 end
8144 end)
8145
8146 self:Paint()
8147 end
8148
8149 funcs.Collapse = function(self,anim)
8150 local guiElems = self.GuiElems
8151 if anim then
8152 TweenSize(guiElems.Top, ud2o(14, 14), "In", "Quart", 4/15, true)
8153 TweenSize(guiElems.Bottom, ud2o(14, 14), "In", "Quart", 4/15, true)
8154 TweenSize(guiElems.Left, ud2o(14, 14), "In", "Quart", 4/15, true)
8155 TweenSize(guiElems.Right, ud2o(14, 14), "In", "Quart", 4/15, true)
8156 else
8157 guiElems.Top.Size = ud2o(14, 14)
8158 guiElems.Bottom.Size = ud2o(14, 14)
8159 guiElems.Left.Size = ud2o(14, 14)
8160 guiElems.Right.Size = ud2o(14, 14)
8161 end
8162 end
8163
8164 funcs.Expand = function(self,anim)
8165 local guiElems = self.GuiElems
8166 if anim then
8167 TweenSize(guiElems.Top, ud2o(14, 0), "InOut", "Quart", 4/15, true)
8168 TweenSize(guiElems.Bottom, ud2o(14, 0), "InOut", "Quart", 4/15, true)
8169 TweenSize(guiElems.Left, ud2o(0, 14), "InOut", "Quart", 4/15, true)
8170 TweenSize(guiElems.Right, ud2o(0, 14), "InOut", "Quart", 4/15, true)
8171 else
8172 guiElems.Top.Size = ud2o(14, 0)
8173 guiElems.Bottom.Size = ud2o(14, 0)
8174 guiElems.Left.Size = ud2o(0, 14)
8175 guiElems.Right.Size = ud2o(0, 14)
8176 end
8177 end
8178
8179 funcs.Paint = function(self)
8180 local guiElems = self.GuiElems
8181
8182 if self.Style == 0 then
8183 local color_base = self.Disabled and self.Colors.Disabled
8184 guiElems.Outline.BackgroundColor3 = color_base or (self.Toggled and self.Colors.Primary) or self.Colors.Secondary
8185 local walls_color = color_base or self.Colors.Primary
8186 guiElems.Top.BackgroundColor3 = walls_color
8187 guiElems.Bottom.BackgroundColor3 = walls_color
8188 guiElems.Left.BackgroundColor3 = walls_color
8189 guiElems.Right.BackgroundColor3 = walls_color
8190 else
8191 guiElems.Outline.BackgroundColor3 = self.Disabled and self.Colors.Disabled or self.Colors.Secondary
8192 guiElems.Filler.BackgroundColor3 = self.Disabled and self.Colors.DisabledBackground or self.Colors.Background
8193 guiElems.Checkmark2.ImageColor3 = self.Disabled and self.Colors.DisabledCheck or self.Colors.Primary
8194 end
8195 end
8196
8197 funcs.SetState = function(self,val,anim)
8198 self.Toggled = val
8199
8200 if self.OutlineColorTween then self.OutlineColorTween:Cancel() end
8201 local setStateTime = tick()
8202 self.LastSetStateTime = setStateTime
8203
8204 if self.Toggled then
8205 if self.Style == 0 then
8206 if anim then
8207 self.OutlineColorTween = service.TweenService:Create(self.GuiElems.Outline, ti(4/15, Enum.EasingStyle.Circular, Enum.EasingDirection.Out), {BackgroundColor3 = self.Colors.Primary})
8208 self.OutlineColorTween:Play()
8209 delay(0.15, function()
8210 if setStateTime ~= self.LastSetStateTime then return end
8211 self:Paint()
8212 TweenSize(self.GuiElems.Checkmark, ud2o(14, 20), "Out", "Bounce", 2/15, true)
8213 end)
8214 else
8215 self.GuiElems.Outline.BackgroundColor3 = self.Colors.Primary
8216 self:Paint()
8217 self.GuiElems.Checkmark.Size = ud2o(14, 20)
8218 end
8219 self:Collapse(anim)
8220 else
8221 self:Paint()
8222 self.GuiElems.Checkmark2.Visible = true
8223 self.GuiElems.Middle.Visible = false
8224 end
8225 else
8226 if self.Style == 0 then
8227 if anim then
8228 self.OutlineColorTween = service.TweenService:Create(self.GuiElems.Outline, ti(4/15, Enum.EasingStyle.Circular, Enum.EasingDirection.In), {BackgroundColor3 = self.Colors.Secondary})
8229 self.OutlineColorTween:Play()
8230 delay(0.15, function()
8231 if setStateTime ~= self.LastSetStateTime then return end
8232 self:Paint()
8233 TweenSize(self.GuiElems.Checkmark, ud2o(0, 20), "Out", "Quad", 1/15, true)
8234 end)
8235 else
8236 self.GuiElems.Outline.BackgroundColor3 = self.Colors.Secondary
8237 self:Paint()
8238 self.GuiElems.Checkmark.Size = ud2o(0, 20)
8239 end
8240 self:Expand(anim)
8241 else
8242 self:Paint()
8243 self.GuiElems.Checkmark2.Visible = false
8244 self.GuiElems.Middle.Visible = self.Toggled == nil
8245 end
8246 end
8247 end
8248
8249 local mt = {__index = funcs}
8250
8251 local function new(style)
8252 local obj = setmetatable({
8253 Toggled = false,
8254 Disabled = false,
8255 OnInput = Lib.Signal.new(),
8256 Style = style or 0,
8257 Colors = {
8258 Background = c3(36,36,36),
8259 Primary = c3(49,176,230),
8260 Secondary = c3(25,25,25),
8261 Disabled = c3(64,64,64),
8262 DisabledBackground = c3(52,52,52),
8263 DisabledCheck = c3(80,80,80)
8264 }
8265 },mt)
8266 initGui(obj)
8267 return obj
8268 end
8269
8270 local function fromFrame(frame)
8271 local obj = setmetatable({
8272 Toggled = false,
8273 Disabled = false,
8274 Colors = {
8275 Background = c3(36,36,36),
8276 Primary = c3(49,176,230),
8277 Secondary = c3(25,25,25),
8278 Disabled = c3(64,64,64),
8279 DisabledBackground = c3(52,52,52)
8280 }
8281 },mt)
8282 initGui(obj,frame)
8283 return obj
8284 end
8285
8286 return {new = new, fromFrame}
8287 end)()
8288
8289 Lib.BrickColorPicker = (function()
8290 local funcs = {}
8291 local paletteCount = 0
8292 local mouse = service.Players.LocalPlayer:GetMouse()
8293 local hexStartX = 4
8294 local hexSizeX = 27
8295 local hexTriangleStart = 1
8296 local hexTriangleSize = 8
8297
8298 local bottomColors = {
8299 Color3.fromRGB(17,17,17),
8300 Color3.fromRGB(99,95,98),
8301 Color3.fromRGB(163,162,165),
8302 Color3.fromRGB(205,205,205),
8303 Color3.fromRGB(223,223,222),
8304 Color3.fromRGB(237,234,234),
8305 Color3.fromRGB(27,42,53),
8306 Color3.fromRGB(91,93,105),
8307 Color3.fromRGB(159,161,172),
8308 Color3.fromRGB(202,203,209),
8309 Color3.fromRGB(231,231,236),
8310 Color3.fromRGB(248,248,248)
8311 }
8312
8313 local function isMouseInHexagon(hex)
8314 local relativeX = mouse.X - hex.AbsolutePosition.X
8315 local relativeY = mouse.Y - hex.AbsolutePosition.Y
8316 if relativeX >= hexStartX and relativeX < hexStartX + hexSizeX then
8317 relativeX = relativeX - 4
8318 local relativeWidth = (13-math.min(relativeX,26 - relativeX))/13
8319 if relativeY >= hexTriangleStart + hexTriangleSize*relativeWidth and relativeY < hex.AbsoluteSize.Y - hexTriangleStart - hexTriangleSize*relativeWidth then
8320 return true
8321 end
8322 end
8323
8324 return false
8325 end
8326
8327 local function hexInput(self,hex,color)
8328 hex.InputBegan:Connect(function(input)
8329 if input.UserInputType == Enum.UserInputType.MouseButton1 and isMouseInHexagon(hex) then
8330 self.OnSelect:Fire(color)
8331 self:Close()
8332 end
8333 end)
8334
8335 hex.InputChanged:Connect(function(input)
8336 if input.UserInputType == Enum.UserInputType.MouseMovement and isMouseInHexagon(hex) then
8337 self.OnPreview:Fire(color)
8338 end
8339 end)
8340 end
8341
8342 local function createGui(self)
8343 local gui = create({
8344 {1,"ScreenGui",{Name="BrickColor",}},
8345 {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),}},
8346 {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,}},
8347 {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,}},
8348 })
8349 local colorFrame = gui.Frame
8350 local hex = colorFrame.Hex
8351
8352 for row = 1,13 do
8353 local columns = math.min(row,14-row)+6
8354 for column = 1,columns do
8355 local nextColor = BrickColor.palette(paletteCount).Color
8356 local newHex = hex:Clone()
8357 newHex.Position = UDim2.new(0, (column-1)*25-(columns-7)*13+3*26 + 1, 0, (row-1)*23 + 4)
8358 newHex.ImageColor3 = nextColor
8359 newHex.Visible = true
8360 hexInput(self,newHex,nextColor)
8361 newHex.Parent = colorFrame
8362 paletteCount = paletteCount + 1
8363 end
8364 end
8365
8366 for column = 1,12 do
8367 local nextColor = bottomColors[column]
8368 local newHex = hex:Clone()
8369 newHex.Position = UDim2.new(0, (column-1)*25-(12-7)*13+3*26 + 3, 0, 308)
8370 newHex.ImageColor3 = nextColor
8371 newHex.Visible = true
8372 hexInput(self,newHex,nextColor)
8373 newHex.Parent = colorFrame
8374 paletteCount = paletteCount + 1
8375 end
8376
8377 colorFrame.MoreColors.MouseButton1Click:Connect(function()
8378 self.OnMoreColors:Fire()
8379 self:Close()
8380 end)
8381
8382 self.Gui = gui
8383 end
8384
8385 funcs.SetMoreColorsVisible = function(self,vis)
8386 local colorFrame = self.Gui.Frame
8387 colorFrame.Size = UDim2.new(0,337,0,380 - (not vis and 33 or 0))
8388 colorFrame.MoreColors.Visible = vis
8389 end
8390
8391 funcs.Show = function(self,x,y,prevColor)
8392 self.PrevColor = prevColor or self.PrevColor
8393
8394 local reverseY = false
8395
8396 local x,y = x or mouse.X, y or mouse.Y
8397 local maxX,maxY = mouse.ViewSizeX,mouse.ViewSizeY
8398 Lib.ShowGui(self.Gui)
8399 local sizeX,sizeY = self.Gui.Frame.AbsoluteSize.X,self.Gui.Frame.AbsoluteSize.Y
8400
8401 if x + sizeX > maxX then x = self.ReverseX and x - sizeX or maxX - sizeX end
8402 if y + sizeY > maxY then reverseY = true end
8403
8404 local closable = false
8405 if self.CloseEvent then self.CloseEvent:Disconnect() end
8406 self.CloseEvent = service.UserInputService.InputBegan:Connect(function(input)
8407 if not closable or input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
8408
8409 if not Lib.CheckMouseInGui(self.Gui.Frame) then
8410 self.CloseEvent:Disconnect()
8411 self:Close()
8412 end
8413 end)
8414
8415 if reverseY then
8416 local newY = y - sizeY - (self.ReverseYOffset or 0)
8417 y = newY >= 0 and newY or 0
8418 end
8419
8420 self.Gui.Frame.Position = UDim2.new(0,x,0,y)
8421
8422 Lib.FastWait()
8423 closable = true
8424 end
8425
8426 funcs.Close = function(self)
8427 self.Gui.Parent = nil
8428 self.OnCancel:Fire()
8429 end
8430
8431 local mt = {__index = funcs}
8432
8433 local function new()
8434 local obj = setmetatable({
8435 OnPreview = Lib.Signal.new(),
8436 OnSelect = Lib.Signal.new(),
8437 OnCancel = Lib.Signal.new(),
8438 OnMoreColors = Lib.Signal.new(),
8439 PrevColor = Color3.new(0,0,0)
8440 },mt)
8441 createGui(obj)
8442 return obj
8443 end
8444
8445 return {new = new}
8446 end)()
8447
8448 Lib.ColorPicker = (function() -- TODO: Convert to newer class model
8449 local funcs = {}
8450
8451 local function new()
8452 local newMt = setmetatable({},{})
8453
8454 newMt.OnSelect = Lib.Signal.new()
8455 newMt.OnCancel = Lib.Signal.new()
8456 newMt.OnPreview = Lib.Signal.new()
8457
8458 local guiContents = create({
8459 {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),}},
8460 {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),}},
8461 {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,}},
8462 {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),}},
8463 {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,}},
8464 {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),}},
8465 {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,}},
8466 {8,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={7},Size=UDim2.new(0,16,0,8),}},
8467 {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),}},
8468 {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),}},
8469 {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),}},
8470 {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,}},
8471 {13,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={12},Size=UDim2.new(0,16,0,8),}},
8472 {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),}},
8473 {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),}},
8474 {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),}},
8475 {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,}},
8476 {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),}},
8477 {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),}},
8478 {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),}},
8479 {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),}},
8480 {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),}},
8481 {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),}},
8482 {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,}},
8483 {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),}},
8484 {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,}},
8485 {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),}},
8486 {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,}},
8487 {29,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={28},Size=UDim2.new(0,16,0,8),}},
8488 {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),}},
8489 {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),}},
8490 {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),}},
8491 {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,}},
8492 {34,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={33},Size=UDim2.new(0,16,0,8),}},
8493 {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),}},
8494 {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),}},
8495 {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),}},
8496 {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,}},
8497 {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),}},
8498 {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,}},
8499 {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),}},
8500 {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,}},
8501 {43,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={42},Size=UDim2.new(0,16,0,8),}},
8502 {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),}},
8503 {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),}},
8504 {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),}},
8505 {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,}},
8506 {48,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={47},Size=UDim2.new(0,16,0,8),}},
8507 {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),}},
8508 {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),}},
8509 {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),}},
8510 {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,}},
8511 {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),}},
8512 {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),}},
8513 {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,}},
8514 {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),}},
8515 {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,}},
8516 {58,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={57},Size=UDim2.new(0,16,0,8),}},
8517 {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),}},
8518 {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),}},
8519 {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),}},
8520 {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,}},
8521 {63,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={62},Size=UDim2.new(0,16,0,8),}},
8522 {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),}},
8523 {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),}},
8524 {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),}},
8525 {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,}},
8526 {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),}},
8527 {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,}},
8528 {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),}},
8529 {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,}},
8530 {72,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={71},Size=UDim2.new(0,16,0,8),}},
8531 {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),}},
8532 {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),}},
8533 {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),}},
8534 {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,}},
8535 {77,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={76},Size=UDim2.new(0,16,0,8),}},
8536 {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),}},
8537 {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),}},
8538 {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),}},
8539 {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,}},
8540 {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),}},
8541 {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,}},
8542 {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),}},
8543 {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,}},
8544 {86,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={85},Size=UDim2.new(0,16,0,8),}},
8545 {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),}},
8546 {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),}},
8547 {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),}},
8548 {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,}},
8549 {91,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={90},Size=UDim2.new(0,16,0,8),}},
8550 {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),}},
8551 {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),}},
8552 {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),}},
8553 {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,}},
8554 {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,}},
8555 {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,}},
8556 {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),}},
8557 {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),}},
8558 {100,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={99},Position=UDim2.new(0,-2,0,-4),Size=UDim2.new(0,8,0,16),}},
8559 {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),}},
8560 {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),}},
8561 {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),}},
8562 {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),}},
8563 {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),}},
8564 })
8565 local window = Lib.Window.new()
8566 window.Resizable = false
8567 window.Alignable = false
8568 window:SetTitle("Color Picker")
8569 window:Resize(450,330)
8570 for i,v in pairs(guiContents:GetChildren()) do
8571 v.Parent = window.GuiElems.Content
8572 end
8573 newMt.Window = window
8574 newMt.Gui = window.Gui
8575 local pickerGui = window.Gui.Main
8576 local pickerTopBar = pickerGui.TopBar
8577 local pickerFrame = pickerGui.Content
8578 local colorSpace = pickerFrame.ColorSpaceFrame.ColorSpace
8579 local colorStrip = pickerFrame.ColorStrip
8580 local previewFrame = pickerFrame.Preview
8581 local basicColorsFrame = pickerFrame.BasicColors
8582 local customColorsFrame = pickerFrame.CustomColors
8583 local okButton = pickerFrame.Ok
8584 local cancelButton = pickerFrame.Cancel
8585 local closeButton = pickerTopBar.Close
8586
8587 local colorScope = colorSpace.Scope
8588 local colorArrow = pickerFrame.ArrowFrame.Arrow
8589
8590 local hueInput = pickerFrame.Hue.Input
8591 local satInput = pickerFrame.Sat.Input
8592 local valInput = pickerFrame.Val.Input
8593
8594 local redInput = pickerFrame.Red.Input
8595 local greenInput = pickerFrame.Green.Input
8596 local blueInput = pickerFrame.Blue.Input
8597
8598 local user = clonerefs(game:GetService("UserInputService"))
8599 local mouse = clonerefs(game:GetService("Players")).LocalPlayer:GetMouse()
8600
8601 local hue,sat,val = 0,0,1
8602 local red,green,blue = 1,1,1
8603 local chosenColor = Color3.new(0,0,0)
8604
8605 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)}
8606 local customColors = {}
8607
8608 local function updateColor(noupdate)
8609 local relativeX,relativeY,relativeStripY = 219 - hue*219, 199 - sat*199, 199 - val*199
8610 local hsvColor = Color3.fromHSV(hue,sat,val)
8611
8612 if noupdate == 2 or not noupdate then
8613 hueInput.Text = tostring(math.ceil(359*hue))
8614 satInput.Text = tostring(math.ceil(255*sat))
8615 valInput.Text = tostring(math.floor(255*val))
8616 end
8617 if noupdate == 1 or not noupdate then
8618 redInput.Text = tostring(math.floor(255*red))
8619 greenInput.Text = tostring(math.floor(255*green))
8620 blueInput.Text = tostring(math.floor(255*blue))
8621 end
8622
8623 chosenColor = Color3.new(red,green,blue)
8624
8625 colorScope.Position = UDim2.new(0,relativeX-9,0,relativeY-9)
8626 colorStrip.ImageColor3 = Color3.fromHSV(hue,sat,1)
8627 colorArrow.Position = UDim2.new(0,-2,0,relativeStripY-4)
8628 previewFrame.BackgroundColor3 = chosenColor
8629
8630 newMt.Color = chosenColor
8631 newMt.OnPreview:Fire(chosenColor)
8632 end
8633
8634 local function colorSpaceInput()
8635 local relativeX = mouse.X - colorSpace.AbsolutePosition.X
8636 local relativeY = mouse.Y - colorSpace.AbsolutePosition.Y
8637
8638 if relativeX < 0 then relativeX = 0 elseif relativeX > 219 then relativeX = 219 end
8639 if relativeY < 0 then relativeY = 0 elseif relativeY > 199 then relativeY = 199 end
8640
8641 hue = (219 - relativeX)/219
8642 sat = (199 - relativeY)/199
8643
8644 local hsvColor = Color3.fromHSV(hue,sat,val)
8645 red,green,blue = hsvColor.r,hsvColor.g,hsvColor.b
8646
8647 updateColor()
8648 end
8649
8650 local function colorStripInput()
8651 local relativeY = mouse.Y - colorStrip.AbsolutePosition.Y
8652
8653 if relativeY < 0 then relativeY = 0 elseif relativeY > 199 then relativeY = 199 end
8654
8655 val = (199 - relativeY)/199
8656
8657 local hsvColor = Color3.fromHSV(hue,sat,val)
8658 red,green,blue = hsvColor.r,hsvColor.g,hsvColor.b
8659
8660 updateColor()
8661 end
8662
8663 local function hookButtons(frame,func)
8664 frame.ArrowFrame.Up.InputBegan:Connect(function(input)
8665 if input.UserInputType == Enum.UserInputType.MouseMovement then
8666 frame.ArrowFrame.Up.BackgroundTransparency = 0.5
8667 elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
8668 local releaseEvent,runEvent
8669
8670 local startTime = tick()
8671 local pressing = true
8672 local startNum = tonumber(frame.Text)
8673
8674 if not startNum then return end
8675
8676 releaseEvent = user.InputEnded:Connect(function(input)
8677 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
8678 releaseEvent:Disconnect()
8679 pressing = false
8680 end)
8681
8682 startNum = startNum + 1
8683 func(startNum)
8684 while pressing do
8685 if tick()-startTime > 0.3 then
8686 startNum = startNum + 1
8687 func(startNum)
8688 end
8689 wait(0.1)
8690 end
8691 end
8692 end)
8693
8694 frame.ArrowFrame.Up.InputEnded:Connect(function(input)
8695 if input.UserInputType == Enum.UserInputType.MouseMovement then
8696 frame.ArrowFrame.Up.BackgroundTransparency = 1
8697 end
8698 end)
8699
8700 frame.ArrowFrame.Down.InputBegan:Connect(function(input)
8701 if input.UserInputType == Enum.UserInputType.MouseMovement then
8702 frame.ArrowFrame.Down.BackgroundTransparency = 0.5
8703 elseif input.UserInputType == Enum.UserInputType.MouseButton1 then
8704 local releaseEvent,runEvent
8705
8706 local startTime = tick()
8707 local pressing = true
8708 local startNum = tonumber(frame.Text)
8709
8710 if not startNum then return end
8711
8712 releaseEvent = user.InputEnded:Connect(function(input)
8713 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
8714 releaseEvent:Disconnect()
8715 pressing = false
8716 end)
8717
8718 startNum = startNum - 1
8719 func(startNum)
8720 while pressing do
8721 if tick()-startTime > 0.3 then
8722 startNum = startNum - 1
8723 func(startNum)
8724 end
8725 wait(0.1)
8726 end
8727 end
8728 end)
8729
8730 frame.ArrowFrame.Down.InputEnded:Connect(function(input)
8731 if input.UserInputType == Enum.UserInputType.MouseMovement then
8732 frame.ArrowFrame.Down.BackgroundTransparency = 1
8733 end
8734 end)
8735 end
8736
8737 colorSpace.InputBegan:Connect(function(input)
8738 if input.UserInputType == Enum.UserInputType.MouseButton1 then
8739 local releaseEvent,mouseEvent
8740
8741 releaseEvent = user.InputEnded:Connect(function(input)
8742 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
8743 releaseEvent:Disconnect()
8744 mouseEvent:Disconnect()
8745 end)
8746
8747 mouseEvent = user.InputChanged:Connect(function(input)
8748 if input.UserInputType == Enum.UserInputType.MouseMovement then
8749 colorSpaceInput()
8750 end
8751 end)
8752
8753 colorSpaceInput()
8754 end
8755 end)
8756
8757 colorStrip.InputBegan:Connect(function(input)
8758 if input.UserInputType == Enum.UserInputType.MouseButton1 then
8759 local releaseEvent,mouseEvent
8760
8761 releaseEvent = user.InputEnded:Connect(function(input)
8762 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
8763 releaseEvent:Disconnect()
8764 mouseEvent:Disconnect()
8765 end)
8766
8767 mouseEvent = user.InputChanged:Connect(function(input)
8768 if input.UserInputType == Enum.UserInputType.MouseMovement then
8769 colorStripInput()
8770 end
8771 end)
8772
8773 colorStripInput()
8774 end
8775 end)
8776
8777 local function updateHue(str)
8778 local num = tonumber(str)
8779 if num then
8780 hue = math.clamp(math.floor(num),0,359)/359
8781 local hsvColor = Color3.fromHSV(hue,sat,val)
8782 red,green,blue = hsvColor.r,hsvColor.g,hsvColor.b
8783 hueInput.Text = tostring(hue*359)
8784 updateColor(1)
8785 end
8786 end
8787 hueInput.FocusLost:Connect(function() updateHue(hueInput.Text) end) hookButtons(hueInput,updateHue)
8788
8789 local function updateSat(str)
8790 local num = tonumber(str)
8791 if num then
8792 sat = math.clamp(math.floor(num),0,255)/255
8793 local hsvColor = Color3.fromHSV(hue,sat,val)
8794 red,green,blue = hsvColor.r,hsvColor.g,hsvColor.b
8795 satInput.Text = tostring(sat*255)
8796 updateColor(1)
8797 end
8798 end
8799 satInput.FocusLost:Connect(function() updateSat(satInput.Text) end) hookButtons(satInput,updateSat)
8800
8801 local function updateVal(str)
8802 local num = tonumber(str)
8803 if num then
8804 val = math.clamp(math.floor(num),0,255)/255
8805 local hsvColor = Color3.fromHSV(hue,sat,val)
8806 red,green,blue = hsvColor.r,hsvColor.g,hsvColor.b
8807 valInput.Text = tostring(val*255)
8808 updateColor(1)
8809 end
8810 end
8811 valInput.FocusLost:Connect(function() updateVal(valInput.Text) end) hookButtons(valInput,updateVal)
8812
8813 local function updateRed(str)
8814 local num = tonumber(str)
8815 if num then
8816 red = math.clamp(math.floor(num),0,255)/255
8817 local newColor = Color3.new(red,green,blue)
8818 hue,sat,val = Color3.toHSV(newColor)
8819 redInput.Text = tostring(red*255)
8820 updateColor(2)
8821 end
8822 end
8823 redInput.FocusLost:Connect(function() updateRed(redInput.Text) end) hookButtons(redInput,updateRed)
8824
8825 local function updateGreen(str)
8826 local num = tonumber(str)
8827 if num then
8828 green = math.clamp(math.floor(num),0,255)/255
8829 local newColor = Color3.new(red,green,blue)
8830 hue,sat,val = Color3.toHSV(newColor)
8831 greenInput.Text = tostring(green*255)
8832 updateColor(2)
8833 end
8834 end
8835 greenInput.FocusLost:Connect(function() updateGreen(greenInput.Text) end) hookButtons(greenInput,updateGreen)
8836
8837 local function updateBlue(str)
8838 local num = tonumber(str)
8839 if num then
8840 blue = math.clamp(math.floor(num),0,255)/255
8841 local newColor = Color3.new(red,green,blue)
8842 hue,sat,val = Color3.toHSV(newColor)
8843 blueInput.Text = tostring(blue*255)
8844 updateColor(2)
8845 end
8846 end
8847 blueInput.FocusLost:Connect(function() updateBlue(blueInput.Text) end) hookButtons(blueInput,updateBlue)
8848
8849 local colorChoice = Instance.new("TextButton")
8850 colorChoice.Name = "Choice"
8851 colorChoice.Size = UDim2.new(0,25,0,18)
8852 colorChoice.BorderColor3 = Color3.fromRGB(55,55,55)
8853 colorChoice.Text = ""
8854 colorChoice.AutoButtonColor = false
8855
8856 local row = 0
8857 local column = 0
8858 for i,v in pairs(basicColors) do
8859 local newColor = colorChoice:Clone()
8860 newColor.BackgroundColor3 = v
8861 newColor.Position = UDim2.new(0,1 + 30*column,0,21 + 23*row)
8862
8863 newColor.MouseButton1Click:Connect(function()
8864 red,green,blue = v.r,v.g,v.b
8865 local newColor = Color3.new(red,green,blue)
8866 hue,sat,val = Color3.toHSV(newColor)
8867 updateColor()
8868 end)
8869
8870 newColor.Parent = basicColorsFrame
8871 column = column + 1
8872 if column == 6 then row = row + 1 column = 0 end
8873 end
8874
8875 row = 0
8876 column = 0
8877 for i = 1,12 do
8878 local color = customColors[i] or Color3.new(0,0,0)
8879 local newColor = colorChoice:Clone()
8880 newColor.BackgroundColor3 = color
8881 newColor.Position = UDim2.new(0,1 + 30*column,0,20 + 23*row)
8882
8883 newColor.MouseButton1Click:Connect(function()
8884 local curColor = customColors[i] or Color3.new(0,0,0)
8885 red,green,blue = curColor.r,curColor.g,curColor.b
8886 hue,sat,val = Color3.toHSV(curColor)
8887 updateColor()
8888 end)
8889
8890 newColor.MouseButton2Click:Connect(function()
8891 customColors[i] = chosenColor
8892 newColor.BackgroundColor3 = chosenColor
8893 end)
8894
8895 newColor.Parent = customColorsFrame
8896 column = column + 1
8897 if column == 6 then row = row + 1 column = 0 end
8898 end
8899
8900 okButton.MouseButton1Click:Connect(function() newMt.OnSelect:Fire(chosenColor) window:Close() end)
8901 okButton.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement then okButton.BackgroundTransparency = 0.4 end end)
8902 okButton.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement then okButton.BackgroundTransparency = 0 end end)
8903
8904 cancelButton.MouseButton1Click:Connect(function() newMt.OnCancel:Fire() window:Close() end)
8905 cancelButton.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement then cancelButton.BackgroundTransparency = 0.4 end end)
8906 cancelButton.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement then cancelButton.BackgroundTransparency = 0 end end)
8907
8908 updateColor()
8909
8910 newMt.SetColor = function(self,color)
8911 red,green,blue = color.r,color.g,color.b
8912 hue,sat,val = Color3.toHSV(color)
8913 updateColor()
8914 end
8915
8916 newMt.Show = function(self)
8917 self.Window:Show()
8918 end
8919
8920 return newMt
8921 end
8922
8923 return {new = new}
8924 end)()
8925
8926 Lib.NumberSequenceEditor = (function()
8927 local function new() -- TODO: Convert to newer class model
8928 local newMt = setmetatable({},{})
8929 newMt.OnSelect = Lib.Signal.new()
8930 newMt.OnCancel = Lib.Signal.new()
8931 newMt.OnPreview = Lib.Signal.new()
8932
8933 local guiContents = create({
8934 {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),}},
8935 {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),}},
8936 {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,}},
8937 {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,}},
8938 {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,}},
8939 {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,}},
8940 {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,}},
8941 {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),}},
8942 {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),}},
8943 {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),}},
8944 {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,}},
8945 {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,}},
8946 {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),}},
8947 {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,}},
8948 {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,}},
8949 })
8950 local window = Lib.Window.new()
8951 window.Resizable = false
8952 window:Resize(680,265)
8953 window:SetTitle("NumberSequence Editor")
8954 newMt.Window = window
8955 newMt.Gui = window.Gui
8956 for i,v in pairs(guiContents:GetChildren()) do
8957 v.Parent = window.GuiElems.Content
8958 end
8959 local gui = window.Gui
8960 local pickerGui = gui.Main
8961 local pickerTopBar = pickerGui.TopBar
8962 local pickerFrame = pickerGui.Content
8963 local numberLine = pickerFrame.NumberLine
8964 local numberLineOutlines = pickerFrame.NumberLineOutlines
8965 local timeBox = pickerFrame.Time.Input
8966 local valueBox = pickerFrame.Value.Input
8967 local envelopeBox = pickerFrame.Envelope.Input
8968 local deleteButton = pickerFrame.Delete
8969 local resetButton = pickerFrame.Reset
8970 local closeButton = pickerFrame.Close
8971 local topClose = pickerTopBar.Close
8972
8973 local points = {{1,0,3},{8,0.05,1},{5,0.6,2},{4,0.7,4},{6,1,4}}
8974 local lines = {}
8975 local eLines = {}
8976 local beginPoint = points[1]
8977 local endPoint = points[#points]
8978 local currentlySelected = nil
8979 local currentPoint = nil
8980 local resetSequence = nil
8981
8982 local user = clonerefs(game:GetService("UserInputService"))
8983 local mouse = clonerefs(game:GetService("Players")).LocalPlayer:GetMouse()
8984
8985 for i = 2,10 do
8986 local newLine = Instance.new("Frame")
8987 newLine.BackgroundTransparency = 0.5
8988 newLine.BackgroundColor3 = Color3.new(96/255,96/255,96/255)
8989 newLine.BorderSizePixel = 0
8990 newLine.Size = UDim2.new(0,1,1,0)
8991 newLine.Position = UDim2.new((i-1)/(11-1),0,0,0)
8992 newLine.Parent = numberLineOutlines
8993 end
8994
8995 for i = 2,4 do
8996 local newLine = Instance.new("Frame")
8997 newLine.BackgroundTransparency = 0.5
8998 newLine.BackgroundColor3 = Color3.new(96/255,96/255,96/255)
8999 newLine.BorderSizePixel = 0
9000 newLine.Size = UDim2.new(1,0,0,1)
9001 newLine.Position = UDim2.new(0,0,(i-1)/(5-1),0)
9002 newLine.Parent = numberLineOutlines
9003 end
9004
9005 local lineTemp = Instance.new("Frame")
9006 lineTemp.BackgroundColor3 = Color3.new(0,0,0)
9007 lineTemp.BorderSizePixel = 0
9008 lineTemp.Size = UDim2.new(0,1,0,1)
9009
9010 local sequenceLine = Instance.new("Frame")
9011 sequenceLine.BackgroundColor3 = Color3.new(0,0,0)
9012 sequenceLine.BorderSizePixel = 0
9013 sequenceLine.Size = UDim2.new(0,1,0,0)
9014
9015 for i = 1,numberLine.AbsoluteSize.X do
9016 local line = sequenceLine:Clone()
9017 eLines[i] = line
9018 line.Name = "E"..tostring(i)
9019 line.BackgroundTransparency = 0.5
9020 line.BackgroundColor3 = Color3.new(199/255,44/255,28/255)
9021 line.Position = UDim2.new(0,i-1,0,0)
9022 line.Parent = numberLine
9023 end
9024
9025 for i = 1,numberLine.AbsoluteSize.X do
9026 local line = sequenceLine:Clone()
9027 lines[i] = line
9028 line.Name = tostring(i)
9029 line.Position = UDim2.new(0,i-1,0,0)
9030 line.Parent = numberLine
9031 end
9032
9033 local envelopeDrag = Instance.new("Frame")
9034 envelopeDrag.BackgroundTransparency = 1
9035 envelopeDrag.BackgroundColor3 = Color3.new(0,0,0)
9036 envelopeDrag.BorderSizePixel = 0
9037 envelopeDrag.Size = UDim2.new(0,7,0,20)
9038 envelopeDrag.Visible = false
9039 envelopeDrag.ZIndex = 2
9040 local envelopeDragLine = Instance.new("Frame",envelopeDrag)
9041 envelopeDragLine.Name = "Line"
9042 envelopeDragLine.BackgroundColor3 = Color3.new(0,0,0)
9043 envelopeDragLine.BorderSizePixel = 0
9044 envelopeDragLine.Position = UDim2.new(0,3,0,0)
9045 envelopeDragLine.Size = UDim2.new(0,1,0,20)
9046 envelopeDragLine.ZIndex = 2
9047
9048 local envelopeDragTop,envelopeDragBottom = envelopeDrag:Clone(),envelopeDrag:Clone()
9049 envelopeDragTop.Parent = numberLine
9050 envelopeDragBottom.Parent = numberLine
9051
9052 local function buildSequence()
9053 local newPoints = {}
9054 for i,v in pairs(points) do
9055 table.insert(newPoints,NumberSequenceKeypoint.new(v[2],v[1],v[3]))
9056 end
9057 newMt.Sequence = NumberSequence.new(newPoints)
9058 newMt.OnSelect:Fire(newMt.Sequence)
9059 end
9060
9061 local function round(num,places)
9062 local multi = 10^places
9063 return math.floor(num*multi + 0.5)/multi
9064 end
9065
9066 local function updateInputs(point)
9067 if point then
9068 currentPoint = point
9069 local rawT,rawV,rawE = point[2],point[1],point[3]
9070 timeBox.Text = round(rawT,(rawT < 0.01 and 5) or (rawT < 0.1 and 4) or 3)
9071 valueBox.Text = round(rawV,(rawV < 0.01 and 5) or (rawV < 0.1 and 4) or (rawV < 1 and 3) or 2)
9072 envelopeBox.Text = round(rawE,(rawE < 0.01 and 5) or (rawE < 0.1 and 4) or (rawV < 1 and 3) or 2)
9073
9074 local envelopeDistance = numberLine.AbsoluteSize.Y*(point[3]/10)
9075 envelopeDragTop.Position = UDim2.new(0,point[4].Position.X.Offset-1,0,point[4].Position.Y.Offset-envelopeDistance-17)
9076 envelopeDragTop.Visible = true
9077 envelopeDragBottom.Position = UDim2.new(0,point[4].Position.X.Offset-1,0,point[4].Position.Y.Offset+envelopeDistance+2)
9078 envelopeDragBottom.Visible = true
9079 end
9080 end
9081
9082 envelopeDragTop.InputBegan:Connect(function(input)
9083 if input.UserInputType ~= Enum.UserInputType.MouseButton1 or not currentPoint or Lib.CheckMouseInGui(currentPoint[4].Select) then return end
9084 local mouseEvent,releaseEvent
9085 local maxSize = numberLine.AbsoluteSize.Y
9086
9087 local mouseDelta = math.abs(envelopeDragTop.AbsolutePosition.Y - mouse.Y)
9088
9089 envelopeDragTop.Line.Position = UDim2.new(0,2,0,0)
9090 envelopeDragTop.Line.Size = UDim2.new(0,3,0,20)
9091
9092 releaseEvent = user.InputEnded:Connect(function(input)
9093 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
9094 mouseEvent:Disconnect()
9095 releaseEvent:Disconnect()
9096 envelopeDragTop.Line.Position = UDim2.new(0,3,0,0)
9097 envelopeDragTop.Line.Size = UDim2.new(0,1,0,20)
9098 end)
9099
9100 mouseEvent = user.InputChanged:Connect(function(input)
9101 if input.UserInputType == Enum.UserInputType.MouseMovement then
9102 local topDiff = (currentPoint[4].AbsolutePosition.Y+2)-(mouse.Y-mouseDelta)-19
9103 local newEnvelope = 10*(math.max(topDiff,0)/maxSize)
9104 local maxEnvelope = math.min(currentPoint[1],10-currentPoint[1])
9105 currentPoint[3] = math.min(newEnvelope,maxEnvelope)
9106 newMt:Redraw()
9107 buildSequence()
9108 updateInputs(currentPoint)
9109 end
9110 end)
9111 end)
9112
9113 envelopeDragBottom.InputBegan:Connect(function(input)
9114 if input.UserInputType ~= Enum.UserInputType.MouseButton1 or not currentPoint or Lib.CheckMouseInGui(currentPoint[4].Select) then return end
9115 local mouseEvent,releaseEvent
9116 local maxSize = numberLine.AbsoluteSize.Y
9117
9118 local mouseDelta = math.abs(envelopeDragBottom.AbsolutePosition.Y - mouse.Y)
9119
9120 envelopeDragBottom.Line.Position = UDim2.new(0,2,0,0)
9121 envelopeDragBottom.Line.Size = UDim2.new(0,3,0,20)
9122
9123 releaseEvent = user.InputEnded:Connect(function(input)
9124 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
9125 mouseEvent:Disconnect()
9126 releaseEvent:Disconnect()
9127 envelopeDragBottom.Line.Position = UDim2.new(0,3,0,0)
9128 envelopeDragBottom.Line.Size = UDim2.new(0,1,0,20)
9129 end)
9130
9131 mouseEvent = user.InputChanged:Connect(function(input)
9132 if input.UserInputType == Enum.UserInputType.MouseMovement then
9133 local bottomDiff = (mouse.Y+(20-mouseDelta))-(currentPoint[4].AbsolutePosition.Y+2)-19
9134 local newEnvelope = 10*(math.max(bottomDiff,0)/maxSize)
9135 local maxEnvelope = math.min(currentPoint[1],10-currentPoint[1])
9136 currentPoint[3] = math.min(newEnvelope,maxEnvelope)
9137 newMt:Redraw()
9138 buildSequence()
9139 updateInputs(currentPoint)
9140 end
9141 end)
9142 end)
9143
9144 local function placePoint(point)
9145 local newPoint = Instance.new("Frame")
9146 newPoint.Name = "Point"
9147 newPoint.BorderSizePixel = 0
9148 newPoint.Size = UDim2.new(0,5,0,5)
9149 newPoint.Position = UDim2.new(0,math.floor((numberLine.AbsoluteSize.X-1) * point[2])-2,0,numberLine.AbsoluteSize.Y*(10-point[1])/10-2)
9150 newPoint.BackgroundColor3 = Color3.new(0,0,0)
9151
9152 local newSelect = Instance.new("Frame")
9153 newSelect.Name = "Select"
9154 newSelect.BackgroundTransparency = 1
9155 newSelect.BackgroundColor3 = Color3.new(199/255,44/255,28/255)
9156 newSelect.Position = UDim2.new(0,-2,0,-2)
9157 newSelect.Size = UDim2.new(0,9,0,9)
9158 newSelect.Parent = newPoint
9159
9160 newPoint.Parent = numberLine
9161
9162 newSelect.InputBegan:Connect(function(input)
9163 if input.UserInputType == Enum.UserInputType.MouseMovement then
9164 for i,v in pairs(points) do v[4].Select.BackgroundTransparency = 1 end
9165 newSelect.BackgroundTransparency = 0
9166 updateInputs(point)
9167 end
9168 if input.UserInputType == Enum.UserInputType.MouseButton1 and not currentlySelected then
9169 currentPoint = point
9170 local mouseEvent,releaseEvent
9171 currentlySelected = true
9172 newSelect.BackgroundColor3 = Color3.new(249/255,191/255,59/255)
9173
9174 local oldEnvelope = point[3]
9175
9176 releaseEvent = user.InputEnded:Connect(function(input)
9177 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
9178 mouseEvent:Disconnect()
9179 releaseEvent:Disconnect()
9180 currentlySelected = nil
9181 newSelect.BackgroundColor3 = Color3.new(199/255,44/255,28/255)
9182 end)
9183
9184 mouseEvent = user.InputChanged:Connect(function(input)
9185 if input.UserInputType == Enum.UserInputType.MouseMovement then
9186 local maxX = numberLine.AbsoluteSize.X-1
9187 local relativeX = mouse.X - numberLine.AbsolutePosition.X
9188 if relativeX < 0 then relativeX = 0 end
9189 if relativeX > maxX then relativeX = maxX end
9190 local maxY = numberLine.AbsoluteSize.Y-1
9191 local relativeY = mouse.Y - numberLine.AbsolutePosition.Y
9192 if relativeY < 0 then relativeY = 0 end
9193 if relativeY > maxY then relativeY = maxY end
9194 if point ~= beginPoint and point ~= endPoint then
9195 point[2] = relativeX/maxX
9196 end
9197 point[1] = 10-(relativeY/maxY)*10
9198 local maxEnvelope = math.min(point[1],10-point[1])
9199 point[3] = math.min(oldEnvelope,maxEnvelope)
9200 newMt:Redraw()
9201 updateInputs(point)
9202 for i,v in pairs(points) do v[4].Select.BackgroundTransparency = 1 end
9203 newSelect.BackgroundTransparency = 0
9204 buildSequence()
9205 end
9206 end)
9207 end
9208 end)
9209
9210 return newPoint
9211 end
9212
9213 local function placePoints()
9214 for i,v in pairs(points) do
9215 v[4] = placePoint(v)
9216 end
9217 end
9218
9219 local function redraw(self)
9220 local numberLineSize = numberLine.AbsoluteSize
9221 table.sort(points,function(a,b) return a[2] < b[2] end)
9222 for i,v in pairs(points) do
9223 v[4].Position = UDim2.new(0,math.floor((numberLineSize.X-1) * v[2])-2,0,(numberLineSize.Y-1)*(10-v[1])/10-2)
9224 end
9225 lines[1].Size = UDim2.new(0,1,0,0)
9226 for i = 1,#points-1 do
9227 local fromPoint = points[i]
9228 local toPoint = points[i+1]
9229 local deltaY = toPoint[4].Position.Y.Offset-fromPoint[4].Position.Y.Offset
9230 local deltaX = toPoint[4].Position.X.Offset-fromPoint[4].Position.X.Offset
9231 local slope = deltaY/deltaX
9232
9233 local fromEnvelope = fromPoint[3]
9234 local nextEnvelope = toPoint[3]
9235
9236 local currentRise = math.abs(slope)
9237 local totalRise = 0
9238 local maxRise = math.abs(toPoint[4].Position.Y.Offset-fromPoint[4].Position.Y.Offset)
9239
9240 for lineCount = math.min(fromPoint[4].Position.X.Offset+1,toPoint[4].Position.X.Offset),toPoint[4].Position.X.Offset do
9241 if deltaX == 0 and deltaY == 0 then return end
9242 local riseNow = math.floor(currentRise)
9243 local line = lines[lineCount+3]
9244 if line then
9245 if totalRise+riseNow > maxRise then riseNow = maxRise-totalRise end
9246 if math.sign(slope) == -1 then
9247 line.Position = UDim2.new(0,lineCount+2,0,fromPoint[4].Position.Y.Offset + -(totalRise+riseNow)+2)
9248 else
9249 line.Position = UDim2.new(0,lineCount+2,0,fromPoint[4].Position.Y.Offset + totalRise+2)
9250 end
9251 line.Size = UDim2.new(0,1,0,math.max(riseNow,1))
9252 end
9253 totalRise = totalRise + riseNow
9254 currentRise = currentRise - riseNow + math.abs(slope)
9255
9256 local envPercent = (lineCount-fromPoint[4].Position.X.Offset)/(toPoint[4].Position.X.Offset-fromPoint[4].Position.X.Offset)
9257 local envLerp = fromEnvelope+(nextEnvelope-fromEnvelope)*envPercent
9258 local relativeSize = (envLerp/10)*numberLineSize.Y
9259
9260 local line = eLines[lineCount + 3]
9261 if line then
9262 line.Position = UDim2.new(0,lineCount+2,0,lines[lineCount+3].Position.Y.Offset-math.floor(relativeSize))
9263 line.Size = UDim2.new(0,1,0,math.floor(relativeSize*2))
9264 end
9265 end
9266 end
9267 end
9268 newMt.Redraw = redraw
9269
9270 local function loadSequence(self,seq)
9271 resetSequence = seq
9272 for i,v in pairs(points) do if v[4] then v[4]:Destroy() end end
9273 points = {}
9274 for i,v in pairs(seq.Keypoints) do
9275 local maxEnvelope = math.min(v.Value,10-v.Value)
9276 local newPoint = {v.Value,v.Time,math.min(v.Envelope,maxEnvelope)}
9277 newPoint[4] = placePoint(newPoint)
9278 table.insert(points,newPoint)
9279 end
9280 beginPoint = points[1]
9281 endPoint = points[#points]
9282 currentlySelected = nil
9283 redraw()
9284 envelopeDragTop.Visible = false
9285 envelopeDragBottom.Visible = false
9286 end
9287 newMt.SetSequence = loadSequence
9288
9289 timeBox.FocusLost:Connect(function()
9290 local point = currentPoint
9291 local num = tonumber(timeBox.Text)
9292 if point and num and point ~= beginPoint and point ~= endPoint then
9293 num = math.clamp(num,0,1)
9294 point[2] = num
9295 redraw()
9296 buildSequence()
9297 updateInputs(point)
9298 end
9299 end)
9300
9301 valueBox.FocusLost:Connect(function()
9302 local point = currentPoint
9303 local num = tonumber(valueBox.Text)
9304 if point and num then
9305 local oldEnvelope = point[3]
9306 num = math.clamp(num,0,10)
9307 point[1] = num
9308 local maxEnvelope = math.min(point[1],10-point[1])
9309 point[3] = math.min(oldEnvelope,maxEnvelope)
9310 redraw()
9311 buildSequence()
9312 updateInputs(point)
9313 end
9314 end)
9315
9316 envelopeBox.FocusLost:Connect(function()
9317 local point = currentPoint
9318 local num = tonumber(envelopeBox.Text)
9319 if point and num then
9320 num = math.clamp(num,0,5)
9321 local maxEnvelope = math.min(point[1],10-point[1])
9322 point[3] = math.min(num,maxEnvelope)
9323 redraw()
9324 buildSequence()
9325 updateInputs(point)
9326 end
9327 end)
9328
9329 local function buttonAnimations(button,inverse)
9330 button.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement then button.BackgroundTransparency = (inverse and 0.5 or 0.4) end end)
9331 button.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement then button.BackgroundTransparency = (inverse and 1 or 0) end end)
9332 end
9333
9334 numberLine.InputBegan:Connect(function(input)
9335 if input.UserInputType == Enum.UserInputType.MouseButton1 and #points < 20 then
9336 if Lib.CheckMouseInGui(envelopeDragTop) or Lib.CheckMouseInGui(envelopeDragBottom) then return end
9337 for i,v in pairs(points) do
9338 if Lib.CheckMouseInGui(v[4].Select) then return end
9339 end
9340 local maxX = numberLine.AbsoluteSize.X-1
9341 local relativeX = mouse.X - numberLine.AbsolutePosition.X
9342 if relativeX < 0 then relativeX = 0 end
9343 if relativeX > maxX then relativeX = maxX end
9344 local maxY = numberLine.AbsoluteSize.Y-1
9345 local relativeY = mouse.Y - numberLine.AbsolutePosition.Y
9346 if relativeY < 0 then relativeY = 0 end
9347 if relativeY > maxY then relativeY = maxY end
9348
9349 local raw = relativeX/maxX
9350 local newPoint = {10-(relativeY/maxY)*10,raw,0}
9351 newPoint[4] = placePoint(newPoint)
9352 table.insert(points,newPoint)
9353 redraw()
9354 buildSequence()
9355 end
9356 end)
9357
9358 deleteButton.MouseButton1Click:Connect(function()
9359 if currentPoint and currentPoint ~= beginPoint and currentPoint ~= endPoint then
9360 for i,v in pairs(points) do
9361 if v == currentPoint then
9362 v[4]:Destroy()
9363 table.remove(points,i)
9364 break
9365 end
9366 end
9367 currentlySelected = nil
9368 redraw()
9369 buildSequence()
9370 updateInputs(points[1])
9371 end
9372 end)
9373
9374 resetButton.MouseButton1Click:Connect(function()
9375 if resetSequence then
9376 newMt:SetSequence(resetSequence)
9377 buildSequence()
9378 end
9379 end)
9380
9381 closeButton.MouseButton1Click:Connect(function()
9382 window:Close()
9383 end)
9384
9385 buttonAnimations(deleteButton)
9386 buttonAnimations(resetButton)
9387 buttonAnimations(closeButton)
9388
9389 placePoints()
9390 redraw()
9391
9392 newMt.Show = function(self)
9393 window:Show()
9394 end
9395
9396 return newMt
9397 end
9398
9399 return {new = new}
9400 end)()
9401
9402 Lib.ColorSequenceEditor = (function() -- TODO: Convert to newer class model
9403 local function new()
9404 local newMt = setmetatable({},{})
9405 newMt.OnSelect = Lib.Signal.new()
9406 newMt.OnCancel = Lib.Signal.new()
9407 newMt.OnPreview = Lib.Signal.new()
9408 newMt.OnPickColor = Lib.Signal.new()
9409
9410 local guiContents = create({
9411 {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),}},
9412 {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),}},
9413 {3,"Frame",{BackgroundColor3=Color3.new(1,1,1),BorderSizePixel=0,Name="Gradient",Parent={2},Size=UDim2.new(1,0,1,0),}},
9414 {4,"UIGradient",{Parent={3},}},
9415 {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),}},
9416 {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),}},
9417 {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),}},
9418 {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,}},
9419 {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,}},
9420 {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),}},
9421 {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,}},
9422 {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,}},
9423 {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,}},
9424 {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,}},
9425 {15,"Frame",{BackgroundTransparency=1,Name="Arrow",Parent={1},Size=UDim2.new(0,16,0,16),Visible=false,}},
9426 {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),}},
9427 {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),}},
9428 {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),}},
9429 {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),}},
9430 {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),}},
9431 })
9432 local window = Lib.Window.new()
9433 window.Resizable = false
9434 window:Resize(650,150)
9435 window:SetTitle("ColorSequence Editor")
9436 newMt.Window = window
9437 newMt.Gui = window.Gui
9438 for i,v in pairs(guiContents:GetChildren()) do
9439 v.Parent = window.GuiElems.Content
9440 end
9441 local gui = window.Gui
9442 local pickerGui = gui.Main
9443 local pickerTopBar = pickerGui.TopBar
9444 local pickerFrame = pickerGui.Content
9445 local colorLine = pickerFrame.ColorLine
9446 local gradient = colorLine.Gradient.UIGradient
9447 local arrowFrame = pickerFrame.Arrows
9448 local arrow = pickerFrame.Arrow
9449 local cursor = pickerFrame.Cursor
9450 local timeBox = pickerFrame.Time.Input
9451 local colorBox = pickerFrame.ColorBox
9452 local deleteButton = pickerFrame.Delete
9453 local resetButton = pickerFrame.Reset
9454 local closeButton = pickerFrame.Close
9455 local topClose = pickerTopBar.Close
9456
9457 local user = clonerefs(game:GetService("UserInputService"))
9458 local mouse = clonerefs(game:GetService("Players")).LocalPlayer:GetMouse()
9459
9460 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}}
9461 local resetSequence = nil
9462
9463 local beginPoint = colors[1]
9464 local endPoint = colors[#colors]
9465
9466 local currentlySelected = nil
9467 local currentPoint = nil
9468
9469 local sequenceLine = Instance.new("Frame")
9470 sequenceLine.BorderSizePixel = 0
9471 sequenceLine.Size = UDim2.new(0,1,1,0)
9472
9473 newMt.Sequence = ColorSequence.new(Color3.new(1,1,1))
9474 local function buildSequence(noupdate)
9475 local newPoints = {}
9476 table.sort(colors,function(a,b) return a[2] < b[2] end)
9477 for i,v in pairs(colors) do
9478 table.insert(newPoints,ColorSequenceKeypoint.new(v[2],v[1]))
9479 end
9480 newMt.Sequence = ColorSequence.new(newPoints)
9481 if not noupdate then newMt.OnSelect:Fire(newMt.Sequence) end
9482 end
9483
9484 local function round(num,places)
9485 local multi = 10^places
9486 return math.floor(num*multi + 0.5)/multi
9487 end
9488
9489 local function updateInputs(point)
9490 if point then
9491 currentPoint = point
9492 local raw = point[2]
9493 timeBox.Text = round(raw,(raw < 0.01 and 5) or (raw < 0.1 and 4) or 3)
9494 colorBox.BackgroundColor3 = point[1]
9495 end
9496 end
9497
9498 local function placeArrow(ind,point)
9499 local newArrow = arrow:Clone()
9500 newArrow.Position = UDim2.new(0,ind-1,0,0)
9501 newArrow.Visible = true
9502 newArrow.Parent = arrowFrame
9503
9504 newArrow.InputBegan:Connect(function(input)
9505 if input.UserInputType == Enum.UserInputType.MouseMovement then
9506 cursor.Visible = true
9507 cursor.Position = UDim2.new(0,9 + newArrow.Position.X.Offset,0,0)
9508 end
9509 if input.UserInputType == Enum.UserInputType.MouseButton1 then
9510 updateInputs(point)
9511 if point == beginPoint or point == endPoint or currentlySelected then return end
9512
9513 local mouseEvent,releaseEvent
9514 currentlySelected = true
9515
9516 releaseEvent = user.InputEnded:Connect(function(input)
9517 if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
9518 mouseEvent:Disconnect()
9519 releaseEvent:Disconnect()
9520 currentlySelected = nil
9521 cursor.Visible = false
9522 end)
9523
9524 mouseEvent = user.InputChanged:Connect(function(input)
9525 if input.UserInputType == Enum.UserInputType.MouseMovement then
9526 local maxSize = colorLine.AbsoluteSize.X-1
9527 local relativeX = mouse.X - colorLine.AbsolutePosition.X
9528 if relativeX < 0 then relativeX = 0 end
9529 if relativeX > maxSize then relativeX = maxSize end
9530 local raw = relativeX/maxSize
9531 point[2] = relativeX/maxSize
9532 updateInputs(point)
9533 cursor.Visible = true
9534 cursor.Position = UDim2.new(0,9 + newArrow.Position.X.Offset,0,0)
9535 buildSequence()
9536 newMt:Redraw()
9537 end
9538 end)
9539 end
9540 end)
9541
9542 newArrow.InputEnded:Connect(function(input)
9543 if input.UserInputType == Enum.UserInputType.MouseMovement then
9544 cursor.Visible = false
9545 end
9546 end)
9547
9548 return newArrow
9549 end
9550
9551 local function placeArrows()
9552 for i,v in pairs(colors) do
9553 v[3] = placeArrow(math.floor((colorLine.AbsoluteSize.X-1) * v[2]) + 1,v)
9554 end
9555 end
9556
9557 local function redraw(self)
9558 gradient.Color = newMt.Sequence or ColorSequence.new(Color3.new(1,1,1))
9559
9560 for i = 2,#colors do
9561 local nextColor = colors[i]
9562 local endPos = math.floor((colorLine.AbsoluteSize.X-1) * nextColor[2]) + 1
9563 nextColor[3].Position = UDim2.new(0,endPos,0,0)
9564 end
9565 end
9566 newMt.Redraw = redraw
9567
9568 local function loadSequence(self,seq)
9569 resetSequence = seq
9570 for i,v in pairs(colors) do if v[3] then v[3]:Destroy() end end
9571 colors = {}
9572 currentlySelected = nil
9573 for i,v in pairs(seq.Keypoints) do
9574 local newPoint = {v.Value,v.Time}
9575 newPoint[3] = placeArrow(v.Time,newPoint)
9576 table.insert(colors,newPoint)
9577 end
9578 beginPoint = colors[1]
9579 endPoint = colors[#colors]
9580 currentlySelected = nil
9581 updateInputs(colors[1])
9582 buildSequence(true)
9583 redraw()
9584 end
9585 newMt.SetSequence = loadSequence
9586
9587 local function buttonAnimations(button,inverse)
9588 button.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement then button.BackgroundTransparency = (inverse and 0.5 or 0.4) end end)
9589 button.InputEnded:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement then button.BackgroundTransparency = (inverse and 1 or 0) end end)
9590 end
9591
9592 colorLine.InputBegan:Connect(function(input)
9593 if input.UserInputType == Enum.UserInputType.MouseButton1 and #colors < 20 then
9594 local maxSize = colorLine.AbsoluteSize.X-1
9595 local relativeX = mouse.X - colorLine.AbsolutePosition.X
9596 if relativeX < 0 then relativeX = 0 end
9597 if relativeX > maxSize then relativeX = maxSize end
9598
9599 local raw = relativeX/maxSize
9600 local fromColor = nil
9601 local toColor = nil
9602 for i,col in pairs(colors) do
9603 if col[2] >= raw then
9604 fromColor = colors[math.max(i-1,1)]
9605 toColor = colors[i]
9606 break
9607 end
9608 end
9609 local lerpColor = fromColor[1]:lerp(toColor[1],(raw-fromColor[2])/(toColor[2]-fromColor[2]))
9610 local newPoint = {lerpColor,raw}
9611 newPoint[3] = placeArrow(newPoint[2],newPoint)
9612 table.insert(colors,newPoint)
9613 updateInputs(newPoint)
9614 buildSequence()
9615 redraw()
9616 end
9617 end)
9618
9619 colorLine.InputChanged:Connect(function(input)
9620 if input.UserInputType == Enum.UserInputType.MouseMovement then
9621 local maxSize = colorLine.AbsoluteSize.X-1
9622 local relativeX = mouse.X - colorLine.AbsolutePosition.X
9623 if relativeX < 0 then relativeX = 0 end
9624 if relativeX > maxSize then relativeX = maxSize end
9625 cursor.Visible = true
9626 cursor.Position = UDim2.new(0,10 + relativeX,0,0)
9627 end
9628 end)
9629
9630 colorLine.InputEnded:Connect(function(input)
9631 if input.UserInputType == Enum.UserInputType.MouseMovement then
9632 local inArrow = false
9633 for i,v in pairs(colors) do
9634 if Lib.CheckMouseInGui(v[3]) then
9635 inArrow = v[3]
9636 end
9637 end
9638 cursor.Visible = inArrow and true or false
9639 if inArrow then cursor.Position = UDim2.new(0,9 + inArrow.Position.X.Offset,0,0) end
9640 end
9641 end)
9642
9643 timeBox:GetPropertyChangedSignal("Text"):Connect(function()
9644 local point = currentPoint
9645 local num = tonumber(timeBox.Text)
9646 if point and num and point ~= beginPoint and point ~= endPoint then
9647 num = math.clamp(num,0,1)
9648 point[2] = num
9649 buildSequence()
9650 redraw()
9651 end
9652 end)
9653
9654 colorBox.InputBegan:Connect(function(input)
9655 if input.UserInputType == Enum.UserInputType.MouseButton1 then
9656 local editor = newMt.ColorPicker
9657 if not editor then
9658 editor = Lib.ColorPicker.new()
9659 editor.Window:SetTitle("ColorSequence Color Picker")
9660
9661 editor.OnSelect:Connect(function(col)
9662 if currentPoint then
9663 currentPoint[1] = col
9664 end
9665 buildSequence()
9666 redraw()
9667 end)
9668
9669 newMt.ColorPicker = editor
9670 end
9671
9672 editor.Window:ShowAndFocus()
9673 end
9674 end)
9675
9676 deleteButton.MouseButton1Click:Connect(function()
9677 if currentPoint and currentPoint ~= beginPoint and currentPoint ~= endPoint then
9678 for i,v in pairs(colors) do
9679 if v == currentPoint then
9680 v[3]:Destroy()
9681 table.remove(colors,i)
9682 break
9683 end
9684 end
9685 currentlySelected = nil
9686 updateInputs(colors[1])
9687 buildSequence()
9688 redraw()
9689 end
9690 end)
9691
9692 resetButton.MouseButton1Click:Connect(function()
9693 if resetSequence then
9694 newMt:SetSequence(resetSequence)
9695 end
9696 end)
9697
9698 closeButton.MouseButton1Click:Connect(function()
9699 window:Close()
9700 end)
9701
9702 topClose.MouseButton1Click:Connect(function()
9703 window:Close()
9704 end)
9705
9706 buttonAnimations(deleteButton)
9707 buttonAnimations(resetButton)
9708 buttonAnimations(closeButton)
9709
9710 placeArrows()
9711 redraw()
9712
9713 newMt.Show = function(self)
9714 window:Show()
9715 end
9716
9717 return newMt
9718 end
9719
9720 return {new = new}
9721 end)()
9722
9723 Lib.ViewportTextBox = (function()
9724 local textService = clonerefs(game:GetService("TextService"))
9725
9726 local props = {
9727 OffsetX = 0,
9728 TextBox = PH,
9729 CursorPos = -1,
9730 Gui = PH,
9731 View = PH
9732 }
9733 local funcs = {}
9734 funcs.Update = function(self)
9735 local cursorPos = self.CursorPos or -1
9736 local text = self.TextBox.Text
9737 if text == "" then self.TextBox.Position = UDim2.new(0,0,0,0) return end
9738 if cursorPos == -1 then return end
9739
9740 local cursorText = text:sub(1,cursorPos-1)
9741 local pos = nil
9742 local leftEnd = -self.TextBox.Position.X.Offset
9743 local rightEnd = leftEnd + self.View.AbsoluteSize.X
9744
9745 local totalTextSize = textService:GetTextSize(text,self.TextBox.TextSize,self.TextBox.Font,Vector2.new(999999999,100)).X
9746 local cursorTextSize = textService:GetTextSize(cursorText,self.TextBox.TextSize,self.TextBox.Font,Vector2.new(999999999,100)).X
9747
9748 if cursorTextSize > rightEnd then
9749 pos = math.max(-1,cursorTextSize - self.View.AbsoluteSize.X + 2)
9750 elseif cursorTextSize < leftEnd then
9751 pos = math.max(-1,cursorTextSize-2)
9752 elseif totalTextSize < rightEnd then
9753 pos = math.max(-1,totalTextSize - self.View.AbsoluteSize.X + 2)
9754 end
9755
9756 if pos then
9757 self.TextBox.Position = UDim2.new(0,-pos,0,0)
9758 self.TextBox.Size = UDim2.new(1,pos,1,0)
9759 end
9760 end
9761
9762 funcs.GetText = function(self)
9763 return self.TextBox.Text
9764 end
9765
9766 funcs.SetText = function(self,text)
9767 self.TextBox.Text = text
9768 end
9769
9770 local mt = getGuiMT(props,funcs)
9771
9772 local function convert(textbox)
9773 local obj = initObj(props,mt)
9774
9775 local view = Instance.new("Frame")
9776 view.BackgroundTransparency = textbox.BackgroundTransparency
9777 view.BackgroundColor3 = textbox.BackgroundColor3
9778 view.BorderSizePixel = textbox.BorderSizePixel
9779 view.BorderColor3 = textbox.BorderColor3
9780 view.Position = textbox.Position
9781 view.Size = textbox.Size
9782 view.ClipsDescendants = true
9783 view.Name = textbox.Name
9784 textbox.BackgroundTransparency = 1
9785 textbox.Position = UDim2.new(0,0,0,0)
9786 textbox.Size = UDim2.new(1,0,1,0)
9787 textbox.TextXAlignment = Enum.TextXAlignment.Left
9788 textbox.Name = "Input"
9789
9790 obj.TextBox = textbox
9791 obj.View = view
9792 obj.Gui = view
9793
9794 textbox.Changed:Connect(function(prop)
9795 if prop == "Text" or prop == "CursorPosition" or prop == "AbsoluteSize" then
9796 local cursorPos = obj.TextBox.CursorPosition
9797 if cursorPos ~= -1 then obj.CursorPos = cursorPos end
9798 obj:Update()
9799 end
9800 end)
9801
9802 obj:Update()
9803
9804 view.Parent = textbox.Parent
9805 textbox.Parent = view
9806
9807 return obj
9808 end
9809
9810 local function new()
9811 local textBox = Instance.new("TextBox")
9812 textBox.Size = UDim2.new(0,100,0,20)
9813 textBox.BackgroundColor3 = Settings.Theme.TextBox
9814 textBox.BorderColor3 = Settings.Theme.Outline3
9815 textBox.ClearTextOnFocus = false
9816 textBox.TextColor3 = Settings.Theme.Text
9817 textBox.Font = Enum.Font.SourceSans
9818 textBox.TextSize = 14
9819 textBox.Text = ""
9820 return convert(textBox)
9821 end
9822
9823 return {new = new, convert = convert}
9824 end)()
9825
9826 Lib.Label = (function()
9827 local props,funcs = {},{}
9828
9829 local mt = getGuiMT(props,funcs)
9830
9831 local function new()
9832 local label = Instance.new("TextLabel")
9833 label.BackgroundTransparency = 1
9834 label.TextXAlignment = Enum.TextXAlignment.Left
9835 label.TextColor3 = Settings.Theme.Text
9836 label.TextTransparency = 0.1
9837 label.Size = UDim2.new(0,100,0,20)
9838 label.Font = Enum.Font.SourceSans
9839 label.TextSize = 14
9840
9841 local obj = setmetatable({
9842 Gui = label
9843 },mt)
9844 return obj
9845 end
9846
9847 return {new = new}
9848 end)()
9849
9850 Lib.Frame = (function()
9851 local props,funcs = {},{}
9852
9853 local mt = getGuiMT(props,funcs)
9854
9855 local function new()
9856 local fr = Instance.new("Frame")
9857 fr.BackgroundColor3 = Settings.Theme.Main1
9858 fr.BorderColor3 = Settings.Theme.Outline1
9859 fr.Size = UDim2.new(0,50,0,50)
9860
9861 local obj = setmetatable({
9862 Gui = fr
9863 },mt)
9864 return obj
9865 end
9866
9867 return {new = new}
9868 end)()
9869
9870 Lib.Button = (function()
9871 local props = {
9872 Gui = PH,
9873 Anim = PH,
9874 Disabled = false,
9875 OnClick = SIGNAL,
9876 OnDown = SIGNAL,
9877 OnUp = SIGNAL,
9878 AllowedButtons = {1}
9879 }
9880 local funcs = {}
9881 local tableFind = table.find
9882
9883 funcs.Trigger = function(self,event,button)
9884 if not self.Disabled and tableFind(self.AllowedButtons,button) then
9885 self["On"..event]:Fire(button)
9886 end
9887 end
9888
9889 funcs.SetDisabled = function(self,dis)
9890 self.Disabled = dis
9891
9892 if dis then
9893 self.Anim:Disable()
9894 self.Gui.TextTransparency = 0.5
9895 else
9896 self.Anim.Enable()
9897 self.Gui.TextTransparency = 0
9898 end
9899 end
9900
9901 local mt = getGuiMT(props,funcs)
9902
9903 local function new()
9904 local b = Instance.new("TextButton")
9905 b.AutoButtonColor = false
9906 b.TextColor3 = Settings.Theme.Text
9907 b.TextTransparency = 0.1
9908 b.Size = UDim2.new(0,100,0,20)
9909 b.Font = Enum.Font.SourceSans
9910 b.TextSize = 14
9911 b.BackgroundColor3 = Settings.Theme.Button
9912 b.BorderColor3 = Settings.Theme.Outline2
9913
9914 local obj = initObj(props,mt)
9915 obj.Gui = b
9916 obj.Anim = Lib.ButtonAnim(b,{Mode = 2, StartColor = Settings.Theme.Button, HoverColor = Settings.Theme.ButtonHover, PressColor = Settings.Theme.ButtonPress, OutlineColor = Settings.Theme.Outline2})
9917
9918 b.MouseButton1Click:Connect(function() obj:Trigger("Click",1) end)
9919 b.MouseButton1Down:Connect(function() obj:Trigger("Down",1) end)
9920 b.MouseButton1Up:Connect(function() obj:Trigger("Up",1) end)
9921
9922 b.MouseButton2Click:Connect(function() obj:Trigger("Click",2) end)
9923 b.MouseButton2Down:Connect(function() obj:Trigger("Down",2) end)
9924 b.MouseButton2Up:Connect(function() obj:Trigger("Up",2) end)
9925
9926 return obj
9927 end
9928
9929 return {new = new}
9930 end)()
9931
9932 Lib.DropDown = (function()
9933 local props = {
9934 Gui = PH,
9935 Anim = PH,
9936 Context = PH,
9937 Selected = PH,
9938 Disabled = false,
9939 CanBeEmpty = true,
9940 Options = {},
9941 GuiElems = {},
9942 OnSelect = SIGNAL
9943 }
9944 local funcs = {}
9945
9946 funcs.Update = function(self)
9947 local options = self.Options
9948
9949 if #options > 0 then
9950 if not self.Selected then
9951 if not self.CanBeEmpty then
9952 self.Selected = options[1]
9953 self.GuiElems.Label.Text = options[1]
9954 else
9955 self.GuiElems.Label.Text = "- Select -"
9956 end
9957 else
9958 self.GuiElems.Label.Text = self.Selected
9959 end
9960 else
9961 self.GuiElems.Label.Text = "- Select -"
9962 end
9963 end
9964
9965 funcs.ShowOptions = function(self)
9966 local context = self.Context
9967
9968 context.Width = self.Gui.AbsoluteSize.X
9969 context.ReverseYOffset = self.Gui.AbsoluteSize.Y
9970 context:Show(self.Gui.AbsolutePosition.X, self.Gui.AbsolutePosition.Y + context.ReverseYOffset)
9971 end
9972
9973 funcs.SetOptions = function(self,opts)
9974 self.Options = opts
9975
9976 local context = self.Context
9977 local options = self.Options
9978 context:Clear()
9979
9980 local onClick = function(option) self.Selected = option self.OnSelect:Fire(option) self:Update() end
9981
9982 if self.CanBeEmpty then
9983 context:Add({Name = "- Select -", OnClick = function() self.Selected = nil self.OnSelect:Fire(nil) self:Update() end})
9984 end
9985
9986 for i = 1,#options do
9987 context:Add({Name = options[i], OnClick = onClick})
9988 end
9989
9990 self:Update()
9991 end
9992
9993 funcs.SetSelected = function(self,opt)
9994 self.Selected = type(opt) == "number" and self.Options[opt] or opt
9995 self:Update()
9996 end
9997
9998 local mt = getGuiMT(props,funcs)
9999
10000 local function new()
10001 local f = Instance.new("TextButton")
10002 f.AutoButtonColor = false
10003 f.Text = ""
10004 f.Size = UDim2.new(0,100,0,20)
10005 f.BackgroundColor3 = Settings.Theme.TextBox
10006 f.BorderColor3 = Settings.Theme.Outline3
10007
10008 local label = Lib.Label.new()
10009 label.Position = UDim2.new(0,2,0,0)
10010 label.Size = UDim2.new(1,-22,1,0)
10011 label.TextTruncate = Enum.TextTruncate.AtEnd
10012 label.Parent = f
10013 local arrow = create({
10014 {1,"Frame",{BackgroundTransparency=1,Name="EnumArrow",Position=UDim2.new(1,-16,0,2),Size=UDim2.new(0,16,0,16),}},
10015 {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),}},
10016 {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),}},
10017 {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),}},
10018 })
10019 arrow.Parent = f
10020
10021 local obj = initObj(props,mt)
10022 obj.Gui = f
10023 obj.Anim = Lib.ButtonAnim(f,{Mode = 2, StartColor = Settings.Theme.TextBox, LerpTo = Settings.Theme.Button, LerpDelta = 0.15})
10024 obj.Context = Lib.ContextMenu.new()
10025 obj.Context.Iconless = true
10026 obj.Context.MaxHeight = 200
10027 obj.Selected = nil
10028 obj.GuiElems = {Label = label}
10029 f.MouseButton1Down:Connect(function() obj:ShowOptions() end)
10030 obj:Update()
10031 return obj
10032 end
10033
10034 return {new = new}
10035 end)()
10036
10037 Lib.ClickSystem = (function()
10038 local props = {
10039 LastItem = PH,
10040 OnDown = SIGNAL,
10041 OnRelease = SIGNAL,
10042 AllowedButtons = {1},
10043 Combo = 0,
10044 MaxCombo = 2,
10045 ComboTime = 0.5,
10046 Items = {},
10047 ItemCons = {},
10048 ClickId = -1,
10049 LastButton = ""
10050 }
10051 local funcs = {}
10052 local tostring = tostring
10053
10054 local disconnect = function(con)
10055 local pos = table.find(con.Signal.Connections,con)
10056 if pos then table.remove(con.Signal.Connections,pos) end
10057 end
10058
10059 funcs.Trigger = function(self,item,button)
10060 if table.find(self.AllowedButtons,button) then
10061 if self.LastButton ~= button or self.LastItem ~= item or self.Combo == self.MaxCombo or tick() - self.ClickId > self.ComboTime then
10062 self.Combo = 0
10063 self.LastButton = button
10064 self.LastItem = item
10065 end
10066 self.Combo = self.Combo + 1
10067 self.ClickId = tick()
10068
10069 local release
10070 release = service.UserInputService.InputEnded:Connect(function(input)
10071 if input.UserInputType == Enum.UserInputType["MouseButton"..button] then
10072 release:Disconnect()
10073 if Lib.CheckMouseInGui(item) and self.LastButton == button and self.LastItem == item then
10074 self["OnRelease"]:Fire(item,self.Combo,button)
10075 end
10076 end
10077 end)
10078
10079 self["OnDown"]:Fire(item,self.Combo,button)
10080 end
10081 end
10082
10083 funcs.Add = function(self,item)
10084 if table.find(self.Items,item) then return end
10085
10086 local cons = {}
10087 cons[1] = item.MouseButton1Down:Connect(function() self:Trigger(item,1) end)
10088 cons[2] = item.MouseButton2Down:Connect(function() self:Trigger(item,2) end)
10089
10090 self.ItemCons[item] = cons
10091 self.Items[#self.Items+1] = item
10092 end
10093
10094 funcs.Remove = function(self,item)
10095 local ind = table.find(self.Items,item)
10096 if not ind then return end
10097
10098 for i,v in pairs(self.ItemCons[item]) do
10099 v:Disconnect()
10100 end
10101 self.ItemCons[item] = nil
10102 table.remove(self.Items,ind)
10103 end
10104
10105 local mt = {__index = funcs}
10106
10107 local function new()
10108 local obj = initObj(props,mt)
10109
10110 return obj
10111 end
10112
10113 return {new = new}
10114 end)()
10115
10116 return Lib
10117end
10118
10119return {InitDeps = initDeps, InitAfterMain = initAfterMain, Main = main}
10120end
10121}
10122
10123-- Main vars
10124local Main, Explorer, Properties, ScriptViewer, DefaultSettings, Notebook, Serializer, Lib
10125local API, RMD
10126
10127-- Default Settings
10128DefaultSettings = (function()
10129 local rgb = Color3.fromRGB
10130 return {
10131 Explorer = {
10132 _Recurse = true,
10133 Sorting = true,
10134 TeleportToOffset = Vector3.new(0,0,0),
10135 ClickToRename = true,
10136 AutoUpdateSearch = true,
10137 AutoUpdateMode = 0, -- 0 Default, 1 no tree update, 2 no descendant events, 3 frozen
10138 PartSelectionBox = true,
10139 GuiSelectionBox = true,
10140 CopyPathUseGetChildren = true
10141 },
10142 Properties = {
10143 _Recurse = true,
10144 MaxConflictCheck = 50,
10145 ShowDeprecated = false,
10146 ShowHidden = false,
10147 ClearOnFocus = false,
10148 LoadstringInput = true,
10149 NumberRounding = 3,
10150 ShowAttributes = false,
10151 MaxAttributes = 50,
10152 ScaleType = 1 -- 0 Full Name Shown, 1 Equal Halves
10153 },
10154 Theme = {
10155 _Recurse = true,
10156 Main1 = rgb(52,52,52),
10157 Main2 = rgb(45,45,45),
10158 Outline1 = rgb(33,33,33), -- Mainly frames
10159 Outline2 = rgb(55,55,55), -- Mainly button
10160 Outline3 = rgb(30,30,30), -- Mainly textbox
10161 TextBox = rgb(38,38,38),
10162 Menu = rgb(32,32,32),
10163 ListSelection = rgb(11,90,175),
10164 Button = rgb(60,60,60),
10165 ButtonHover = rgb(68,68,68),
10166 ButtonPress = rgb(40,40,40),
10167 Highlight = rgb(75,75,75),
10168 Text = rgb(255,255,255),
10169 PlaceholderText = rgb(100,100,100),
10170 Important = rgb(255,0,0),
10171 ExplorerIconMap = "",
10172 MiscIconMap = "",
10173 Syntax = {
10174 Text = rgb(204,204,204),
10175 Background = rgb(36,36,36),
10176 Selection = rgb(255,255,255),
10177 SelectionBack = rgb(11,90,175),
10178 Operator = rgb(204,204,204),
10179 Number = rgb(255,198,0),
10180 String = rgb(173,241,149),
10181 Comment = rgb(102,102,102),
10182 Keyword = rgb(248,109,124),
10183 Error = rgb(255,0,0),
10184 FindBackground = rgb(141,118,0),
10185 MatchingWord = rgb(85,85,85),
10186 BuiltIn = rgb(132,214,247),
10187 CurrentLine = rgb(45,50,65),
10188 LocalMethod = rgb(253,251,172),
10189 LocalProperty = rgb(97,161,241),
10190 Nil = rgb(255,198,0),
10191 Bool = rgb(255,198,0),
10192 Function = rgb(248,109,124),
10193 Local = rgb(248,109,124),
10194 Self = rgb(248,109,124),
10195 FunctionName = rgb(253,251,172),
10196 Bracket = rgb(204,204,204)
10197 },
10198 }
10199 }
10200end)()
10201
10202-- Vars
10203local Settings = {}
10204local Apps = {}
10205local env = {}
10206local service = setmetatable({},{__index = function(self,name)
10207 local serv = clonerefs(game:GetService(name))
10208 self[name] = serv
10209 return serv
10210end})
10211local plr = service.Players.LocalPlayer or service.Players.PlayerAdded:wait()
10212
10213local create = function(data)
10214 local insts = {}
10215 for i,v in pairs(data) do insts[v[1]] = Instance.new(v[2]) end
10216
10217 for _,v in pairs(data) do
10218 for prop,val in pairs(v[3]) do
10219 if type(val) == "table" then
10220 insts[v[1]][prop] = insts[val[1]]
10221 else
10222 insts[v[1]][prop] = val
10223 end
10224 end
10225 end
10226
10227 return insts[1]
10228end
10229
10230local createSimple = function(class,props)
10231 local inst = Instance.new(class)
10232 for i,v in next,props do
10233 inst[i] = v
10234 end
10235 return inst
10236end
10237
10238Main = (function()
10239 local Main = {}
10240
10241 Main.ModuleList = {"Explorer","Properties","ScriptViewer"}
10242 Main.Elevated = false
10243 Main.MissingEnv = {}
10244 Main.Version = "" -- Beta 1.0.0
10245 Main.Mouse = plr:GetMouse()
10246 Main.AppControls = {}
10247 Main.Apps = Apps
10248 Main.MenuApps = {}
10249
10250 Main.DisplayOrders = {
10251 SideWindow = 8,
10252 Window = 10,
10253 Menu = 100000,
10254 Core = 101000
10255 }
10256
10257 Main.GetInitDeps = function()
10258 return {
10259 Main = Main,
10260 Lib = Lib,
10261 Apps = Apps,
10262 Settings = Settings,
10263
10264 API = API,
10265 RMD = RMD,
10266 env = env,
10267 service = service,
10268 plr = plr,
10269 create = create,
10270 createSimple = createSimple
10271 }
10272 end
10273
10274 Main.Error = function(str)
10275 if rconsoleprint then
10276 rconsoleprint("DEX ERROR: "..tostring(str).."\n")
10277 wait(9e9)
10278 else
10279 error(str)
10280 end
10281 end
10282
10283 Main.LoadModule = function(name)
10284 if Main.Elevated then -- If you don't have filesystem api then ur outta luck tbh
10285 local control
10286
10287 if EmbeddedModules then -- Offline Modules
10288 control = EmbeddedModules[name]()
10289
10290 if not control then Main.Error("Missing Embedded Module: "..name) end
10291 end
10292
10293 Main.AppControls[name] = control
10294 control.InitDeps(Main.GetInitDeps())
10295
10296 local moduleData = control.Main()
10297 Apps[name] = moduleData
10298 return moduleData
10299 else
10300 local module = script:WaitForChild("Modules"):WaitForChild(name,2)
10301 if not module then Main.Error("CANNOT FIND MODULE "..name) end
10302
10303 local control = require(module)
10304 Main.AppControls[name] = control
10305 control.InitDeps(Main.GetInitDeps())
10306
10307 local moduleData = control.Main()
10308 Apps[name] = moduleData
10309 return moduleData
10310 end
10311 end
10312
10313 Main.LoadModules = function()
10314 for i,v in pairs(Main.ModuleList) do
10315 local s,e = pcall(Main.LoadModule,v)
10316 if not s then
10317 Main.Error("FAILED LOADING " + v + " CAUSE " + e)
10318 end
10319 end
10320
10321 -- Init Major Apps and define them in modules
10322 Explorer = Apps.Explorer
10323 Properties = Apps.Properties
10324 ScriptViewer = Apps.ScriptViewer
10325 Notebook = Apps.Notebook
10326 local appTable = {
10327 Explorer = Explorer,
10328 Properties = Properties,
10329 ScriptViewer = ScriptViewer,
10330 Notebook = Notebook
10331 }
10332
10333 Main.AppControls.Lib.InitAfterMain(appTable)
10334 for i,v in pairs(Main.ModuleList) do
10335 local control = Main.AppControls[v]
10336 if control then
10337 control.InitAfterMain(appTable)
10338 end
10339 end
10340 end
10341
10342 Main.InitEnv = function()
10343 setmetatable(env, {__newindex = function(self, name, func)
10344 if not func then Main.MissingEnv[#Main.MissingEnv + 1] = name return end
10345 rawset(self, name, func)
10346 end})
10347
10348 -- file
10349 env.readfile = readfile
10350 env.writefile = writefile
10351 env.appendfile = appendfile
10352 env.makefolder = makefolder
10353 env.listfiles = listfiles
10354 env.loadfile = loadfile
10355 env.saveinstance = saveinstance
10356
10357 -- debug
10358 env.getupvalues = debug.getupvalues or getupvals
10359 env.getconstants = debug.getconstants or getconsts
10360 env.islclosure = islclosure or is_l_closure
10361 env.checkcaller = checkcaller
10362 env.getreg = getreg
10363 env.getgc = getgc
10364
10365 -- other
10366 env.setfflag = setfflag
10367 env.decompile = decompile
10368 env.protectgui = protect_gui or (syn and syn.protect_gui)
10369 env.gethui = gethui
10370 env.setclipboard = setclipboard
10371 env.getnilinstances = getnilinstances or get_nil_instances
10372 env.getloadedmodules = getloadedmodules
10373
10374 if identifyexecutor then Main.Executor = identifyexecutor() end
10375
10376 Main.GuiHolder = Main.Elevated and service.CoreGui or plr:FindFirstChildOfClass("PlayerGui")
10377
10378 setmetatable(env, nil)
10379 end
10380
10381 Main.LoadSettings = function()
10382 local s,data = pcall(env.readfile or error,"DexSettings.json")
10383 if s and data and data ~= "" then
10384 local s,decoded = service.HttpService:JSONDecode(data)
10385 if s and decoded then
10386 for i,v in next,decoded do
10387
10388 end
10389 else
10390 -- TODO: Notification
10391 end
10392 else
10393 Main.ResetSettings()
10394 end
10395 end
10396
10397 Main.ResetSettings = function()
10398 local function recur(t,res)
10399 for set,val in pairs(t) do
10400 if type(val) == "table" and val._Recurse then
10401 if type(res[set]) ~= "table" then
10402 res[set] = {}
10403 end
10404 recur(val,res[set])
10405 else
10406 res[set] = val
10407 end
10408 end
10409 return res
10410 end
10411 recur(DefaultSettings,Settings)
10412 end
10413
10414 Main.FetchAPI = function()
10415 local api,rawAPI
10416 if Main.Elevated then
10417 if Main.LocalDepsUpToDate() then
10418 local localAPI = Lib.ReadFile("dex/rbx_api.dat")
10419 if localAPI then
10420 rawAPI = localAPI
10421 else
10422 Main.DepsVersionData[1] = ""
10423 end
10424 end
10425 rawAPI = rawAPI or game:HttpGet("http://setup.roblox.com/"..Main.RobloxVersion.."-API-Dump.json")
10426 else
10427 if script:FindFirstChild("API") then
10428 rawAPI = require(script.API)
10429 else
10430 error("NO API EXISTS")
10431 end
10432 end
10433 Main.RawAPI = rawAPI
10434 api = service.HttpService:JSONDecode(rawAPI)
10435
10436 local classes,enums = {},{}
10437 local categoryOrder,seenCategories = {},{}
10438
10439 local function insertAbove(t,item,aboveItem)
10440 local findPos = table.find(t,item)
10441 if not findPos then return end
10442 table.remove(t,findPos)
10443
10444 local pos = table.find(t,aboveItem)
10445 if not pos then return end
10446 table.insert(t,pos,item)
10447 end
10448
10449 for _,class in pairs(api.Classes) do
10450 local newClass = {}
10451 newClass.Name = class.Name
10452 newClass.Superclass = class.Superclass
10453 newClass.Properties = {}
10454 newClass.Functions = {}
10455 newClass.Events = {}
10456 newClass.Callbacks = {}
10457 newClass.Tags = {}
10458
10459 if class.Tags then for c,tag in pairs(class.Tags) do newClass.Tags[tag] = true end end
10460 for __,member in pairs(class.Members) do
10461 local newMember = {}
10462 newMember.Name = member.Name
10463 newMember.Class = class.Name
10464 newMember.Security = member.Security
10465 newMember.Tags ={}
10466 if member.Tags then for c,tag in pairs(member.Tags) do newMember.Tags[tag] = true end end
10467
10468 local mType = member.MemberType
10469 if mType == "Property" then
10470 local propCategory = member.Category or "Other"
10471 propCategory = propCategory:match("^%s*(.-)%s*$")
10472 if not seenCategories[propCategory] then
10473 categoryOrder[#categoryOrder+1] = propCategory
10474 seenCategories[propCategory] = true
10475 end
10476 newMember.ValueType = member.ValueType
10477 newMember.Category = propCategory
10478 newMember.Serialization = member.Serialization
10479 table.insert(newClass.Properties,newMember)
10480 elseif mType == "Function" then
10481 newMember.Parameters = {}
10482 newMember.ReturnType = member.ReturnType.Name
10483 for c,param in pairs(member.Parameters) do
10484 table.insert(newMember.Parameters,{Name = param.Name, Type = param.Type.Name})
10485 end
10486 table.insert(newClass.Functions,newMember)
10487 elseif mType == "Event" then
10488 newMember.Parameters = {}
10489 for c,param in pairs(member.Parameters) do
10490 table.insert(newMember.Parameters,{Name = param.Name, Type = param.Type.Name})
10491 end
10492 table.insert(newClass.Events,newMember)
10493 end
10494 end
10495
10496 classes[class.Name] = newClass
10497 end
10498
10499 for _,class in pairs(classes) do
10500 class.Superclass = classes[class.Superclass]
10501 end
10502
10503 for _,enum in pairs(api.Enums) do
10504 local newEnum = {}
10505 newEnum.Name = enum.Name
10506 newEnum.Items = {}
10507 newEnum.Tags = {}
10508
10509 if enum.Tags then for c,tag in pairs(enum.Tags) do newEnum.Tags[tag] = true end end
10510 for __,item in pairs(enum.Items) do
10511 local newItem = {}
10512 newItem.Name = item.Name
10513 newItem.Value = item.Value
10514 table.insert(newEnum.Items,newItem)
10515 end
10516
10517 enums[enum.Name] = newEnum
10518 end
10519
10520 local function getMember(class,member)
10521 if not classes[class] or not classes[class][member] then return end
10522 local result = {}
10523
10524 local currentClass = classes[class]
10525 while currentClass do
10526 for _,entry in pairs(currentClass[member]) do
10527 result[#result+1] = entry
10528 end
10529 currentClass = currentClass.Superclass
10530 end
10531
10532 table.sort(result,function(a,b) return a.Name < b.Name end)
10533 return result
10534 end
10535
10536 insertAbove(categoryOrder,"Behavior","Tuning")
10537 insertAbove(categoryOrder,"Appearance","Data")
10538 insertAbove(categoryOrder,"Attachments","Axes")
10539 insertAbove(categoryOrder,"Cylinder","Slider")
10540 insertAbove(categoryOrder,"Localization","Jump Settings")
10541 insertAbove(categoryOrder,"Surface","Motion")
10542 insertAbove(categoryOrder,"Surface Inputs","Surface")
10543 insertAbove(categoryOrder,"Part","Surface Inputs")
10544 insertAbove(categoryOrder,"Assembly","Surface Inputs")
10545 insertAbove(categoryOrder,"Character","Controls")
10546 categoryOrder[#categoryOrder+1] = "Unscriptable"
10547 categoryOrder[#categoryOrder+1] = "Attributes"
10548
10549 local categoryOrderMap = {}
10550 for i = 1,#categoryOrder do
10551 categoryOrderMap[categoryOrder[i]] = i
10552 end
10553
10554 return {
10555 Classes = classes,
10556 Enums = enums,
10557 CategoryOrder = categoryOrderMap,
10558 GetMember = getMember
10559 }
10560 end
10561
10562 Main.FetchRMD = function()
10563 local rawXML
10564 if Main.Elevated then
10565 if Main.LocalDepsUpToDate() then
10566 local localRMD = Lib.ReadFile("dex/rbx_rmd.dat")
10567 if localRMD then
10568 rawXML = localRMD
10569 else
10570 Main.DepsVersionData[1] = ""
10571 end
10572 end
10573 rawXML = rawXML or game:HttpGet("https://raw.githubusercontent.com/CloneTrooper1019/Roblox-Client-Tracker/roblox/ReflectionMetadata.xml")
10574 else
10575 if script:FindFirstChild("RMD") then
10576 rawXML = require(script.RMD)
10577 else
10578 error("NO RMD EXISTS")
10579 end
10580 end
10581 Main.RawRMD = rawXML
10582 local parsed = Lib.ParseXML(rawXML)
10583 local classList = parsed.children[1].children[1].children
10584 local enumList = parsed.children[1].children[2].children
10585 local propertyOrders = {}
10586
10587 local classes,enums = {},{}
10588 for _,class in pairs(classList) do
10589 local className = ""
10590 for _,child in pairs(class.children) do
10591 if child.tag == "Properties" then
10592 local data = {Properties = {}, Functions = {}}
10593 local props = child.children
10594 for _,prop in pairs(props) do
10595 local name = prop.attrs.name
10596 name = name:sub(1,1):upper()..name:sub(2)
10597 data[name] = prop.children[1].text
10598 end
10599 className = data.Name
10600 classes[className] = data
10601 elseif child.attrs.class == "ReflectionMetadataProperties" then
10602 local members = child.children
10603 for _,member in pairs(members) do
10604 if member.attrs.class == "ReflectionMetadataMember" then
10605 local data = {}
10606 if member.children[1].tag == "Properties" then
10607 local props = member.children[1].children
10608 for _,prop in pairs(props) do
10609 if prop.attrs then
10610 local name = prop.attrs.name
10611 name = name:sub(1,1):upper()..name:sub(2)
10612 data[name] = prop.children[1].text
10613 end
10614 end
10615 if data.PropertyOrder then
10616 local orders = propertyOrders[className]
10617 if not orders then orders = {} propertyOrders[className] = orders end
10618 orders[data.Name] = tonumber(data.PropertyOrder)
10619 end
10620 classes[className].Properties[data.Name] = data
10621 end
10622 end
10623 end
10624 elseif child.attrs.class == "ReflectionMetadataFunctions" then
10625 local members = child.children
10626 for _,member in pairs(members) do
10627 if member.attrs.class == "ReflectionMetadataMember" then
10628 local data = {}
10629 if member.children[1].tag == "Properties" then
10630 local props = member.children[1].children
10631 for _,prop in pairs(props) do
10632 if prop.attrs then
10633 local name = prop.attrs.name
10634 name = name:sub(1,1):upper()..name:sub(2)
10635 data[name] = prop.children[1].text
10636 end
10637 end
10638 classes[className].Functions[data.Name] = data
10639 end
10640 end
10641 end
10642 end
10643 end
10644 end
10645
10646 for _,enum in pairs(enumList) do
10647 local enumName = ""
10648 for _,child in pairs(enum.children) do
10649 if child.tag == "Properties" then
10650 local data = {Items = {}}
10651 local props = child.children
10652 for _,prop in pairs(props) do
10653 local name = prop.attrs.name
10654 name = name:sub(1,1):upper()..name:sub(2)
10655 data[name] = prop.children[1].text
10656 end
10657 enumName = data.Name
10658 enums[enumName] = data
10659 elseif child.attrs.class == "ReflectionMetadataEnumItem" then
10660 local data = {}
10661 if child.children[1].tag == "Properties" then
10662 local props = child.children[1].children
10663 for _,prop in pairs(props) do
10664 local name = prop.attrs.name
10665 name = name:sub(1,1):upper()..name:sub(2)
10666 data[name] = prop.children[1].text
10667 end
10668 enums[enumName].Items[data.Name] = data
10669 end
10670 end
10671 end
10672 end
10673
10674 return {Classes = classes, Enums = enums, PropertyOrders = propertyOrders}
10675 end
10676
10677 Main.ShowGui = function(gui)
10678 if env.protectgui then
10679 env.protectgui(gui)
10680 end
10681 gui.Parent = Main.GuiHolder
10682 end
10683
10684 Main.CreateIntro = function(initStatus) -- TODO: Must theme and show errors
10685 local gui = create({
10686 {1,"ScreenGui",{Name="Intro",}},
10687 {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),}},
10688 {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),}},
10689 {4,"UIGradient",{Parent={3},Rotation=30,Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenceKeypoint.new(1,1,0),}),}},
10690 {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,}},
10691 {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,}},
10692 {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,}},
10693 {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),}},
10694 {9,"Frame",{BackgroundColor3=Color3.new(0.2392156869173,0.56078433990479,0.86274510622025),BorderSizePixel=0,Name="Bar",Parent={8},Size=UDim2.new(0,0,1,0),}},
10695 {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),}},
10696 {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,}},
10697 {12,"UIGradient",{Parent={11},Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenceKeypoint.new(1,1,0),}),}},
10698 {13,"TextLabel",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Font=3,Name="Version",Parent={2},Position=UDim2.new(1,-110,1,-35),Size=UDim2.new(0,105,0,20),Text=Main.Version,TextColor3=Color3.new(1,1,1),TextSize=14,TextXAlignment=1,}},
10699 {14,"UIGradient",{Parent={13},Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenceKeypoint.new(1,1,0),}),}},
10700 {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),}},
10701 {16,"UIGradient",{Parent={15},Rotation=-30,Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenceKeypoint.new(1,1,0),}),}},
10702 {17,"UIGradient",{Parent={2},Rotation=-30,Transparency=NumberSequence.new({NumberSequenceKeypoint.new(0,1,0),NumberSequenceKeypoint.new(1,1,0),}),}},
10703 })
10704 Main.ShowGui(gui)
10705 local backGradient = gui.Main.UIGradient
10706 local outlinesGradient = gui.Main.Outlines.UIGradient
10707 local holderGradient = gui.Main.Holder.UIGradient
10708 local titleText = gui.Main.Holder.Title
10709 local descText = gui.Main.Holder.Desc
10710 local versionText = gui.Main.Version
10711 local versionGradient = versionText.UIGradient
10712 local creatorText = gui.Main.Creator
10713 local creatorGradient = creatorText.UIGradient
10714 local statusText = gui.Main.Holder.StatusText
10715 local progressBar = gui.Main.Holder.ProgressBar
10716 local tweenS = service.TweenService
10717
10718 local renderStepped = service.RunService.RenderStepped
10719 local signalWait = renderStepped.wait
10720 local fastwait = function(s)
10721 if not s then return signalWait(renderStepped) end
10722 local start = tick()
10723 while tick() - start < s do signalWait(renderStepped) end
10724 end
10725
10726 statusText.Text = initStatus
10727
10728 local function tweenNumber(n,ti,func)
10729 local tweenVal = Instance.new("IntValue")
10730 tweenVal.Value = 0
10731 tweenVal.Changed:Connect(func)
10732 local tween = tweenS:Create(tweenVal,ti,{Value = n})
10733 tween:Play()
10734 tween.Completed:Connect(function()
10735 tweenVal:Destroy()
10736 end)
10737 end
10738
10739 local ti = TweenInfo.new(0.4,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
10740 tweenNumber(100,ti,function(val)
10741 val = val/200
10742 local start = NumberSequenceKeypoint.new(0,0)
10743 local a1 = NumberSequenceKeypoint.new(val,0)
10744 local a2 = NumberSequenceKeypoint.new(math.min(0.5,val+math.min(0.05,val)),1)
10745 if a1.Time == a2.Time then a2 = a1 end
10746 local b1 = NumberSequenceKeypoint.new(1-val,0)
10747 local b2 = NumberSequenceKeypoint.new(math.max(0.5,1-val-math.min(0.05,val)),1)
10748 if b1.Time == b2.Time then b2 = b1 end
10749 local goal = NumberSequenceKeypoint.new(1,0)
10750 backGradient.Transparency = NumberSequence.new({start,a1,a2,b2,b1,goal})
10751 outlinesGradient.Transparency = NumberSequence.new({start,a1,a2,b2,b1,goal})
10752 end)
10753
10754 fastwait(0.4)
10755
10756 tweenNumber(100,ti,function(val)
10757 val = val/166.66
10758 local start = NumberSequenceKeypoint.new(0,0)
10759 local a1 = NumberSequenceKeypoint.new(val,0)
10760 local a2 = NumberSequenceKeypoint.new(val+0.01,1)
10761 local goal = NumberSequenceKeypoint.new(1,1)
10762 holderGradient.Transparency = NumberSequence.new({start,a1,a2,goal})
10763 end)
10764
10765 tweenS:Create(titleText,ti,{Position = UDim2.new(0,60,0,15), TextTransparency = 0}):Play()
10766 tweenS:Create(descText,ti,{Position = UDim2.new(0,20,0,60), TextTransparency = 0}):Play()
10767
10768 local function rightTextTransparency(obj)
10769 tweenNumber(100,ti,function(val)
10770 val = val/100
10771 local a1 = NumberSequenceKeypoint.new(1-val,0)
10772 local a2 = NumberSequenceKeypoint.new(math.max(0,1-val-0.01),1)
10773 if a1.Time == a2.Time then a2 = a1 end
10774 local start = NumberSequenceKeypoint.new(0,a1 == a2 and 0 or 1)
10775 local goal = NumberSequenceKeypoint.new(1,0)
10776 obj.Transparency = NumberSequence.new({start,a2,a1,goal})
10777 end)
10778 end
10779 rightTextTransparency(versionGradient)
10780 rightTextTransparency(creatorGradient)
10781
10782 fastwait(0.9)
10783
10784 local progressTI = TweenInfo.new(0.25,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
10785
10786 tweenS:Create(statusText,progressTI,{Position = UDim2.new(0,20,0,120), TextTransparency = 0}):Play()
10787 tweenS:Create(progressBar,progressTI,{Position = UDim2.new(0,60,0,145), Size = UDim2.new(0,100,0,4)}):Play()
10788
10789 fastwait(0.25)
10790
10791 local function setProgress(text,n)
10792 statusText.Text = text
10793 tweenS:Create(progressBar.Bar,progressTI,{Size = UDim2.new(n,0,1,0)}):Play()
10794 end
10795
10796 local function close()
10797 tweenS:Create(titleText,progressTI,{TextTransparency = 1}):Play()
10798 tweenS:Create(descText,progressTI,{TextTransparency = 1}):Play()
10799 tweenS:Create(versionText,progressTI,{TextTransparency = 1}):Play()
10800 tweenS:Create(creatorText,progressTI,{TextTransparency = 1}):Play()
10801 tweenS:Create(statusText,progressTI,{TextTransparency = 1}):Play()
10802 tweenS:Create(progressBar,progressTI,{BackgroundTransparency = 1}):Play()
10803 tweenS:Create(progressBar.Bar,progressTI,{BackgroundTransparency = 1}):Play()
10804 tweenS:Create(progressBar.ImageLabel,progressTI,{ImageTransparency = 1}):Play()
10805
10806 tweenNumber(100,TweenInfo.new(0.4,Enum.EasingStyle.Back,Enum.EasingDirection.In),function(val)
10807 val = val/250
10808 local start = NumberSequenceKeypoint.new(0,0)
10809 local a1 = NumberSequenceKeypoint.new(0.6+val,0)
10810 local a2 = NumberSequenceKeypoint.new(math.min(1,0.601+val),1)
10811 if a1.Time == a2.Time then a2 = a1 end
10812 local goal = NumberSequenceKeypoint.new(1,a1 == a2 and 0 or 1)
10813 holderGradient.Transparency = NumberSequence.new({start,a1,a2,goal})
10814 end)
10815
10816 fastwait(0.5)
10817 gui.Main.BackgroundTransparency = 1
10818 outlinesGradient.Rotation = 30
10819
10820 tweenNumber(100,ti,function(val)
10821 val = val/100
10822 local start = NumberSequenceKeypoint.new(0,1)
10823 local a1 = NumberSequenceKeypoint.new(val,1)
10824 local a2 = NumberSequenceKeypoint.new(math.min(1,val+math.min(0.05,val)),0)
10825 if a1.Time == a2.Time then a2 = a1 end
10826 local goal = NumberSequenceKeypoint.new(1,a1 == a2 and 1 or 0)
10827 outlinesGradient.Transparency = NumberSequence.new({start,a1,a2,goal})
10828 holderGradient.Transparency = NumberSequence.new({start,a1,a2,goal})
10829 end)
10830
10831 fastwait(0.45)
10832 gui:Destroy()
10833 end
10834
10835 return {SetProgress = setProgress, Close = close}
10836 end
10837
10838 Main.CreateApp = function(data)
10839 if Main.MenuApps[data.Name] then return end -- TODO: Handle conflict
10840 local control = {}
10841
10842 local app = Main.AppTemplate:Clone()
10843
10844 local iconIndex = data.Icon
10845 if data.IconMap and iconIndex then
10846 if type(iconIndex) == "number" then
10847 data.IconMap:Display(app.Main.Icon,iconIndex)
10848 elseif type(iconIndex) == "string" then
10849 data.IconMap:DisplayByKey(app.Main.Icon,iconIndex)
10850 end
10851 elseif type(iconIndex) == "string" then
10852 app.Main.Icon.Image = iconIndex
10853 else
10854 app.Main.Icon.Image = ""
10855 end
10856
10857 local function updateState()
10858 app.Main.BackgroundTransparency = data.Open and 0 or (Lib.CheckMouseInGui(app.Main) and 0 or 1)
10859 app.Main.Highlight.Visible = data.Open
10860 end
10861
10862 local function enable(silent)
10863 if data.Open then return end
10864 data.Open = true
10865 updateState()
10866 if not silent then
10867 if data.Window then data.Window:Show() end
10868 if data.OnClick then data.OnClick(data.Open) end
10869 end
10870 end
10871
10872 local function disable(silent)
10873 if not data.Open then return end
10874 data.Open = false
10875 updateState()
10876 if not silent then
10877 if data.Window then data.Window:Hide() end
10878 if data.OnClick then data.OnClick(data.Open) end
10879 end
10880 end
10881
10882 updateState()
10883
10884 local ySize = service.TextService:GetTextSize(data.Name,14,Enum.Font.SourceSans,Vector2.new(62,999999)).Y
10885 app.Main.Size = UDim2.new(1,0,0,math.clamp(46+ySize,60,74))
10886 app.Main.AppName.Text = data.Name
10887
10888 app.Main.InputBegan:Connect(function(input)
10889 if input.UserInputType == Enum.UserInputType.MouseMovement then
10890 app.Main.BackgroundTransparency = 0
10891 app.Main.BackgroundColor3 = Settings.Theme.ButtonHover
10892 end
10893 end)
10894
10895 app.Main.InputEnded:Connect(function(input)
10896 if input.UserInputType == Enum.UserInputType.MouseMovement then
10897 app.Main.BackgroundTransparency = data.Open and 0 or 1
10898 app.Main.BackgroundColor3 = Settings.Theme.Button
10899 end
10900 end)
10901
10902 app.Main.MouseButton1Click:Connect(function()
10903 if data.Open then disable() else enable() end
10904 end)
10905
10906 local window = data.Window
10907 if window then
10908 window.OnActivate:Connect(function() enable(true) end)
10909 window.OnDeactivate:Connect(function() disable(true) end)
10910 end
10911
10912 app.Visible = true
10913 app.Parent = Main.AppsContainer
10914 Main.AppsFrame.CanvasSize = UDim2.new(0,0,0,Main.AppsContainerGrid.AbsoluteCellCount.Y*82 + 8)
10915
10916 control.Enable = enable
10917 control.Disable = disable
10918 Main.MenuApps[data.Name] = control
10919 return control
10920 end
10921
10922 Main.SetMainGuiOpen = function(val)
10923 Main.MainGuiOpen = val
10924
10925 Main.MainGui.OpenButton.Text = val and "X" or "Dex"
10926 if val then Main.MainGui.OpenButton.MainFrame.Visible = true end
10927 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)
10928 --Main.MainGui.OpenButton.BackgroundTransparency = val and 0 or (Lib.CheckMouseInGui(Main.MainGui.OpenButton) and 0 or 0.2)
10929 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()
10930
10931 if Main.MainGuiMouseEvent then Main.MainGuiMouseEvent:Disconnect() end
10932
10933 if not val then
10934 local startTime = tick()
10935 Main.MainGuiCloseTime = startTime
10936 coroutine.wrap(function()
10937 Lib.FastWait(0.2)
10938 if not Main.MainGuiOpen and startTime == Main.MainGuiCloseTime then Main.MainGui.OpenButton.MainFrame.Visible = false end
10939 end)()
10940 else
10941 Main.MainGuiMouseEvent = service.UserInputService.InputBegan:Connect(function(input)
10942 if input.UserInputType == Enum.UserInputType.MouseButton1 and not Lib.CheckMouseInGui(Main.MainGui.OpenButton) and not Lib.CheckMouseInGui(Main.MainGui.OpenButton.MainFrame) then
10943 Main.SetMainGuiOpen(false)
10944 end
10945 end)
10946 end
10947 end
10948
10949 Main.CreateMainGui = function()
10950 local gui = create({
10951 {1,"ScreenGui",{IgnoreGuiInset=true,Name="MainMenu",}},
10952 {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,}},
10953 {3,"UICorner",{CornerRadius=UDim.new(0,4),Parent={2},}},
10954 {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),}},
10955 {5,"UICorner",{CornerRadius=UDim.new(0,4),Parent={4},}},
10956 {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),}},
10957 {7,"UICorner",{CornerRadius=UDim.new(0,4),Parent={6},}},
10958 {8,"Frame",{BackgroundColor3=Color3.new(0.20392157137394,0.20392157137394,0.20392157137394),BorderSizePixel=0,Name="CoverFrame",Parent={6},Size=UDim2.new(1,0,0,4),}},
10959 {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),}},
10960 {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,}},
10961 {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),}},
10962 {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,}},
10963 {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),}},
10964 {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),}},
10965 {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),}},
10966 {16,"UIGridLayout",{CellSize=UDim2.new(0,66,0,74),Parent={15},SortOrder=2,}},
10967 {17,"Frame",{BackgroundColor3=Color3.new(1,1,1),BackgroundTransparency=1,Name="App",Parent={1},Size=UDim2.new(0,100,0,100),Visible=false,}},
10968 {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,}},
10969 {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),}},
10970 {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,}},
10971 {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),}},
10972 })
10973 Main.MainGui = gui
10974 Main.AppsFrame = gui.OpenButton.MainFrame.AppsFrame
10975 Main.AppsContainer = Main.AppsFrame.Container
10976 Main.AppsContainerGrid = Main.AppsContainer.UIGridLayout
10977 Main.AppTemplate = gui.App
10978 Main.MainGuiOpen = false
10979
10980 local openButton = gui.OpenButton
10981 openButton.BackgroundTransparency = 0.2
10982 openButton.MainFrame.Size = UDim2.new(0,0,0,0)
10983 openButton.MainFrame.Visible = false
10984 openButton.MouseButton1Click:Connect(function()
10985 Main.SetMainGuiOpen(not Main.MainGuiOpen)
10986 end)
10987
10988 openButton.InputBegan:Connect(function(input)
10989 if input.UserInputType == Enum.UserInputType.MouseMovement then
10990 service.TweenService:Create(Main.MainGui.OpenButton,TweenInfo.new(0,Enum.EasingStyle.Quad,Enum.EasingDirection.Out),{BackgroundTransparency = 0}):Play()
10991 end
10992 end)
10993
10994 openButton.InputEnded:Connect(function(input)
10995 if input.UserInputType == Enum.UserInputType.MouseMovement then
10996 service.TweenService:Create(Main.MainGui.OpenButton,TweenInfo.new(0,Enum.EasingStyle.Quad,Enum.EasingDirection.Out),{BackgroundTransparency = Main.MainGuiOpen and 0 or 0.2}):Play()
10997 end
10998 end)
10999
11000 -- Create Main Apps
11001 Main.CreateApp({Name = "Explorer", IconMap = Main.LargeIcons, Icon = "Explorer", Open = true, Window = Explorer.Window})
11002
11003 Main.CreateApp({Name = "Properties", IconMap = Main.LargeIcons, Icon = "Properties", Open = true, Window = Properties.Window})
11004
11005 Main.CreateApp({Name = "Script Viewer", IconMap = Main.LargeIcons, Icon = "Script_Viewer", Window = ScriptViewer.Window})
11006
11007 local cptsOnMouseClick = nil
11008 Main.CreateApp({Name = "Click part to select", IconMap = Main.LargeIcons, Icon = 6, OnClick = function(callback)
11009 if callback then
11010 local mouse = Main.Mouse
11011 cptsOnMouseClick = mouse.Button1Down:Connect(function()
11012 pcall(function()
11013 local object = mouse.Target
11014 if nodes[object] then
11015 selection:Set(nodes[object])
11016 Explorer.ViewNode(nodes[object])
11017 end
11018 end)
11019 end)
11020 else if cptsOnMouseClick ~= nil then cptsOnMouseClick:Disconnect() cptsOnMouseClick = nil end end
11021 end})
11022
11023 Lib.ShowGui(gui)
11024 end
11025
11026 Main.SetupFilesystem = function()
11027 if not env.writefile or not env.makefolder then return end
11028 local writefile, makefolder = env.writefile, env.makefolder
11029 makefolder("dex")
11030 makefolder("dex/assets")
11031 makefolder("dex/saved")
11032 makefolder("dex/plugins")
11033 makefolder("dex/ModuleCache")
11034 end
11035
11036 Main.LocalDepsUpToDate = function()
11037 return Main.DepsVersionData and Main.ClientVersion == Main.DepsVersionData[1]
11038 end
11039
11040 Main.Init = function()
11041 Main.Elevated = pcall(function() local a = clonerefs(game:GetService("CoreGui")):GetFullName() end)
11042 Main.InitEnv()
11043 Main.LoadSettings()
11044 Main.SetupFilesystem()
11045
11046 -- Load Lib
11047 local intro = Main.CreateIntro("Initializing Library")
11048 Lib = Main.LoadModule("Lib")
11049 Lib.FastWait()
11050
11051 -- Init other stuff
11052 --Main.IncompatibleTest()
11053
11054 -- Init icons
11055 Main.MiscIcons = Lib.IconMap.new("rbxassetid://6511490623",256,256,16,16)
11056 Main.MiscIcons:SetDict({
11057 Reference = 0, Cut = 1, Cut_Disabled = 2, Copy = 3, Copy_Disabled = 4, Paste = 5, Paste_Disabled = 6,
11058 Delete = 7, Delete_Disabled = 8, Group = 9, Group_Disabled = 10, Ungroup = 11, Ungroup_Disabled = 12, TeleportTo = 13,
11059 Rename = 14, JumpToParent = 15, ExploreData = 16, Save = 17, CallFunction = 18, CallRemote = 19, Undo = 20,
11060 Undo_Disabled = 21, Redo = 22, Redo_Disabled = 23, Expand_Over = 24, Expand = 25, Collapse_Over = 26, Collapse = 27,
11061 SelectChildren = 28, SelectChildren_Disabled = 29, InsertObject = 30, ViewScript = 31, AddStar = 32, RemoveStar = 33, Script_Disabled = 34,
11062 LocalScript_Disabled = 35, Play = 36, Pause = 37, Rename_Disabled = 38
11063 })
11064 Main.LargeIcons = Lib.IconMap.new("rbxassetid://6579106223",256,256,32,32)
11065 Main.LargeIcons:SetDict({
11066 Explorer = 0, Properties = 1, Script_Viewer = 2,
11067 })
11068
11069 -- Fetch version if needed
11070 intro.SetProgress("Fetching Roblox Version",0.2)
11071 if Main.Elevated then
11072 local fileVer = Lib.ReadFile("dex/deps_version.dat")
11073 Main.ClientVersion = Version()
11074 if fileVer then
11075 Main.DepsVersionData = string.split(fileVer,"\n")
11076 if Main.LocalDepsUpToDate() then
11077 Main.RobloxVersion = Main.DepsVersionData[2]
11078 end
11079 end
11080 Main.RobloxVersion = Main.RobloxVersion or game:HttpGet("http://setup.roblox.com/versionQTStudio")
11081 end
11082
11083 -- Fetch external deps
11084 intro.SetProgress("Fetching API",0.35)
11085 API = Main.FetchAPI()
11086 Lib.FastWait()
11087 intro.SetProgress("Fetching RMD",0.5)
11088 RMD = Main.FetchRMD()
11089 Lib.FastWait()
11090
11091 -- Save external deps locally if needed
11092 if Main.Elevated and env.writefile and not Main.LocalDepsUpToDate() then
11093 env.writefile("dex/deps_version.dat",Main.ClientVersion.."\n"..Main.RobloxVersion)
11094 env.writefile("dex/rbx_api.dat",Main.RawAPI)
11095 env.writefile("dex/rbx_rmd.dat",Main.RawRMD)
11096 end
11097
11098 -- Load other modules
11099 intro.SetProgress("Loading Modules",0.75)
11100 Main.AppControls.Lib.InitDeps(Main.GetInitDeps()) -- Missing deps now available
11101 Main.LoadModules()
11102 Lib.FastWait()
11103
11104 -- Init other modules
11105 intro.SetProgress("Initializing Modules",0.9)
11106 Explorer.Init()
11107 Properties.Init()
11108 ScriptViewer.Init()
11109 Lib.FastWait()
11110
11111 -- Done
11112 intro.SetProgress("Complete",1)
11113 coroutine.wrap(function()
11114 Lib.FastWait(1.25)
11115 intro.Close()
11116 end)()
11117
11118 -- Init window system, create main menu, show explorer and properties
11119 Lib.Window.Init()
11120 Main.CreateMainGui()
11121 Explorer.Window:Show({Align = "right", Pos = 1, Size = 0.5, Silent = true})
11122 Properties.Window:Show({Align = "right", Pos = 2, Size = 0.5, Silent = true})
11123 Lib.DeferFunc(function() Lib.Window.ToggleSide("right") end)
11124 end
11125
11126 return Main
11127end)()
11128
11129-- Start
11130Main.Init()