ilovescripting

SimpleSpy

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