Vincent_Ablat

Remote spy

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