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