Facebook
From A, 1 Month ago, written in Plain Text.
Embed
Download Paste or View Raw
Hits: 159
  1. -[[
  2.     SimpleSpy v2.2 SOURCE
  3.  
  4.     Credits:
  5.         exx - basically everything
  6.         Frosty - GUI to Lua
  7. ]]
  8.  
  9. -- shuts down the previous instance of SimpleSpy
  10. if _G.SimpleSpyExecuted and type(_G.SimpleSpyShutdown) == "function" then
  11.     _G.SimpleSpyShutdown()
  12. end
  13.  
  14. local Players = game:GetService("Players")
  15. local CoreGui = game:GetService("CoreGui")
  16. local Highlight = loadstring(game:HttpGet("https://github.com/exxtremestuffs/SimpleSpySource/raw/master/highlight.lua"))()
  17.  
  18. ---- GENERATED (kinda sorta mostly) BY GUI to LUA ----
  19.  
  20. -- Instances:
  21.  
  22. local SimpleSpy2 = Instance.new("ScreenGui")
  23. local Background = Instance.new("Frame")
  24. local LeftPanel = Instance.new("Frame")
  25. local LogList = Instance.new("ScrollingFrame")
  26. local UIListLayout = Instance.new("UIListLayout")
  27. local RemoteTemplate = Instance.new("Frame")
  28. local ColorBar = Instance.new("Frame")
  29. local Text = Instance.new("TextLabel")
  30. local Button = Instance.new("TextButton")
  31. local RightPanel = Instance.new("Frame")
  32. local CodeBox = Instance.new("Frame")
  33. local ScrollingFrame = Instance.new("ScrollingFrame")
  34. local UIGridLayout = Instance.new("UIGridLayout")
  35. local FunctionTemplate = Instance.new("Frame")
  36. local ColorBar_2 = Instance.new("Frame")
  37. local Text_2 = Instance.new("TextLabel")
  38. local Button_2 = Instance.new("TextButton")
  39. local TopBar = Instance.new("Frame")
  40. local Simple = Instance.new("TextButton")
  41. local CloseButton = Instance.new("TextButton")
  42. local ImageLabel = Instance.new("ImageLabel")
  43. local MaximizeButton = Instance.new("TextButton")
  44. local ImageLabel_2 = Instance.new("ImageLabel")
  45. local MinimizeButton = Instance.new("TextButton")
  46. local ImageLabel_3 = Instance.new("ImageLabel")
  47. local ToolTip = Instance.new("Frame")
  48. local TextLabel = Instance.new("TextLabel")
  49.  
  50. --Properties:
  51.  
  52. SimpleSpy2.Name = "SimpleSpy2"
  53. SimpleSpy2.ResetOnSpawn = false
  54.  
  55. Background.Name = "Background"
  56. Background.Parent = SimpleSpy2
  57. Background.BackgroundColor3 = Color3.new(1, 1, 1)
  58. Background.BackgroundTransparency = 1
  59. Background.Position = UDim2.new(0, 500, 0, 200)
  60. Background.Size = UDim2.new(0, 450, 0, 268)
  61.  
  62. LeftPanel.Name = "LeftPanel"
  63. LeftPanel.Parent = Background
  64. LeftPanel.BackgroundColor3 = Color3.new(0.207843, 0.203922, 0.215686)
  65. LeftPanel.BorderSizePixel = 0
  66. LeftPanel.Position = UDim2.new(0, 0, 0, 19)
  67. LeftPanel.Size = UDim2.new(0, 131, 0, 249)
  68.  
  69. LogList.Name = "LogList"
  70. LogList.Parent = LeftPanel
  71. LogList.Active = true
  72. LogList.BackgroundColor3 = Color3.new(1, 1, 1)
  73. LogList.BackgroundTransparency = 1
  74. LogList.BorderSizePixel = 0
  75. LogList.Position = UDim2.new(0, 0, 0, 9)
  76. LogList.Size = UDim2.new(0, 131, 0, 232)
  77. LogList.CanvasSize = UDim2.new(0, 0, 0, 0)
  78. LogList.ScrollBarThickness = 4
  79.  
  80. UIListLayout.Parent = LogList
  81. UIListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
  82. UIListLayout.SortOrder = Enum.SortOrder.LayoutOrder
  83.  
  84. RemoteTemplate.Name = "RemoteTemplate"
  85. RemoteTemplate.Parent = LogList
  86. RemoteTemplate.BackgroundColor3 = Color3.new(1, 1, 1)
  87. RemoteTemplate.BackgroundTransparency = 1
  88. RemoteTemplate.Size = UDim2.new(0, 117, 0, 27)
  89.  
  90. ColorBar.Name = "ColorBar"
  91. ColorBar.Parent = RemoteTemplate
  92. ColorBar.BackgroundColor3 = Color3.new(1, 0.94902, 0)
  93. ColorBar.BorderSizePixel = 0
  94. ColorBar.Position = UDim2.new(0, 0, 0, 1)
  95. ColorBar.Size = UDim2.new(0, 7, 0, 18)
  96. ColorBar.ZIndex = 2
  97.  
  98. Text.Name = "Text"
  99. Text.Parent = RemoteTemplate
  100. Text.BackgroundColor3 = Color3.new(1, 1, 1)
  101. Text.BackgroundTransparency = 1
  102. Text.Position = UDim2.new(0, 12, 0, 1)
  103. Text.Size = UDim2.new(0, 105, 0, 18)
  104. Text.ZIndex = 2
  105. Text.Font = Enum.Font.SourceSans
  106. Text.Text = "TEXT"
  107. Text.TextColor3 = Color3.new(1, 1, 1)
  108. Text.TextSize = 14
  109. Text.TextXAlignment = Enum.TextXAlignment.Left
  110.  
  111. Button.Name = "Button"
  112. Button.Parent = RemoteTemplate
  113. Button.BackgroundColor3 = Color3.new(0, 0, 0)
  114. Button.BackgroundTransparency = 0.75
  115. Button.BorderColor3 = Color3.new(1, 1, 1)
  116. Button.Position = UDim2.new(0, 0, 0, 1)
  117. Button.Size = UDim2.new(0, 117, 0, 18)
  118. Button.AutoButtonColor = false
  119. Button.Font = Enum.Font.SourceSans
  120. Button.Text = ""
  121. Button.TextColor3 = Color3.new(0, 0, 0)
  122. Button.TextSize = 14
  123.  
  124. RightPanel.Name = "RightPanel"
  125. RightPanel.Parent = Background
  126. RightPanel.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
  127. RightPanel.BorderSizePixel = 0
  128. RightPanel.Position = UDim2.new(0, 131, 0, 19)
  129. RightPanel.Size = UDim2.new(0, 319, 0, 249)
  130.  
  131. CodeBox.Name = "CodeBox"
  132. CodeBox.Parent = RightPanel
  133. CodeBox.BackgroundColor3 = Color3.new(0.0823529, 0.0745098, 0.0784314)
  134. CodeBox.BorderSizePixel = 0
  135. CodeBox.Size = UDim2.new(0, 319, 0, 119)
  136.  
  137. ScrollingFrame.Parent = RightPanel
  138. ScrollingFrame.Active = true
  139. ScrollingFrame.BackgroundColor3 = Color3.new(1, 1, 1)
  140. ScrollingFrame.BackgroundTransparency = 1
  141. ScrollingFrame.Position = UDim2.new(0, 0, 0.5, 0)
  142. ScrollingFrame.Size = UDim2.new(1, 0, 0.5, -9)
  143. ScrollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0)
  144. ScrollingFrame.ScrollBarThickness = 4
  145.  
  146. UIGridLayout.Parent = ScrollingFrame
  147. UIGridLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
  148. UIGridLayout.SortOrder = Enum.SortOrder.LayoutOrder
  149. UIGridLayout.CellPadding = UDim2.new(0, 0, 0, 0)
  150. UIGridLayout.CellSize = UDim2.new(0, 94, 0, 27)
  151.  
  152. FunctionTemplate.Name = "FunctionTemplate"
  153. FunctionTemplate.Parent = ScrollingFrame
  154. FunctionTemplate.BackgroundColor3 = Color3.new(1, 1, 1)
  155. FunctionTemplate.BackgroundTransparency = 1
  156. FunctionTemplate.Size = UDim2.new(0, 117, 0, 23)
  157.  
  158. ColorBar_2.Name = "ColorBar"
  159. ColorBar_2.Parent = FunctionTemplate
  160. ColorBar_2.BackgroundColor3 = Color3.new(1, 1, 1)
  161. ColorBar_2.BorderSizePixel = 0
  162. ColorBar_2.Position = UDim2.new(0, 7, 0, 10)
  163. ColorBar_2.Size = UDim2.new(0, 7, 0, 18)
  164. ColorBar_2.ZIndex = 3
  165.  
  166. Text_2.Name = "Text"
  167. Text_2.Parent = FunctionTemplate
  168. Text_2.BackgroundColor3 = Color3.new(1, 1, 1)
  169. Text_2.BackgroundTransparency = 1
  170. Text_2.Position = UDim2.new(0, 19, 0, 10)
  171. Text_2.Size = UDim2.new(0, 69, 0, 18)
  172. Text_2.ZIndex = 2
  173. Text_2.Font = Enum.Font.SourceSans
  174. Text_2.Text = "TEXT"
  175. Text_2.TextColor3 = Color3.new(1, 1, 1)
  176. Text_2.TextSize = 14
  177. Text_2.TextStrokeColor3 = Color3.new(0.145098, 0.141176, 0.14902)
  178. Text_2.TextXAlignment = Enum.TextXAlignment.Left
  179.  
  180. Button_2.Name = "Button"
  181. Button_2.Parent = FunctionTemplate
  182. Button_2.BackgroundColor3 = Color3.new(0, 0, 0)
  183. Button_2.BackgroundTransparency = 0.69999998807907
  184. Button_2.BorderColor3 = Color3.new(1, 1, 1)
  185. Button_2.Position = UDim2.new(0, 7, 0, 10)
  186. Button_2.Size = UDim2.new(0, 80, 0, 18)
  187. Button_2.AutoButtonColor = false
  188. Button_2.Font = Enum.Font.SourceSans
  189. Button_2.Text = ""
  190. Button_2.TextColor3 = Color3.new(0, 0, 0)
  191. Button_2.TextSize = 14
  192.  
  193. TopBar.Name = "TopBar"
  194. TopBar.Parent = Background
  195. TopBar.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
  196. TopBar.BorderSizePixel = 0
  197. TopBar.Size = UDim2.new(0, 450, 0, 19)
  198.  
  199. Simple.Name = "Simple"
  200. Simple.Parent = TopBar
  201. Simple.BackgroundColor3 = Color3.new(1, 1, 1)
  202. Simple.AutoButtonColor = false
  203. Simple.BackgroundTransparency = 1
  204. Simple.Position = UDim2.new(0, 5, 0, 0)
  205. Simple.Size = UDim2.new(0, 57, 0, 18)
  206. Simple.Font = Enum.Font.SourceSansBold
  207. Simple.Text = "SimpleSpy"
  208. Simple.TextColor3 = Color3.new(1, 1, 1)
  209. Simple.TextSize = 14
  210. Simple.TextXAlignment = Enum.TextXAlignment.Left
  211.  
  212. CloseButton.Name = "CloseButton"
  213. CloseButton.Parent = TopBar
  214. CloseButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
  215. CloseButton.BorderSizePixel = 0
  216. CloseButton.Position = UDim2.new(1, -19, 0, 0)
  217. CloseButton.Size = UDim2.new(0, 19, 0, 19)
  218. CloseButton.Font = Enum.Font.SourceSans
  219. CloseButton.Text = ""
  220. CloseButton.TextColor3 = Color3.new(0, 0, 0)
  221. CloseButton.TextSize = 14
  222.  
  223. ImageLabel.Parent = CloseButton
  224. ImageLabel.BackgroundColor3 = Color3.new(1, 1, 1)
  225. ImageLabel.BackgroundTransparency = 1
  226. ImageLabel.Position = UDim2.new(0, 5, 0, 5)
  227. ImageLabel.Size = UDim2.new(0, 9, 0, 9)
  228. ImageLabel.Image = "http://www.roblox.com/asset/?id=5597086202"
  229.  
  230. MaximizeButton.Name = "MaximizeButton"
  231. MaximizeButton.Parent = TopBar
  232. MaximizeButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
  233. MaximizeButton.BorderSizePixel = 0
  234. MaximizeButton.Position = UDim2.new(1, -38, 0, 0)
  235. MaximizeButton.Size = UDim2.new(0, 19, 0, 19)
  236. MaximizeButton.Font = Enum.Font.SourceSans
  237. MaximizeButton.Text = ""
  238. MaximizeButton.TextColor3 = Color3.new(0, 0, 0)
  239. MaximizeButton.TextSize = 14
  240.  
  241. ImageLabel_2.Parent = MaximizeButton
  242. ImageLabel_2.BackgroundColor3 = Color3.new(1, 1, 1)
  243. ImageLabel_2.BackgroundTransparency = 1
  244. ImageLabel_2.Position = UDim2.new(0, 5, 0, 5)
  245. ImageLabel_2.Size = UDim2.new(0, 9, 0, 9)
  246. ImageLabel_2.Image = "http://www.roblox.com/asset/?id=5597108117"
  247.  
  248. MinimizeButton.Name = "MinimizeButton"
  249. MinimizeButton.Parent = TopBar
  250. MinimizeButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
  251. MinimizeButton.BorderSizePixel = 0
  252. MinimizeButton.Position = UDim2.new(1, -57, 0, 0)
  253. MinimizeButton.Size = UDim2.new(0, 19, 0, 19)
  254. MinimizeButton.Font = Enum.Font.SourceSans
  255. MinimizeButton.Text = ""
  256. MinimizeButton.TextColor3 = Color3.new(0, 0, 0)
  257. MinimizeButton.TextSize = 14
  258.  
  259. ImageLabel_3.Parent = MinimizeButton
  260. ImageLabel_3.BackgroundColor3 = Color3.new(1, 1, 1)
  261. ImageLabel_3.BackgroundTransparency = 1
  262. ImageLabel_3.Position = UDim2.new(0, 5, 0, 5)
  263. ImageLabel_3.Size = UDim2.new(0, 9, 0, 9)
  264. ImageLabel_3.Image = "http://www.roblox.com/asset/?id=5597105827"
  265.  
  266. ToolTip.Name = "ToolTip"
  267. ToolTip.Parent = SimpleSpy2
  268. ToolTip.BackgroundColor3 = Color3.fromRGB(26, 26, 26)
  269. ToolTip.BackgroundTransparency = 0.1
  270. ToolTip.BorderColor3 = Color3.new(1, 1, 1)
  271. ToolTip.Size = UDim2.new(0, 200, 0, 50)
  272. ToolTip.ZIndex = 3
  273. ToolTip.Visible = false
  274.  
  275. TextLabel.Parent = ToolTip
  276. TextLabel.BackgroundColor3 = Color3.new(1, 1, 1)
  277. TextLabel.BackgroundTransparency = 1
  278. TextLabel.Position = UDim2.new(0, 2, 0, 2)
  279. TextLabel.Size = UDim2.new(0, 196, 0, 46)
  280. TextLabel.ZIndex = 3
  281. TextLabel.Font = Enum.Font.SourceSans
  282. TextLabel.Text = "This is some slightly longer text."
  283. TextLabel.TextColor3 = Color3.new(1, 1, 1)
  284. TextLabel.TextSize = 14
  285. TextLabel.TextWrapped = true
  286. TextLabel.TextXAlignment = Enum.TextXAlignment.Left
  287. TextLabel.TextYAlignment = Enum.TextYAlignment.Top
  288.  
  289. -------------------------------------------------------------------------------
  290. -- init
  291. local RunService = game:GetService("RunService")
  292. local UserInputService = game:GetService("UserInputService")
  293. local TweenService = game:GetService("TweenService")
  294. local ContentProvider = game:GetService("ContentProvider")
  295. local TextService = game:GetService("TextService")
  296. local Mouse = game:GetService("Players").LocalPlayer:GetMouse()
  297.  
  298. local selectedColor = Color3.new(0.321569, 0.333333, 1)
  299. local deselectedColor = Color3.new(0.8, 0.8, 0.8)
  300. --- So things are descending
  301. local layoutOrderNum = 999999999
  302. --- Whether or not the gui is closing
  303. local mainClosing = false
  304. --- Whether or not the gui is closed (defaults to false)
  305. local closed = false
  306. --- Whether or not the sidebar is closing
  307. local sideClosing = false
  308. --- Whether or not the sidebar is closed (defaults to true but opens automatically on remote selection)
  309. local sideClosed = false
  310. --- Whether or not the code box is maximized (defaults to false)
  311. local maximized = false
  312. --- The event logs to be read from
  313. local logs = {}
  314. --- The event currently selected.Log (defaults to nil)
  315. local selected = nil
  316. --- The blacklist (can be a string name or the Remote Instance)
  317. local blacklist = {}
  318. --- The block list (can be a string name or the Remote Instance)
  319. local blocklist = {}
  320. --- Whether or not to add getNil function
  321. local getNil = false
  322. --- Array of remotes (and original functions) connected to
  323. local connectedRemotes = {}
  324. --- True = hookfunction, false = namecall
  325. local toggle = false
  326. local gm = getrawmetatable(game)
  327. local original = gm.__namecall
  328. setreadonly(gm, false)
  329. --- used to prevent recursives
  330. local prevTables = {}
  331. --- holds logs (for deletion)
  332. local remoteLogs = {}
  333. --- used for hookfunction
  334. local remoteEvent = Instance.new("RemoteEvent")
  335. --- used for hookfunction
  336. local remoteFunction = Instance.new("RemoteFunction")
  337. local originalEvent = remoteEvent.FireServer
  338. local originalFunction = remoteFunction.InvokeServer
  339. --- the maximum amount of remotes allowed in logs
  340. _G.SIMPLESPYCONFIG_MaxRemotes = 500
  341. --- how many spaces to indent
  342. local indent = 4
  343. --- used for task scheduler
  344. local scheduled = {}
  345. --- RBXScriptConnect of the task scheduler
  346. local schedulerconnect
  347. local SimpleSpy = {}
  348. local topstr = ""
  349. local bottomstr = ""
  350. local remotesFadeIn
  351. local rightFadeIn
  352. local codebox
  353. local p
  354. local getnilrequired = false
  355.  
  356. -- autoblock variables
  357. local autoblock = false
  358. local history = {}
  359. local excluding = {}
  360.  
  361. -- function info variables
  362. local funcEnabled = true
  363.  
  364. -- remote hooking/connecting api variables
  365. local remoteSignals = {}
  366. local remoteHooks = {}
  367.  
  368. -- original mouse icon
  369. local oldIcon = Mouse.Icon
  370.  
  371. -- if mouse inside gui
  372. local mouseInGui = false
  373.  
  374. -- handy array of RBXScriptConnections to disconnect on shutdown
  375. local connections = {}
  376.  
  377. -- whether or not SimpleSpy uses 'getcallingscript()' to get the script (default is false because detection)
  378. local useGetCallingScript = false
  379.  
  380. -- functions
  381.  
  382. --- Converts arguments to a string and generates code that calls the specified method with them, recommended to be used in conjunction with ValueToString (method must be a string, e.g. `game:GetService("ReplicatedStorage").Remote:FireServer`)
  383. --- @param method string
  384. --- @param args any[]
  385. --- @return string
  386. function SimpleSpy:ArgsToString(method, args)
  387.     assert(typeof(method) == "string", "string expected, got " .. typeof(method))
  388.     assert(typeof(args) == "table", "table expected, got " .. typeof(args))
  389.     return v2v({args = args}) .. "nn" .. method .. "(unpack(args))"
  390. end
  391.  
  392. --- Converts a value to variables with the specified index as the variable name (if nil/invalid then the name will be assigned automatically)
  393. --- @param t any[]
  394. --- @return string
  395. function SimpleSpy:TableToVars(t)
  396.     assert(typeof(t) == "table", "table expected, got " .. typeof(t))
  397.     return v2v(t)
  398. end
  399.  
  400. --- Converts a value to a variable with the specified `variablename` (if nil/invalid then the name will be assigned automatically)
  401. --- @param value any
  402. --- @return string
  403. function SimpleSpy:ValueToVar(value, variablename)
  404.     assert(variablename == nil or typeof(variablename) == "string", "string expected, got " .. typeof(variablename))
  405.     if not variablename then
  406.         variablename = 1
  407.     end
  408.     return v2v({[variablename] = value})
  409. end
  410.  
  411. --- Converts any value to a string, cannot preserve function contents
  412. --- @param value any
  413. --- @return string
  414. function SimpleSpy:ValueToString(value)
  415.     return v2s(value)
  416. end
  417.  
  418. --- Generates the simplespy function info
  419. --- @param func function
  420. --- @return string
  421. function SimpleSpy:GetFunctionInfo(func)
  422.     assert(typeof(func) == "function", "Instance expected, got " .. typeof(func))
  423.     return v2v{functionInfo = {
  424.         info = debug.getinfo(func),
  425.         constants = debug.getconstants(func)
  426.     }}
  427. end
  428.  
  429. --- Gets the ScriptSignal for a specified remote being fired
  430. --- @param remote Instance
  431. function SimpleSpy:GetRemoteFiredSignal(remote)
  432.     assert(typeof(remote) == "Instance", "Instance expected, got " .. typeof(remote))
  433.     if not remoteSignals[remote] then
  434.         remoteSignals[remote] = newSignal()
  435.     end
  436.     return remoteSignals[remote]
  437. end
  438.  
  439. --- Allows for direct hooking of remotes **THIS CAN BE VERY DANGEROUS**
  440. --- @param remote Instance
  441. --- @param f function
  442. function SimpleSpy:HookRemote(remote, f)
  443.     assert(typeof(remote) == "Instance", "Instance expected, got " .. typeof(remote))
  444.     assert(typeof(f) == "function", "function expected, got " .. typeof(f))
  445.     remoteHooks[remote] = f
  446. end
  447.  
  448. --- Blocks the specified remote instance/string
  449. --- @param remote any
  450. function SimpleSpy:BlockRemote(remote)
  451.     assert(typeof(remote) == "Instance" or typeof(remote) == "string", "Instance | string expected, got " .. typeof(remote))
  452.     blocklist[remote] = true
  453. end
  454.  
  455. --- Excludes the specified remote from logs (instance/string)
  456. --- @param remote any
  457. function SimpleSpy:ExcludeRemote(remote)
  458.     assert(typeof(remote) == "Instance" or typeof(remote) == "string", "Instance | string expected, got " .. typeof(remote))
  459.     blacklist[remote] = true
  460. end
  461.  
  462. --- Creates a new ScriptSignal that can be connected to and fired
  463. --- @return table
  464. function newSignal()
  465.     local connected = {}
  466.     return {
  467.         Connect = function(self, f)
  468.             assert(connected, "Signal is closed")
  469.             connected[tostring(f)] = f
  470.             return setmetatable({
  471.                 Connected = true,
  472.                 Disconnect = function(self)
  473.                     if not connected then
  474.                         warn("Signal is already closed")
  475.                     end
  476.                     self.Connected = false
  477.                     connected[tostring(f)] = nil
  478.                 end
  479.             },
  480.             {
  481.                 __index = function(self, i)
  482.                     if i == "Connected" then
  483.                         return not not connected[tostring(f)]
  484.                     end
  485.                 end
  486.             })
  487.         end,
  488.         Fire = function(self, ...)
  489.             for _, f in pairs(connected) do
  490.                 coroutine.wrap(f)(...)
  491.             end
  492.         end
  493.     }
  494. end
  495.  
  496. --- Prevents remote spam from causing lag (clears logs after `_G.SIMPLESPYCONFIG_MaxRemotes` or 500 remotes)
  497. function clean()
  498.     local max = _G.SIMPLESPYCONFIG_MaxRemotes
  499.     if not typeof(max) == "number" and math.floor(max) ~= max then
  500.         max = 500
  501.     end
  502.     if #remoteLogs > max then
  503.         for i = 100, #remoteLogs do
  504.             local v = remoteLogs[i]
  505.             if typeof(v[1]) == "RBXScriptConnection" then
  506.                 v[1]:Disconnect()
  507.             end
  508.             if typeof(v[2]) == "Instance" then
  509.                 v[2]:Destroy()
  510.             end
  511.         end
  512.         local newLogs = {}
  513.         for i = 1, 100 do
  514.             table.insert(newLogs, remoteLogs[i])
  515.         end
  516.         remoteLogs = newLogs
  517.     end
  518. end
  519.  
  520. --- Scales the ToolTip to fit containing text
  521. function scaleToolTip()
  522.     local size = TextService:GetTextSize(TextLabel.Text, TextLabel.TextSize, TextLabel.Font, Vector2.new(196, math.huge))
  523.     TextLabel.Size = UDim2.new(0, size.X, 0, size.Y)
  524.     ToolTip.Size = UDim2.new(0, size.X + 4, 0, size.Y + 4)
  525. end
  526.  
  527. --- Executed when the toggle button (the SimpleSpy logo) is hovered over
  528. function onToggleButtonHover()
  529.     if not toggle then
  530.         TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(252, 51, 51)}):Play()
  531.     else
  532.         TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(68, 206, 91)}):Play()
  533.     end
  534. end
  535.  
  536. --- Executed when the toggle button is unhovered over
  537. function onToggleButtonUnhover()
  538.     TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(255, 255, 255)}):Play()
  539. end
  540.  
  541. --- Executed when the X button is hovered over
  542. function onXButtonHover()
  543.     TweenService:Create(CloseButton, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(255, 60, 60)}):Play()
  544. end
  545.  
  546. --- Executed when the X button is unhovered over
  547. function onXButtonUnhover()
  548.     TweenService:Create(CloseButton, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(37, 36, 38)}):Play()
  549. end
  550.  
  551. --- Toggles the remote spy method (when button clicked)
  552. function onToggleButtonClick()
  553.     if toggle then
  554.         TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(252, 51, 51)}):Play()
  555.     else
  556.         TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(68, 206, 91)}):Play()
  557.     end
  558.     toggleSpyMethod()
  559. end
  560.  
  561. --- Reconnects bringBackOnResize if the current viewport changes and also connects it initially
  562. function connectResize()
  563.     local lastCam = workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(bringBackOnResize)
  564.     workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
  565.         lastCam:Disconnect()
  566.         if workspace.CurrentCamera then
  567.             lastCam = workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(bringBackOnResize)
  568.         end
  569.     end)
  570. end
  571.  
  572. --- Brings gui back if it gets lost offscreen (connected to the camera viewport changing)
  573. function bringBackOnResize()
  574.     local currentX = Background.AbsolutePosition.X
  575.     local currentY = Background.AbsolutePosition.Y
  576.     local viewportSize = workspace.CurrentCamera.ViewportSize
  577.     if (currentX < 0) or (currentX > (viewportSize.X - (sideClosed and 131 or TopBar.AbsoluteSize.X))) then
  578.         if currentX < 0 then
  579.             currentX = 0
  580.         else
  581.             currentX = viewportSize.X - (sideClosed and 131 or TopBar.AbsoluteSize.X)
  582.         end
  583.     end
  584.     if (currentY < 0) or (currentY > (viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36)) then
  585.         if currentY < 0 then
  586.             currentY = 0
  587.         else
  588.             currentY = viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36
  589.         end
  590.     end
  591.      TweenService.Create(TweenService, Background, TweenInfo.new(0.1), {Positi currentX, 0, currentY)}):Play()
  592. end
  593.  
  594. --- Drags gui (so long as mouse is held down)
  595. function onBarInput(input)
  596.     if input.UserInputType == Enum.UserInputType.MouseButton1 then
  597.         local lastPos = UserInputService.GetMouseLocation(UserInputService)
  598.         local mainPos = Background.AbsolutePosition
  599.         local offset = mainPos - lastPos
  600.         local currentPos = offset + lastPos
  601.         RunService.BindToRenderStep(RunService, "drag", 1,
  602.             function()
  603.                 local newPos = UserInputService.GetMouseLocation(UserInputService)
  604.                 if newPos ~= lastPos then
  605.                     local currentX = (offset + newPos).X
  606.                     local currentY = (offset + newPos).Y
  607.                     local viewportSize = workspace.CurrentCamera.ViewportSize
  608.                     if (currentX < 0 and currentX < currentPos.X) or (currentX > (viewportSize.X - (sideClosed and 131 or TopBar.AbsoluteSize.X)) and currentX > currentPos.X) then
  609.                         if currentX < 0 then
  610.                             currentX = 0
  611.                         else
  612.                             currentX = viewportSize.X - (sideClosed and 131 or TopBar.AbsoluteSize.X)
  613.                         end
  614.                     end
  615.                     if (currentY < 0 and currentY < currentPos.Y) or (currentY > (viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36) and currentY > currentPos.Y) then
  616.                         if currentY < 0 then
  617.                             currentY = 0
  618.                         else
  619.                             currentY = viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36
  620.                         end
  621.                     end
  622.                     currentPos = Vector2.new(currentX, currentY)
  623.                     lastPos = newPos
  624.                      TweenService.Create(TweenService, Background, TweenInfo.new(0.1), {Positi currentPos.X, 0, currentPos.Y)}):Play()
  625.                 end
  626.                 if not UserInputService:IsMouseButtonPressed(Enum.UserInputType.MouseButton1) then
  627.                     RunService.UnbindFromRenderStep(RunService, "drag")
  628.                 end
  629.             end
  630.         )
  631.     end
  632. end
  633.  
  634. --- Fades out the table of elements (and makes them invisible), returns a function to make them visible again
  635. function fadeOut(elements)
  636.     local data = {}
  637.     for _, v in pairs(elements) do
  638.         if typeof(v) == "Instance" and v:IsA("GuiObject") and v.Visible then
  639.             coroutine.wrap(function()
  640.                 data[v] = {
  641.                     BackgroundTransparency = v.BackgroundTransparency
  642.                 }
  643.                 TweenService:Create(v, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play()
  644.                 if v:IsA("TextBox") or v:IsA("TextButton") or v:IsA("TextLabel") then
  645.                     data[v].TextTransparency = v.TextTransparency
  646.                     TweenService:Create(v, TweenInfo.new(0.5), {TextTransparency = 1}):Play()
  647.                 elseif v:IsA("ImageButton") or v:IsA("ImageLabel") then
  648.                     data[v].ImageTransparency = v.ImageTransparency
  649.                     TweenService:Create(v, TweenInfo.new(0.5), {ImageTransparency = 1}):Play()
  650.                 end
  651.                 wait(0.5)
  652.                 v.Visible = false
  653.                 for i, x in pairs(data[v]) do
  654.                     v[i] = x
  655.                 end
  656.                 data[v] = true
  657.             end)()
  658.         end
  659.     end
  660.     return function()
  661.         for i, _ in pairs(data) do
  662.             coroutine.wrap(function()
  663.                 local properties = {
  664.                     BackgroundTransparency = i.BackgroundTransparency
  665.                 }
  666.                 i.BackgroundTransparency = 1
  667.                 TweenService:Create(i, TweenInfo.new(0.5), {BackgroundTransparency = properties.BackgroundTransparency}):Play()
  668.                 if i:IsA("TextBox") or i:IsA("TextButton") or i:IsA("TextLabel") then
  669.                     properties.TextTransparency = i.TextTransparency
  670.                     i.TextTransparency = 1
  671.                     TweenService:Create(i, TweenInfo.new(0.5), {TextTransparency = properties.TextTransparency}):Play()
  672.                 elseif i:IsA("ImageButton") or i:IsA("ImageLabel") then
  673.                     properties.ImageTransparency = i.ImageTransparency
  674.                     i.ImageTransparency = 1
  675.                     TweenService:Create(i, TweenInfo.new(0.5), {ImageTransparency = properties.ImageTransparency}):Play()
  676.                 end
  677.                 i.Visible = true
  678.             end)()
  679.         end
  680.     end
  681. end
  682.  
  683. --- Expands and minimizes the gui (closed is the toggle boolean)
  684. function toggleMinimize(override)
  685.     if mainClosing and not override or maximized then
  686.         return
  687.     end
  688.     mainClosing = true
  689.     closed = not closed
  690.     if closed then
  691.         if not sideClosed then
  692.             toggleSideTray(true)
  693.         end
  694.         LeftPanel.Visible = true
  695.         TweenService:Create(LeftPanel, TweenInfo.new(0.5), {Size = UDim2.new(0, 131, 0, 0)}):Play()
  696.         wait(0.5)
  697.         remotesFadeIn = fadeOut(LeftPanel:GetDescendants())
  698.         wait(0.5)
  699.     else
  700.         TweenService:Create(LeftPanel, TweenInfo.new(0.5), {Size = UDim2.new(0, 131, 0, 249)}):Play()
  701.         wait(0.5)
  702.         if remotesFadeIn then
  703.             remotesFadeIn()
  704.             remotesFadeIn = nil
  705.         end
  706.         bringBackOnResize()
  707.     end
  708.     mainClosing = false
  709. end
  710.  
  711. --- Expands and minimizes the sidebar (sideClosed is the toggle boolean)
  712. function toggleSideTray(override)
  713.     if sideClosing and not override or maximized then
  714.         return
  715.     end
  716.     sideClosing = true
  717.     sideClosed = not sideClosed
  718.     if sideClosed then
  719.         rightFadeIn = fadeOut(RightPanel:GetDescendants())
  720.         wait(0.5)
  721.         minimizeSize(0.5)
  722.         wait(0.5)
  723.         RightPanel.Visible = false
  724.     else
  725.         if closed then
  726.             toggleMinimize(true)
  727.         end
  728.         RightPanel.Visible = true
  729.         maximizeSize(0.5)
  730.         wait(0.5)
  731.         if rightFadeIn then
  732.             rightFadeIn()
  733.         end
  734.         bringBackOnResize()
  735.     end
  736.     sideClosing = false
  737. end
  738.  
  739. --- Expands code box to fit screen for more convenient viewing
  740. function toggleMaximize()
  741.     if not sideClosed and not maximized then
  742.         maximized = true
  743.         local disable = Instance.new("TextButton")
  744.         local prevSize = UDim2.new(0, CodeBox.AbsoluteSize.X, 0, CodeBox.AbsoluteSize.Y)
  745.         local prevPos = UDim2.new(0,CodeBox.AbsolutePosition.X, 0, CodeBox.AbsolutePosition.Y)
  746.         disable.Size = UDim2.new(1, 0, 1, 0)
  747.         disable.BackgroundColor3 = Color3.new()
  748.         disable.BorderSizePixel = 0
  749.         disable.Text = 0
  750.         disable.ZIndex = 3
  751.         disable.BackgroundTransparency = 1
  752.          disable.AutoButt
  753.         CodeBox.ZIndex = 4
  754.          CodeBox.Positi
  755.         CodeBox.Size = prevSize
  756.          TweenService:Create(CodeBox, TweenInfo.new(0.5), {Size = UDim2.new(0.5, 0, 0.5, 0), Positi 0, 0.25, 0)}):Play()
  757.         TweenService:Create(disable, TweenInfo.new(0.5), {BackgroundTransparency = 0.5}):Play()
  758.         disable.MouseButton1Click:Connect(function()
  759.             if UserInputService:GetMouseLocation().Y + 36 >= CodeBox.AbsolutePosition.Y and UserInputService:GetMouseLocation().Y + 36 <= CodeBox.AbsolutePosition.Y + CodeBox.AbsoluteSize.Y
  760.                 and UserInputService:GetMouseLocation().X >= CodeBox.AbsolutePosition.X and UserInputService:GetMouseLocation().X <= CodeBox.AbsolutePosition.X + CodeBox.AbsoluteSize.X then
  761.                 return
  762.             end
  763.              TweenService:Create(CodeBox, TweenInfo.new(0.5), {Size = prevSize, Positi}):Play()
  764.             TweenService:Create(disable, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play()
  765.             wait(0.5)
  766.             disable:Destroy()
  767.             CodeBox.Size = UDim2.new(1, 0, 0.5, 0)
  768.              CodeBox.Positi 0, 0, 0)
  769.             CodeBox.ZIndex = 0
  770.             maximized = false
  771.         end)
  772.     end
  773. end
  774.  
  775. --- Checks if cursor is within resize range
  776. --- @param p Vector2
  777. function isInResizeRange(p)
  778.     local relativeP = p - Background.AbsolutePosition
  779.     local range = 5
  780.     if relativeP.X >= TopBar.AbsoluteSize.X - range and relativeP.Y >= Background.AbsoluteSize.Y - range
  781.         and relativeP.X <= TopBar.AbsoluteSize.X and relativeP.Y <= Background.AbsoluteSize.Y then
  782.         return true, 'B'
  783.     elseif relativeP.X >= TopBar.AbsoluteSize.X - range and relativeP.X <= Background.AbsoluteSize.X then
  784.         return true, 'X'
  785.     elseif relativeP.Y >= Background.AbsoluteSize.Y - range and relativeP.Y <= Background.AbsoluteSize.Y then
  786.         return true, 'Y'
  787.     end
  788.     return false
  789. end
  790.  
  791. --- Called when mouse enters SimpleSpy
  792. function mouseEntered()
  793.     local customCursor = Instance.new("ImageLabel")
  794.     customCursor.Size = UDim2.fromOffset(200, 200)
  795.     customCursor.ZIndex = 1e5
  796.     customCursor.BackgroundTransparency = 1
  797.     customCursor.Image = ""
  798.     customCursor.Parent = SimpleSpy2
  799.      UserInputService.OverrideMouseIc
  800.     RunService:BindToRenderStep("SIMPLESPY_CURSOR", 1, function()
  801.         if mouseInGui and _G.SimpleSpyExecuted then
  802.              local mouseLocati - Vector2.new(0, 36)
  803.              customCursor.Positi - customCursor.AbsoluteSize.X / 2, mouseLocation.Y - customCursor.AbsoluteSize.Y / 2)
  804.             local inRange, type = isInResizeRange(mouseLocation)
  805.             if inRange and not sideClosed and not closed then
  806.                 customCursor.Image = type == 'B' and "rbxassetid://6065821980" or type == 'X' and "rbxassetid://6065821086" or type == 'Y' and "rbxassetid://6065821596"
  807.             elseif inRange and not closed and type == 'Y' or type == 'B' then
  808.                 customCursor.Image = "rbxassetid://6065821596"
  809.             elseif customCursor.Image ~= "rbxassetid://6065775281" then
  810.                 customCursor.Image = "rbxassetid://6065775281"
  811.             end
  812.         else
  813.              UserInputService.OverrideMouseIc
  814.             customCursor:Destroy()
  815.             RunService:UnbindFromRenderStep("SIMPLESPY_CURSOR")
  816.         end
  817.     end)
  818. end
  819.  
  820. --- Called when mouse moves
  821. function mouseMoved()
  822.     local mousePos = UserInputService:GetMouseLocation() - Vector2.new(0, 36)
  823.     if not closed
  824.     and mousePos.X >= TopBar.AbsolutePosition.X and mousePos.X <= TopBar.AbsolutePosition.X + TopBar.AbsoluteSize.X
  825.     and mousePos.Y >= Background.AbsolutePosition.Y and mousePos.Y <= Background.AbsolutePosition.Y + Background.AbsoluteSize.Y then
  826.         if not mouseInGui then
  827.             mouseInGui = true
  828.             mouseEntered()
  829.         end
  830.     else
  831.         mouseInGui = false
  832.     end
  833. end
  834.  
  835. --- Adjusts the ui elements to the 'Maximized' size
  836. function maximizeSize(speed)
  837.     if not speed then
  838.         speed = 0.05
  839.     end
  840.     TweenService:Create(LeftPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play()
  841.     TweenService:Create(RightPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play()
  842.     TweenService:Create(TopBar, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X, TopBar.AbsoluteSize.Y) }):Play()
  843.      TweenService:Create(ScrollingFrame, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X, 110), Positi Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play()
  844.     TweenService:Create(CodeBox, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play()
  845.     TweenService:Create(LogList, TweenInfo.new(speed), { Size = UDim2.fromOffset(LogList.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y - 18) }):Play()
  846. end
  847.  
  848. --- Adjusts the ui elements to close the side
  849. function minimizeSize(speed)
  850.     if not speed then
  851.         speed = 0.05
  852.     end
  853.     TweenService:Create(LeftPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play()
  854.     TweenService:Create(RightPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(0, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play()
  855.     TweenService:Create(TopBar, TweenInfo.new(speed), { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, TopBar.AbsoluteSize.Y) }):Play()
  856.      TweenService:Create(ScrollingFrame, TweenInfo.new(speed), { Size = UDim2.fromOffset(0, 119), Positi Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play()
  857.     TweenService:Create(CodeBox, TweenInfo.new(speed), { Size = UDim2.fromOffset(0, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play()
  858.     TweenService:Create(LogList, TweenInfo.new(speed), { Size = UDim2.fromOffset(LogList.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y - 18) }):Play()
  859. end
  860.  
  861. --- Called on user input while mouse in 'Background' frame
  862. --- @param input InputObject
  863. function backgroundUserInput(input)
  864.     local inRange, type = isInResizeRange(UserInputService:GetMouseLocation() - Vector2.new(0, 36))
  865.     if input.UserInputType == Enum.UserInputType.MouseButton1 and inRange then
  866.         local lastPos = UserInputService:GetMouseLocation()
  867.         local offset = Background.AbsoluteSize - lastPos
  868.         local currentPos = lastPos + offset
  869.         RunService:BindToRenderStep("SIMPLESPY_RESIZE", 1, function()
  870.             local newPos = UserInputService:GetMouseLocation()
  871.             if newPos ~= lastPos then
  872.                 local currentX = (newPos + offset).X
  873.                 local currentY = (newPos + offset).Y
  874.                 if currentX < 450 then
  875.                     currentX = 450
  876.                 end
  877.                 if currentY < 268 then
  878.                     currentY = 268
  879.                 end
  880.                 currentPos = Vector2.new(currentX, currentY)
  881.                 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)
  882.                 if sideClosed then
  883.                     minimizeSize()
  884.                 else
  885.                     maximizeSize()
  886.                 end
  887.                 lastPos = newPos
  888.             end
  889.         end)
  890.         table.insert(connections, UserInputService.InputEnded:Connect(function(inputE)
  891.             if input == inputE then
  892.                 RunService:UnbindFromRenderStep("SIMPLESPY_RESIZE")
  893.             end
  894.         end))
  895.     end
  896. end
  897.  
  898. --- Gets the player an instance is descended from
  899. function getPlayerFromInstance(instance)
  900.     for _, v in pairs(Players:GetPlayers()) do
  901.         if v.Character and (instance:IsDescendantOf(v.Character) or instance == v.Character) then
  902.             return v
  903.         end
  904.     end
  905. end
  906.  
  907. --- Runs on MouseButton1Click of an event frame
  908. function eventSelect(frame)
  909.     if selected and selected.Log  then
  910.         TweenService:Create(selected.Log.Button, TweenInfo.new(0.5), {BackgroundColor3 = Color3.fromRGB(0, 0, 0)}):Play()
  911.         selected = nil
  912.     end
  913.     for _, v in pairs(logs) do
  914.         if frame == v.Log then
  915.             selected = v
  916.         end
  917.     end
  918.     if selected and selected.Log then
  919.         TweenService:Create(frame.Button, TweenInfo.new(0.5), {BackgroundColor3 = Color3.fromRGB(92, 126, 229)}):Play()
  920.         codebox:setRaw(selected.GenScript)
  921.     end
  922.     if sideClosed then
  923.         toggleSideTray()
  924.     end
  925. end
  926.  
  927. --- Updates the canvas size to fit the current amount of function buttons
  928. function updateFunctionCanvas()
  929.     ScrollingFrame.CanvasSize = UDim2.fromOffset(UIGridLayout.AbsoluteContentSize.X, UIGridLayout.AbsoluteContentSize.Y)
  930. end
  931.  
  932. --- Updates the canvas size to fit the amount of current remotes
  933. function updateRemoteCanvas()
  934.     LogList.CanvasSize = UDim2.fromOffset(UIListLayout.AbsoluteContentSize.X, UIListLayout.AbsoluteContentSize.Y)
  935. end
  936.  
  937. --- Allows for toggling of the tooltip and easy setting of le description
  938. --- @param enable boolean
  939. --- @param text string
  940. function makeToolTip(enable, text)
  941.     if enable then
  942.         if ToolTip.Visible then
  943.             ToolTip.Visible = false
  944.             RunService:UnbindFromRenderStep("ToolTip")
  945.         end
  946.         local first = true
  947.         RunService:BindToRenderStep("ToolTip", 1, function()
  948.             local topLeft = Vector2.new(Mouse.X + 20, Mouse.Y + 20)
  949.             local bottomRight = topLeft + ToolTip.AbsoluteSize
  950.             if topLeft.X < 0 then
  951.                 topLeft = Vector2.new(0, topLeft.Y)
  952.             elseif bottomRight.X > workspace.CurrentCamera.ViewportSize.X then
  953.                 topLeft = Vector2.new(workspace.CurrentCamera.ViewportSize.X - ToolTip.AbsoluteSize.X, topLeft.Y)
  954.             end
  955.             if topLeft.Y < 0 then
  956.                 topLeft = Vector2.new(topLeft.X, 0)
  957.             elseif bottomRight.Y > workspace.CurrentCamera.ViewportSize.Y - 35 then
  958.                 topLeft = Vector2.new(topLeft.X, workspace.CurrentCamera.ViewportSize.Y - ToolTip.AbsoluteSize.Y - 35)
  959.             end
  960.             if topLeft.X <= Mouse.X and topLeft.Y <= Mouse.Y then
  961.                 topLeft = Vector2.new(Mouse.X - ToolTip.AbsoluteSize.X - 2, Mouse.Y - ToolTip.AbsoluteSize.Y - 2)
  962.             end
  963.             if first then
  964.                  ToolTip.Positi topLeft.Y)
  965.                 first = false
  966.             else
  967.                 ToolTip:TweenPosition(UDim2.fromOffset(topLeft.X, topLeft.Y), "Out", "Linear", 0.1)
  968.             end
  969.         end)
  970.         TextLabel.Text = text
  971.         ToolTip.Visible = true
  972.     else
  973.         if ToolTip.Visible then
  974.             ToolTip.Visible = false
  975.             RunService:UnbindFromRenderStep("ToolTip")
  976.         end
  977.     end
  978. end
  979.  
  980. --- Creates new function button (below codebox)
  981. --- @param name string
  982. ---@param description function
  983. ---@param onClick function
  984. function newButton(name, description, onClick)
  985.      local butt
  986.     button.Text.Text = name
  987.     button.Button.MouseEnter:Connect(function()
  988.         makeToolTip(true, description())
  989.     end)
  990.     button.Button.MouseLeave:Connect(function()
  991.         makeToolTip(false)
  992.     end)
  993.     button.AncestryChanged:Connect(function()
  994.         makeToolTip(false)
  995.     end)
  996.     button.Button.MouseButton1Click:Connect(function(...)
  997.         onClick(button, ...)
  998.     end)
  999.     button.Parent = ScrollingFrame
  1000.     updateFunctionCanvas()
  1001. end
  1002.  
  1003. --- Adds new Remote to logs
  1004. --- @param name string The name of the remote being logged
  1005. --- @param type string The type of the remote being logged (either 'function' or 'event')
  1006. --- @param gen_script any
  1007. --- @param remote any
  1008. --- @param function_info string
  1009. --- @param blocked any
  1010. function newRemote(type, name, gen_script, remote, function_info, blocked, src)
  1011.     local remoteFrame = RemoteTemplate:Clone()
  1012.     remoteFrame.Text.Text = name
  1013.     remoteFrame.ColorBar.BackgroundColor3 = type == "event" and Color3.new(255, 242, 0) or Color3.fromRGB(99, 86, 245)
  1014.     local id = Instance.new("IntValue")
  1015.     id.Name = "ID"
  1016.     id.Value = #logs + 1
  1017.     id.Parent = remoteFrame
  1018.     logs[#logs + 1] = {
  1019.         Name = name,
  1020.         GenScript = gen_script,
  1021.          Functi
  1022.         Remote = remote,
  1023.         Log = remoteFrame,
  1024.         Blocked = blocked,
  1025.         Source = src
  1026.     }
  1027.     if blocked then
  1028.         logs[#logs].GenScript = "-- THIS REMOTE WAS PREVENTED FROM FIRING THE SERVER BY SIMPLESPYnn" .. logs[#logs].GenScript
  1029.     end
  1030.      local c
  1031.         eventSelect(remoteFrame)
  1032.     end)
  1033.     if layoutOrderNum < 1 then
  1034.         layoutOrderNum = 999999999
  1035.     end
  1036.     remoteFrame.LayoutOrder = layoutOrderNum
  1037.     layoutOrderNum = layoutOrderNum - 1
  1038.     remoteFrame.Parent = LogList
  1039.     table.insert(remoteLogs, 1, {connect, remoteFrame})
  1040.     clean()
  1041.     updateRemoteCanvas()
  1042. end
  1043.  
  1044. --- Generates a script from the provided arguments (first has to be remote path)
  1045. function genScript(remote, ...)
  1046.     prevTables = {}
  1047.     local gen = ""
  1048.     local args = {...}
  1049.     if #args > 0 then
  1050.         if not pcall(function()
  1051.                 gen = v2v({args = args}) .. "n"
  1052.             end)
  1053.         then
  1054.             gen = gen .. "-- TableToString failure! Reverting to legacy functionality (results may vary)nlocal args = {"
  1055.             if
  1056.                 not pcall(
  1057.                     function()
  1058.                         for i, v in pairs(args) do
  1059.                             if type(i) ~= "Instance" and type(i) ~= "userdata" then
  1060.                                 gen = gen .. "n    [" .. tostring(i) .. "] = "
  1061.                             elseif type(i) == "string" then
  1062.                                 gen = gen .. 'n    ["' .. tostring(i) .. '"] = '
  1063.                             elseif type(i) == "userdata" and typeof(i) ~= "Instance" then
  1064.                                 gen = gen .. "n    [" .. typeof(i) .. ".new(" .. tostring(i) .. ")] = "
  1065.                             elseif type(i) == "userdata" then
  1066.                                 gen = gen .. "n    [game." .. i:GetFullName() .. ")] = "
  1067.                             end
  1068.                             if type(v) ~= "Instance" and type(v) ~= "userdata" then
  1069.                                 gen = gen .. tostring(v)
  1070.                             elseif type(v) == "string" then
  1071.                                 gen = gen .. '"' .. tostring(v) .. '"'
  1072.                             elseif type(v) == "userdata" and typeof(v) ~= "Instance" then
  1073.                                 gen = gen .. typeof(v) .. ".new(" .. tostring(v) .. ")"
  1074.                             elseif type(v) == "userdata" then
  1075.                                 gen = gen .. "game." .. v:GetFullName()
  1076.                             end
  1077.                         end
  1078.                         gen = gen .. "n}nn"
  1079.                     end
  1080.                 )
  1081.              then
  1082.                 gen = gen .. "}n-- Legacy tableToString failure! Unable to decompile."
  1083.             end
  1084.         end
  1085.         if not remote:IsDescendantOf(game) and not getnilrequired then
  1086.             gen = "function getNil(name,class) for _,v in pairs(getnilinstances())do if v.ClassName==class and v.Name==name then return v;end end endnn" .. gen
  1087.         end
  1088.         if remote:IsA("RemoteEvent") then
  1089.             gen = gen .. v2s(remote) .. ":FireServer(unpack(args))"
  1090.         elseif remote:IsA("RemoteFunction") then
  1091.             gen = gen .. v2s(remote) .. ":InvokeServer(unpack(args))"
  1092.         end
  1093.     else
  1094.         if remote:IsA("RemoteEvent") then
  1095.             gen = gen .. v2s(remote) .. ":FireServer()"
  1096.         elseif remote:IsA("RemoteFunction") then
  1097.             gen = gen .. v2s(remote) .. ":InvokeServer()"
  1098.         end
  1099.     end
  1100.     gen = "" .. gen
  1101.     prevTables = {}
  1102.     return gen
  1103. end
  1104.  
  1105. --- value-to-string: value, string (out), level (indentation), parent table, var name, is from tovar
  1106. function v2s(v, l, p, n, vtv, i, pt, path, tables)
  1107.     if typeof(v) == "number" then
  1108.         if v == math.huge then
  1109.             return "math.huge"
  1110.         elseif tostring(v):match("nan") then
  1111.             return "0/0 --[[NaN]]"
  1112.         end
  1113.         return tostring(v)
  1114.     elseif typeof(v) == "boolean" then
  1115.         return tostring(v)
  1116.     elseif typeof(v) == "string" then
  1117.         return formatstr(v)
  1118.     elseif typeof(v) == "function" then
  1119.         return f2s(v)
  1120.     elseif typeof(v) == "table" then
  1121.         return t2s(v, l, p, n, vtv, i, pt, path, tables)
  1122.     elseif typeof(v) == "Instance" then
  1123.         return i2p(v)
  1124.     elseif typeof(v) == "userdata" then
  1125.         return "newproxy(true)"
  1126.     elseif type(v) == "userdata" then
  1127.         return u2s(v)
  1128.     else
  1129.         return "nil --[[" .. typeof(v) .. "]]"
  1130.     end
  1131. end
  1132.  
  1133. --- value-to-variable
  1134. --- @param t any
  1135. function v2v(t)
  1136.     topstr = ""
  1137.     bottomstr = ""
  1138.     getnilrequired = false
  1139.     local ret = ""
  1140.     local count = 1
  1141.     for i, v in pairs(t) do
  1142.         if type(i) == "string" and i:match("^[%a_]+[%w_]*$") then
  1143.             ret = ret .. "local " .. i .. " = " .. v2s(v, nil, nil, i, true) .. "n"
  1144.         elseif tostring(i):match("^[%a_]+[%w_]*$") then
  1145.             ret = ret .. "local " .. tostring(i):lower() .. "_" .. tostring(count) .. " = " .. v2s(v, nil, nil, tostring(i):lower() .. "_" .. tostring(count), true) .. "n"
  1146.         else
  1147.             ret = ret .. "local " .. type(v) .. "_" .. tostring(count) .. " = " .. v2s(v, nil, nil, type(v) .. "_" .. tostring(count), true) .. "n"
  1148.         end
  1149.         count = count + 1
  1150.     end
  1151.     if getnilrequired then
  1152.         topstr = "function getNil(name,class) for _,v in pairs(getnilinstances())do if v.ClassName==class and v.Name==name then return v;end end endn" .. topstr
  1153.     end
  1154.     if #topstr > 0 then
  1155.         ret = topstr .. "n" .. ret
  1156.     end
  1157.     if #bottomstr > 0 then
  1158.         ret = ret .. bottomstr
  1159.     end
  1160.     return ret
  1161. end
  1162.  
  1163. --- table-to-string
  1164. --- @param t table
  1165. --- @param l number
  1166. --- @param p table
  1167. --- @param n string
  1168. --- @param vtv boolean
  1169. --- @param i any
  1170. --- @param pt table
  1171. --- @param path string
  1172. --- @param tables table
  1173. function t2s(t, l, p, n, vtv, i, pt, path, tables)
  1174.     for k, x in pairs(getrenv()) do
  1175.         local isgucci, gpath
  1176.         if rawequal(x, t) then
  1177.             isgucci, gpath = true, ""
  1178.         elseif type(x) == "table" then
  1179.             isgucci, gpath = v2p(t, x)
  1180.         end
  1181.         if isgucci then
  1182.             if type(k) == "string" and k:match("^[%a_]+[%w_]*$") then
  1183.                 return k .. gpath
  1184.             else
  1185.                 return "getrenv()[" .. v2s(k) .. "]" .. gpath
  1186.             end
  1187.         end
  1188.     end
  1189.     if not path then
  1190.         path = ""
  1191.     end
  1192.     if not l then
  1193.         l = 0
  1194.         tables = {}
  1195.     end
  1196.     if not p then
  1197.         p = t
  1198.     end
  1199.     for _, v in pairs(tables) do
  1200.         if n and rawequal(v, t) then
  1201.             bottomstr = bottomstr .. "n" .. tostring(n) .. tostring(path) .. " = " .. tostring(n) .. tostring(({v2p(v, p)})[2])
  1202.             return "{} --[[DUPLICATE]]"
  1203.         end
  1204.     end
  1205.     table.insert(tables, t)
  1206.     local s =  "{"
  1207.     local size = 0
  1208.     l = l + indent
  1209.     for k, v in pairs(t) do
  1210.         size = size + 1
  1211.         if size > (_G.SimpleSpyMaxTableSize and _G.SimpleSpyMaxTableSize or 1000) then
  1212.             break
  1213.         end
  1214.         if rawequal(k, t) then
  1215.             bottomstr = bottomstr .. "n" .. tostring(n) .. tostring(path) .. "[" .. tostring(n) .. tostring(path) .. "]" .. " = " .. (v == k and tostring(n) .. tostring(path) or v2s(v, l, p, n, vtv, k, t, path .. "[" .. tostring(n) .. tostring(path) .. "]", tables))
  1216.             size -= 1
  1217.             continue
  1218.         end
  1219.         local currentPath = ""
  1220.         if type(k) == "string" and k:match("^[%a_]+[%w_]*$") then
  1221.             currentPath = "." .. k
  1222.         else
  1223.             currentPath = "[" .. v2s(k, nil, p, n, vtv, i, pt, path) .. "]"
  1224.         end
  1225.         s = s .. "n" .. string.rep(" ", l) .. "[" .. v2s(k, l, p, n, vtv, k, t, path .. currentPath, tables) .. "] = " .. v2s(v, l, p, n, vtv, k, t, path .. currentPath, tables) .. ","
  1226.     end
  1227.     if #s > 1 then
  1228.         s = s:sub(1, #s - 1)
  1229.     end
  1230.     if size > 0 then
  1231.         s = s .. "n" .. string.rep(" ", l - indent)
  1232.     end
  1233.     return s .. "}"
  1234. end
  1235.  
  1236. --- function-to-string
  1237. function f2s(f)
  1238.     for k, x in pairs(getgenv()) do
  1239.         local isgucci, gpath
  1240.         if rawequal(x, f) then
  1241.             isgucci, gpath = true, ""
  1242.         elseif type(x) == "table" then
  1243.             isgucci, gpath = v2p(f, x)
  1244.         end
  1245.         if isgucci then
  1246.             if type(k) == "string" and k:match("^[%a_]+[%w_]*$") then
  1247.                 return k .. gpath
  1248.             else
  1249.                 return "getgenv()[" .. v2s(k) .. "]" .. gpath
  1250.             end
  1251.         end
  1252.     end
  1253.     -- uwu some cool stuff here once bork finishes up
  1254.     -- if SimpleSpy.GetExternalLoader then
  1255.     --     local ExternalLoader = SimpleSpy:GetExternalLoader()
  1256.     --     local loaded, path = pcall(function() ExternalLoader:LoadAsset("Bork_Functions") end)
  1257.     --     if loaded then
  1258.     --         local functions = loadfile(path .. "functions.lua")
  1259.     --         local out = functions[f]
  1260.     --         if out then
  1261.     --             return out
  1262.     --         end
  1263.     --     end
  1264.     -- end
  1265.     -- local isgucci, gpath = v2p(f, getgc())
  1266.     -- if isgucci then
  1267.     --     return "getgc()" .. gpath
  1268.     -- end
  1269.     if debug.getinfo(f).name:match("^[%a_]+[%w_]*$") then
  1270.         return "function()end --[[" .. debug.getinfo(f).name .. "]]"
  1271.     end
  1272.     return "function()end --[[" .. tostring(f) .. "]]"
  1273. end
  1274.  
  1275. --- instance-to-path
  1276. --- @param i userdata
  1277. function i2p(i)
  1278.     local player = getplayer(i)
  1279.     local parent = i
  1280.     local out = ""
  1281.     if parent == nil then
  1282.         return "nil"
  1283.     elseif player then
  1284.         while true do
  1285.             if parent and parent == player.Character then
  1286.                 if player == Players.LocalPlayer then
  1287.                     return 'game:GetService("Players").LocalPlayer.Character' .. out
  1288.                 else
  1289.                     return i2p(player) .. ".Character" .. out
  1290.                 end
  1291.             else
  1292.                 if parent.Name:match("[%a_]+[%w+]*") ~= parent.Name then
  1293.                     out = '[' .. formatstr(parent.Name) .. ']' .. out
  1294.                 else
  1295.                     out = "." .. parent.Name .. out
  1296.                 end
  1297.             end
  1298.             parent = parent.Parent
  1299.         end
  1300.     elseif parent ~= game then
  1301.         while true do
  1302.             if parent and parent.Parent == game then
  1303.                 if game:GetService(parent.ClassName) then
  1304.                     if parent.ClassName == "Workspace" then
  1305.                         return "workspace" .. out
  1306.                     else
  1307.                         return 'game:GetService("' .. parent.ClassName .. '")' .. out
  1308.                     end
  1309.                 else
  1310.                     if parent.Name:match("[%a_]+[%w_]*") then
  1311.                         return "game." .. parent.Name .. out
  1312.                     else
  1313.                         return 'game[' .. formatstr(parent.Name) .. ']' .. out
  1314.                     end
  1315.                 end
  1316.             elseif parent.Parent == nil then
  1317.                 getnilrequired = true
  1318.                 return 'getNil(' .. formatstr(parent.Name) .. ', "' .. parent.ClassName .. '")' .. out
  1319.             elseif parent == Players.LocalPlayer then
  1320.                 out = ".LocalPlayer" .. out
  1321.             else
  1322.                 if parent.Name:match("[%a_]+[%w_]*") ~= parent.Name then
  1323.                     out = '[' .. formatstr(parent.Name) .. ']' .. out
  1324.                 else
  1325.                     out = "." .. parent.Name .. out
  1326.                 end
  1327.             end
  1328.             parent = parent.Parent
  1329.         end
  1330.     else
  1331.         return "game"
  1332.     end
  1333. end
  1334.  
  1335. --- userdata-to-string: userdata
  1336. --- @param u userdata
  1337. function u2s(u)
  1338.     if typeof(u) == "TweenInfo" then
  1339.         -- TweenInfo
  1340.         return "TweenInfo.new(" ..tostring(u.Time) .. ", Enum.EasingStyle." .. tostring(u.EasingStyle) .. ", Enum.EasingDirection." .. tostring(u.EasingDirection) .. ", " .. tostring(u.RepeatCount) .. ", " .. tostring(u.Reverses) .. ", " .. tostring(u.DelayTime) .. ")"
  1341.     elseif typeof(u) == "Ray" then
  1342.         -- Ray
  1343.         return "Ray.new(" .. u2s(u.Origin) .. ", " .. u2s(u.Direction) .. ")"
  1344.     elseif typeof(u) == "NumberSequence" then
  1345.         -- NumberSequence
  1346.         local ret = "NumberSequence.new("
  1347.         for i, v in pairs(u.KeyPoints) do
  1348.             ret = ret .. tostring(v)
  1349.             if i < #u.Keypoints then
  1350.                 ret = ret .. ", "
  1351.             end
  1352.         end
  1353.         return ret .. ")"
  1354.     elseif typeof(u) == "DockWidgetPluginGuiInfo" then
  1355.         -- DockWidgetPluginGuiInfo
  1356.         return "DockWidgetPluginGuiInfo.new(Enum.InitialDockState" .. tostring(u) .. ")"
  1357.     elseif typeof(u) == "ColorSequence" then
  1358.         -- ColorSequence
  1359.         local ret = "ColorSequence.new("
  1360.         for i, v in pairs(u.KeyPoints) do
  1361.             ret = ret .. "Color3.new(" .. tostring(v) .. ")"
  1362.             if i < #u.Keypoints then
  1363.                 ret = ret .. ", "
  1364.             end
  1365.         end
  1366.         return ret .. ")"
  1367.     elseif typeof(u) == "BrickColor" then
  1368.         -- BrickColor
  1369.         return "BrickColor.new(" .. tostring(u.Number) .. ")"
  1370.     elseif typeof(u) == "NumberRange" then
  1371.         -- NumberRange
  1372.         return "NumberRange.new(" .. tostring(u.Min) .. ", " .. tostring(u.Max) .. ")"
  1373.     elseif typeof(u) == "Region3" then
  1374.         -- Region3
  1375.         local center = u.CFrame.Position
  1376.         local size = u.CFrame.Size
  1377.         local vector1 = center - size / 2
  1378.         local vector2 = center + size / 2
  1379.         return "Region3.new(" .. u2s(vector1) .. ", " .. u2s(vector2) .. ")"
  1380.     elseif typeof(u) == "Faces" then
  1381.         -- Faces
  1382.         local faces = {}
  1383.         if u.Top then
  1384.             table.insert(faces, "Enum.NormalId.Top")
  1385.         end
  1386.         if u.Bottom then
  1387.             table.insert(faces, "Enum.NormalId.Bottom")
  1388.         end
  1389.         if u.Left then
  1390.             table.insert(faces, "Enum.NormalId.Left")
  1391.         end
  1392.         if u.Right then
  1393.             table.insert(faces, "Enum.NormalId.Right")
  1394.         end
  1395.         if u.Back then
  1396.             table.insert(faces, "Enum.NormalId.Back")
  1397.         end
  1398.         if u.Front then
  1399.             table.insert(faces, "Enum.NormalId.Front")
  1400.         end
  1401.         return "Faces.new(" .. table.concat(faces, ", ") .. ")"
  1402.     elseif typeof(u) == "EnumItem" then
  1403.         return tostring(u)
  1404.     elseif typeof(u) == "Enums" then
  1405.         return "Enum"
  1406.     elseif typeof(u) == "Enum" then
  1407.         return "Enum." .. tostring(u)
  1408.     elseif typeof(u) == "RBXScriptSignal" then
  1409.         return "nil --[[RBXScriptSignal]]"
  1410.     elseif typeof(u) == "Vector3" then
  1411.         return string.format("Vector3.new(%s, %s, %s)", v2s(u.X), v2s(u.Y), v2s(u.Z))
  1412.     elseif typeof(u) == "CFrame" then
  1413.         return string.format("CFrame.new(%s, %s)", v2s(u.Position), v2s(u.LookVector))
  1414.     elseif typeof(u) == "DockWidgetPluginGuiInfo" then
  1415.         return string.format("DockWidgetPluginGuiInfo(%s, %s, %s, %s, %s, %s, %s)", "Enum.InitialDockState.Right", v2s(u.InitialEnabled), v2s(u.InitialEnabledShouldOverrideRestore), v2s(u.FloatingXSize), v2s(u.FloatingYSize), v2s(u.MinWidth), v2s(u.MinHeight))
  1416.     elseif typeof(u) == "RBXScriptConnection" then
  1417.         return "nil --[[RBXScriptConnection " .. tostring(u) .. "]]"
  1418.     elseif typeof(u) == "RaycastResult" then
  1419.         return "nil --[[RaycastResult " .. tostring(u) .. "]]"
  1420.     elseif typeof(u) == "PathWaypoint" then
  1421.         return string.format("PathWaypoint.new(%s, %s)", v2s(u.Position), v2s(u.Action))
  1422.     else
  1423.         return typeof(u) .. ".new(" .. tostring(u) .. ")"
  1424.     end
  1425. end
  1426.  
  1427. --- Gets the player an instance is descended from
  1428. function getplayer(instance)
  1429.     for _, v in pairs(Players:GetPlayers()) do
  1430.         if v.Character and (instance:IsDescendantOf(v.Character) or instance == v.Character) then
  1431.             return v
  1432.         end
  1433.     end
  1434. end
  1435.  
  1436. --- value-to-path (in table)
  1437. function v2p(x, t, path, prev)
  1438.     if not path then
  1439.         path = ""
  1440.     end
  1441.     if not prev then
  1442.         prev = {}
  1443.     end
  1444.     if rawequal(x, t) then
  1445.         return true, ""
  1446.     end
  1447.     for i, v in pairs(t) do
  1448.         if rawequal(v, x) then
  1449.             if type(i) == "string" and i:match("^[%a_]+[%w_]*$") then
  1450.                 return true, (path .. "." .. i)
  1451.             else
  1452.                 return true, (path .. "[" .. v2s(i) .. "]")
  1453.             end
  1454.         end
  1455.         if type(v) == "table" then
  1456.             local duplicate = false
  1457.             for _, y in pairs(prev) do
  1458.                 if rawequal(y, v) then
  1459.                     duplicate = true
  1460.                 end
  1461.             end
  1462.             if not duplicate then
  1463.                 table.insert(prev, t)
  1464.                 local found
  1465.                 found, p = v2p(x, v, path, prev)
  1466.                 if found then
  1467.                     if type(i) == "string" and i:match("^[%a_]+[%w_]*$") then
  1468.                         return true, "." .. i .. p
  1469.                     else
  1470.                         return true, "[" .. v2s(i) .. "]" .. p
  1471.                     end
  1472.                 end
  1473.             end
  1474.         end
  1475.     end
  1476.     return false, ""
  1477. end
  1478.  
  1479. --- format s: string, byte encrypt (for weird symbols)
  1480. function formatstr(s)
  1481.     return '"' .. handlespecials(s) .. '"'
  1482. end
  1483.  
  1484. --- Adds 's to the text as a replacement to whitespace chars and other things because string.format can't yayeet
  1485. function handlespecials(s)
  1486.     local i = 0
  1487.     repeat
  1488.         i = i + 1
  1489.         local char = s:sub(i, i)
  1490.         if string.byte(char) then
  1491.             if char == "n" then
  1492.                 s = s:sub(0, i - 1) .. "n" .. s:sub(i + 1, -1)
  1493.                 i = i + 1
  1494.             elseif char == "t" then
  1495.                 s = s:sub(0, i - 1) .. "t" .. s:sub(i + 1, -1)
  1496.                 i = i + 1
  1497.             elseif char == "" then
  1498.                 s = s:sub(0, i - 1) .. "" .. s:sub(i + 1, -1)
  1499.                 i = i + 1
  1500.             elseif char == '"' then
  1501.                 s = s:sub(0, i - 1) .. '"' .. s:sub(i + 1, -1)
  1502.                 i = i + 1
  1503.             elseif string.byte(char) > 126 or string.byte(char) < 32 then
  1504.                 s = s:sub(0, i - 1) .. "" .. string.byte(char) .. s:sub(i + 1, -1)
  1505.                 i = i + #tostring(string.byte(char))
  1506.             end
  1507.         end
  1508.     until char == ""
  1509.     return s
  1510. end
  1511.  
  1512. --- finds script from 'src' from getinfo, returns nil if not found
  1513. --- @param src string
  1514. function getScriptFromSrc(src)
  1515.     local realPath
  1516.     local runningTest
  1517.     --- @type number
  1518.     local s, e
  1519.     local match = false
  1520.     if src:sub(1, 1) == "=" then
  1521.         realPath = game
  1522.         s = 2
  1523.     else
  1524.         runningTest = src:sub(2, e and e - 1 or -1)
  1525.         for _, v in pairs(getnilinstances()) do
  1526.             if v.Name == runningTest then
  1527.                 realPath = v
  1528.                 break
  1529.             end
  1530.         end
  1531.         s = #runningTest + 1
  1532.     end
  1533.     if realPath then
  1534.         e = src:sub(s, -1):find("%.")
  1535.         local i = 0
  1536.         repeat
  1537.             i += 1
  1538.             if not e then
  1539.                 runningTest = src:sub(s, -1)
  1540.                 local test = realPath.FindFirstChild(realPath, runningTest)
  1541.                 if test then
  1542.                     realPath = test
  1543.                 end
  1544.                 match = true
  1545.             else
  1546.                 runningTest = src:sub(s, e)
  1547.                 local test = realPath.FindFirstChild(realPath, runningTest)
  1548.                 local yeOld = e
  1549.                 if test then
  1550.                     realPath = test
  1551.                     s = e + 2
  1552.                     e = src:sub(e + 2, -1):find("%.")
  1553.                     e = e and e + yeOld or e
  1554.                 else
  1555.                     e = src:sub(e + 2, -1):find("%.")
  1556.                     e = e and e + yeOld or e
  1557.                 end
  1558.             end
  1559.         until match or i >= 50
  1560.     end
  1561.     return realPath
  1562. end
  1563.  
  1564. --- schedules the provided function (and calls it with any args after)
  1565. function schedule(f, ...)
  1566.     table.insert(scheduled, {f, ...})
  1567. end
  1568.  
  1569. --- the big (well tbh small now) boi task scheduler himself, handles p much anything as quicc as possible
  1570. function taskscheduler()
  1571.     if not toggle then
  1572.         scheduled = {}
  1573.         return
  1574.     end
  1575.     if #scheduled > 1000 then
  1576.         table.remove(scheduled, #scheduled)
  1577.     end
  1578.     if #scheduled > 0 then
  1579.         local currentf = scheduled[1]
  1580.         table.remove(scheduled, 1)
  1581.         if type(currentf) == "table" and type(currentf[1]) == "function" then
  1582.             pcall(unpack(currentf))
  1583.         end
  1584.     end
  1585. end
  1586.  
  1587. --- Handles remote logs
  1588. function remoteHandler(hookfunction, methodName, remote, args, func, calling)
  1589.     if remote:IsA("RemoteEvent") or remote:IsA("RemoteFunction") then
  1590.         if funcEnabled and not calling then
  1591.             _, calling = pcall(getScriptFromSrc, debug.getinfo(func).source)
  1592.         end
  1593.         coroutine.wrap(function()
  1594.             if remoteSignals[remote] then
  1595.                 remoteSignals[remote]:Fire(args)
  1596.             end
  1597.         end)()
  1598.         if autoblock then
  1599.             if excluding[remote] then
  1600.                 return
  1601.             end
  1602.             if not history[remote] then
  1603.                 history[remote] = {badOccurances = 0, lastCall = tick()}
  1604.             end
  1605.             if tick() - history[remote].lastCall < 1 then
  1606.                 history[remote].badOccurances += 1
  1607.                 return
  1608.             else
  1609.                 history[remote].badOccurances = 0
  1610.             end
  1611.             if history[remote].badOccurances > 3 then
  1612.                 excluding[remote] = true
  1613.                 return
  1614.             end
  1615.             history[remote].lastCall = tick()
  1616.         end
  1617.         local functionInfoStr
  1618.         local src
  1619.         if func and islclosure(func) then
  1620.             local functionInfo = {}
  1621.             pcall(function() functionInfo.info = debug.getinfo(func) end)
  1622.             pcall(function() functionInfo.constants = debug.getconstants(func) end)
  1623.             pcall(function() functionInfoStr = v2v{functionInfo = functionInfo} end)
  1624.             pcall(function() if type(calling) == "userdata" then src = calling end end)
  1625.         end
  1626.         if methodName:lower() == "fireserver" then
  1627.             newRemote("event", remote.Name, genScript(remote, table.unpack(args)), remote, functionInfoStr, (blocklist[remote] or blocklist[remote.Name]), src)
  1628.         elseif methodName:lower() == "invokeserver" then
  1629.             newRemote("function", remote.Name, genScript(remote, table.unpack(args)), remote, functionInfoStr, (blocklist[remote] or blocklist[remote.Name]), src)
  1630.         end
  1631.     end
  1632. end
  1633.  
  1634. --- Used for hookfunction
  1635. function hookRemote(remoteType, remote, ...)
  1636.     local args = {...}
  1637.     if remoteHooks[remote] then
  1638.         args = remoteHooks[remote](args)
  1639.     end
  1640.     if typeof(remote) == "Instance" and not (blacklist[remote] or blacklist[remote.Name]) then
  1641.         local func
  1642.         local calling
  1643.         if funcEnabled then
  1644.             func = debug.getinfo(4).func
  1645.             calling = useGetCallingScript and getcallingscript() or nil
  1646.         end
  1647.         schedule(remoteHandler, true, remoteType == "RemoteEvent" and "fireserver" or "invokeserver", remote, args, func, calling)
  1648.         if (blocklist[remote] or blocklist[remote.Name]) then
  1649.             return
  1650.         end
  1651.     end
  1652.     if remoteType == "RemoteEvent" then
  1653.         if remoteHooks[remote] then
  1654.             return originalEvent(remote, unpack(args))
  1655.         end
  1656.         return originalEvent(remote, ...)
  1657.     else
  1658.         if remoteHooks[remote] then
  1659.             return originalFunction(remote, unpack(args))
  1660.         end
  1661.         return originalFunction(remote, ...)
  1662.     end
  1663. end
  1664.  
  1665. local newnamecall = newcclosure(function(...)
  1666.     local args = {...}
  1667.     local methodName = getnamecallmethod()
  1668.     local remote = args[1]
  1669.     if (methodName:lower() == "invokeserver" or methodName:lower() == "fireserver") and not (blacklist[remote] or blacklist[remote.Name]) then
  1670.         if remoteHooks[remote] then
  1671.             args = remoteHooks[remote]({args, unpack(args, 2)})
  1672.         end
  1673.         local func
  1674.         local calling
  1675.         if funcEnabled then
  1676.             func = debug.getinfo(3).func
  1677.             calling = useGetCallingScript and getcallingscript() or nil
  1678.         end
  1679.         coroutine.wrap(function()
  1680.             schedule(remoteHandler, false, methodName, remote, {unpack(args, 2)}, func, calling)
  1681.         end)()
  1682.     end
  1683.     if typeof(remote) == "Instance" and (methodName:lower() == "invokeserver" or methodName:lower() == "fireserver") and (blocklist[remote] or blocklist[remote.Name]) then
  1684.         return nil
  1685.     elseif (methodName:lower() == "invokeserver" or methodName:lower() == "fireserver") and remoteHooks[remote] then
  1686.         return original(unpack(args))
  1687.     else
  1688.         return original(...)
  1689.     end
  1690. end)
  1691.  
  1692. local newFireServer = newcclosure(function(...) return hookRemote("RemoteEvent", ...) end)
  1693.  
  1694. local newInvokeServer = newcclosure(function(...) return hookRemote("RemoteFunction", ...) end)
  1695.  
  1696. --- Toggles on and off the remote spy
  1697. function toggleSpy()
  1698.     if not toggle then
  1699.         setreadonly(gm, false)
  1700.         if not original then
  1701.             original = gm.__namecall
  1702.             if not original then
  1703.                 warn("SimpleSpy: namecall method not found!n")
  1704.                 onToggleButtonClick()
  1705.                 return
  1706.             end
  1707.         end
  1708.         gm.__namecall = newnamecall
  1709.         originalEvent = hookfunction(remoteEvent.FireServer, newFireServer)
  1710.         originalFunction = hookfunction(remoteFunction.InvokeServer, newInvokeServer)
  1711.     else
  1712.         setreadonly(gm, false)
  1713.         gm.__namecall = original
  1714.         hookfunction(remoteEvent.FireServer, originalEvent)
  1715.         hookfunction(remoteFunction.InvokeServer, originalFunction)
  1716.     end
  1717. end
  1718.  
  1719. --- Toggles between the two remotespy methods (hookfunction currently = disabled)
  1720. function toggleSpyMethod()
  1721.     toggleSpy()
  1722.     toggle = not toggle
  1723. end
  1724.  
  1725. --- Shuts down the remote spy
  1726. function shutdown()
  1727.     if schedulerconnect then
  1728.         schedulerconnect:Disconnect()
  1729.     end
  1730.     for _, connection in pairs(connections) do
  1731.         coroutine.wrap(function()
  1732.             connection:Disconnect()
  1733.         end)()
  1734.     end
  1735.     setreadonly(gm, false)
  1736.     SimpleSpy2:Destroy()
  1737.     hookfunction(remoteEvent.FireServer, originalEvent)
  1738.     hookfunction(remoteFunction.InvokeServer, originalFunction)
  1739.     gm.__namecall = original
  1740.     _G.SimpleSpyExecuted = false
  1741. end
  1742.  
  1743. -- main
  1744. if not _G.SimpleSpyExecuted then
  1745.     local succeeded, err = pcall(function()
  1746.         _G.SimpleSpyShutdown = shutdown
  1747.         ContentProvider:PreloadAsync({"rbxassetid://6065821980", "rbxassetid://6065774948", "rbxassetid://6065821086", "rbxassetid://6065821596", ImageLabel, ImageLabel_2, ImageLabel_3})
  1748.         onToggleButtonClick()
  1749.         RemoteTemplate.Parent = nil
  1750.         FunctionTemplate.Parent = nil
  1751.         codebox = Highlight.new(CodeBox)
  1752.         codebox:setRaw("")
  1753.         getgenv().SimpleSpy = SimpleSpy
  1754.         TextLabel:GetPropertyChangedSignal("Text"):Connect(scaleToolTip)
  1755.         TopBar.InputBegan:Connect(onBarInput)
  1756.         MinimizeButton.MouseButton1Click:Connect(toggleMinimize)
  1757.         MaximizeButton.MouseButton1Click:Connect(toggleSideTray)
  1758.         Simple.MouseButton1Click:Connect(onToggleButtonClick)
  1759.         CloseButton.MouseEnter:Connect(onXButtonHover)
  1760.         CloseButton.MouseLeave:Connect(onXButtonUnhover)
  1761.         Simple.MouseEnter:Connect(onToggleButtonHover)
  1762.         Simple.MouseLeave:Connect(onToggleButtonUnhover)
  1763.         CloseButton.MouseButton1Click:Connect(shutdown)
  1764.         table.insert(connections, UserInputService.InputBegan:Connect(backgroundUserInput))
  1765.         table.insert(connections, Mouse.Move:Connect(mouseMoved))
  1766.         connectResize()
  1767.         SimpleSpy2.Enabled = true
  1768.         coroutine.wrap(function()
  1769.             wait(1)
  1770.             onToggleButtonUnhover()
  1771.         end)()
  1772.         schedulerconnect = RunService.Heartbeat:Connect(taskscheduler)
  1773.         if syn and syn.protect_gui then pcall(syn.protect_gui, SimpleSpy2) end
  1774.         SimpleSpy2.Parent = gethui and gethui() or CoreGui
  1775.     end)
  1776.     if succeeded then
  1777.         _G.SimpleSpyExecuted = true
  1778.     else
  1779.         warn("A fatal error has occured, SimpleSpy was unable to launch properly.nPlease DM this error message to @exx#9394:nn" .. tostring(err))
  1780.         SimpleSpy2:Destroy()
  1781.         hookfunction(remoteEvent.FireServer, originalEvent)
  1782.         hookfunction(remoteFunction.InvokeServer, originalFunction)
  1783.         gm.__namecall = original
  1784.         return
  1785.     end
  1786. else
  1787.     SimpleSpy2:Destroy()
  1788.     return
  1789. end
  1790.  
  1791. ----- ADD ONS ----- (easily add or remove additonal functionality to the RemoteSpy!)
  1792. --[[
  1793.     Some helpful things:
  1794.         - add your function in here, and create buttons for them through the 'newButton' function
  1795.         - the first argument provided is the TextButton the player clicks to run the function
  1796.         - generated scripts are generated when the namecall is initially fired and saved in remoteFrame objects
  1797.         - blacklisted remotes will be ignored directly in namecall (less lag)
  1798.         - the properties of a 'remoteFrame' object:
  1799.             {
  1800.                 Name: (string) The name of the Remote
  1801.                 GenScript: (string) The generated script that appears in the codebox (generated when namecall fired)
  1802.                 Source: (Instance (LocalScript)) The script that fired/invoked the remote
  1803.                 Remote: (Instance (RemoteEvent) | Instance (RemoteFunction)) The remote that was fired/invoked
  1804.                 Log: (Instance (TextButton)) The button being used for the remote (same as 'selected.Log')
  1805.             }
  1806.         - globals list: (contact @exx#9394 for more information or if you have suggestions for more to be added)
  1807.             - closed: (boolean) whether or not the GUI is currently minimized
  1808.             - logs: (table[remoteFrame]) full of remoteFrame objects (properties listed above)
  1809.             - selected: (remoteFrame) the currently selected remoteFrame (properties listed above)
  1810.             - blacklist: (string[] | Instance[] (RemoteEvent) | Instance[] (RemoteFunction)) an array of blacklisted names and remotes
  1811.             - codebox: (Instance (TextBox)) the textbox that holds all the code- cleared often
  1812. ]]
  1813. -- Copies the contents of the codebox
  1814. newButton(
  1815.     "Copy Code",
  1816.     function() return "Click to copy code" end,
  1817.     function()
  1818.         setclipboard(codebox:getString())
  1819.         TextLabel.Text = "Copied successfully!"
  1820.     end
  1821. )
  1822.  
  1823. --- Copies the source script (that fired the remote)
  1824. newButton(
  1825.     "Copy Remote",
  1826.     function() return "Click to copy the path of the remote" end,
  1827.     function()
  1828.         if selected then
  1829.             setclipboard(v2s(selected.Remote))
  1830.             TextLabel.Text = "Copied!"
  1831.         end
  1832.     end
  1833. )
  1834.  
  1835. -- Executes the contents of the codebox through loadstring
  1836. newButton(
  1837.     "Run Code",
  1838.     function() return "Click to execute code" end,
  1839.     function()
  1840.         local orText = "Click to execute code"
  1841.         TextLabel.Text = "Executing..."
  1842.         local succeeded = pcall(function() return loadstring(codebox:getString())() end)
  1843.         if succeeded then
  1844.             TextLabel.Text = "Executed successfully!"
  1845.         else
  1846.             TextLabel.Text = "Execution error!"
  1847.         end
  1848.     end
  1849. )
  1850.  
  1851. --- Gets the calling script (not super reliable but w/e)
  1852. newButton(
  1853.     "Get Script",
  1854.     function() return "Click to copy calling script to clipboardnWARNING: Not super reliable, nil == could not find" end,
  1855.     function()
  1856.         if selected then
  1857.             setclipboard(SimpleSpy:ValueToString(selected.Source))
  1858.             TextLabel.Text = "Done!"
  1859.         end
  1860.     end
  1861. )
  1862.  
  1863. --- Decompiles the script that fired the remote and puts it in the code box
  1864. newButton(
  1865.     "Function Info",
  1866.     function() return "Click to view calling function information" end,
  1867.     function()
  1868.         if selected then
  1869.             if selected.Function then
  1870.                 codebox:setRaw("-- Calling function infon-- Generated by the SimpleSpy serializernn" .. tostring(selected.Function))
  1871.             end
  1872.             TextLabel.Text = "Done! Function info generated by the SimpleSpy Serializer."
  1873.         end
  1874.     end
  1875. )
  1876.  
  1877. --- Clears the Remote logs
  1878. newButton(
  1879.     "Clr Logs",
  1880.     function() return "Click to clear logs" end,
  1881.     function()
  1882.         TextLabel.Text = "Clearing..."
  1883.         logs = {}
  1884.         for _, v in pairs(LogList:GetChildren()) do
  1885.             if not v:IsA("UIListLayout") then
  1886.                 v:Destroy()
  1887.             end
  1888.         end
  1889.         codebox:setRaw("")
  1890.         selected = nil
  1891.         TextLabel.Text = "Logs cleared!"
  1892.     end
  1893. )
  1894.  
  1895. --- Excludes the selected.Log Remote from the RemoteSpy
  1896. newButton(
  1897.     "Exclude (i)",
  1898.     function() return "Click to exclude this Remote" end,
  1899.     function()
  1900.         if selected then
  1901.             blacklist[selected.Remote] = true
  1902.             TextLabel.Text = "Excluded!"
  1903.         end
  1904.     end
  1905. )
  1906.  
  1907. --- Excludes all Remotes that share the same name as the selected.Log remote from the RemoteSpy
  1908. newButton(
  1909.     "Exclude (n)",
  1910.     function() return "Click to exclude all remotes with this name" end,
  1911.     function()
  1912.         if selected then
  1913.             blacklist[selected.Name] = true
  1914.             TextLabel.Text = "Excluded!"
  1915.         end
  1916.     end
  1917. )
  1918.  
  1919. --- clears blacklist
  1920. newButton(
  1921.     "Clr Blacklist",
  1922.     function() return "Click to clear the blacklist" end,
  1923.     function()
  1924.         blacklist = {}
  1925.         TextLabel.Text = "Blacklist cleared!"
  1926.     end
  1927. )
  1928.  
  1929. --- Prevents the selected.Log Remote from firing the server (still logged)
  1930. newButton(
  1931.     "Block (i)",
  1932.     function() return "Click to stop this remote from firing" end,
  1933.     function()
  1934.         if selected then
  1935.             blocklist[selected.Remote] = true
  1936.             TextLabel.Text = "Excluded!"
  1937.         end
  1938.     end
  1939. )
  1940.  
  1941. --- Prevents all remotes from firing that share the same name as the selected.Log remote from the RemoteSpy (still logged)
  1942. newButton(
  1943.     "Block (n)",
  1944.     function() return "Click to stop remotes with this name from firing" end,
  1945.     function()
  1946.         if selected then
  1947.             blocklist[selected.Name] = true
  1948.             TextLabel.Text = "Excluded!"
  1949.         end
  1950.     end
  1951. )
  1952.  
  1953. --- clears blacklist
  1954. newButton(
  1955.     "Clr Blocklist",
  1956.     function() return "Click to stop blocking remotes" end,
  1957.     function()
  1958.         blocklist = {}
  1959.         TextLabel.Text = "Blocklist cleared!"
  1960.     end
  1961. )
  1962.  
  1963. --- Attempts to decompile the source script
  1964. newButton(
  1965.     "Decompile",
  1966.     function() return "Attempts to decompile source scriptnWARNING: Not super reliable, nil == could not find" end,
  1967.     function()
  1968.         if selected then
  1969.             if selected.Source then
  1970.                 codebox:setRaw(decompile(selected.Source))
  1971.                 TextLabel.Text = "Done!"
  1972.             else
  1973.                 TextLabel.Text = "Source not found!"
  1974.             end
  1975.         end
  1976.     end
  1977. )
  1978.  
  1979. newButton(
  1980.     "Disable Info",
  1981.     function() return string.format("[%s] Toggle function info (because it can cause lag in some games)", funcEnabled and "ENABLED" or "DISABLED") end,
  1982.     function()
  1983.         funcEnabled = not funcEnabled
  1984.         TextLabel.Text = string.format("[%s] Toggle function info (because it can cause lag in some games)", funcEnabled and "ENABLED" or "DISABLED")
  1985.     end
  1986. )
  1987.  
  1988. newButton(
  1989.     "Autoblock",
  1990.     function() return string.format("[%s] [BETA] Intelligently detects and excludes spammy remote calls from logs", autoblock and "ENABLED" or "DISABLED") end,
  1991.     function()
  1992.         autoblock = not autoblock
  1993.         TextLabel.Text = string.format("[%s] [BETA] Intelligently detects and excludes spammy remote calls from logs", autoblock and "ENABLED" or "DISABLED")
  1994.         history = {}
  1995.         excluding = {}
  1996.     end
  1997. )
  1998.  
  1999. newButton(
  2000.     "CallingScript",
  2001.     function() return string.format("[%s] [UNSAFE] Uses 'getcallingscript' to get calling script for Decompile and GetScript. Much more reliable, but opens up SimpleSpy to detection and/or instability.", useGetCallingScript and "ENABLED" or "DISABLED") end,
  2002.     function()
  2003.         useGetCallingScript = not useGetCallingScript
  2004.         TextLabel.Text = string.format("[%s] [UNSAFE] Uses 'getcallingscript' to get calling script for Decompile and GetScript. Much more reliable, but opens up SimpleSpy to detection and/or instability.", useGetCallingScript and "ENABLED" or "DISABLED")
  2005.     end
  2006. )