NukeVsCity

Faat dump remotes to workspace

Oct 17th, 2025 (edited)
42
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 97.17 KB | None | 0 0
  1. --!native
  2. --50/50 this breaks but it's a beta for a reason!
  3.  
  4. if getgenv().SimpleSpyExecuted and type(getgenv().SimpleSpyShutdown) == "function" then
  5.     getgenv().SimpleSpyShutdown()
  6. end
  7.  
  8. local realconfigs = {
  9.     logcheckcaller = false,
  10.     autoblock = false,
  11.     funcEnabled = true,
  12.     advancedinfo = false,
  13.     --logreturnvalues = false,
  14.     supersecretdevtoggle = false
  15. }
  16.  
  17. local configs = newproxy(true)
  18. local configsmetatable = getmetatable(configs)
  19.  
  20. configsmetatable.__index = function(self,index)
  21.     return realconfigs[index]
  22. end
  23.  
  24. local oth = syn and syn.oth
  25. local unhook = oth and oth.unhook
  26. local hook = oth and oth.hook
  27.  
  28. local lower = string.lower
  29. local byte = string.byte
  30. local round = math.round
  31. local running = coroutine.running
  32. local resume = coroutine.resume
  33. local status = coroutine.status
  34. local yield = coroutine.yield
  35. local create = coroutine.create
  36. local close = coroutine.close
  37. local OldDebugId = game.GetDebugId
  38. local info = debug.info
  39.  
  40. local IsA = game.IsA
  41. local tostring = tostring
  42. local tonumber = tonumber
  43. local delay = task.delay
  44. local spawn = task.spawn
  45. local clear = table.clear
  46. local clone = table.clone
  47.  
  48. local function blankfunction(...)
  49.     return ...
  50. end
  51.  
  52. local get_thread_identity = (syn and syn.get_thread_identity) or getidentity or getthreadidentity
  53. local set_thread_identity = (syn and syn.set_thread_identity) or setidentity
  54. local islclosure = islclosure or is_l_closure
  55. local threadfuncs = (get_thread_identity and set_thread_identity and true) or false
  56.  
  57. local getinfo = getinfo or blankfunction
  58. local getupvalues = getupvalues or debug.getupvalues or blankfunction
  59. local getconstants = getconstants or debug.getconstants or blankfunction
  60.  
  61. local getcustomasset = getsynasset or getcustomasset
  62. local getcallingscript = getcallingscript or blankfunction
  63. local newcclosure = newcclosure or blankfunction
  64. local clonefunction = clonefunction or blankfunction
  65. local cloneref = cloneref or blankfunction
  66. local request = request or syn and syn.request
  67. local makewritable = makewriteable or function(tbl)
  68.     setreadonly(tbl,false)
  69. end
  70. local makereadonly = makereadonly or function(tbl)
  71.     setreadonly(tbl,true)
  72. end
  73. local isreadonly = isreadonly or table.isfrozen
  74.  
  75. local setclipboard = setclipboard or toclipboard or set_clipboard or (Clipboard and Clipboard.set) or function(...)
  76.     return ErrorPrompt("Attempted to set clipboard: "..(...),true)
  77. end
  78.  
  79. local hookmetamethod = hookmetamethod or (makewriteable and makereadonly and getrawmetatable) and function(obj: object, metamethod: string, func: Function)
  80.     local old = getrawmetatable(obj)
  81.  
  82.     if hookfunction then
  83.         return hookfunction(old[metamethod],func)
  84.     else
  85.         local oldmetamethod = old[metamethod]
  86.         makewriteable(old)
  87.         old[metamethod] = func
  88.         makereadonly(old)
  89.         return oldmetamethod
  90.     end
  91. end
  92.  
  93. local function Create(instance, properties, children)
  94.     local obj = Instance.new(instance)
  95.  
  96.     for i, v in next, properties or {} do
  97.         obj[i] = v
  98.         for _, child in next, children or {} do
  99.             child.Parent = obj;
  100.         end
  101.     end
  102.     return obj;
  103. end
  104.  
  105. local function SafeGetService(service)
  106.     return cloneref(game:GetService(service))
  107. end
  108.  
  109. local function Search(logtable,tbl)
  110.     table.insert(logtable,tbl)
  111.    
  112.     for i,v in tbl do
  113.         if type(v) == "table" then
  114.             return table.find(logtable,v) ~= nil or Search(v)
  115.         end
  116.     end
  117. end
  118.  
  119. local function IsCyclicTable(tbl)
  120.     local checkedtables = {}
  121.  
  122.     local function SearchTable(tbl)
  123.         table.insert(checkedtables,tbl)
  124.        
  125.         for i,v in next, tbl do -- Stupid mistake on my part thanks 59it for pointing it out
  126.             if type(v) == "table" then
  127.                 return table.find(checkedtables,v) and true or SearchTable(v)
  128.             end
  129.         end
  130.     end
  131.  
  132.     return SearchTable(tbl)
  133. end
  134.  
  135. local function deepclone(args: table, copies: table): table
  136.     local copy = nil
  137.     copies = copies or {}
  138.  
  139.     if type(args) == 'table' then
  140.         if copies[args] then
  141.             copy = copies[args]
  142.         else
  143.             copy = {}
  144.             copies[args] = copy
  145.             for i, v in next, args do
  146.                 copy[deepclone(i, copies)] = deepclone(v, copies)
  147.             end
  148.         end
  149.     elseif typeof(args) == "Instance" then
  150.         copy = cloneref(args)
  151.     else
  152.         copy = args
  153.     end
  154.     return copy
  155. end
  156.  
  157. local function rawtostring(userdata)
  158.     if type(userdata) == "table" or typeof(userdata) == "userdata" then
  159.         local rawmetatable = getrawmetatable(userdata)
  160.         local cachedstring = rawmetatable and rawget(rawmetatable, "__tostring")
  161.  
  162.         if cachedstring then
  163.             local wasreadonly = isreadonly(rawmetatable)
  164.             if wasreadonly then
  165.                 makewritable(rawmetatable)
  166.             end
  167.             rawset(rawmetatable, "__tostring", nil)
  168.             local safestring = tostring(userdata)
  169.             rawset(rawmetatable, "__tostring", cachedstring)
  170.             if wasreadonly then
  171.                 makereadonly(rawmetatable)
  172.             end
  173.             return safestring
  174.         end
  175.     end
  176.     return tostring(userdata)
  177. end
  178.  
  179. local CoreGui = SafeGetService("CoreGui")
  180. local Players = SafeGetService("Players")
  181. local RunService = SafeGetService("RunService")
  182. local UserInputService = SafeGetService("UserInputService")
  183. local TweenService = SafeGetService("TweenService")
  184. local ContentProvider = SafeGetService("ContentProvider")
  185. local TextService = SafeGetService("TextService")
  186. local http = SafeGetService("HttpService")
  187. local GuiInset = game:GetService("GuiService"):GetGuiInset() :: Vector2 -- pulled from rewrite
  188.  
  189. local function jsone(str) return http:JSONEncode(str) end
  190. local function jsond(str)
  191.     local suc,err = pcall(http.JSONDecode,http,str)
  192.     return suc and err or suc
  193. end
  194.  
  195. function ErrorPrompt(Message,state)
  196.     if getrenv then
  197.         local ErrorPrompt = getrenv().require(CoreGui:WaitForChild("RobloxGui"):WaitForChild("Modules"):WaitForChild("ErrorPrompt")) -- File can be located in your roblox folder (C:\Users\%Username%\AppData\Local\Roblox\Versions\whateverversionitis\ExtraContent\scripts\CoreScripts\Modules)
  198.         local prompt = ErrorPrompt.new("Default",{HideErrorCode = true})
  199.         local ErrorStoarge = Create("ScreenGui",{Parent = CoreGui,ResetOnSpawn = false})
  200.         local thread = state and running()
  201.         prompt:setParent(ErrorStoarge)
  202.         prompt:setErrorTitle("Simple Spy V3 Error")
  203.         prompt:updateButtons({{
  204.             Text = "Proceed",
  205.             Callback = function()
  206.                 prompt:_close()
  207.                 ErrorStoarge:Destroy()
  208.                 if thread then
  209.                     resume(thread)
  210.                 end
  211.             end,
  212.             Primary = true
  213.         }}, 'Default')
  214.         prompt:_open(Message)
  215.         if thread then
  216.             yield(thread)
  217.         end
  218.     else
  219.         warn(Message)
  220.     end
  221. end
  222.  
  223. local Highlight = (isfile and loadfile and isfile("Highlight.lua") and loadfile("Highlight.lua")()) or loadstring(game:HttpGet("https://raw.githubusercontent.com/78n/SimpleSpy/main/Highlight.lua"))()
  224. local LazyFix = loadstring(game:HttpGet("https://raw.githubusercontent.com/78n/Roblox/refs/heads/main/Lua/Libraries/DataToCode/DataToCode.luau"))() -- Very lazy fix as I'm legit just pasting it from the rewrite
  225.  
  226. local SimpleSpy3 = Create("ScreenGui",{ResetOnSpawn = false})
  227. local Storage = Create("Folder",{})
  228. local Background = Create("Frame",{Parent = SimpleSpy3,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Position = UDim2.new(0, 500, 0, 200),Size = UDim2.new(0, 450, 0, 268)})
  229. local LeftPanel = Create("Frame",{Parent = Background,BackgroundColor3 = Color3.fromRGB(53, 52, 55),BorderSizePixel = 0,Position = UDim2.new(0, 0, 0, 19),Size = UDim2.new(0, 131, 0, 249)})
  230. local LogList = Create("ScrollingFrame",{Parent = LeftPanel,Active = true,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,BorderSizePixel = 0,Position = UDim2.new(0, 0, 0, 9),Size = UDim2.new(0, 131, 0, 232),CanvasSize = UDim2.new(0, 0, 0, 0),ScrollBarThickness = 4})
  231. local UIListLayout = Create("UIListLayout",{Parent = LogList,HorizontalAlignment = Enum.HorizontalAlignment.Center,SortOrder = Enum.SortOrder.LayoutOrder})
  232. local RightPanel = Create("Frame",{Parent = Background,BackgroundColor3 = Color3.fromRGB(37, 36, 38),BorderSizePixel = 0,Position = UDim2.new(0, 131, 0, 19),Size = UDim2.new(0, 319, 0, 249)})
  233. local CodeBox = Create("Frame",{Parent = RightPanel,BackgroundColor3 = Color3.new(0.0823529, 0.0745098, 0.0784314),BorderSizePixel = 0,Size = UDim2.new(0, 319, 0, 119)})
  234. local ScrollingFrame = Create("ScrollingFrame",{Parent = RightPanel,Active = true,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Position = UDim2.new(0, 0, 0.5, 0),Size = UDim2.new(1, 0, 0.5, -9),CanvasSize = UDim2.new(0, 0, 0, 0),ScrollBarThickness = 4})
  235. local UIGridLayout = Create("UIGridLayout",{Parent = ScrollingFrame,HorizontalAlignment = Enum.HorizontalAlignment.Center,SortOrder = Enum.SortOrder.LayoutOrder,CellPadding = UDim2.new(0, 0, 0, 0),CellSize = UDim2.new(0, 94, 0, 27)})
  236. local TopBar = Create("Frame",{Parent = Background,BackgroundColor3 = Color3.fromRGB(37, 35, 38),BorderSizePixel = 0,Size = UDim2.new(0, 450, 0, 19)})
  237. local Simple = Create("TextButton",{Parent = TopBar,BackgroundColor3 = Color3.new(1, 1, 1),AutoButtonColor = false,BackgroundTransparency = 1,Position = UDim2.new(0, 5, 0, 0),Size = UDim2.new(0, 57, 0, 18),Font = Enum.Font.SourceSansBold,Text =  "SimpleSpy",TextColor3 = Color3.new(1, 1, 1),TextSize = 14,TextXAlignment = Enum.TextXAlignment.Left})
  238. local CloseButton = Create("TextButton",{Parent = TopBar,BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902),BorderSizePixel = 0,Position = UDim2.new(1, -19, 0, 0),Size = UDim2.new(0, 19, 0, 19),Font = Enum.Font.SourceSans,Text = "",TextColor3 = Color3.new(0, 0, 0),TextSize = 14})
  239. local ImageLabel = Create("ImageLabel",{Parent = CloseButton,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Position = UDim2.new(0, 5, 0, 5),Size = UDim2.new(0, 9, 0, 9),Image = "http://www.roblox.com/asset/?id=5597086202"})
  240. local MaximizeButton = Create("TextButton",{Parent = TopBar,BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902),BorderSizePixel = 0,Position = UDim2.new(1, -38, 0, 0),Size = UDim2.new(0, 19, 0, 19),Font = Enum.Font.SourceSans,Text = "",TextColor3 = Color3.new(0, 0, 0),TextSize = 14})
  241. local ImageLabel_2 = Create("ImageLabel",{Parent = MaximizeButton,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Position = UDim2.new(0, 5, 0, 5),Size = UDim2.new(0, 9, 0, 9),Image = "http://www.roblox.com/asset/?id=5597108117"})
  242. local MinimizeButton = Create("TextButton",{Parent = TopBar,BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902),BorderSizePixel = 0,Position = UDim2.new(1, -57, 0, 0),Size = UDim2.new(0, 19, 0, 19),Font = Enum.Font.SourceSans,Text = "",TextColor3 = Color3.new(0, 0, 0),TextSize = 14})
  243. local ImageLabel_3 = Create("ImageLabel",{Parent = MinimizeButton,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Position = UDim2.new(0, 5, 0, 5),Size = UDim2.new(0, 9, 0, 9),Image = "http://www.roblox.com/asset/?id=5597105827"})
  244.  
  245. local ToolTip = Create("Frame",{Parent = SimpleSpy3,BackgroundColor3 = Color3.fromRGB(26, 26, 26),BackgroundTransparency = 0.1,BorderColor3 = Color3.new(1, 1, 1),Size = UDim2.new(0, 200, 0, 50),ZIndex = 3,Visible = false})
  246. local TextLabel = Create("TextLabel",{Parent = ToolTip,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Position = UDim2.new(0, 2, 0, 2),Size = UDim2.new(0, 196, 0, 46),ZIndex = 3,Font = Enum.Font.SourceSans,Text = "This is some slightly longer text.",TextColor3 = Color3.new(1, 1, 1),TextSize = 14,TextWrapped = true,TextXAlignment = Enum.TextXAlignment.Left,TextYAlignment = Enum.TextYAlignment.Top})
  247.  
  248. -------------------------------------------------------------------------------
  249.  
  250. local selectedColor = Color3.new(0.321569, 0.333333, 1)
  251. local deselectedColor = Color3.new(0.8, 0.8, 0.8)
  252. --- So things are descending
  253. local layoutOrderNum = 999999999
  254. --- Whether or not the gui is closing
  255. local mainClosing = false
  256. --- Whether or not the gui is closed (defaults to false)
  257. local closed = false
  258. --- Whether or not the sidebar is closing
  259. local sideClosing = false
  260. --- Whether or not the sidebar is closed (defaults to true but opens automatically on remote selection)
  261. local sideClosed = false
  262. --- Whether or not the code box is maximized (defaults to false)
  263. local maximized = false
  264. --- The event logs to be read from
  265. local logs = {}
  266. --- The event currently selected.Log (defaults to nil)
  267. local selected = nil
  268. --- The blacklist (can be a string name or the Remote Instance)
  269. local blacklist = {}
  270. --- The block list (can be a string name or the Remote Instance)
  271. local blocklist = {}
  272. --- Whether or not to add getNil function
  273. local getNil = false
  274. --- Array of remotes (and original functions) connected to
  275. local connectedRemotes = {}
  276. --- True = hookfunction, false = namecall
  277. local toggle = false
  278. --- used to prevent recursives
  279. local prevTables = {}
  280. --- holds logs (for deletion)
  281. local remoteLogs = {}
  282. --- used for hookfunction
  283. getgenv().SIMPLESPYCONFIG_MaxRemotes = 300
  284. local indent = 4
  285. local scheduled = {}
  286. local schedulerconnect
  287. local SimpleSpy = {}
  288. local topstr = ""
  289. local bottomstr = ""
  290. local remotesFadeIn
  291. local rightFadeIn
  292. local codebox
  293. local p
  294. local getnilrequired = false
  295.  
  296. -- autoblock variables
  297. local history = {}
  298. local excluding = {}
  299.  
  300. -- if mouse inside gui
  301. local mouseInGui = false
  302.  
  303. local connections = {}
  304. local DecompiledScripts = {}
  305. local generation = {}
  306. local running_threads = {}
  307. local originalnamecall
  308.  
  309. local remoteEvent = Instance.new("RemoteEvent",Storage)
  310. local unreliableRemoteEvent = Instance.new("UnreliableRemoteEvent")
  311. local remoteFunction = Instance.new("RemoteFunction",Storage)
  312. local NamecallHandler = Instance.new("BindableEvent",Storage)
  313. local IndexHandler = Instance.new("BindableEvent",Storage)
  314. local GetDebugIdHandler = Instance.new("BindableFunction",Storage) --Thanks engo for the idea of using BindableFunctions
  315.  
  316. local originalEvent = remoteEvent.FireServer
  317. local originalUnreliableEvent = unreliableRemoteEvent.FireServer
  318. local originalFunction = remoteFunction.InvokeServer
  319. local GetDebugIDInvoke = GetDebugIdHandler.Invoke
  320.  
  321. function GetDebugIdHandler.OnInvoke(obj: Instance) -- To avoid having to set thread identity and ect
  322.     return OldDebugId(obj)
  323. end
  324.  
  325. local function ThreadGetDebugId(obj: Instance): string
  326.     return GetDebugIDInvoke(GetDebugIdHandler,obj) -- indexing to avoid having to setnamecall later
  327. end
  328.  
  329. local synv3 = false
  330.  
  331. if syn and identifyexecutor then
  332.     local _, version = identifyexecutor()
  333.     if (version and version:sub(1, 2) == 'v3') then
  334.         synv3 = true
  335.     end
  336. end
  337.  
  338. xpcall(function()
  339.     if isfile and readfile and isfolder and makefolder then
  340.         local cachedconfigs = isfile("SimpleSpy//Settings.json") and jsond(readfile("SimpleSpy//Settings.json"))
  341.  
  342.         if cachedconfigs then
  343.             for i,v in next, realconfigs do
  344.                 if cachedconfigs[i] == nil then
  345.                     cachedconfigs[i] = v
  346.                 end
  347.             end
  348.             realconfigs = cachedconfigs
  349.         end
  350.  
  351.         if not isfolder("SimpleSpy") then
  352.             makefolder("SimpleSpy")
  353.         end
  354.         if not isfolder("SimpleSpy//Assets") then
  355.             makefolder("SimpleSpy//Assets")
  356.         end
  357.         if not isfile("SimpleSpy//Settings.json") then
  358.             writefile("SimpleSpy//Settings.json",jsone(realconfigs))
  359.         end
  360.  
  361.         configsmetatable.__newindex = function(self,index,newindex)
  362.             realconfigs[index] = newindex
  363.             writefile("SimpleSpy//Settings.json",jsone(realconfigs))
  364.         end
  365.     else
  366.         configsmetatable.__newindex = function(self,index,newindex)
  367.             realconfigs[index] = newindex
  368.         end
  369.     end
  370. end,function(err)
  371.     ErrorPrompt(("An error has occured: (%s)"):format(err))
  372. end)
  373.  
  374. local function logthread(thread: thread)
  375.     table.insert(running_threads,thread)
  376. end
  377.  
  378. --- Prevents remote spam from causing lag (clears logs after `getgenv().SIMPLESPYCONFIG_MaxRemotes` or 500 remotes)
  379. function clean()
  380.     local max = getgenv().SIMPLESPYCONFIG_MaxRemotes
  381.     if not typeof(max) == "number" and math.floor(max) ~= max then
  382.         max = 500
  383.     end
  384.     if #remoteLogs > max then
  385.         for i = 100, #remoteLogs do
  386.             local v = remoteLogs[i]
  387.             if typeof(v[1]) == "RBXScriptConnection" then
  388.                 v[1]:Disconnect()
  389.             end
  390.             if typeof(v[2]) == "Instance" then
  391.                 v[2]:Destroy()
  392.             end
  393.         end
  394.         local newLogs = {}
  395.         for i = 1, 100 do
  396.             table.insert(newLogs, remoteLogs[i])
  397.         end
  398.         remoteLogs = newLogs
  399.     end
  400. end
  401.  
  402. local function ThreadIsNotDead(thread: thread): boolean
  403.     return not status(thread) == "dead"
  404. end
  405.  
  406. --- Scales the ToolTip to fit containing text
  407. function scaleToolTip()
  408.     local size = TextService:GetTextSize(TextLabel.Text, TextLabel.TextSize, TextLabel.Font, Vector2.new(196, math.huge))
  409.     TextLabel.Size = UDim2.new(0, size.X, 0, size.Y)
  410.     ToolTip.Size = UDim2.new(0, size.X + 4, 0, size.Y + 4)
  411. end
  412.  
  413. --- Executed when the toggle button (the SimpleSpy logo) is hovered over
  414. function onToggleButtonHover()
  415.     if not toggle then
  416.         TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(252, 51, 51)}):Play()
  417.     else
  418.         TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(68, 206, 91)}):Play()
  419.     end
  420. end
  421.  
  422. --- Executed when the toggle button is unhovered over
  423. function onToggleButtonUnhover()
  424.     TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(255, 255, 255)}):Play()
  425. end
  426.  
  427. --- Executed when the X button is hovered over
  428. function onXButtonHover()
  429.     TweenService:Create(CloseButton, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(255, 60, 60)}):Play()
  430. end
  431.  
  432. --- Executed when the X button is unhovered over
  433. function onXButtonUnhover()
  434.     TweenService:Create(CloseButton, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(37, 36, 38)}):Play()
  435. end
  436.  
  437. --- Toggles the remote spy method (when button clicked)
  438. function onToggleButtonClick()
  439.     if toggle then
  440.         TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(252, 51, 51)}):Play()
  441.     else
  442.         TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(68, 206, 91)}):Play()
  443.     end
  444.     toggleSpyMethod()
  445. end
  446.  
  447. --- Reconnects bringBackOnResize if the current viewport changes and also connects it initially
  448. function connectResize()
  449.     if not workspace.CurrentCamera then
  450.         workspace:GetPropertyChangedSignal("CurrentCamera"):Wait()
  451.     end
  452.     local lastCam = workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(bringBackOnResize)
  453.     workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
  454.         lastCam:Disconnect()
  455.         if typeof(lastCam) == 'Connection' then
  456.             lastCam:Disconnect()
  457.         end
  458.         lastCam = workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(bringBackOnResize)
  459.     end)
  460. end
  461.  
  462. --- Brings gui back if it gets lost offscreen (connected to the camera viewport changing)
  463. function bringBackOnResize()
  464.     validateSize()
  465.     if sideClosed then
  466.         minimizeSize()
  467.     else
  468.         maximizeSize()
  469.     end
  470.     local currentX = Background.AbsolutePosition.X
  471.     local currentY = Background.AbsolutePosition.Y
  472.     local viewportSize = workspace.CurrentCamera.ViewportSize
  473.     if (currentX < 0) or (currentX > (viewportSize.X - (sideClosed and 131 or Background.AbsoluteSize.X))) then
  474.         if currentX < 0 then
  475.             currentX = 0
  476.         else
  477.             currentX = viewportSize.X - (sideClosed and 131 or Background.AbsoluteSize.X)
  478.         end
  479.     end
  480.     if (currentY < 0) or (currentY > (viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - GuiInset.Y)) then
  481.         if currentY < 0 then
  482.             currentY = 0
  483.         else
  484.             currentY = viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - GuiInset.Y
  485.         end
  486.     end
  487.     TweenService.Create(TweenService, Background, TweenInfo.new(0.1), {Position = UDim2.new(0, currentX, 0, currentY)}):Play()
  488. end
  489.  
  490. --- Drags gui (so long as mouse is held down)
  491. --- @param input InputObject
  492. function onBarInput(input)
  493.     if input.UserInputType == Enum.UserInputType.MouseButton1 then
  494.         local lastPos = UserInputService:GetMouseLocation()
  495.         local mainPos = Background.AbsolutePosition
  496.         local offset = mainPos - lastPos
  497.         local currentPos = offset + lastPos
  498.         if not connections["drag"] then
  499.             connections["drag"] = RunService.RenderStepped:Connect(function()
  500.                 local newPos = UserInputService:GetMouseLocation()
  501.                 if newPos ~= lastPos then
  502.                     local currentX = (offset + newPos).X
  503.                     local currentY = (offset + newPos).Y
  504.                     local viewportSize = workspace.CurrentCamera.ViewportSize
  505.                     if (currentX < 0 and currentX < currentPos.X) or (currentX > (viewportSize.X - (sideClosed and 131 or TopBar.AbsoluteSize.X)) and currentX > currentPos.X) then
  506.                         if currentX < 0 then
  507.                             currentX = 0
  508.                         else
  509.                             currentX = viewportSize.X - (sideClosed and 131 or TopBar.AbsoluteSize.X)
  510.                         end
  511.                     end
  512.                     if (currentY < 0 and currentY < currentPos.Y) or (currentY > (viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - GuiInset.Y) and currentY > currentPos.Y) then
  513.                         if currentY < 0 then
  514.                             currentY = 0
  515.                         else
  516.                             currentY = viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - GuiInset.Y
  517.                         end
  518.                     end
  519.                     currentPos = Vector2.new(currentX, currentY)
  520.                     lastPos = newPos
  521.                     TweenService.Create(TweenService, Background, TweenInfo.new(0.1), {Position = UDim2.new(0, currentPos.X, 0, currentPos.Y)}):Play()
  522.                 end
  523.                     -- if input.UserInputState ~= Enum.UserInputState.Begin then
  524.                     --     RunService.UnbindFromRenderStep(RunService, "drag")
  525.                     -- end
  526.             end)
  527.         end
  528.         table.insert(connections, UserInputService.InputEnded:Connect(function(inputE)
  529.             if input == inputE then
  530.                 if connections["drag"] then
  531.                     connections["drag"]:Disconnect()
  532.                     connections["drag"] = nil
  533.                 end
  534.             end
  535.         end))
  536.     end
  537. end
  538.  
  539. --- Fades out the table of elements (and makes them invisible), returns a function to make them visible again
  540. function fadeOut(elements)
  541.     local data = {}
  542.     for _, v in next, elements do
  543.         if typeof(v) == "Instance" and v:IsA("GuiObject") and v.Visible then
  544.             spawn(function()
  545.                 data[v] = {
  546.                     BackgroundTransparency = v.BackgroundTransparency
  547.                 }
  548.                 TweenService:Create(v, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play()
  549.                 if v:IsA("TextBox") or v:IsA("TextButton") or v:IsA("TextLabel") then
  550.                     data[v].TextTransparency = v.TextTransparency
  551.                     TweenService:Create(v, TweenInfo.new(0.5), {TextTransparency = 1}):Play()
  552.                 elseif v:IsA("ImageButton") or v:IsA("ImageLabel") then
  553.                     data[v].ImageTransparency = v.ImageTransparency
  554.                     TweenService:Create(v, TweenInfo.new(0.5), {ImageTransparency = 1}):Play()
  555.                 end
  556.                 delay(0.5,function()
  557.                     v.Visible = false
  558.                     for i, x in next, data[v] do
  559.                         v[i] = x
  560.                     end
  561.                     data[v] = true
  562.                 end)
  563.             end)
  564.         end
  565.     end
  566.     return function()
  567.         for i, _ in next, data do
  568.             spawn(function()
  569.                 local properties = {
  570.                     BackgroundTransparency = i.BackgroundTransparency
  571.                 }
  572.                 i.BackgroundTransparency = 1
  573.                 TweenService:Create(i, TweenInfo.new(0.5), {BackgroundTransparency = properties.BackgroundTransparency}):Play()
  574.                 if i:IsA("TextBox") or i:IsA("TextButton") or i:IsA("TextLabel") then
  575.                     properties.TextTransparency = i.TextTransparency
  576.                     i.TextTransparency = 1
  577.                     TweenService:Create(i, TweenInfo.new(0.5), {TextTransparency = properties.TextTransparency}):Play()
  578.                 elseif i:IsA("ImageButton") or i:IsA("ImageLabel") then
  579.                     properties.ImageTransparency = i.ImageTransparency
  580.                     i.ImageTransparency = 1
  581.                     TweenService:Create(i, TweenInfo.new(0.5), {ImageTransparency = properties.ImageTransparency}):Play()
  582.                 end
  583.                 i.Visible = true
  584.             end)
  585.         end
  586.     end
  587. end
  588.  
  589. --- Expands and minimizes the gui (closed is the toggle boolean)
  590. function toggleMinimize(override)
  591.     if mainClosing and not override or maximized then
  592.         return
  593.     end
  594.     mainClosing = true
  595.     closed = not closed
  596.     if closed then
  597.         if not sideClosed then
  598.             toggleSideTray(true)
  599.         end
  600.         LeftPanel.Visible = true
  601.         remotesFadeIn = fadeOut(LeftPanel:GetDescendants())
  602.         TweenService:Create(LeftPanel, TweenInfo.new(0.5), {Size = UDim2.new(0, 131, 0, 0)}):Play()
  603.         wait(0.5)
  604.     else
  605.         TweenService:Create(LeftPanel, TweenInfo.new(0.5), {Size = UDim2.new(0, 131, 0, 249)}):Play()
  606.         wait(0.5)
  607.         if remotesFadeIn then
  608.             remotesFadeIn()
  609.             remotesFadeIn = nil
  610.         end
  611.         bringBackOnResize()
  612.     end
  613.     mainClosing = false
  614. end
  615.  
  616. --- Expands and minimizes the sidebar (sideClosed is the toggle boolean)
  617. function toggleSideTray(override)
  618.     if sideClosing and not override or maximized then
  619.         return
  620.     end
  621.     sideClosing = true
  622.     sideClosed = not sideClosed
  623.     if sideClosed then
  624.         rightFadeIn = fadeOut(RightPanel:GetDescendants())
  625.         wait(0.5)
  626.         minimizeSize(0.5)
  627.         wait(0.5)
  628.         RightPanel.Visible = false
  629.     else
  630.         if closed then
  631.             toggleMinimize(true)
  632.         end
  633.         RightPanel.Visible = true
  634.         maximizeSize(0.5)
  635.         wait(0.5)
  636.         if rightFadeIn then
  637.             rightFadeIn()
  638.         end
  639.         bringBackOnResize()
  640.     end
  641.     sideClosing = false
  642. end
  643.  
  644. --- Expands code box to fit screen for more convenient viewing
  645. function toggleMaximize()
  646.     if not sideClosed and not maximized then
  647.         maximized = true
  648.         local disable = Instance.new("TextButton")
  649.         local prevSize = UDim2.new(0, CodeBox.AbsoluteSize.X, 0, CodeBox.AbsoluteSize.Y)
  650.         local prevPos = UDim2.new(0,CodeBox.AbsolutePosition.X, 0, CodeBox.AbsolutePosition.Y)
  651.         disable.Size = UDim2.new(1, 0, 1, 0)
  652.         disable.BackgroundColor3 = Color3.new()
  653.         disable.BorderSizePixel = 0
  654.         disable.Text = 0
  655.         disable.ZIndex = 3
  656.         disable.BackgroundTransparency = 1
  657.         disable.AutoButtonColor = false
  658.         CodeBox.ZIndex = 4
  659.         CodeBox.Position = prevPos
  660.         CodeBox.Size = prevSize
  661.         TweenService:Create(CodeBox, TweenInfo.new(0.5), {Size = UDim2.new(0.5, 0, 0.5, 0), Position = UDim2.new(0.25, 0, 0.25, 0)}):Play()
  662.         TweenService:Create(disable, TweenInfo.new(0.5), {BackgroundTransparency = 0.5}):Play()
  663.         disable.MouseButton1Click:Connect(function()
  664.             if UserInputService:GetMouseLocation().Y + GuiInset.Y >= CodeBox.AbsolutePosition.Y and UserInputService:GetMouseLocation().Y + GuiInset.Y <= CodeBox.AbsolutePosition.Y + CodeBox.AbsoluteSize.Y and UserInputService:GetMouseLocation().X >= CodeBox.AbsolutePosition.X and UserInputService:GetMouseLocation().X <= CodeBox.AbsolutePosition.X + CodeBox.AbsoluteSize.X then
  665.                 return
  666.             end
  667.             TweenService:Create(CodeBox, TweenInfo.new(0.5), {Size = prevSize, Position = prevPos}):Play()
  668.             TweenService:Create(disable, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play()
  669.             wait(0.5)
  670.             disable:Destroy()
  671.             CodeBox.Size = UDim2.new(1, 0, 0.5, 0)
  672.             CodeBox.Position = UDim2.new(0, 0, 0, 0)
  673.             CodeBox.ZIndex = 0
  674.             maximized = false
  675.         end)
  676.     end
  677. end
  678.  
  679. --- Checks if cursor is within resize range
  680. --- @param p Vector2
  681. function isInResizeRange(p)
  682.     local relativeP = p - Background.AbsolutePosition
  683.     local range = 5
  684.     if relativeP.X >= TopBar.AbsoluteSize.X - range and relativeP.Y >= Background.AbsoluteSize.Y - range
  685.         and relativeP.X <= TopBar.AbsoluteSize.X and relativeP.Y <= Background.AbsoluteSize.Y then
  686.         return true, 'B'
  687.     elseif relativeP.X >= TopBar.AbsoluteSize.X - range and relativeP.X <= Background.AbsoluteSize.X then
  688.         return true, 'X'
  689.     elseif relativeP.Y >= Background.AbsoluteSize.Y - range and relativeP.Y <= Background.AbsoluteSize.Y then
  690.         return true, 'Y'
  691.     end
  692.     return false
  693. end
  694.  
  695. --- Checks if cursor is within dragging range
  696. --- @param p Vector2
  697. function isInDragRange(p)
  698.     local relativeP = p - Background.AbsolutePosition
  699.     local topbarAS = TopBar.AbsoluteSize
  700.     return relativeP.X <= topbarAS.X - CloseButton.AbsoluteSize.X * 3 and relativeP.X >= 0 and relativeP.Y <= topbarAS.Y and relativeP.Y >= 0 or false
  701. end
  702.  
  703. --- Called when mouse enters SimpleSpy
  704. local customCursor = Create("ImageLabel",{Parent = SimpleSpy3,Visible = false,Size = UDim2.fromOffset(200, 200),ZIndex = 1e9,BackgroundTransparency = 1,Image = "",Parent = SimpleSpy3})
  705. function mouseEntered()
  706.     local con = connections["SIMPLESPY_CURSOR"]
  707.     if con then
  708.         con:Disconnect()
  709.         connections["SIMPLESPY_CURSOR"] = nil
  710.     end
  711.     connections["SIMPLESPY_CURSOR"] = RunService.RenderStepped:Connect(function()
  712.         UserInputService.MouseIconEnabled = not mouseInGui
  713.         customCursor.Visible = mouseInGui
  714.         if mouseInGui and getgenv().SimpleSpyExecuted then
  715.             local mouseLocation = UserInputService:GetMouseLocation() - GuiInset
  716.             customCursor.Position = UDim2.fromOffset(mouseLocation.X - customCursor.AbsoluteSize.X / 2, mouseLocation.Y - customCursor.AbsoluteSize.Y / 2)
  717.             local inRange, type = isInResizeRange(mouseLocation)
  718.             if inRange and not closed then
  719.                 if not sideClosed then
  720.                     customCursor.Image = type == 'B' and "rbxassetid://6065821980" or type == 'X' and "rbxassetid://6065821086" or type == 'Y' and "rbxassetid://6065821596"
  721.                 elseif type == 'Y' or type == 'B' then
  722.                     customCursor.Image = "rbxassetid://6065821596"
  723.                 end
  724.             elseif customCursor.Image ~= "rbxassetid://6065775281" then
  725.                 customCursor.Image = "rbxassetid://6065775281"
  726.             end
  727.         else
  728.             connections["SIMPLESPY_CURSOR"]:Disconnect()
  729.         end
  730.     end)
  731. end
  732.  
  733. --- Called when mouse moves
  734. function mouseMoved()
  735.     local mousePos = UserInputService:GetMouseLocation() - GuiInset
  736.     if not closed
  737.     and mousePos.X >= TopBar.AbsolutePosition.X and mousePos.X <= TopBar.AbsolutePosition.X + TopBar.AbsoluteSize.X
  738.     and mousePos.Y >= Background.AbsolutePosition.Y and mousePos.Y <= Background.AbsolutePosition.Y + Background.AbsoluteSize.Y then
  739.         if not mouseInGui then
  740.             mouseInGui = true
  741.             mouseEntered()
  742.         end
  743.     else
  744.         mouseInGui = false
  745.     end
  746. end
  747.  
  748. --- Adjusts the ui elements to the 'Maximized' size
  749. function maximizeSize(speed)
  750.     if not speed then
  751.         speed = 0.05
  752.     end
  753.     TweenService:Create(LeftPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play()
  754.     TweenService:Create(RightPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play()
  755.     TweenService:Create(TopBar, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X, TopBar.AbsoluteSize.Y) }):Play()
  756.     TweenService:Create(ScrollingFrame, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X, 110), Position = UDim2.fromOffset(0, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play()
  757.     TweenService:Create(CodeBox, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play()
  758.     TweenService:Create(LogList, TweenInfo.new(speed), { Size = UDim2.fromOffset(LogList.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y - 18) }):Play()
  759. end
  760.  
  761. --- Adjusts the ui elements to close the side
  762. function minimizeSize(speed)
  763.     if not speed then
  764.         speed = 0.05
  765.     end
  766.     TweenService:Create(LeftPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play()
  767.     TweenService:Create(RightPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(0, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play()
  768.     TweenService:Create(TopBar, TweenInfo.new(speed), { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, TopBar.AbsoluteSize.Y) }):Play()
  769.     TweenService:Create(ScrollingFrame, TweenInfo.new(speed), { Size = UDim2.fromOffset(0, 119), Position = UDim2.fromOffset(0, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play()
  770.     TweenService:Create(CodeBox, TweenInfo.new(speed), { Size = UDim2.fromOffset(0, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play()
  771.     TweenService:Create(LogList, TweenInfo.new(speed), { Size = UDim2.fromOffset(LogList.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y - 18) }):Play()
  772. end
  773.  
  774. --- Ensures size is within screensize limitations
  775. function validateSize()
  776.     local x, y = Background.AbsoluteSize.X, Background.AbsoluteSize.Y
  777.     local screenSize = workspace.CurrentCamera.ViewportSize
  778.     if x + Background.AbsolutePosition.X > screenSize.X then
  779.         if screenSize.X - Background.AbsolutePosition.X >= 450 then
  780.             x = screenSize.X - Background.AbsolutePosition.X
  781.         else
  782.             x = 450
  783.         end
  784.     elseif y + Background.AbsolutePosition.Y > screenSize.Y then
  785.         if screenSize.X - Background.AbsolutePosition.Y >= 268 then
  786.             y = screenSize.Y - Background.AbsolutePosition.Y
  787.         else
  788.             y = 268
  789.         end
  790.     end
  791.     Background.Size = UDim2.fromOffset(x, y)
  792. end
  793.  
  794. --- Called on user input while mouse in 'Background' frame
  795. --- @param input InputObject
  796. function backgroundUserInput(input)
  797.     local mousePos = UserInputService:GetMouseLocation() - GuiInset
  798.     local inResizeRange, type = isInResizeRange(mousePos)
  799.     if input.UserInputType == Enum.UserInputType.MouseButton1 and inResizeRange then
  800.         local lastPos = UserInputService:GetMouseLocation()
  801.         local offset = Background.AbsoluteSize - lastPos
  802.         local currentPos = lastPos + offset
  803.         if not connections["SIMPLESPY_RESIZE"] then
  804.             connections["SIMPLESPY_RESIZE"] = RunService.RenderStepped:Connect(function()
  805.                 local newPos = UserInputService:GetMouseLocation()
  806.                 if newPos ~= lastPos then
  807.                     local currentX = (newPos + offset).X
  808.                     local currentY = (newPos + offset).Y
  809.                     if currentX < 450 then
  810.                         currentX = 450
  811.                     end
  812.                     if currentY < 268 then
  813.                         currentY = 268
  814.                     end
  815.                     currentPos = Vector2.new(currentX, currentY)
  816.                     Background.Size = UDim2.fromOffset((not sideClosed and not closed and (type == "X" or type == "B")) and currentPos.X or Background.AbsoluteSize.X, (--[[(not sideClosed or currentPos.X <= LeftPanel.AbsolutePosition.X + LeftPanel.AbsoluteSize.X) and]] not closed and (type == "Y" or type == "B")) and currentPos.Y or Background.AbsoluteSize.Y)
  817.                     validateSize()
  818.                     if sideClosed then
  819.                         minimizeSize()
  820.                     else
  821.                         maximizeSize()
  822.                     end
  823.                     lastPos = newPos
  824.                 end
  825.             end)
  826.         end
  827.         table.insert(connections, UserInputService.InputEnded:Connect(function(inputE)
  828.             if input == inputE then
  829.                 if connections["SIMPLESPY_RESIZE"] then
  830.                     connections["SIMPLESPY_RESIZE"]:Disconnect()
  831.                     connections["SIMPLESPY_RESIZE"] = nil
  832.                 end
  833.             end
  834.         end))
  835.     elseif isInDragRange(mousePos) then
  836.         onBarInput(input)
  837.     end
  838. end
  839.  
  840. --- Gets the player an instance is descended from
  841. function getPlayerFromInstance(instance)
  842.     for _, v in next, Players:GetPlayers() do
  843.         if v.Character and (instance:IsDescendantOf(v.Character) or instance == v.Character) then
  844.             return v
  845.         end
  846.     end
  847. end
  848.  
  849. --- Runs on MouseButton1Click of an event frame
  850. function eventSelect(frame)
  851.     if selected and selected.Log  then
  852.         if selected.Button then
  853.             spawn(function()
  854.                 TweenService:Create(selected.Button, TweenInfo.new(0.5), {BackgroundColor3 = Color3.fromRGB(0, 0, 0)}):Play()
  855.             end)
  856.         end
  857.         selected = nil
  858.     end
  859.     for _, v in next, logs do
  860.         if frame == v.Log then
  861.             selected = v
  862.         end
  863.     end
  864.     if selected and selected.Log then
  865.         spawn(function()
  866.             TweenService:Create(frame.Button, TweenInfo.new(0.5), {BackgroundColor3 = Color3.fromRGB(92, 126, 229)}):Play()
  867.         end)
  868.         codebox:setRaw(selected.GenScript)
  869.     end
  870.     if sideClosed then
  871.         toggleSideTray()
  872.     end
  873. end
  874.  
  875. --- Updates the canvas size to fit the current amount of function buttons
  876. function updateFunctionCanvas()
  877.     ScrollingFrame.CanvasSize = UDim2.fromOffset(UIGridLayout.AbsoluteContentSize.X, UIGridLayout.AbsoluteContentSize.Y)
  878. end
  879.  
  880. --- Updates the canvas size to fit the amount of current remotes
  881. function updateRemoteCanvas()
  882.     LogList.CanvasSize = UDim2.fromOffset(UIListLayout.AbsoluteContentSize.X, UIListLayout.AbsoluteContentSize.Y)
  883. end
  884.  
  885. --- Allows for toggling of the tooltip and easy setting of le description
  886. --- @param enable boolean
  887. --- @param text string
  888. function makeToolTip(enable, text)
  889.     if enable and text then
  890.         if ToolTip.Visible then
  891.             ToolTip.Visible = false
  892.             local tooltip = connections["ToolTip"]
  893.             if tooltip then
  894.                 tooltip:Disconnect()
  895.             end
  896.         end
  897.         local first = true
  898.         connections["ToolTip"] = RunService.RenderStepped:Connect(function()
  899.             local MousePos = UserInputService:GetMouseLocation()
  900.             local topLeft = MousePos + Vector2.new(20, -15)
  901.             local bottomRight = topLeft + ToolTip.AbsoluteSize
  902.             local ViewportSize = workspace.CurrentCamera.ViewportSize
  903.             local ViewportSizeX = ViewportSize.X
  904.             local ViewportSizeY = ViewportSize.Y
  905.  
  906.             if topLeft.X < 0 then
  907.                 topLeft = Vector2.new(0, topLeft.Y)
  908.             elseif bottomRight.X > ViewportSizeX then
  909.                 topLeft = Vector2.new(ViewportSizeX - ToolTip.AbsoluteSize.X, topLeft.Y)
  910.             end
  911.             if topLeft.Y < 0 then
  912.                 topLeft = Vector2.new(topLeft.X, 0)
  913.             elseif bottomRight.Y > ViewportSizeY - 35 then
  914.                 topLeft = Vector2.new(topLeft.X, ViewportSizeY - ToolTip.AbsoluteSize.Y - 35)
  915.             end
  916.             if topLeft.X <= MousePos.X and topLeft.Y <= MousePos.Y then
  917.                 topLeft = Vector2.new(MousePos.X - ToolTip.AbsoluteSize.X - 2, MousePos.Y - ToolTip.AbsoluteSize.Y - 2)
  918.             end
  919.             if first then
  920.                 ToolTip.Position = UDim2.fromOffset(topLeft.X, topLeft.Y)
  921.                 first = false
  922.             else
  923.                 ToolTip:TweenPosition(UDim2.fromOffset(topLeft.X, topLeft.Y), "Out", "Linear", 0.1)
  924.             end
  925.         end)
  926.         TextLabel.Text = text
  927.         TextLabel.TextScaled = true
  928.         ToolTip.Visible = true
  929.         return
  930.     else
  931.         if ToolTip.Visible then
  932.             ToolTip.Visible = false
  933.             local tooltip = connections["ToolTip"]
  934.             if tooltip then
  935.                 tooltip:Disconnect()
  936.             end
  937.         end
  938.     end
  939. end
  940.  
  941. --- Creates new function button (below codebox)
  942. --- @param name string
  943. ---@param description function
  944. ---@param onClick function
  945. function newButton(name, description, onClick)
  946.     local FunctionTemplate = Create("Frame",{Name = "FunctionTemplate",Parent = ScrollingFrame,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Size = UDim2.new(0, 117, 0, 23)})
  947.     local ColorBar = Create("Frame",{Name = "ColorBar",Parent = FunctionTemplate,BackgroundColor3 = Color3.new(1, 1, 1),BorderSizePixel = 0,Position = UDim2.new(0, 7, 0, 10),Size = UDim2.new(0, 7, 0, 18),ZIndex = 3})
  948.     local Text = Create("TextLabel",{Text = name,Name = "Text",Parent = FunctionTemplate,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Position = UDim2.new(0, 19, 0, 10),Size = UDim2.new(0, 69, 0, 18),ZIndex = 2,Font = Enum.Font.SourceSans,TextColor3 = Color3.new(1, 1, 1),TextSize = 14,TextStrokeColor3 = Color3.new(0.145098, 0.141176, 0.14902),TextXAlignment = Enum.TextXAlignment.Left})
  949.     local Button = Create("TextButton",{Name = "Button",Parent = FunctionTemplate,BackgroundColor3 = Color3.new(0, 0, 0),BackgroundTransparency = 0.69999998807907,BorderColor3 = Color3.new(1, 1, 1),Position = UDim2.new(0, 7, 0, 10),Size = UDim2.new(0, 80, 0, 18),AutoButtonColor = false,Font = Enum.Font.SourceSans,Text = "",TextColor3 = Color3.new(0, 0, 0),TextSize = 14})
  950.  
  951.     Button.MouseEnter:Connect(function()
  952.         makeToolTip(true, description())
  953.     end)
  954.     Button.MouseLeave:Connect(function()
  955.         makeToolTip(false)
  956.     end)
  957.     FunctionTemplate.AncestryChanged:Connect(function()
  958.         makeToolTip(false)
  959.     end)
  960.     Button.MouseButton1Click:Connect(function(...)
  961.         logthread(running())
  962.         onClick(FunctionTemplate, ...)
  963.     end)
  964.     updateFunctionCanvas()
  965. end
  966.  
  967. --- Adds new Remote to logs
  968. --- @param name string The name of the remote being logged
  969. --- @param type string The type of the remote being logged (either 'function' or 'event')
  970. --- @param args any
  971. --- @param remote any
  972. --- @param function_info string
  973. --- @param blocked any
  974. -- Adds new Remote to logs + dumps one line to disk immediately
  975. function newRemote(type, data)
  976.     if layoutOrderNum < 1 then layoutOrderNum = 999999999 end
  977.     local remote = data.remote
  978.     local callingscript = data.callingscript
  979.  
  980.     local RemoteTemplate = Create("Frame", {
  981.         LayoutOrder = layoutOrderNum, Name = "RemoteTemplate", Parent = LogList,
  982.         BackgroundColor3 = Color3.new(1, 1, 1), BackgroundTransparency = 1,
  983.         Size = UDim2.new(0, 117, 0, 27)
  984.     })
  985.     local ColorBar = Create("Frame", {
  986.         Name = "ColorBar", Parent = RemoteTemplate,
  987.         BackgroundColor3 = (type == "event" and Color3.fromRGB(255, 242, 0)) or Color3.fromRGB(99, 86, 245),
  988.         BorderSizePixel = 0, Position = UDim2.new(0, 0, 0, 1), Size = UDim2.new(0, 7, 0, 18), ZIndex = 2
  989.     })
  990.     local Text = Create("TextLabel", {
  991.         TextTruncate = Enum.TextTruncate.AtEnd, Name = "Text", Parent = RemoteTemplate,
  992.         BackgroundColor3 = Color3.new(1, 1, 1), BackgroundTransparency = 1,
  993.         Position = UDim2.new(0, 12, 0, 1), Size = UDim2.new(0, 105, 0, 18), ZIndex = 2,
  994.         Font = Enum.Font.SourceSans, Text = remote.Name, TextColor3 = Color3.new(1, 1, 1),
  995.         TextSize = 14, TextXAlignment = Enum.TextXAlignment.Left
  996.     })
  997.     local Button = Create("TextButton", {
  998.         Name = "Button", Parent = RemoteTemplate, BackgroundColor3 = Color3.new(0, 0, 0),
  999.         BackgroundTransparency = 0.75, BorderColor3 = Color3.new(1, 1, 1),
  1000.         Position = UDim2.new(0, 0, 0, 1), Size = UDim2.new(0, 117, 0, 18),
  1001.         AutoButtonColor = false, Font = Enum.Font.SourceSans, Text = "",
  1002.         TextColor3 = Color3.new(0, 0, 0), TextSize = 14
  1003.     })
  1004.  
  1005.     local log = {
  1006.         Name = remote.name,
  1007.         Function = data.infofunc or "--Function Info is disabled",
  1008.         Remote = remote,
  1009.         DebugId = data.id,
  1010.         metamethod = data.metamethod,
  1011.         args = data.args,
  1012.         Log = RemoteTemplate,
  1013.         Button = Button,
  1014.         Blocked = data.blocked,
  1015.         Source = callingscript,
  1016.         returnvalue = data.returnvalue,
  1017.         GenScript = "-- Generating, please wait...\n-- (If this message persists, the remote args are likely extremely long)"
  1018.     }
  1019.  
  1020.     -- ======= dump one compact line to disk (no varargs used) =======
  1021.     do
  1022.         local path = getgenv().REMOTE_DUMP_PATH or "remote_dump.txt"
  1023.         local function safestr(v)
  1024.             local t = typeof(v)
  1025.             if t == "Instance" then
  1026.                 local ok, full = pcall(function() return v:GetFullName() end)
  1027.                 return ("Instance<%s:%s>"):format(v.ClassName, ok and full or (v.Name or "?"))
  1028.             elseif t == "string" then
  1029.                 if #v > 120 then v = v:sub(1,117) .. "..." end
  1030.                 return ("%q"):format(v)
  1031.             elseif t == "table" then
  1032.                 local n, parts = 0, {}
  1033.                 for k,val in pairs(v) do
  1034.                     n += 1; if n > 10 then parts[#parts+1] = "..."; break end
  1035.                     parts[#parts+1] = "["..tostring(k).."]="..tostring(val)
  1036.                 end
  1037.                 return "table{"..table.concat(parts, ", ").."}"
  1038.             else
  1039.                 return t .. ":" .. tostring(v)
  1040.             end
  1041.         end
  1042.  
  1043.         local rpath = "?"
  1044.         if remote and remote.GetFullName then
  1045.             local ok, full = pcall(function() return remote:GetFullName() end)
  1046.             if ok then rpath = full end
  1047.         end
  1048.  
  1049.         local argparts = {}
  1050.         if data.args then
  1051.             for i = 1, math.min(#data.args, 15) do
  1052.                 argparts[i] = safestr(data.args[i])
  1053.             end
  1054.         end
  1055.  
  1056.         local where = callingscript and tostring(callingscript) or ""
  1057.         local line = ("[%s] %s | %s | args=[%s]%s"):format(
  1058.             os.date("%H:%M:%S"),
  1059.             tostring(type),
  1060.             rpath,
  1061.             table.concat(argparts, ", "),
  1062.             (where ~= "" and (" | src="..where) or "")
  1063.         )
  1064.  
  1065.         if appendfile then
  1066.             pcall(appendfile, path, line .. "\n")
  1067.         elseif writefile then
  1068.             local prev = ""
  1069.             if isfile and isfile(path) and readfile then
  1070.                 prev = readfile(path) or ""
  1071.             end
  1072.             pcall(writefile, path, prev .. line .. "\n")
  1073.         end
  1074.     end
  1075.     -- ===============================================================
  1076.  
  1077.     logs[#logs + 1] = log
  1078.     local connect = Button.MouseButton1Click:Connect(function()
  1079.         logthread(running())
  1080.         eventSelect(RemoteTemplate)
  1081.         log.GenScript = genScript(log.Remote, log.args)
  1082.         if blocked then
  1083.             log.GenScript = "-- THIS REMOTE WAS PREVENTED FROM FIRING TO THE SERVER BY SIMPLESPY\n\n" .. log.GenScript
  1084.         end
  1085.         if selected == log and RemoteTemplate then
  1086.             eventSelect(RemoteTemplate)
  1087.         end
  1088.     end)
  1089.     layoutOrderNum -= 1
  1090.     table.insert(remoteLogs, 1, {connect, RemoteTemplate})
  1091.     clean()
  1092.     updateRemoteCanvas()
  1093. end
  1094.  
  1095.  
  1096. --- Generates a script from the provided arguments (first has to be remote path)
  1097. function genScript(remote, args)
  1098.     prevTables = {}
  1099.     local gen = ""
  1100.     if #args > 0 then
  1101.         xpcall(function()
  1102.             gen = "local args = "..LazyFix.Convert(args, true) .. "\n"
  1103.         end,function(err)
  1104.             gen ..= "-- An error has occured:\n--"..err.."\n-- TableToString failure! Reverting to legacy functionality (results may vary)\nlocal args = {"
  1105.             xpcall(function()
  1106.                 for i, v in next, args do
  1107.                     if type(i) ~= "Instance" and type(i) ~= "userdata" then
  1108.                         gen = gen .. "\n    [object] = "
  1109.                     elseif type(i) == "string" then
  1110.                         gen = gen .. '\n    ["' .. i .. '"] = '
  1111.                     elseif type(i) == "userdata" and typeof(i) ~= "Instance" then
  1112.                         gen = gen .. "\n    [" .. string.format("nil --[[%s]]", typeof(v)) .. ")] = "
  1113.                     elseif type(i) == "userdata" then
  1114.                          gen = gen .. "\n    [game." .. i:GetFullName() .. ")] = "
  1115.                     end
  1116.                     if type(v) ~= "Instance" and type(v) ~= "userdata" then
  1117.                         gen = gen .. "object"
  1118.                     elseif type(v) == "string" then
  1119.                         gen = gen .. '"' .. v .. '"'
  1120.                     elseif type(v) == "userdata" and typeof(v) ~= "Instance" then
  1121.                         gen = gen .. string.format("nil --[[%s]]", typeof(v))
  1122.                     elseif type(v) == "userdata" then
  1123.                         gen = gen .. "game." .. v:GetFullName()
  1124.                     end
  1125.                 end
  1126.                 gen ..= "\n}\n\n"
  1127.             end,function()
  1128.                 gen ..= "}\n-- Legacy tableToString failure! Unable to decompile."
  1129.             end)
  1130.         end)
  1131.         if not remote:IsDescendantOf(game) and not getnilrequired then
  1132.             gen = "function getNil(name,class) for _,v in next, getnilinstances()do if v.ClassName==class and v.Name==name then return v;end end end\n\n" .. gen
  1133.         end
  1134.         if remote:IsA("RemoteEvent") or remote:IsA("UnreliableRemoteEvent") then
  1135.             gen ..= LazyFix.ConvertKnown("Instance", remote) .. ":FireServer(unpack(args))"
  1136.         elseif remote:IsA("RemoteFunction") then
  1137.             gen = gen .. LazyFix.ConvertKnown("Instance", remote) .. ":InvokeServer(unpack(args))"
  1138.         end
  1139.     else
  1140.         if remote:IsA("RemoteEvent") or remote:IsA("UnreliableRemoteEvent") then
  1141.             gen ..= LazyFix.ConvertKnown("Instance", remote) .. ":FireServer()"
  1142.         elseif remote:IsA("RemoteFunction") then
  1143.             gen ..= LazyFix.ConvertKnown("Instance", remote) .. ":InvokeServer()"
  1144.         end
  1145.     end
  1146.     prevTables = {}
  1147.     return gen
  1148. end
  1149.  
  1150. --- value-to-string: value, string (out), level (indentation), parent table, var name, is from tovar
  1151. local CustomGeneration = {
  1152.     Vector3 = (function()
  1153.         local temp = {}
  1154.         for i,v in Vector3 do
  1155.             if type(v) == "vector" then
  1156.                 temp[v] = `Vector3.{i}`
  1157.             end
  1158.         end
  1159.         return temp
  1160.     end)(),
  1161.     Vector2 = (function()
  1162.         local temp = {}
  1163.         for i,v in Vector2 do
  1164.             if type(v) == "userdata" then
  1165.                 temp[v] = `Vector2.{i}`
  1166.             end
  1167.         end
  1168.         return temp
  1169.     end)(),
  1170.     CFrame = {
  1171.         [CFrame.identity] = "CFrame.identity"
  1172.     }
  1173. }
  1174.  
  1175. local number_table = {
  1176.     ["inf"] = "math.huge",
  1177.     ["-inf"] = "-math.huge",
  1178.     ["nan"] = "0/0"
  1179. }
  1180.  
  1181. local ufunctions
  1182. ufunctions = {
  1183.     TweenInfo = function(u)
  1184.         return `TweenInfo.new({u.Time}, {u.EasingStyle}, {u.EasingDirection}, {u.RepeatCount}, {u.Reverses}, {u.DelayTime})`
  1185.     end,
  1186.     Ray = function(u)
  1187.         local Vector3tostring = ufunctions["Vector3"]
  1188.  
  1189.         return `Ray.new({Vector3tostring(u.Origin)}, {Vector3tostring(u.Direction)})`
  1190.     end,
  1191.     BrickColor = function(u)
  1192.         return `BrickColor.new({u.Number})`
  1193.     end,
  1194.     NumberRange = function(u)
  1195.         return `NumberRange.new({u.Min}, {u.Max})`
  1196.     end,
  1197.     Region3 = function(u)
  1198.         local center = u.CFrame.Position
  1199.         local centersize = u.Size/2
  1200.         local Vector3tostring = ufunctions["Vector3"]
  1201.  
  1202.         return `Region3.new({Vector3tostring(center-centersize)}, {Vector3tostring(center+centersize)})`
  1203.     end,
  1204.     Faces = function(u)
  1205.         local faces = {}
  1206.         if u.Top then
  1207.             table.insert(faces, "Top")
  1208.         end
  1209.         if u.Bottom then
  1210.             table.insert(faces, "Enum.NormalId.Bottom")
  1211.         end
  1212.         if u.Left then
  1213.             table.insert(faces, "Enum.NormalId.Left")
  1214.         end
  1215.         if u.Right then
  1216.             table.insert(faces, "Enum.NormalId.Right")
  1217.         end
  1218.         if u.Back then
  1219.             table.insert(faces, "Enum.NormalId.Back")
  1220.         end
  1221.         if u.Front then
  1222.             table.insert(faces, "Enum.NormalId.Front")
  1223.         end
  1224.         return `Faces.new({table.concat(faces, ", ")})`
  1225.     end,
  1226.     EnumItem = function(u)
  1227.         return tostring(u)
  1228.     end,
  1229.     Enums = function(u)
  1230.         return "Enum"
  1231.     end,
  1232.     Enum = function(u)
  1233.         return `Enum.{u}`
  1234.     end,
  1235.     Vector3 = function(u)
  1236.         return CustomGeneration.Vector3[u] or `Vector3.new({u})`
  1237.     end,
  1238.     Vector2 = function(u)
  1239.         return CustomGeneration.Vector2[u] or `Vector2.new({u})`
  1240.     end,
  1241.     CFrame = function(u)
  1242.         return CustomGeneration.CFrame[u] or `CFrame.new({table.concat({u:GetComponents()},", ")})`
  1243.     end,
  1244.     PathWaypoint = function(u)
  1245.         return `PathWaypoint.new({ufunctions["Vector3"](u.Position)}, {u.Action}, "{u.Label}")`
  1246.     end,
  1247.     UDim = function(u)
  1248.         return `UDim.new({u})`
  1249.     end,
  1250.     UDim2 = function(u)
  1251.         return `UDim2.new({u})`
  1252.     end,
  1253.     Rect = function(u)
  1254.         local Vector2tostring = ufunctions["Vector2"]
  1255.         return `Rect.new({Vector2tostring(u.Min)}, {Vector2tostring(u.Max)})`
  1256.     end,
  1257.     Color3 = function(u)
  1258.         return `Color3.new({u.R}, {u.G}, {u.B})`
  1259.     end,
  1260.     RBXScriptSignal = function(u) -- The server doesnt recive this
  1261.         return "RBXScriptSignal --[[RBXScriptSignal's are not supported]]"
  1262.     end,
  1263.     RBXScriptConnection = function(u) -- The server doesnt recive this
  1264.         return "RBXScriptConnection --[[RBXScriptConnection's are not supported]]"
  1265.     end,
  1266. }
  1267.  
  1268. local typeofv2sfunctions = {
  1269.     number = function(v)
  1270.         local number = tostring(v)
  1271.         return number_table[number] or number
  1272.     end,
  1273.     boolean = function(v)
  1274.         return tostring(v)
  1275.     end,
  1276.     string = function(v,l)
  1277.         return formatstr(v, l)
  1278.     end,
  1279.     ["function"] = function(v) -- The server doesnt recive this
  1280.         return f2s(v)
  1281.     end,
  1282.     table = function(v, l, p, n, vtv, i, pt, path, tables, tI)
  1283.         return t2s(v, l, p, n, vtv, i, pt, path, tables, tI)
  1284.     end,
  1285.     Instance = function(v)
  1286.         local DebugId = OldDebugId(v)
  1287.         return i2p(v,generation[DebugId])
  1288.     end,
  1289.     userdata = function(v) -- The server doesnt recive this
  1290.         if configs.advancedinfo then
  1291.             if getrawmetatable(v) then
  1292.                 return "newproxy(true)"
  1293.             end
  1294.             return "newproxy(false)"
  1295.         end
  1296.         return "newproxy(true)"
  1297.     end
  1298. }
  1299.  
  1300. local typev2sfunctions = {
  1301.     userdata = function(v,vtypeof)
  1302.         if ufunctions[vtypeof] then
  1303.             return ufunctions[vtypeof](v)
  1304.         end
  1305.         return `{vtypeof}({rawtostring(v)}) --[[Generation Failure]]`
  1306.     end,
  1307.     vector = ufunctions["Vector3"]
  1308. }
  1309.  
  1310.  
  1311. function v2s(v, l, p, n, vtv, i, pt, path, tables, tI)
  1312.     local vtypeof = typeof(v)
  1313.     local vtypeoffunc = typeofv2sfunctions[vtypeof]
  1314.     local vtypefunc = typev2sfunctions[type(v)]
  1315.     local vtype = type(v)
  1316.     if not tI then
  1317.         tI = {0}
  1318.     else
  1319.         tI[1] += 1
  1320.     end
  1321.  
  1322.     if vtypeoffunc then
  1323.         return vtypeoffunc(v, l, p, n, vtv, i, pt, path, tables, tI)
  1324.     elseif vtypefunc then
  1325.         return vtypefunc(v,vtypeof)
  1326.     end
  1327.     return `{vtypeof}({rawtostring(v)}) --[[Generation Failure]]`
  1328. end
  1329.  
  1330. --- value-to-variable
  1331. --- @param t any
  1332. function v2v(t)
  1333.     topstr = ""
  1334.     bottomstr = ""
  1335.     getnilrequired = false
  1336.     local ret = ""
  1337.     local count = 1
  1338.     for i, v in next, t do
  1339.         if type(i) == "string" and i:match("^[%a_]+[%w_]*$") then
  1340.             ret = ret .. "local " .. i .. " = " .. v2s(v, nil, nil, i, true) .. "\n"
  1341.         elseif rawtostring(i):match("^[%a_]+[%w_]*$") then
  1342.             ret = ret .. "local " .. lower(rawtostring(i)) .. "_" .. rawtostring(count) .. " = " .. v2s(v, nil, nil, lower(rawtostring(i)) .. "_" .. rawtostring(count), true) .. "\n"
  1343.         else
  1344.             ret = ret .. "local " .. type(v) .. "_" .. rawtostring(count) .. " = " .. v2s(v, nil, nil, type(v) .. "_" .. rawtostring(count), true) .. "\n"
  1345.         end
  1346.         count = count + 1
  1347.     end
  1348.     if getnilrequired then
  1349.         topstr = "function getNil(name,class) for _,v in next, getnilinstances() do if v.ClassName==class and v.Name==name then return v;end end end\n" .. topstr
  1350.     end
  1351.     if #topstr > 0 then
  1352.         ret = topstr .. "\n" .. ret
  1353.     end
  1354.     if #bottomstr > 0 then
  1355.         ret = ret .. bottomstr
  1356.     end
  1357.     return ret
  1358. end
  1359.  
  1360. function tabletostring(tbl: table,format: boolean)
  1361.    
  1362. end
  1363.  
  1364. --- table-to-string
  1365. --- @param t table
  1366. --- @param l number
  1367. --- @param p table
  1368. --- @param n string
  1369. --- @param vtv boolean
  1370. --- @param i any
  1371. --- @param pt table
  1372. --- @param path string
  1373. --- @param tables table
  1374. --- @param tI table
  1375. function t2s(t, l, p, n, vtv, i, pt, path, tables, tI)
  1376.     local globalIndex = table.find(getgenv(), t) -- checks if table is a global
  1377.     if type(globalIndex) == "string" then
  1378.         return globalIndex
  1379.     end
  1380.     if not tI then
  1381.         tI = {0}
  1382.     end
  1383.     if not path then -- sets path to empty string (so it doesn't have to manually provided every time)
  1384.         path = ""
  1385.     end
  1386.     if not l then -- sets the level to 0 (for indentation) and tables for logging tables it already serialized
  1387.         l = 0
  1388.         tables = {}
  1389.     end
  1390.     if not p then -- p is the previous table but doesn't really matter if it's the first
  1391.         p = t
  1392.     end
  1393.     for _, v in next, tables do -- checks if the current table has been serialized before
  1394.         if n and rawequal(v, t) then
  1395.             bottomstr = bottomstr .. "\n" .. rawtostring(n) .. rawtostring(path) .. " = " .. rawtostring(n) .. rawtostring(({v2p(v, p)})[2])
  1396.             return "{} --[[DUPLICATE]]"
  1397.         end
  1398.     end
  1399.     table.insert(tables, t) -- logs table to past tables
  1400.     local s =  "{" -- start of serialization
  1401.     local size = 0
  1402.     l += indent -- set indentation level
  1403.     for k, v in next, t do -- iterates over table
  1404.         size = size + 1 -- changes size for max limit
  1405.         if size > (getgenv().SimpleSpyMaxTableSize or 1000) then
  1406.             s = s .. "\n" .. string.rep(" ", l) .. "-- MAXIMUM TABLE SIZE REACHED, CHANGE 'getgenv().SimpleSpyMaxTableSize' TO ADJUST MAXIMUM SIZE "
  1407.             break
  1408.         end
  1409.         if rawequal(k, t) then -- checks if the table being iterated over is being used as an index within itself (yay, lua)
  1410.             bottomstr ..= `\n{n}{path}[{n}{path}] = {(rawequal(v,k) and `{n}{path}` or v2s(v, l, p, n, vtv, k, t, `{path}[{n}{path}]`, tables))}`
  1411.             --bottomstr = bottomstr .. "\n" .. rawtostring(n) .. rawtostring(path) .. "[" .. rawtostring(n) .. rawtostring(path) .. "]" .. " = " .. (rawequal(v, k) and rawtostring(n) .. rawtostring(path) or v2s(v, l, p, n, vtv, k, t, path .. "[" .. rawtostring(n) .. rawtostring(path) .. "]", tables))
  1412.             size -= 1
  1413.             continue
  1414.         end
  1415.         local currentPath = "" -- initializes the path of 'v' within 't'
  1416.         if type(k) == "string" and k:match("^[%a_]+[%w_]*$") then -- cleanly handles table path generation (for the first half)
  1417.             currentPath = "." .. k
  1418.         else
  1419.             currentPath = "[" .. v2s(k, l, p, n, vtv, k, t, path .. currentPath, tables, tI) .. "]"
  1420.         end
  1421.         if size % 100 == 0 then
  1422.             scheduleWait()
  1423.         end
  1424.         -- actually serializes the member of the table
  1425.         s = s .. "\n" .. string.rep(" ", l) .. "[" .. v2s(k, l, p, n, vtv, k, t, path .. currentPath, tables, tI) .. "] = " .. v2s(v, l, p, n, vtv, k, t, path .. currentPath, tables, tI) .. ","
  1426.     end
  1427.     if #s > 1 then -- removes the last comma because it looks nicer (no way to tell if it's done 'till it's done so...)
  1428.         s = s:sub(1, #s - 1)
  1429.     end
  1430.     if size > 0 then -- cleanly indents the last curly bracket
  1431.         s = s .. "\n" .. string.rep(" ", l - indent)
  1432.     end
  1433.     return s .. "}"
  1434. end
  1435.  
  1436. --- function-to-string
  1437. function f2s(f)
  1438.     for k, x in next, getgenv() do
  1439.         local isgucci, gpath
  1440.         if rawequal(x, f) then
  1441.             isgucci, gpath = true, ""
  1442.         elseif type(x) == "table" then
  1443.             isgucci, gpath = v2p(f, x)
  1444.         end
  1445.         if isgucci and type(k) ~= "function" then
  1446.             if type(k) == "string" and k:match("^[%a_]+[%w_]*$") then
  1447.                 return k .. gpath
  1448.             else
  1449.                 return "getgenv()[" .. v2s(k) .. "]" .. gpath
  1450.             end
  1451.         end
  1452.     end
  1453.    
  1454.     if configs.funcEnabled then
  1455.         local funcname = info(f,"n")
  1456.        
  1457.         if funcname and funcname:match("^[%a_]+[%w_]*$") then
  1458.             return `function {funcname}() end -- Function Called: {funcname}`
  1459.         end
  1460.     end
  1461.     return tostring(f)
  1462. end
  1463.  
  1464. --- instance-to-path
  1465. --- @param i userdata
  1466. function i2p(i,customgen)
  1467.     if customgen then
  1468.         return customgen
  1469.     end
  1470.     local player = getplayer(i)
  1471.     local parent = i
  1472.     local out = ""
  1473.     if parent == nil then
  1474.         return "nil"
  1475.     elseif player then
  1476.         while true do
  1477.             if parent and parent == player.Character then
  1478.                 if player == Players.LocalPlayer then
  1479.                     return 'game:GetService("Players").LocalPlayer.Character' .. out
  1480.                 else
  1481.                     return i2p(player) .. ".Character" .. out
  1482.                 end
  1483.             else
  1484.                 if parent.Name:match("[%a_]+[%w+]*") ~= parent.Name then
  1485.                     out = ':FindFirstChild(' .. formatstr(parent.Name) .. ')' .. out
  1486.                 else
  1487.                     out = "." .. parent.Name .. out
  1488.                 end
  1489.             end
  1490.             task.wait()
  1491.             parent = parent.Parent
  1492.         end
  1493.     elseif parent ~= game then
  1494.         while true do
  1495.             if parent and parent.Parent == game then
  1496.                 if SafeGetService(parent.ClassName) then
  1497.                     if lower(parent.ClassName) == "workspace" then
  1498.                         return `workspace{out}`
  1499.                     else
  1500.                         return 'game:GetService("' .. parent.ClassName .. '")' .. out
  1501.                     end
  1502.                 else
  1503.                     if parent.Name:match("[%a_]+[%w_]*") then
  1504.                         return "game." .. parent.Name .. out
  1505.                     else
  1506.                         return 'game:FindFirstChild(' .. formatstr(parent.Name) .. ')' .. out
  1507.                     end
  1508.                 end
  1509.             elseif not parent.Parent then
  1510.                 getnilrequired = true
  1511.                 return 'getNil(' .. formatstr(parent.Name) .. ', "' .. parent.ClassName .. '")' .. out
  1512.             else
  1513.                 if parent.Name:match("[%a_]+[%w_]*") ~= parent.Name then
  1514.                     out = ':WaitForChild(' .. formatstr(parent.Name) .. ')' .. out
  1515.                 else
  1516.                     out = ':WaitForChild("' .. parent.Name .. '")'..out
  1517.                 end
  1518.             end
  1519.             if i:IsDescendantOf(Players.LocalPlayer) then
  1520.                 return 'game:GetService("Players").LocalPlayer'..out
  1521.             end
  1522.             parent = parent.Parent
  1523.             task.wait()
  1524.         end
  1525.     else
  1526.         return "game"
  1527.     end
  1528. end
  1529.  
  1530. --- Gets the player an instance is descended from
  1531. function getplayer(instance)
  1532.     for _, v in next, Players:GetPlayers() do
  1533.         if v.Character and (instance:IsDescendantOf(v.Character) or instance == v.Character) then
  1534.             return v
  1535.         end
  1536.     end
  1537. end
  1538.  
  1539. --- value-to-path (in table)
  1540. function v2p(x, t, path, prev)
  1541.     if not path then
  1542.         path = ""
  1543.     end
  1544.     if not prev then
  1545.         prev = {}
  1546.     end
  1547.     if rawequal(x, t) then
  1548.         return true, ""
  1549.     end
  1550.     for i, v in next, t do
  1551.         if rawequal(v, x) then
  1552.             if type(i) == "string" and i:match("^[%a_]+[%w_]*$") then
  1553.                 return true, (path .. "." .. i)
  1554.             else
  1555.                 return true, (path .. "[" .. v2s(i) .. "]")
  1556.             end
  1557.         end
  1558.         if type(v) == "table" then
  1559.             local duplicate = false
  1560.             for _, y in next, prev do
  1561.                 if rawequal(y, v) then
  1562.                     duplicate = true
  1563.                 end
  1564.             end
  1565.             if not duplicate then
  1566.                 table.insert(prev, t)
  1567.                 local found
  1568.                 found, p = v2p(x, v, path, prev)
  1569.                 if found then
  1570.                     if type(i) == "string" and i:match("^[%a_]+[%w_]*$") then
  1571.                         return true, "." .. i .. p
  1572.                     else
  1573.                         return true, "[" .. v2s(i) .. "]" .. p
  1574.                     end
  1575.                 end
  1576.             end
  1577.         end
  1578.     end
  1579.     return false, ""
  1580. end
  1581.  
  1582. --- format s: string, byte encrypt (for weird symbols)
  1583. function formatstr(s, indentation)
  1584.     if not indentation then
  1585.         indentation = 0
  1586.     end
  1587.     local handled, reachedMax = handlespecials(s, indentation)
  1588.     return '"' .. handled .. '"' .. (reachedMax and " --[[ MAXIMUM STRING SIZE REACHED, CHANGE 'getgenv().SimpleSpyMaxStringSize' TO ADJUST MAXIMUM SIZE ]]" or "")
  1589. end
  1590.  
  1591. --- Adds \'s to the text as a replacement to whitespace chars and other things because string.format can't yayeet
  1592.  
  1593. local function isFinished(coroutines: table)
  1594.     for _, v in next, coroutines do
  1595.         if status(v) == "running" then
  1596.             return false
  1597.         end
  1598.     end
  1599.     return true
  1600. end
  1601.  
  1602. local specialstrings = {
  1603.     ["\n"] = function(thread,index)
  1604.         resume(thread,index,"\\n")
  1605.     end,
  1606.     ["\t"] = function(thread,index)
  1607.         resume(thread,index,"\\t")
  1608.     end,
  1609.     ["\\"] = function(thread,index)
  1610.         resume(thread,index,"\\\\")
  1611.     end,
  1612.     ['"'] = function(thread,index)
  1613.         resume(thread,index,"\\\"")
  1614.     end
  1615. }
  1616.  
  1617. function handlespecials(s, indentation)
  1618.     local i = 0
  1619.     local n = 1
  1620.     local coroutines = {}
  1621.     local coroutineFunc = function(i, r)
  1622.         s = s:sub(0, i - 1) .. r .. s:sub(i + 1, -1)
  1623.     end
  1624.     local timeout = 0
  1625.     repeat
  1626.         i += 1
  1627.         if timeout >= 10 then
  1628.             task.wait()
  1629.             timeout = 0
  1630.         end
  1631.         local char = s:sub(i, i)
  1632.  
  1633.         if byte(char) then
  1634.             timeout += 1
  1635.             local c = create(coroutineFunc)
  1636.             table.insert(coroutines, c)
  1637.             local specialfunc = specialstrings[char]
  1638.  
  1639.             if specialfunc then
  1640.                 specialfunc(c,i)
  1641.                 i += 1
  1642.             elseif byte(char) > 126 or byte(char) < 32 then
  1643.                 resume(c, i, "\\" .. byte(char))
  1644.                 -- s = s:sub(0, i - 1) .. "\\" .. byte(char) .. s:sub(i + 1, -1)
  1645.                 i += #rawtostring(byte(char))
  1646.             end
  1647.             if i >= n * 100 then
  1648.                 local extra = string.format('" ..\n%s"', string.rep(" ", indentation + indent))
  1649.                 s = s:sub(0, i) .. extra .. s:sub(i + 1, -1)
  1650.                 i += #extra
  1651.                 n += 1
  1652.             end
  1653.         end
  1654.     until char == "" or i > (getgenv().SimpleSpyMaxStringSize or 10000)
  1655.     while not isFinished(coroutines) do
  1656.         RunService.Heartbeat:Wait()
  1657.     end
  1658.     clear(coroutines)
  1659.     if i > (getgenv().SimpleSpyMaxStringSize or 10000) then
  1660.         s = string.sub(s, 0, getgenv().SimpleSpyMaxStringSize or 10000)
  1661.         return s, true
  1662.     end
  1663.     return s, false
  1664. end
  1665.  
  1666. --- finds script from 'src' from getinfo, returns nil if not found
  1667. --- @param src string
  1668. function getScriptFromSrc(src)
  1669.     local realPath
  1670.     local runningTest
  1671.     --- @type number
  1672.     local s, e
  1673.     local match = false
  1674.     if src:sub(1, 1) == "=" then
  1675.         realPath = game
  1676.         s = 2
  1677.     else
  1678.         runningTest = src:sub(2, e and e - 1 or -1)
  1679.         for _, v in next, getnilinstances() do
  1680.             if v.Name == runningTest then
  1681.                 realPath = v
  1682.                 break
  1683.             end
  1684.         end
  1685.         s = #runningTest + 1
  1686.     end
  1687.     if realPath then
  1688.         e = src:sub(s, -1):find("%.")
  1689.         local i = 0
  1690.         repeat
  1691.             i += 1
  1692.             if not e then
  1693.                 runningTest = src:sub(s, -1)
  1694.                 local test = realPath.FindFirstChild(realPath, runningTest)
  1695.                 if test then
  1696.                     realPath = test
  1697.                 end
  1698.                 match = true
  1699.             else
  1700.                 runningTest = src:sub(s, e)
  1701.                 local test = realPath.FindFirstChild(realPath, runningTest)
  1702.                 local yeOld = e
  1703.                 if test then
  1704.                     realPath = test
  1705.                     s = e + 2
  1706.                     e = src:sub(e + 2, -1):find("%.")
  1707.                     e = e and e + yeOld or e
  1708.                 else
  1709.                     e = src:sub(e + 2, -1):find("%.")
  1710.                     e = e and e + yeOld or e
  1711.                 end
  1712.             end
  1713.         until match or i >= 50
  1714.     end
  1715.     return realPath
  1716. end
  1717.  
  1718. --- schedules the provided function (and calls it with any args after)
  1719.  
  1720. function schedule(f, ...)
  1721.     table.insert(scheduled, {f, ...})
  1722. end
  1723.  
  1724. --- yields the current thread until the scheduler gives the ok
  1725. function scheduleWait()
  1726.     local thread = running()
  1727.     schedule(function()
  1728.         resume(thread)
  1729.     end)
  1730.     yield()
  1731. end
  1732.  
  1733. --- the big (well tbh small now) boi task scheduler himself, handles p much anything as quicc as possible
  1734. local function taskscheduler()
  1735.     if not toggle then
  1736.         scheduled = {}
  1737.         return
  1738.     end
  1739.     if #scheduled > SIMPLESPYCONFIG_MaxRemotes + 100 then
  1740.         table.remove(scheduled, #scheduled)
  1741.     end
  1742.     if #scheduled > 0 then
  1743.         local currentf = scheduled[1]
  1744.         table.remove(scheduled, 1)
  1745.         if type(currentf) == "table" and type(currentf[1]) == "function" then
  1746.             pcall(unpack(currentf))
  1747.         end
  1748.     end
  1749. end
  1750.  
  1751. local function tablecheck(tabletocheck,instance,id)
  1752.     return tabletocheck[id] or tabletocheck[instance.Name]
  1753. end
  1754.  
  1755. function remoteHandler(data)
  1756.     if configs.autoblock then
  1757.         local id = data.id
  1758.  
  1759.         if excluding[id] then
  1760.             return
  1761.         end
  1762.         if not history[id] then
  1763.             history[id] = {badOccurances = 0, lastCall = tick()}
  1764.         end
  1765.         if tick() - history[id].lastCall < 1 then
  1766.             history[id].badOccurances += 1
  1767.             return
  1768.         else
  1769.             history[id].badOccurances = 0
  1770.         end
  1771.         if history[id].badOccurances > 3 then
  1772.             excluding[id] = true
  1773.             return
  1774.         end
  1775.         history[id].lastCall = tick()
  1776.     end
  1777.  
  1778.     if (data.remote:IsA("RemoteEvent") or data.remote:IsA("UnreliableRemoteEvent")) and lower(data.method) == "fireserver" then
  1779.         newRemote("event", data)
  1780.     elseif data.remote:IsA("RemoteFunction") and lower(data.method) == "invokeserver" then
  1781.         newRemote("function", data)
  1782.     end
  1783. end
  1784.  
  1785. local newindex = function(method,originalfunction,...)
  1786.     if typeof(...) == 'Instance' then
  1787.         local remote = cloneref(...)
  1788.  
  1789.         if remote:IsA("RemoteEvent") or remote:IsA("RemoteFunction") or remote:IsA("UnreliableRemoteEvent") then
  1790.             if not configs.logcheckcaller and checkcaller() then return originalfunction(...) end
  1791.             local id = ThreadGetDebugId(remote)
  1792.             local blockcheck = tablecheck(blocklist,remote,id)
  1793.             local args = {select(2,...)}
  1794.  
  1795.             if not tablecheck(blacklist,remote,id) and not IsCyclicTable(args) then
  1796.                 local data = {
  1797.                     method = method,
  1798.                     remote = remote,
  1799.                     args = deepclone(args),
  1800.                     infofunc = infofunc,
  1801.                     callingscript = callingscript,
  1802.                     metamethod = "__index",
  1803.                     blockcheck = blockcheck,
  1804.                     id = id,
  1805.                     returnvalue = {}
  1806.                 }
  1807.                 args = nil
  1808.  
  1809.                 if configs.funcEnabled then
  1810.                     data.infofunc = info(2,"f")
  1811.                     local calling = getcallingscript()
  1812.                     data.callingscript = calling and cloneref(calling) or nil
  1813.                 end
  1814.  
  1815.                 schedule(remoteHandler,data)
  1816.  
  1817.                 --[[if configs.logreturnvalues and remote:IsA("RemoteFunction") then
  1818.                     local thread = running()
  1819.                     local returnargs = {...}
  1820.                     local returndata
  1821.  
  1822.                     spawn(function()
  1823.                         setnamecallmethod(method)
  1824.                         returndata = originalnamecall(unpack(returnargs))
  1825.                         data.returnvalue.data = returndata
  1826.                         if ThreadIsNotDead(thread) then
  1827.                             resume(thread)
  1828.                         end
  1829.                      end)
  1830.                     yield()
  1831.                     if not blockcheck then
  1832.                         return returndata
  1833.                     end
  1834.                 end]]
  1835.                 end
  1836.             if blockcheck then return end
  1837.         end
  1838.     end
  1839.     return originalfunction(...)
  1840. end
  1841.  
  1842. local newnamecall = newcclosure(function(...)
  1843.     local method = getnamecallmethod()
  1844.  
  1845.     if method and (method == "FireServer" or method == "fireServer" or method == "InvokeServer" or method == "invokeServer") then
  1846.         if typeof(...) == 'Instance' then
  1847.             local remote = cloneref(...)
  1848.  
  1849.             if IsA(remote,"RemoteEvent") or IsA(remote,"RemoteFunction") or IsA(remote,"UnreliableRemoteEvent") then    
  1850.                 if not configs.logcheckcaller and checkcaller() then return originalnamecall(...) end
  1851.                 local id = ThreadGetDebugId(remote)
  1852.                 local blockcheck = tablecheck(blocklist,remote,id)
  1853.                 local args = {select(2,...)}
  1854.  
  1855.                 if not tablecheck(blacklist,remote,id) and not IsCyclicTable(args) then
  1856.                     local data = {
  1857.                         method = method,
  1858.                         remote = remote,
  1859.                         args = deepclone(args),
  1860.                         infofunc = infofunc,
  1861.                         callingscript = callingscript,
  1862.                         metamethod = "__namecall",
  1863.                         blockcheck = blockcheck,
  1864.                         id = id,
  1865.                         returnvalue = {}
  1866.                     }
  1867.                     args = nil
  1868.  
  1869.                     if configs.funcEnabled then
  1870.                         data.infofunc = info(2,"f")
  1871.                         local calling = getcallingscript()
  1872.                         data.callingscript = calling and cloneref(calling) or nil
  1873.                     end
  1874.  
  1875.                     schedule(remoteHandler,data)
  1876.                    
  1877.                     --[[if configs.logreturnvalues and remote.IsA(remote,"RemoteFunction") then
  1878.                         local thread = running()
  1879.                         local returnargs = {...}
  1880.                         local returndata
  1881.  
  1882.                         spawn(function()
  1883.                             setnamecallmethod(method)
  1884.                             returndata = originalnamecall(unpack(returnargs))
  1885.                             data.returnvalue.data = returndata
  1886.                             if ThreadIsNotDead(thread) then
  1887.                                 resume(thread)
  1888.                             end
  1889.                         end)
  1890.                         yield()
  1891.                         if not blockcheck then
  1892.                             return returndata
  1893.                         end
  1894.                     end]]
  1895.                 end
  1896.                 if blockcheck then return end
  1897.             end
  1898.         end
  1899.     end
  1900.     return originalnamecall(...)
  1901. end)
  1902.  
  1903. local newFireServer = newcclosure(function(...)
  1904.     return newindex("FireServer",originalEvent,...)
  1905. end)
  1906.  
  1907. local newUnreliableFireServer = newcclosure(function(...)
  1908.     return newindex("FireServer",originalUnreliableEvent,...)
  1909. end)
  1910.  
  1911. local newInvokeServer = newcclosure(function(...)
  1912.     return newindex("InvokeServer",originalFunction,...)
  1913. end)
  1914.  
  1915. local function disablehooks()
  1916.     if synv3 then
  1917.         unhook(getrawmetatable(game).__namecall,originalnamecall)
  1918.         unhook(Instance.new("RemoteEvent").FireServer, originalEvent)
  1919.         unhook(Instance.new("RemoteFunction").InvokeServer, originalFunction)
  1920.         unhook(Instance.new("UnreliableRemoteEvent").FireServer, originalUnreliableEvent)
  1921.         restorefunction(originalnamecall)
  1922.         restorefunction(originalEvent)
  1923.         restorefunction(originalFunction)
  1924.     else
  1925.         if hookmetamethod then
  1926.             hookmetamethod(game,"__namecall",originalnamecall)
  1927.         else
  1928.             hookfunction(getrawmetatable(game).__namecall,originalnamecall)
  1929.         end
  1930.         hookfunction(Instance.new("RemoteEvent").FireServer, originalEvent)
  1931.         hookfunction(Instance.new("RemoteFunction").InvokeServer, originalFunction)
  1932.         hookfunction(Instance.new("UnreliableRemoteEvent").FireServer, originalUnreliableEvent)
  1933.     end
  1934. end
  1935.  
  1936. --- Toggles on and off the remote spy
  1937. function toggleSpy()
  1938.     if not toggle then
  1939.         local oldnamecall
  1940.         if synv3 then
  1941.             oldnamecall = hook(getrawmetatable(game).__namecall,clonefunction(newnamecall))
  1942.             originalEvent = hook(Instance.new("RemoteEvent").FireServer, clonefunction(newFireServer))
  1943.             originalFunction = hook(Instance.new("RemoteFunction").InvokeServer, clonefunction(newInvokeServer))
  1944.             originalUnreliableEvent = hook(Instance.new("UnreliableRemoteEvent").FireServer, clonefunction(newUnreliableFireServer))
  1945.         else
  1946.             if hookmetamethod then
  1947.                 oldnamecall = hookmetamethod(game, "__namecall", clonefunction(newnamecall))
  1948.             else
  1949.                 oldnamecall = hookfunction(getrawmetatable(game).__namecall,clonefunction(newnamecall))
  1950.             end
  1951.             originalEvent = hookfunction(Instance.new("RemoteEvent").FireServer, clonefunction(newFireServer))
  1952.             originalFunction = hookfunction(Instance.new("RemoteFunction").InvokeServer, clonefunction(newInvokeServer))
  1953.             originalUnreliableEvent = hookfunction(Instance.new("UnreliableRemoteEvent").FireServer, clonefunction(newUnreliableFireServer))
  1954.         end
  1955.         originalnamecall = originalnamecall or function(...)
  1956.             return oldnamecall(...)
  1957.         end
  1958.     else
  1959.         disablehooks()
  1960.     end
  1961. end
  1962.  
  1963. --- Toggles between the two remotespy methods (hookfunction currently = disabled)
  1964. function toggleSpyMethod()
  1965.     toggleSpy()
  1966.     toggle = not toggle
  1967. end
  1968.  
  1969. --- Shuts down the remote spy
  1970. local function shutdown()
  1971.     if schedulerconnect then
  1972.         schedulerconnect:Disconnect()
  1973.     end
  1974.     for _, connection in next, connections do
  1975.         connection:Disconnect()
  1976.     end
  1977.     for i,v in next, running_threads do
  1978.         if ThreadIsNotDead(v) then
  1979.             close(v)
  1980.         end
  1981.     end
  1982.     clear(running_threads)
  1983.     clear(connections)
  1984.     clear(logs)
  1985.     clear(remoteLogs)
  1986.     disablehooks()
  1987.     SimpleSpy3:Destroy()
  1988.     Storage:Destroy()
  1989.     UserInputService.MouseIconEnabled = true
  1990.     getgenv().SimpleSpyExecuted = false
  1991. end
  1992.  
  1993. -- main
  1994. if not getgenv().SimpleSpyExecuted then
  1995.     local succeeded,err = pcall(function()
  1996.         if not RunService:IsClient() then
  1997.             error("SimpleSpy cannot run on the server!")
  1998.         end
  1999.         getgenv().SimpleSpyShutdown = shutdown
  2000.         onToggleButtonClick()
  2001.         if not hookmetamethod then
  2002.             ErrorPrompt("Simple Spy V3 will not function to it's fullest capablity due to your executor not supporting hookmetamethod.",true)
  2003.         end
  2004.         codebox = Highlight.new(CodeBox)
  2005.         logthread(spawn(function()
  2006.             local suc,err = pcall(game.HttpGet,game,"https://raw.githubusercontent.com/78n/SimpleSpy/main/UpdateLog.lua")
  2007.             codebox:setRaw((suc and err) or "")
  2008.         end))
  2009.         getgenv().SimpleSpy = SimpleSpy
  2010.         getgenv().getNil = function(name,class)
  2011.             for _,v in next, getnilinstances() do
  2012.                 if v.ClassName == class and v.Name == name then
  2013.                     return v;
  2014.                 end
  2015.             end
  2016.         end
  2017.         Background.MouseEnter:Connect(function(...)
  2018.             mouseInGui = true
  2019.             mouseEntered()
  2020.         end)
  2021.         Background.MouseLeave:Connect(function(...)
  2022.             mouseInGui = false
  2023.             mouseEntered()
  2024.         end)
  2025.         TextLabel:GetPropertyChangedSignal("Text"):Connect(scaleToolTip)
  2026.         -- TopBar.InputBegan:Connect(onBarInput)
  2027.         MinimizeButton.MouseButton1Click:Connect(toggleMinimize)
  2028.         MaximizeButton.MouseButton1Click:Connect(toggleSideTray)
  2029.         Simple.MouseButton1Click:Connect(onToggleButtonClick)
  2030.         CloseButton.MouseEnter:Connect(onXButtonHover)
  2031.         CloseButton.MouseLeave:Connect(onXButtonUnhover)
  2032.         Simple.MouseEnter:Connect(onToggleButtonHover)
  2033.         Simple.MouseLeave:Connect(onToggleButtonUnhover)
  2034.         CloseButton.MouseButton1Click:Connect(shutdown)
  2035.         table.insert(connections, UserInputService.InputBegan:Connect(backgroundUserInput))
  2036.         connectResize()
  2037.         SimpleSpy3.Enabled = true
  2038.         logthread(spawn(function()
  2039.             delay(1,onToggleButtonUnhover)
  2040.         end))
  2041.         schedulerconnect = RunService.Heartbeat:Connect(taskscheduler)
  2042.         bringBackOnResize()
  2043.         SimpleSpy3.Parent = (gethui and gethui()) or (syn and syn.protect_gui and syn.protect_gui(SimpleSpy3)) or CoreGui
  2044.         logthread(spawn(function()
  2045.             local lp = Players.LocalPlayer or Players:GetPropertyChangedSignal("LocalPlayer"):Wait() or Players.LocalPlayer
  2046.             generation = {
  2047.                 [OldDebugId(lp)] = 'game:GetService("Players").LocalPlayer',
  2048.                 [OldDebugId(lp:GetMouse())] = 'game:GetService("Players").LocalPlayer:GetMouse',
  2049.                 [OldDebugId(game)] = "game",
  2050.                 [OldDebugId(workspace)] = "workspace"
  2051.             }
  2052.         end))
  2053.     end)
  2054.     if succeeded then
  2055.         getgenv().SimpleSpyExecuted = true
  2056.     else
  2057.         shutdown()
  2058.         ErrorPrompt("An error has occured:\n"..rawtostring(err))
  2059.         return
  2060.     end
  2061. else
  2062.     SimpleSpy3:Destroy()
  2063.     return
  2064. end
  2065.  
  2066. function SimpleSpy:newButton(name, description, onClick)
  2067.     return newButton(name, description, onClick)
  2068. end
  2069.  
  2070. ----- ADD ONS ----- (easily add or remove additonal functionality to the RemoteSpy!)
  2071. --[[
  2072.     Some helpful things:
  2073.         - add your function in here, and create buttons for them through the 'newButton' function
  2074.         - the first argument provided is the TextButton the player clicks to run the function
  2075.         - generated scripts are generated when the namecall is initially fired and saved in remoteFrame objects
  2076.         - blacklisted remotes will be ignored directly in namecall (less lag)
  2077.         - the properties of a 'remoteFrame' object:
  2078.             {
  2079.                 Name: (string) The name of the Remote
  2080.                 GenScript: (string) The generated script that appears in the codebox (generated when namecall fired)
  2081.                 Source: (Instance (LocalScript)) The script that fired/invoked the remote
  2082.                 Remote: (Instance (RemoteEvent) | Instance (RemoteFunction)) The remote that was fired/invoked
  2083.                 Log: (Instance (TextButton)) The button being used for the remote (same as 'selected.Log')
  2084.             }
  2085.         - globals list: (contact @exx#9394 for more information or if you have suggestions for more to be added)
  2086.             - closed: (boolean) whether or not the GUI is currently minimized
  2087.             - logs: (table[remoteFrame]) full of remoteFrame objects (properties listed above)
  2088.             - selected: (remoteFrame) the currently selected remoteFrame (properties listed above)
  2089.             - blacklist: (string[] | Instance[] (RemoteEvent) | Instance[] (RemoteFunction)) an array of blacklisted names and remotes
  2090.             - codebox: (Instance (TextBox)) the textbox that holds all the code- cleared often
  2091. ]]
  2092. -- Copies the contents of the codebox
  2093. newButton(
  2094.     "Copy Code",
  2095.     function() return "Click to copy code" end,
  2096.     function()
  2097.         setclipboard(codebox:getString())
  2098.         TextLabel.Text = "Copied successfully!"
  2099.     end
  2100. )
  2101.  
  2102. --- Copies the source script (that fired the remote)
  2103. newButton(
  2104.     "Copy Remote",
  2105.     function() return "Click to copy the path of the remote" end,
  2106.     function()
  2107.         if selected and selected.Remote then
  2108.             setclipboard(v2s(selected.Remote))
  2109.             TextLabel.Text = "Copied!"
  2110.         end
  2111.     end
  2112. )
  2113.  
  2114. -- Executes the contents of the codebox through loadstring
  2115. newButton("Run Code",
  2116.     function() return "Click to execute code" end,
  2117.     function()
  2118.         local Remote = selected and selected.Remote
  2119.         if Remote then
  2120.             TextLabel.Text = "Executing..."
  2121.             xpcall(function()
  2122.                 local returnvalue
  2123.                 if Remote:IsA("RemoteEvent") or Remote:IsA("UnreliableRemoteEvent") then
  2124.                     returnvalue = Remote:FireServer(unpack(selected.args))
  2125.                 elseif Remote:IsA("RemoteFunction") then
  2126.                     returnvalue = Remote:InvokeServer(unpack(selected.args))
  2127.                 end
  2128.  
  2129.                 TextLabel.Text = ("Executed successfully!\n%s"):format(v2s(returnvalue))
  2130.             end,function(err)
  2131.                 TextLabel.Text = ("Execution error!\n%s"):format(err)
  2132.             end)
  2133.             return
  2134.         end
  2135.         TextLabel.Text = "Source not found"
  2136.     end
  2137. )
  2138.  
  2139. --- Gets the calling script (not super reliable but w/e)
  2140. newButton(
  2141.     "Get Script",
  2142.     function() return "Click to copy calling script to clipboard\nWARNING: Not super reliable, nil == could not find" end,
  2143.     function()
  2144.         if selected then
  2145.             if not selected.Source then
  2146.                 selected.Source = rawget(getfenv(selected.Function),"script")
  2147.             end
  2148.             setclipboard(v2s(selected.Source))
  2149.             TextLabel.Text = "Done!"
  2150.         end
  2151.     end
  2152. )
  2153.  
  2154. --- Decompiles the script that fired the remote and puts it in the code box
  2155. newButton("Function Info",function() return "Click to view calling function information" end,
  2156. function()
  2157.     local func = selected and selected.Function
  2158.     if func then
  2159.         local typeoffunc = typeof(func)
  2160.  
  2161.         if typeoffunc ~= 'string' then
  2162.             codebox:setRaw("--[[Generating Function Info please wait]]")
  2163.             RunService.Heartbeat:Wait()
  2164.             local lclosure = islclosure(func)
  2165.             local SourceScript = rawget(getfenv(func),"script")
  2166.             local CallingScript = selected.Source or nil
  2167.             local info = {}
  2168.            
  2169.             info = {
  2170.                 info = getinfo(func),
  2171.                 constants = lclosure and deepclone(getconstants(func)) or "N/A --Lua Closure expected got C Closure",
  2172.                 upvalues = deepclone(getupvalues(func)),
  2173.                 script = {
  2174.                     SourceScript = SourceScript or 'nil',
  2175.                     CallingScript = CallingScript or 'nil'
  2176.                 }
  2177.             }
  2178.                    
  2179.             if configs.advancedinfo then
  2180.                 local Remote = selected.Remote
  2181.  
  2182.                 info["advancedinfo"] = {
  2183.                     Metamethod = selected.metamethod,
  2184.                     DebugId = {
  2185.                         SourceScriptDebugId = SourceScript and typeof(SourceScript) == "Instance" and OldDebugId(SourceScript) or "N/A",
  2186.                         CallingScriptDebugId = CallingScript and typeof(SourceScript) == "Instance" and OldDebugId(CallingScript) or "N/A",
  2187.                         RemoteDebugId = OldDebugId(Remote)
  2188.                     },
  2189.                     Protos = lclosure and getprotos(func) or "N/A --Lua Closure expected got C Closure"
  2190.                 }
  2191.  
  2192.                 if Remote:IsA("RemoteFunction") then
  2193.                     info["advancedinfo"]["OnClientInvoke"] = getcallbackmember and (getcallbackmember(Remote,"OnClientInvoke") or "N/A") or "N/A --Missing function getcallbackmember"
  2194.                 elseif getconnections then
  2195.                     info["advancedinfo"]["OnClientEvents"] = {}
  2196.  
  2197.                     for i,v in next, getconnections(Remote.OnClientEvent) do
  2198.                         info["advancedinfo"]["OnClientEvents"][i] = {
  2199.                             Function = v.Function or "N/A",
  2200.                             State = v.State or "N/A"
  2201.                         }
  2202.                     end
  2203.                 end
  2204.             end
  2205.             codebox:setRaw("--[[Converting table to string please wait]]")
  2206.             selected.Function = v2v({functionInfo = info})
  2207.         end
  2208.         codebox:setRaw("-- Calling function info\n-- Generated by the SimpleSpy V3 serializer\n\n"..selected.Function)
  2209.         TextLabel.Text = "Done! Function info generated by the SimpleSpy V3 Serializer."
  2210.     else
  2211.         TextLabel.Text = "Error! Selected function was not found."
  2212.     end
  2213. end)
  2214.  
  2215. --- Clears the Remote logs
  2216. newButton(
  2217.     "Clr Logs",
  2218.     function() return "Click to clear logs" end,
  2219.     function()
  2220.         TextLabel.Text = "Clearing..."
  2221.         clear(logs)
  2222.         for i,v in next, LogList:GetChildren() do
  2223.             if not v:IsA("UIListLayout") then
  2224.                 v:Destroy()
  2225.             end
  2226.         end
  2227.         codebox:setRaw("")
  2228.         selected = nil
  2229.         TextLabel.Text = "Logs cleared!"
  2230.     end
  2231. )
  2232.  
  2233. --- Excludes the selected.Log Remote from the RemoteSpy
  2234. newButton(
  2235.     "Exclude (i)",
  2236.     function() return "Click to exclude this Remote.\nExcluding a remote makes SimpleSpy ignore it, but it will continue to be usable." end,
  2237.     function()
  2238.         if selected then
  2239.             blacklist[OldDebugId(selected.Remote)] = true
  2240.             TextLabel.Text = "Excluded!"
  2241.         end
  2242.     end
  2243. )
  2244.  
  2245. --- Excludes all Remotes that share the same name as the selected.Log remote from the RemoteSpy
  2246. newButton(
  2247.     "Exclude (n)",
  2248.     function() return "Click to exclude all remotes with this name.\nExcluding a remote makes SimpleSpy ignore it, but it will continue to be usable." end,
  2249.     function()
  2250.         if selected then
  2251.             blacklist[selected.Name] = true
  2252.             TextLabel.Text = "Excluded!"
  2253.         end
  2254.     end
  2255. )
  2256.  
  2257. --- clears blacklist
  2258. newButton("Clr Blacklist",
  2259. function() return "Click to clear the blacklist.\nExcluding a remote makes SimpleSpy ignore it, but it will continue to be usable." end,
  2260. function()
  2261.     blacklist = {}
  2262.     TextLabel.Text = "Blacklist cleared!"
  2263. end)
  2264.  
  2265. --- Prevents the selected.Log Remote from firing the server (still logged)
  2266. newButton(
  2267.     "Block (i)",
  2268.     function() return "Click to stop this remote from firing.\nBlocking a remote won't remove it from SimpleSpy logs, but it will not continue to fire the server." end,
  2269.     function()
  2270.         if selected then
  2271.             blocklist[OldDebugId(selected.Remote)] = true
  2272.             TextLabel.Text = "Excluded!"
  2273.         end
  2274.     end
  2275. )
  2276.  
  2277. --- Prevents all remotes from firing that share the same name as the selected.Log remote from the RemoteSpy (still logged)
  2278. newButton("Block (n)",function()
  2279.     return "Click to stop remotes with this name from firing.\nBlocking a remote won't remove it from SimpleSpy logs, but it will not continue to fire the server." end,
  2280.     function()
  2281.         if selected then
  2282.             blocklist[selected.Name] = true
  2283.             TextLabel.Text = "Excluded!"
  2284.         end
  2285.     end
  2286. )
  2287.  
  2288. --- clears blacklist
  2289. newButton(
  2290.     "Clr Blocklist",
  2291.     function() return "Click to stop blocking remotes.\nBlocking a remote won't remove it from SimpleSpy logs, but it will not continue to fire the server." end,
  2292.     function()
  2293.         blocklist = {}
  2294.         TextLabel.Text = "Blocklist cleared!"
  2295.     end
  2296. )
  2297.  
  2298. --- Attempts to decompile the source script
  2299. newButton("Decompile",
  2300.     function()
  2301.         return "Decompile source script"
  2302.     end,function()
  2303.         if decompile then
  2304.             if selected and selected.Source then
  2305.                 local Source = selected.Source
  2306.                 if not DecompiledScripts[Source] then
  2307.                     codebox:setRaw("--[[Decompiling]]")
  2308.  
  2309.                     xpcall(function()
  2310.                         local decompiledsource = decompile(Source):gsub("-- Decompiled with the Synapse X Luau decompiler.","")
  2311.                         local Sourcev2s = v2s(Source)
  2312.                         if (decompiledsource):find("script") and Sourcev2s then
  2313.                             DecompiledScripts[Source] = ("local script = %s\n%s"):format(Sourcev2s,decompiledsource)
  2314.                         end
  2315.                     end,function(err)
  2316.                         return codebox:setRaw(("--[[\nAn error has occured\n%s\n]]"):format(err))
  2317.                     end)
  2318.                 end
  2319.                 codebox:setRaw(DecompiledScripts[Source] or "--No Source Found")
  2320.                 TextLabel.Text = "Done!"
  2321.             else
  2322.                 TextLabel.Text = "Source not found!"
  2323.             end
  2324.         else
  2325.             TextLabel.Text = "Missing function (decompile)"
  2326.         end
  2327.     end
  2328. )
  2329.  
  2330.     --[[newButton(
  2331.         "returnvalue",
  2332.         function() return "Get a Remote's return data" end,
  2333.         function()
  2334.             if selected then
  2335.                 local Remote = selected.Remote
  2336.                 if Remote and Remote:IsA("RemoteFunction") then
  2337.                     if selected.returnvalue and selected.returnvalue.data then
  2338.                         return codebox:setRaw(v2s(selected.returnvalue.data))
  2339.                     end
  2340.                     return codebox:setRaw("No data was returned")
  2341.                 else
  2342.                     codebox:setRaw("RemoteFunction expected got "..(Remote and Remote.ClassName))
  2343.                 end
  2344.             end
  2345.         end
  2346.     )]]
  2347.  
  2348. newButton(
  2349.     "Disable Info",
  2350.     function() return string.format("[%s] Toggle function info (because it can cause lag in some games)", configs.funcEnabled and "ENABLED" or "DISABLED") end,
  2351.     function()
  2352.         configs.funcEnabled = not configs.funcEnabled
  2353.         TextLabel.Text = string.format("[%s] Toggle function info (because it can cause lag in some games)", configs.funcEnabled and "ENABLED" or "DISABLED")
  2354.     end
  2355. )
  2356.  
  2357. newButton(
  2358.     "Autoblock",
  2359.     function() return string.format("[%s] [BETA] Intelligently detects and excludes spammy remote calls from logs", configs.autoblock and "ENABLED" or "DISABLED") end,
  2360.     function()
  2361.         configs.autoblock = not configs.autoblock
  2362.         TextLabel.Text = string.format("[%s] [BETA] Intelligently detects and excludes spammy remote calls from logs", configs.autoblock and "ENABLED" or "DISABLED")
  2363.         history = {}
  2364.         excluding = {}
  2365.     end
  2366. )
  2367.  
  2368. newButton("Logcheckcaller",function()
  2369.     return ("[%s] Log remotes fired by the client"):format(configs.logcheckcaller and "ENABLED" or "DISABLED")
  2370. end,
  2371. function()
  2372.     configs.logcheckcaller = not configs.logcheckcaller
  2373.     TextLabel.Text = ("[%s] Log remotes fired by the client"):format(configs.logcheckcaller and "ENABLED" or "DISABLED")
  2374. end)
  2375.  
  2376. --[[newButton("Log returnvalues",function()
  2377.     return ("[BETA] [%s] Log RemoteFunction's return values"):format(configs.logcheckcaller and "ENABLED" or "DISABLED")
  2378. end,
  2379. function()
  2380.     configs.logreturnvalues = not configs.logreturnvalues
  2381.     TextLabel.Text = ("[BETA] [%s] Log RemoteFunction's return values"):format(configs.logreturnvalues and "ENABLED" or "DISABLED")
  2382. end)]]
  2383.  
  2384. newButton("Advanced Info",function()
  2385.     return ("[%s] Display more remoteinfo"):format(configs.advancedinfo and "ENABLED" or "DISABLED")
  2386. end,
  2387. function()
  2388.     configs.advancedinfo = not configs.advancedinfo
  2389.     TextLabel.Text = ("[%s] Display more remoteinfo"):format(configs.advancedinfo and "ENABLED" or "DISABLED")
  2390. end)
  2391.  
  2392. newButton("Join Discord",function()
  2393.     return "Joins The Simple Spy Discord"
  2394. end,
  2395. function()
  2396.     setclipboard("https://discord.com/invite/AWS6ez9")
  2397.     TextLabel.Text = "Copied invite to your clipboard"
  2398.     if request then
  2399.         request({Url = 'http://127.0.0.1:6463/rpc?v=1',Method = 'POST',Headers = {['Content-Type'] = 'application/json', Origin = 'https://discord.com'},Body = http:JSONEncode({cmd = 'INVITE_BROWSER',nonce = http:GenerateGUID(false),args = {code = 'AWS6ez9'}})})
  2400.     end
  2401. end)
  2402.  
  2403. if configs.supersecretdevtoggle then
  2404.     newButton("Load SSV2.2",function()
  2405.         return "Load's Simple Spy V2.2"
  2406.     end,
  2407.     function()
  2408.         loadstring(game:HttpGet("https://raw.githubusercontent.com/exxtremestuffs/SimpleSpySource/master/SimpleSpy.lua"))()
  2409.     end)
  2410.     newButton("Load SSV3",function()
  2411.         return "Load's Simple Spy V3"
  2412.     end,
  2413.     function()
  2414.         loadstring(game:HttpGet("https://raw.githubusercontent.com/78n/SimpleSpy/main/SimpleSpySource.lua"))()
  2415.     end)
  2416.     local SuperSecretFolder = Create("Folder",{Parent = SimpleSpy3})
  2417.     newButton("SUPER SECRET BUTTON",function()
  2418.         return "You dont need a discription you already know what it does"
  2419.     end,
  2420.     function()
  2421.         SuperSecretFolder:ClearAllChildren()
  2422.         local random = listfiles("Music")
  2423.         local NotSound = Create("Sound",{Parent = SuperSecretFolder,Looped = false,Volume = math.random(1,5),SoundId = getsynasset(random[math.random(1,#random)])})
  2424.         NotSound:Play()
  2425.     end)
  2426. end
Add Comment
Please, Sign In to add comment