· 4 years ago · Jul 30, 2021, 05:28 AM
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
10if _G.SimpleSpyExecuted and type(_G.SimpleSpyShutdown) == "function" then
11 _G.SimpleSpyShutdown()
12end
13
14local Players = game:GetService("Players")
15local CoreGui = game:GetService("CoreGui")
16local 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
22local SimpleSpy2 = Instance.new("ScreenGui")
23local Background = Instance.new("Frame")
24local LeftPanel = Instance.new("Frame")
25local LogList = Instance.new("ScrollingFrame")
26local UIListLayout = Instance.new("UIListLayout")
27local RemoteTemplate = Instance.new("Frame")
28local ColorBar = Instance.new("Frame")
29local Text = Instance.new("TextLabel")
30local Button = Instance.new("TextButton")
31local RightPanel = Instance.new("Frame")
32local CodeBox = Instance.new("Frame")
33local ScrollingFrame = Instance.new("ScrollingFrame")
34local UIGridLayout = Instance.new("UIGridLayout")
35local FunctionTemplate = Instance.new("Frame")
36local ColorBar_2 = Instance.new("Frame")
37local Text_2 = Instance.new("TextLabel")
38local Button_2 = Instance.new("TextButton")
39local TopBar = Instance.new("Frame")
40local Simple = Instance.new("TextButton")
41local CloseButton = Instance.new("TextButton")
42local ImageLabel = Instance.new("ImageLabel")
43local MaximizeButton = Instance.new("TextButton")
44local ImageLabel_2 = Instance.new("ImageLabel")
45local MinimizeButton = Instance.new("TextButton")
46local ImageLabel_3 = Instance.new("ImageLabel")
47local ToolTip = Instance.new("Frame")
48local TextLabel = Instance.new("TextLabel")
49
50--Properties:
51
52SimpleSpy2.Name = "SimpleSpy2"
53SimpleSpy2.ResetOnSpawn = false
54
55Background.Name = "Background"
56Background.Parent = SimpleSpy2
57Background.BackgroundColor3 = Color3.new(1, 1, 1)
58Background.BackgroundTransparency = 1
59Background.Position = UDim2.new(0, 500, 0, 200)
60Background.Size = UDim2.new(0, 450, 0, 268)
61
62LeftPanel.Name = "LeftPanel"
63LeftPanel.Parent = Background
64LeftPanel.BackgroundColor3 = Color3.fromRGB(53, 52, 55)
65LeftPanel.BorderSizePixel = 0
66LeftPanel.Position = UDim2.new(0, 0, 0, 19)
67LeftPanel.Size = UDim2.new(0, 131, 0, 249)
68
69LogList.Name = "LogList"
70LogList.Parent = LeftPanel
71LogList.Active = true
72LogList.BackgroundColor3 = Color3.new(1, 1, 1)
73LogList.BackgroundTransparency = 1
74LogList.BorderSizePixel = 0
75LogList.Position = UDim2.new(0, 0, 0, 9)
76LogList.Size = UDim2.new(0, 131, 0, 232)
77LogList.CanvasSize = UDim2.new(0, 0, 0, 0)
78LogList.ScrollBarThickness = 4
79
80UIListLayout.Parent = LogList
81UIListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
82UIListLayout.SortOrder = Enum.SortOrder.LayoutOrder
83
84RemoteTemplate.Name = "RemoteTemplate"
85RemoteTemplate.Parent = LogList
86RemoteTemplate.BackgroundColor3 = Color3.new(1, 1, 1)
87RemoteTemplate.BackgroundTransparency = 1
88RemoteTemplate.Size = UDim2.new(0, 117, 0, 27)
89
90ColorBar.Name = "ColorBar"
91ColorBar.Parent = RemoteTemplate
92ColorBar.BackgroundColor3 = Color3.fromRGB(255, 242, 0)
93ColorBar.BorderSizePixel = 0
94ColorBar.Position = UDim2.new(0, 0, 0, 1)
95ColorBar.Size = UDim2.new(0, 7, 0, 18)
96ColorBar.ZIndex = 2
97
98Text.Name = "Text"
99Text.Parent = RemoteTemplate
100Text.BackgroundColor3 = Color3.new(1, 1, 1)
101Text.BackgroundTransparency = 1
102Text.Position = UDim2.new(0, 12, 0, 1)
103Text.Size = UDim2.new(0, 105, 0, 18)
104Text.ZIndex = 2
105Text.Font = Enum.Font.SourceSans
106Text.Text = "TEXT"
107Text.TextColor3 = Color3.new(1, 1, 1)
108Text.TextSize = 14
109Text.TextXAlignment = Enum.TextXAlignment.Left
110
111Button.Name = "Button"
112Button.Parent = RemoteTemplate
113Button.BackgroundColor3 = Color3.new(0, 0, 0)
114Button.BackgroundTransparency = 0.75
115Button.BorderColor3 = Color3.new(1, 1, 1)
116Button.Position = UDim2.new(0, 0, 0, 1)
117Button.Size = UDim2.new(0, 117, 0, 18)
118Button.AutoButtonColor = false
119Button.Font = Enum.Font.SourceSans
120Button.Text = ""
121Button.TextColor3 = Color3.new(0, 0, 0)
122Button.TextSize = 14
123
124RightPanel.Name = "RightPanel"
125RightPanel.Parent = Background
126RightPanel.BackgroundColor3 = Color3.fromRGB(37, 36, 38)
127RightPanel.BorderSizePixel = 0
128RightPanel.Position = UDim2.new(0, 131, 0, 19)
129RightPanel.Size = UDim2.new(0, 319, 0, 249)
130
131CodeBox.Name = "CodeBox"
132CodeBox.Parent = RightPanel
133CodeBox.BackgroundColor3 = Color3.new(0.0823529, 0.0745098, 0.0784314)
134CodeBox.BorderSizePixel = 0
135CodeBox.Size = UDim2.new(0, 319, 0, 119)
136
137ScrollingFrame.Parent = RightPanel
138ScrollingFrame.Active = true
139ScrollingFrame.BackgroundColor3 = Color3.new(1, 1, 1)
140ScrollingFrame.BackgroundTransparency = 1
141ScrollingFrame.Position = UDim2.new(0, 0, 0.5, 0)
142ScrollingFrame.Size = UDim2.new(1, 0, 0.5, -9)
143ScrollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0)
144ScrollingFrame.ScrollBarThickness = 4
145
146UIGridLayout.Parent = ScrollingFrame
147UIGridLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
148UIGridLayout.SortOrder = Enum.SortOrder.LayoutOrder
149UIGridLayout.CellPadding = UDim2.new(0, 0, 0, 0)
150UIGridLayout.CellSize = UDim2.new(0, 94, 0, 27)
151
152FunctionTemplate.Name = "FunctionTemplate"
153FunctionTemplate.Parent = ScrollingFrame
154FunctionTemplate.BackgroundColor3 = Color3.new(1, 1, 1)
155FunctionTemplate.BackgroundTransparency = 1
156FunctionTemplate.Size = UDim2.new(0, 117, 0, 23)
157
158ColorBar_2.Name = "ColorBar"
159ColorBar_2.Parent = FunctionTemplate
160ColorBar_2.BackgroundColor3 = Color3.new(1, 1, 1)
161ColorBar_2.BorderSizePixel = 0
162ColorBar_2.Position = UDim2.new(0, 7, 0, 10)
163ColorBar_2.Size = UDim2.new(0, 7, 0, 18)
164ColorBar_2.ZIndex = 3
165
166Text_2.Name = "Text"
167Text_2.Parent = FunctionTemplate
168Text_2.BackgroundColor3 = Color3.new(1, 1, 1)
169Text_2.BackgroundTransparency = 1
170Text_2.Position = UDim2.new(0, 19, 0, 10)
171Text_2.Size = UDim2.new(0, 69, 0, 18)
172Text_2.ZIndex = 2
173Text_2.Font = Enum.Font.SourceSans
174Text_2.Text = "TEXT"
175Text_2.TextColor3 = Color3.new(1, 1, 1)
176Text_2.TextSize = 14
177Text_2.TextStrokeColor3 = Color3.new(0.145098, 0.141176, 0.14902)
178Text_2.TextXAlignment = Enum.TextXAlignment.Left
179
180Button_2.Name = "Button"
181Button_2.Parent = FunctionTemplate
182Button_2.BackgroundColor3 = Color3.new(0, 0, 0)
183Button_2.BackgroundTransparency = 0.69999998807907
184Button_2.BorderColor3 = Color3.new(1, 1, 1)
185Button_2.Position = UDim2.new(0, 7, 0, 10)
186Button_2.Size = UDim2.new(0, 80, 0, 18)
187Button_2.AutoButtonColor = false
188Button_2.Font = Enum.Font.SourceSans
189Button_2.Text = ""
190Button_2.TextColor3 = Color3.new(0, 0, 0)
191Button_2.TextSize = 14
192
193TopBar.Name = "TopBar"
194TopBar.Parent = Background
195TopBar.BackgroundColor3 = Color3.fromRGB(37, 35, 38)
196TopBar.BorderSizePixel = 0
197TopBar.Size = UDim2.new(0, 450, 0, 19)
198
199Simple.Name = "Simple"
200Simple.Parent = TopBar
201Simple.BackgroundColor3 = Color3.new(1, 1, 1)
202Simple.AutoButtonColor = false
203Simple.BackgroundTransparency = 1
204Simple.Position = UDim2.new(0, 5, 0, 0)
205Simple.Size = UDim2.new(0, 57, 0, 18)
206Simple.Font = Enum.Font.SourceSansBold
207Simple.Text = "SimpleSpy"
208Simple.TextColor3 = Color3.new(1, 1, 1)
209Simple.TextSize = 14
210Simple.TextXAlignment = Enum.TextXAlignment.Left
211
212CloseButton.Name = "CloseButton"
213CloseButton.Parent = TopBar
214CloseButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
215CloseButton.BorderSizePixel = 0
216CloseButton.Position = UDim2.new(1, -19, 0, 0)
217CloseButton.Size = UDim2.new(0, 19, 0, 19)
218CloseButton.Font = Enum.Font.SourceSans
219CloseButton.Text = ""
220CloseButton.TextColor3 = Color3.new(0, 0, 0)
221CloseButton.TextSize = 14
222
223ImageLabel.Parent = CloseButton
224ImageLabel.BackgroundColor3 = Color3.new(1, 1, 1)
225ImageLabel.BackgroundTransparency = 1
226ImageLabel.Position = UDim2.new(0, 5, 0, 5)
227ImageLabel.Size = UDim2.new(0, 9, 0, 9)
228ImageLabel.Image = "http://www.roblox.com/asset/?id=5597086202"
229
230MaximizeButton.Name = "MaximizeButton"
231MaximizeButton.Parent = TopBar
232MaximizeButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
233MaximizeButton.BorderSizePixel = 0
234MaximizeButton.Position = UDim2.new(1, -38, 0, 0)
235MaximizeButton.Size = UDim2.new(0, 19, 0, 19)
236MaximizeButton.Font = Enum.Font.SourceSans
237MaximizeButton.Text = ""
238MaximizeButton.TextColor3 = Color3.new(0, 0, 0)
239MaximizeButton.TextSize = 14
240
241ImageLabel_2.Parent = MaximizeButton
242ImageLabel_2.BackgroundColor3 = Color3.new(1, 1, 1)
243ImageLabel_2.BackgroundTransparency = 1
244ImageLabel_2.Position = UDim2.new(0, 5, 0, 5)
245ImageLabel_2.Size = UDim2.new(0, 9, 0, 9)
246ImageLabel_2.Image = "http://www.roblox.com/asset/?id=5597108117"
247
248MinimizeButton.Name = "MinimizeButton"
249MinimizeButton.Parent = TopBar
250MinimizeButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
251MinimizeButton.BorderSizePixel = 0
252MinimizeButton.Position = UDim2.new(1, -57, 0, 0)
253MinimizeButton.Size = UDim2.new(0, 19, 0, 19)
254MinimizeButton.Font = Enum.Font.SourceSans
255MinimizeButton.Text = ""
256MinimizeButton.TextColor3 = Color3.new(0, 0, 0)
257MinimizeButton.TextSize = 14
258
259ImageLabel_3.Parent = MinimizeButton
260ImageLabel_3.BackgroundColor3 = Color3.new(1, 1, 1)
261ImageLabel_3.BackgroundTransparency = 1
262ImageLabel_3.Position = UDim2.new(0, 5, 0, 5)
263ImageLabel_3.Size = UDim2.new(0, 9, 0, 9)
264ImageLabel_3.Image = "http://www.roblox.com/asset/?id=5597105827"
265
266ToolTip.Name = "ToolTip"
267ToolTip.Parent = SimpleSpy2
268ToolTip.BackgroundColor3 = Color3.fromRGB(26, 26, 26)
269ToolTip.BackgroundTransparency = 0.1
270ToolTip.BorderColor3 = Color3.new(1, 1, 1)
271ToolTip.Size = UDim2.new(0, 200, 0, 50)
272ToolTip.ZIndex = 3
273ToolTip.Visible = false
274
275TextLabel.Parent = ToolTip
276TextLabel.BackgroundColor3 = Color3.new(1, 1, 1)
277TextLabel.BackgroundTransparency = 1
278TextLabel.Position = UDim2.new(0, 2, 0, 2)
279TextLabel.Size = UDim2.new(0, 196, 0, 46)
280TextLabel.ZIndex = 3
281TextLabel.Font = Enum.Font.SourceSans
282TextLabel.Text = "This is some slightly longer text."
283TextLabel.TextColor3 = Color3.new(1, 1, 1)
284TextLabel.TextSize = 14
285TextLabel.TextWrapped = true
286TextLabel.TextXAlignment = Enum.TextXAlignment.Left
287TextLabel.TextYAlignment = Enum.TextYAlignment.Top
288
289-------------------------------------------------------------------------------
290-- init
291local RunService = game:GetService("RunService")
292local UserInputService = game:GetService("UserInputService")
293local TweenService = game:GetService("TweenService")
294local ContentProvider = game:GetService("ContentProvider")
295local TextService = game:GetService("TextService")
296local Mouse
297
298local selectedColor = Color3.new(0.321569, 0.333333, 1)
299local deselectedColor = Color3.new(0.8, 0.8, 0.8)
300--- So things are descending
301local layoutOrderNum = 999999999
302--- Whether or not the gui is closing
303local mainClosing = false
304--- Whether or not the gui is closed (defaults to false)
305local closed = false
306--- Whether or not the sidebar is closing
307local sideClosing = false
308--- Whether or not the sidebar is closed (defaults to true but opens automatically on remote selection)
309local sideClosed = false
310--- Whether or not the code box is maximized (defaults to false)
311local maximized = false
312--- The event logs to be read from
313local logs = {}
314--- The event currently selected.Log (defaults to nil)
315local selected = nil
316--- The blacklist (can be a string name or the Remote Instance)
317local blacklist = {}
318--- The block list (can be a string name or the Remote Instance)
319local blocklist = {}
320--- Whether or not to add getNil function
321local getNil = false
322--- Array of remotes (and original functions) connected to
323local connectedRemotes = {}
324--- True = hookfunction, false = namecall
325local toggle = false
326local gm
327local original
328--- used to prevent recursives
329local prevTables = {}
330--- holds logs (for deletion)
331local remoteLogs = {}
332--- used for hookfunction
333local remoteEvent = Instance.new("RemoteEvent")
334--- used for hookfunction
335local remoteFunction = Instance.new("RemoteFunction")
336local originalEvent = remoteEvent.FireServer
337local originalFunction = remoteFunction.InvokeServer
338--- the maximum amount of remotes allowed in logs
339_G.SIMPLESPYCONFIG_MaxRemotes = 500
340--- how many spaces to indent
341local indent = 4
342--- used for task scheduler
343local scheduled = {}
344--- RBXScriptConnect of the task scheduler
345local schedulerconnect
346local SimpleSpy = {}
347local topstr = ""
348local bottomstr = ""
349local remotesFadeIn
350local rightFadeIn
351local codebox
352local p
353local getnilrequired = false
354
355-- autoblock variables
356local autoblock = false
357local history = {}
358local excluding = {}
359
360-- function info variables
361local funcEnabled = true
362
363-- remote hooking/connecting api variables
364local remoteSignals = {}
365local remoteHooks = {}
366
367-- original mouse icon
368local oldIcon
369
370-- if mouse inside gui
371local mouseInGui = false
372
373-- handy array of RBXScriptConnections to disconnect on shutdown
374local connections = {}
375
376-- whether or not SimpleSpy uses 'getcallingscript()' to get the script (default is false because detection)
377local useGetCallingScript = false
378
379--- used to enable/disable SimpleSpy's keyToString for remotes
380local 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
388function 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))"
392end
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
397function SimpleSpy:TableToVars(t)
398 assert(typeof(t) == "table", "table expected, got " .. typeof(t))
399 return v2v(t)
400end
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
405function 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})
411end
412
413--- Converts any value to a string, cannot preserve function contents
414--- @param value any
415--- @return string
416function SimpleSpy:ValueToString(value)
417 return v2s(value)
418end
419
420--- Generates the simplespy function info
421--- @param func function
422--- @return string
423function 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 }}
430end
431
432--- Gets the ScriptSignal for a specified remote being fired
433--- @param remote Instance
434function 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]
440end
441
442--- Allows for direct hooking of remotes **THIS CAN BE VERY DANGEROUS**
443--- @param remote Instance
444--- @param f function
445function 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
449end
450
451--- Blocks the specified remote instance/string
452--- @param remote any
453function SimpleSpy:BlockRemote(remote)
454 assert(typeof(remote) == "Instance" or typeof(remote) == "string", "Instance | string expected, got " .. typeof(remote))
455 blocklist[remote] = true
456end
457
458--- Excludes the specified remote from logs (instance/string)
459--- @param remote any
460function SimpleSpy:ExcludeRemote(remote)
461 assert(typeof(remote) == "Instance" or typeof(remote) == "string", "Instance | string expected, got " .. typeof(remote))
462 blacklist[remote] = true
463end
464
465--- Creates a new ScriptSignal that can be connected to and fired
466--- @return table
467function 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 }
508end
509
510--- Prevents remote spam from causing lag (clears logs after `_G.SIMPLESPYCONFIG_MaxRemotes` or 500 remotes)
511function 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
532end
533
534--- Scales the ToolTip to fit containing text
535function 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)
539end
540
541--- Executed when the toggle button (the SimpleSpy logo) is hovered over
542function 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
548end
549
550--- Executed when the toggle button is unhovered over
551function onToggleButtonUnhover()
552 TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(255, 255, 255)}):Play()
553end
554
555--- Executed when the X button is hovered over
556function onXButtonHover()
557 TweenService:Create(CloseButton, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(255, 60, 60)}):Play()
558end
559
560--- Executed when the X button is unhovered over
561function onXButtonUnhover()
562 TweenService:Create(CloseButton, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(37, 36, 38)}):Play()
563end
564
565--- Toggles the remote spy method (when button clicked)
566function 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()
573end
574
575--- Reconnects bringBackOnResize if the current viewport changes and also connects it initially
576function 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)
584end
585
586--- Brings gui back if it gets lost offscreen (connected to the camera viewport changing)
587function 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()
612end
613
614--- Drags gui (so long as mouse is held down)
615--- @param input InputObject
616function 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
658end
659
660--- Fades out the table of elements (and makes them invisible), returns a function to make them visible again
661function 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
707end
708
709--- Expands and minimizes the gui (closed is the toggle boolean)
710function 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
735end
736
737--- Expands and minimizes the sidebar (sideClosed is the toggle boolean)
738function 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
763end
764
765--- Expands code box to fit screen for more convenient viewing
766function 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
799end
800
801--- Checks if cursor is within resize range
802--- @param p Vector2
803function 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
815end
816
817--- Checks if cursor is within dragging range
818--- @param p Vector2
819function 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
826end
827
828--- Called when mouse enters SimpleSpy
829function 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)
855end
856
857--- Called when mouse moves
858function 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
870end
871
872--- Adjusts the ui elements to the 'Maximized' size
873function 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()
883end
884
885--- Adjusts the ui elements to close the side
886function 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()
896end
897
898--- Ensures size is within screensize limitations
899function 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)
916end
917
918--- Called on user input while mouse in 'Background' frame
919--- @param input InputObject
920function 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
957end
958
959--- Gets the player an instance is descended from
960function 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
966end
967
968--- Runs on MouseButton1Click of an event frame
969function 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
986end
987
988--- Updates the canvas size to fit the current amount of function buttons
989function updateFunctionCanvas()
990 ScrollingFrame.CanvasSize = UDim2.fromOffset(UIGridLayout.AbsoluteContentSize.X, UIGridLayout.AbsoluteContentSize.Y)
991end
992
993--- Updates the canvas size to fit the amount of current remotes
994function updateRemoteCanvas()
995 LogList.CanvasSize = UDim2.fromOffset(UIListLayout.AbsoluteContentSize.X, UIListLayout.AbsoluteContentSize.Y)
996end
997
998--- Allows for toggling of the tooltip and easy setting of le description
999--- @param enable boolean
1000--- @param text string
1001function 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
1039end
1040
1041--- Creates new function button (below codebox)
1042--- @param name string
1043---@param description function
1044---@param onClick function
1045function 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()
1062end
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
1071function 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()
1107end
1108
1109--- Generates a script from the provided arguments (first has to be remote path)
1110function 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
1167end
1168
1169--- value-to-string: value, string (out), level (indentation), parent table, var name, is from tovar
1170function 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
1202end
1203
1204--- value-to-variable
1205--- @param t any
1206function 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
1232end
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
1245function 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 .. "}"
1303end
1304
1305--- key-to-string
1306function 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, ...)
1319end
1320
1321--- function-to-string
1322function 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) .. "]]"
1342end
1343
1344--- instance-to-path
1345--- @param i userdata
1346function 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
1402end
1403
1404--- userdata-to-string: userdata
1405--- @param u userdata
1406function 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
1496end
1497
1498--- Gets the player an instance is descended from
1499function 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
1505end
1506
1507--- value-to-path (in table)
1508function 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, ""
1548end
1549
1550--- format s: string, byte encrypt (for weird symbols)
1551function 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 "")
1557end
1558
1559--- Adds \'s to the text as a replacement to whitespace chars and other things because string.format can't yayeet
1560function 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)
1588end
1589
1590-- safe (ish) tostring
1591function 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)
1603end
1604
1605--- finds script from 'src' from getinfo, returns nil if not found
1606--- @param src string
1607function 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
1655end
1656
1657--- schedules the provided function (and calls it with any args after)
1658function schedule(f, ...)
1659 table.insert(scheduled, {f, ...})
1660end
1661
1662--- yields the current thread until the scheduler gives the ok
1663function scheduleWait()
1664 local thread = coroutine.running()
1665 schedule(function()
1666 coroutine.resume(thread)
1667 end)
1668 coroutine.yield()
1669end
1670
1671--- the big (well tbh small now) boi task scheduler himself, handles p much anything as quicc as possible
1672function 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
1687end
1688
1689--- Handles remote logs
1690function 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
1738end
1739
1740--- Used for hookfunction
1741function 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
1769end
1770
1771local 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
1795end, original)
1796
1797local newFireServer = newcclosure(function(...) return hookRemote("RemoteEvent", ...) end, originalEvent)
1798
1799local newInvokeServer = newcclosure(function(...) return hookRemote("RemoteFunction", ...) end, originalFunction)
1800
1801--- Toggles on and off the remote spy
1802function 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
1835end
1836
1837--- Toggles between the two remotespy methods (hookfunction currently = disabled)
1838function toggleSpyMethod()
1839 toggleSpy()
1840 toggle = not toggle
1841end
1842
1843--- Shuts down the remote spy
1844function 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
1867end
1868
1869-- main
1870if 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
1935else
1936 SimpleSpy2:Destroy()
1937 return
1938end
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
1963newButton(
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)
1973newButton(
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
1985newButton(
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)
2001newButton(
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
2013newButton(
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
2027newButton(
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
2045newButton(
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
2057newButton(
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
2069newButton(
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)
2079newButton(
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)
2091newButton(
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
2103newButton(
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
2113newButton(
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
2128newButton(
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
2137newButton(
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
2148newButton(
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
2157newButton(
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)