Advertisement
ohusq

Untitled

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