local Dehashed_Remotes = {} local Hashed_Remotes = game:GetService("ReplicatedStorage").REM for i,v in pairs(require(game:GetService("ReplicatedFirst").Client)["CachedRemotes"]) do if Hashed_Remotes:FindFirstChild(v) then Dehashed_Remotes[v] = i end end if getgenv().SimpleSpyExecuted and type(getgenv().SimpleSpyShutdown) == "function" then getgenv().SimpleSpyShutdown() end local configs = { logcheckcaller = false, autoblock = false, funcEnabled = true, logmetamethod = false, supersecretdevtoggle = false } local game = game local workspace = workspace local table = table local math = math local task = task local coroutine = coroutine local string = string local Color3 = Color3 local Instance = Instance local lower = string.lower local round = math.round local wrap = coroutine.wrap local running = coroutine.running local resume = coroutine.resume local status = coroutine.status local yield = coroutine.yield local create = coroutine.create local CurrentCamera = workspace.CurrentCamera local tostring = tostring local tonumber = tonumber local delay = task.delay local function Create(instance, properties, children) local obj = Instance.new(instance) for i, v in next, properties or {} do obj[i] = v for _, child in next, children or {} do child.Parent = obj; end end return obj; end local function SafeInstance(instace) if cloneref then return cloneref(instace) end return instace end local function SafeGetService(service) if cloneref then return cloneref(game:GetService(service)) end return game:GetService(service) end local CoreGui = SafeGetService("CoreGui") local Players = SafeGetService("Players") local RunService = SafeGetService("RunService") local UserInputService = SafeGetService("UserInputService") local TweenService = SafeGetService("TweenService") local ContentProvider = SafeGetService("ContentProvider") local TextService = SafeGetService("TextService") local http = SafeGetService("HttpService") local function ErrorPrompt(Message,state) if getrenv then local ErrorPrompt = getrenv().require(CoreGui:WaitForChild("RobloxGui"):WaitForChild("Modules"):WaitForChild("ErrorPrompt")) -- File can be located in your roblox folder (C:\Users\%Username%\AppData\Local\Roblox\Versions\whateverversionitis\ExtraContent\scripts\CoreScripts\Modules) local prompt = ErrorPrompt.new("Default",{HideErrorCode = true}) local ErrorStoarge = Create("ScreenGui",{Parent = CoreGui,ResetOnSpawn = false}) prompt:setParent(ErrorStoarge) prompt:setErrorTitle("Simple Spy V3 Error") prompt:updateButtons({{ Text = "Proceed", Callback = function(...) prompt:_close() ErrorStoarge:Destroy() state = false end, Primary = true }}, 'Default') prompt:_open(Message) if state then repeat task.wait() until not state end else warn(Message) end end local getcustomasset = getsynasset or getcustomasset local Highlight = (isfile and loadfile and isfile("Highlight.lua") and loadfile("Highlight.lua")()) or loadstring(game:HttpGet("https://raw.githubusercontent.com/78n/SimpleSpy/main/Highlight.lua"))() ---- GENERATED (kinda sorta mostly) BY GUI to LUA ---- -- Instances: local SimpleSpy3 = Create("ScreenGui",{Name = "SimpleSpy3",ResetOnSpawn = false}) local Storage = Create("Folder",{Name = "Storage",Parent = SimpleSpy3}) local Background = Create("Frame",{Name = "Background",Parent = SimpleSpy3,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Position = UDim2.new(0, 500, 0, 200),Size = UDim2.new(0, 450, 0, 268)}) local LeftPanel = Create("Frame",{Name = "LeftPanel",Parent = Background,BackgroundColor3 = Color3.fromRGB(53, 52, 55),BorderSizePixel = 0,Position = UDim2.new(0, 0, 0, 19),Size = UDim2.new(0, 131, 0, 249)}) local LogList = Create("ScrollingFrame",{Name = "LogList",Parent = LeftPanel,Active = true,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,BorderSizePixel = 0,Position = UDim2.new(0, 0, 0, 9),Size = UDim2.new(0, 131, 0, 232),CanvasSize = UDim2.new(0, 0, 0, 0),ScrollBarThickness = 4}) local UIListLayout = Create("UIListLayout",{Parent = LogList,HorizontalAlignment = Enum.HorizontalAlignment.Center,SortOrder = Enum.SortOrder.LayoutOrder}) local RightPanel = Instance.new("Frame") local CodeBox = Instance.new("Frame") local ScrollingFrame = Instance.new("ScrollingFrame") local UIGridLayout = Instance.new("UIGridLayout") local TopBar = Instance.new("Frame") local Simple = Instance.new("TextButton") local CloseButton = Instance.new("TextButton") local ImageLabel = Instance.new("ImageLabel") local MaximizeButton = Instance.new("TextButton") local ImageLabel_2 = Instance.new("ImageLabel") local MinimizeButton = Instance.new("TextButton") local ImageLabel_3 = Instance.new("ImageLabel") local ToolTip = Instance.new("Frame") local TextLabel = Instance.new("TextLabel") --Properties: RightPanel.Name = "RightPanel" RightPanel.Parent = Background RightPanel.BackgroundColor3 = Color3.fromRGB(37, 36, 38) RightPanel.BorderSizePixel = 0 RightPanel.Position = UDim2.new(0, 131, 0, 19) RightPanel.Size = UDim2.new(0, 319, 0, 249) CodeBox.Name = "CodeBox" CodeBox.Parent = RightPanel CodeBox.BackgroundColor3 = Color3.new(0.0823529, 0.0745098, 0.0784314) CodeBox.BorderSizePixel = 0 CodeBox.Size = UDim2.new(0, 319, 0, 119) ScrollingFrame.Parent = RightPanel ScrollingFrame.Active = true ScrollingFrame.BackgroundColor3 = Color3.new(1, 1, 1) ScrollingFrame.BackgroundTransparency = 1 ScrollingFrame.Position = UDim2.new(0, 0, 0.5, 0) ScrollingFrame.Size = UDim2.new(1, 0, 0.5, -9) ScrollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0) ScrollingFrame.ScrollBarThickness = 4 UIGridLayout.Parent = ScrollingFrame UIGridLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center UIGridLayout.SortOrder = Enum.SortOrder.LayoutOrder UIGridLayout.CellPadding = UDim2.new(0, 0, 0, 0) UIGridLayout.CellSize = UDim2.new(0, 94, 0, 27) TopBar.Name = "TopBar" TopBar.Parent = Background TopBar.BackgroundColor3 = Color3.fromRGB(37, 35, 38) TopBar.BorderSizePixel = 0 TopBar.Size = UDim2.new(0, 450, 0, 19) Simple.Name = "Simple" Simple.Parent = TopBar Simple.BackgroundColor3 = Color3.new(1, 1, 1) Simple.AutoButtonColor = false Simple.BackgroundTransparency = 1 Simple.Position = UDim2.new(0, 5, 0, 0) Simple.Size = UDim2.new(0, 57, 0, 18) Simple.Font = Enum.Font.SourceSansBold Simple.Text = "SimpleSpy" Simple.TextColor3 = Color3.new(1, 1, 1) Simple.TextSize = 14 Simple.TextXAlignment = Enum.TextXAlignment.Left CloseButton.Name = "CloseButton" CloseButton.Parent = TopBar CloseButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902) CloseButton.BorderSizePixel = 0 CloseButton.Position = UDim2.new(1, -19, 0, 0) CloseButton.Size = UDim2.new(0, 19, 0, 19) CloseButton.Font = Enum.Font.SourceSans CloseButton.Text = "" CloseButton.TextColor3 = Color3.new(0, 0, 0) CloseButton.TextSize = 14 ImageLabel.Parent = CloseButton ImageLabel.BackgroundColor3 = Color3.new(1, 1, 1) ImageLabel.BackgroundTransparency = 1 ImageLabel.Position = UDim2.new(0, 5, 0, 5) ImageLabel.Size = UDim2.new(0, 9, 0, 9) ImageLabel.Image = "http://www.roblox.com/asset/?id=5597086202" MaximizeButton.Name = "MaximizeButton" MaximizeButton.Parent = TopBar MaximizeButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902) MaximizeButton.BorderSizePixel = 0 MaximizeButton.Position = UDim2.new(1, -38, 0, 0) MaximizeButton.Size = UDim2.new(0, 19, 0, 19) MaximizeButton.Font = Enum.Font.SourceSans MaximizeButton.Text = "" MaximizeButton.TextColor3 = Color3.new(0, 0, 0) MaximizeButton.TextSize = 14 ImageLabel_2.Parent = MaximizeButton ImageLabel_2.BackgroundColor3 = Color3.new(1, 1, 1) ImageLabel_2.BackgroundTransparency = 1 ImageLabel_2.Position = UDim2.new(0, 5, 0, 5) ImageLabel_2.Size = UDim2.new(0, 9, 0, 9) ImageLabel_2.Image = "http://www.roblox.com/asset/?id=5597108117" MinimizeButton.Name = "MinimizeButton" MinimizeButton.Parent = TopBar MinimizeButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902) MinimizeButton.BorderSizePixel = 0 MinimizeButton.Position = UDim2.new(1, -57, 0, 0) MinimizeButton.Size = UDim2.new(0, 19, 0, 19) MinimizeButton.Font = Enum.Font.SourceSans MinimizeButton.Text = "" MinimizeButton.TextColor3 = Color3.new(0, 0, 0) MinimizeButton.TextSize = 14 ImageLabel_3.Parent = MinimizeButton ImageLabel_3.BackgroundColor3 = Color3.new(1, 1, 1) ImageLabel_3.BackgroundTransparency = 1 ImageLabel_3.Position = UDim2.new(0, 5, 0, 5) ImageLabel_3.Size = UDim2.new(0, 9, 0, 9) ImageLabel_3.Image = "http://www.roblox.com/asset/?id=5597105827" ToolTip.Name = "ToolTip" ToolTip.Parent = SimpleSpy3 ToolTip.BackgroundColor3 = Color3.fromRGB(26, 26, 26) ToolTip.BackgroundTransparency = 0.1 ToolTip.BorderColor3 = Color3.new(1, 1, 1) ToolTip.Size = UDim2.new(0, 200, 0, 50) ToolTip.ZIndex = 3 ToolTip.Visible = false TextLabel.Parent = ToolTip TextLabel.BackgroundColor3 = Color3.new(1, 1, 1) TextLabel.BackgroundTransparency = 1 TextLabel.Position = UDim2.new(0, 2, 0, 2) TextLabel.Size = UDim2.new(0, 196, 0, 46) TextLabel.ZIndex = 3 TextLabel.Font = Enum.Font.SourceSans TextLabel.Text = "This is some slightly longer text." TextLabel.TextColor3 = Color3.new(1, 1, 1) TextLabel.TextSize = 14 TextLabel.TextWrapped = true TextLabel.TextXAlignment = Enum.TextXAlignment.Left TextLabel.TextYAlignment = Enum.TextYAlignment.Top ------------------------------------------------------------------------------- -- init local Mouse local selectedColor = Color3.new(0.321569, 0.333333, 1) local deselectedColor = Color3.new(0.8, 0.8, 0.8) --- So things are descending local layoutOrderNum = 999999999 --- Whether or not the gui is closing local mainClosing = false --- Whether or not the gui is closed (defaults to false) local closed = false --- Whether or not the sidebar is closing local sideClosing = false --- Whether or not the sidebar is closed (defaults to true but opens automatically on remote selection) local sideClosed = false --- Whether or not the code box is maximized (defaults to false) local maximized = false --- The event logs to be read from local logs = {} --- The event currently selected.Log (defaults to nil) local selected = nil --- The blacklist (can be a string name or the Remote Instance) local blacklist = {} --- The block list (can be a string name or the Remote Instance) local blocklist = {} --- Whether or not to add getNil function local getNil = false --- Array of remotes (and original functions) connected to local connectedRemotes = {} --- True = hookfunction, false = namecall local toggle = false --- used to prevent recursives local prevTables = {} --- holds logs (for deletion) local remoteLogs = {} --- used for hookfunction getgenv().SIMPLESPYCONFIG_MaxRemotes = 300 local indent = 4 local scheduled = {} local schedulerconnect local SimpleSpy = {} local topstr = "" local bottomstr = "" local remotesFadeIn local rightFadeIn local codebox local oldIcon local p local getnilrequired = false -- autoblock variables local history = {} local excluding = {} -- remote hooking/connecting api variables local remoteSignals = {} -- if mouse inside gui local mouseInGui = false -- handy array of RBXScriptConnections to disconnect on shutdown local function jsone(str) return http:JSONEncode(str) end local function jsond(str) return http:JSONDecode(str) end local connections = {} local DecompiledScripts = {} local writefiletoggle = false local originalnamecall local remoteEvent = Instance.new("RemoteEvent",Storage) local remoteFunction = Instance.new("RemoteFunction",Storage) local originalEvent = remoteEvent.FireServer local originalFunction = remoteFunction.InvokeServer local methodtypes = { ["fireserver"] = true, ["invokeserver"] = true } local getinfolevel = 3 if identifyexecutor then local _, version = identifyexecutor() if (version and version:sub(1, 2) == 'v3') then getinfolevel = 2 end end local cachedconfigs = isfile and readfile and isfile("SimpleSpy//Settings.json") and jsond(readfile("SimpleSpy//Settings.json")) if cachedconfigs then for i,v in next, configs do if cachedconfigs[i] == nil then cachedconfigs[i] = v end end configs = cachedconfigs end if makefolder and isfolder and isfile and writefile then if not isfolder("SimpleSpy") then makefolder("SimpleSpy") end if not isfolder("SimpleSpy//Assets") then makefolder("SimpleSpy//Assets") end if not isfile("SimpleSpy//Settings.json") then writefile("SimpleSpy//Settings.json",jsone(configs)) end wrap(function() repeat wait(6) writefile("SimpleSpy//Settings.json",jsone(configs)) until not writefiletoggle end)() end --- 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`) --- @param method string --- @param args any[] --- @return string function SimpleSpy:ArgsToString(method, args) assert(typeof(method) == "string", "string expected, got " .. typeof(method)) assert(typeof(args) == "table", "table expected, got " .. typeof(args)) return v2v({args = args}) .. "\n\n" .. method .. "(unpack(args))" end --- Converts a value to variables with the specified index as the variable name (if nil/invalid then the name will be assigned automatically) --- @param t any[] --- @return string function SimpleSpy:TableToVars(t) assert(typeof(t) == "table", "table expected, got " .. typeof(t)) return v2v(t) end --- Converts a value to a variable with the specified `variablename` (if nil/invalid then the name will be assigned automatically) --- @param value any --- @return string function SimpleSpy:ValueToVar(value, variablename) assert(variablename == nil or typeof(variablename) == "string", "string expected, got " .. typeof(variablename)) if not variablename then variablename = 1 end return v2v({[variablename] = value}) end --- Converts any value to a string, cannot preserve function contents --- @param value any --- @return string function SimpleSpy:ValueToString(value) return v2s(value) end --- Gets the ScriptSignal for a specified remote being fired --- @param remote Instance function SimpleSpy:GetRemoteFiredSignal(remote) assert(typeof(remote) == "Instance", "Instance expected, got " .. typeof(remote)) if not remoteSignals[remote] then remoteSignals[remote] = newSignal() end return remoteSignals[remote] end --- Blocks the specified remote instance/string --- @param remote any function SimpleSpy:BlockRemote(remote) assert(typeof(remote) == "Instance" or typeof(remote) == "string", "Instance | string expected, got " .. typeof(remote)) blocklist[remote] = true end --- Excludes the specified remote from logs (instance/string) --- @param remote any function SimpleSpy:ExcludeRemote(remote) assert(typeof(remote) == "Instance" or typeof(remote) == "string", "Instance | string expected, got " .. typeof(remote)) blacklist[remote] = true end --- Creates a new ScriptSignal that can be connected to and fired --- @return table function newSignal() local connected = {} return { Connect = function(self, f) assert(connected, "Signal is closed") connected[tostring(f)] = f return setmetatable({ Connected = true, Disconnect = function(self) if not connected then warn("Signal is already closed") end self.Connected = false connected[tostring(f)] = nil end }, { __index = function(self, i) if i == "Connected" then return not not connected[tostring(f)] end end }) end, Wait = function(self) local thread = running() local connection connection = self:Connect(function() connection:Disconnect() if status(thread) == "suspended" then resume(thread) end end) yield() end, Fire = function(self, ...) for _, f in next, connected do wrap(f)(...) end end } end --- Prevents remote spam from causing lag (clears logs after `getgenv().SIMPLESPYCONFIG_MaxRemotes` or 500 remotes) function clean() local max = getgenv().SIMPLESPYCONFIG_MaxRemotes if not typeof(max) == "number" and math.floor(max) ~= max then max = 500 end if #remoteLogs > max then for i = 100, #remoteLogs do local v = remoteLogs[i] if typeof(v[1]) == "RBXScriptConnection" then v[1]:Disconnect() end if typeof(v[2]) == "Instance" then v[2]:Destroy() end end local newLogs = {} for i = 1, 100 do table.insert(newLogs, remoteLogs[i]) end remoteLogs = newLogs end end --- Scales the ToolTip to fit containing text function scaleToolTip() local size = TextService:GetTextSize(TextLabel.Text, TextLabel.TextSize, TextLabel.Font, Vector2.new(196, math.huge)) TextLabel.Size = UDim2.new(0, size.X, 0, size.Y) ToolTip.Size = UDim2.new(0, size.X + 4, 0, size.Y + 4) end --- Executed when the toggle button (the SimpleSpy logo) is hovered over function onToggleButtonHover() if not toggle then TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(252, 51, 51)}):Play() else TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(68, 206, 91)}):Play() end end --- Executed when the toggle button is unhovered over function onToggleButtonUnhover() TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(255, 255, 255)}):Play() end --- Executed when the X button is hovered over function onXButtonHover() TweenService:Create(CloseButton, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(255, 60, 60)}):Play() end --- Executed when the X button is unhovered over function onXButtonUnhover() TweenService:Create(CloseButton, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(37, 36, 38)}):Play() end --- Toggles the remote spy method (when button clicked) function onToggleButtonClick() if toggle then TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(252, 51, 51)}):Play() else TweenService:Create(Simple, TweenInfo.new(0.5), {TextColor3 = Color3.fromRGB(68, 206, 91)}):Play() end toggleSpyMethod() end --- Reconnects bringBackOnResize if the current viewport changes and also connects it initially function connectResize() local lastCam = CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(bringBackOnResize) workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function() lastCam:Disconnect() if CurrentCamera then if typelastCam == 'Connection' then lastCam:Disconnect() end lastCam = CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(bringBackOnResize) end end) end --- Brings gui back if it gets lost offscreen (connected to the camera viewport changing) function bringBackOnResize() validateSize() if sideClosed then minimizeSize() else maximizeSize() end local currentX = Background.AbsolutePosition.X local currentY = Background.AbsolutePosition.Y local viewportSize = CurrentCamera.ViewportSize if (currentX < 0) or (currentX > (viewportSize.X - (sideClosed and 131 or Background.AbsoluteSize.X))) then if currentX < 0 then currentX = 0 else currentX = viewportSize.X - (sideClosed and 131 or Background.AbsoluteSize.X) end end if (currentY < 0) or (currentY > (viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36)) then if currentY < 0 then currentY = 0 else currentY = viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36 end end TweenService.Create(TweenService, Background, TweenInfo.new(0.1), {Position = UDim2.new(0, currentX, 0, currentY)}):Play() end --- Drags gui (so long as mouse is held down) --- @param input InputObject function onBarInput(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then local lastPos = UserInputService.GetMouseLocation(UserInputService) local mainPos = Background.AbsolutePosition local offset = mainPos - lastPos local currentPos = offset + lastPos connections["drag"] = RunService.RenderStepped:Connect(function() local newPos = UserInputService.GetMouseLocation(UserInputService) if newPos ~= lastPos then local currentX = (offset + newPos).X local currentY = (offset + newPos).Y local viewportSize = CurrentCamera.ViewportSize if (currentX < 0 and currentX < currentPos.X) or (currentX > (viewportSize.X - (sideClosed and 131 or TopBar.AbsoluteSize.X)) and currentX > currentPos.X) then if currentX < 0 then currentX = 0 else currentX = viewportSize.X - (sideClosed and 131 or TopBar.AbsoluteSize.X) end end if (currentY < 0 and currentY < currentPos.Y) or (currentY > (viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36) and currentY > currentPos.Y) then if currentY < 0 then currentY = 0 else currentY = viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36 end end currentPos = Vector2.new(currentX, currentY) lastPos = newPos TweenService.Create(TweenService, Background, TweenInfo.new(0.1), {Position = UDim2.new(0, currentPos.X, 0, currentPos.Y)}):Play() end -- if input.UserInputState ~= Enum.UserInputState.Begin then -- RunService.UnbindFromRenderStep(RunService, "drag") -- end end) table.insert(connections, UserInputService.InputEnded:Connect(function(inputE) if input == inputE then connections["drag"]:Disconnect() end end)) end end --- Fades out the table of elements (and makes them invisible), returns a function to make them visible again function fadeOut(elements) local data = {} for _, v in next, elements do if typeof(v) == "Instance" and v:IsA("GuiObject") and v.Visible then wrap(function() data[v] = { BackgroundTransparency = v.BackgroundTransparency } TweenService:Create(v, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play() if v:IsA("TextBox") or v:IsA("TextButton") or v:IsA("TextLabel") then data[v].TextTransparency = v.TextTransparency TweenService:Create(v, TweenInfo.new(0.5), {TextTransparency = 1}):Play() elseif v:IsA("ImageButton") or v:IsA("ImageLabel") then data[v].ImageTransparency = v.ImageTransparency TweenService:Create(v, TweenInfo.new(0.5), {ImageTransparency = 1}):Play() end delay(0.5,function() v.Visible = false for i, x in next, data[v] do v[i] = x end data[v] = true end) end)() end end return function() for i, _ in next, data do wrap(function() local properties = { BackgroundTransparency = i.BackgroundTransparency } i.BackgroundTransparency = 1 TweenService:Create(i, TweenInfo.new(0.5), {BackgroundTransparency = properties.BackgroundTransparency}):Play() if i:IsA("TextBox") or i:IsA("TextButton") or i:IsA("TextLabel") then properties.TextTransparency = i.TextTransparency i.TextTransparency = 1 TweenService:Create(i, TweenInfo.new(0.5), {TextTransparency = properties.TextTransparency}):Play() elseif i:IsA("ImageButton") or i:IsA("ImageLabel") then properties.ImageTransparency = i.ImageTransparency i.ImageTransparency = 1 TweenService:Create(i, TweenInfo.new(0.5), {ImageTransparency = properties.ImageTransparency}):Play() end i.Visible = true end)() end end end --- Expands and minimizes the gui (closed is the toggle boolean) function toggleMinimize(override) if mainClosing and not override or maximized then return end mainClosing = true closed = not closed if closed then if not sideClosed then toggleSideTray(true) end LeftPanel.Visible = true TweenService:Create(LeftPanel, TweenInfo.new(0.5), {Size = UDim2.new(0, 131, 0, 0)}):Play() wait(0.5) remotesFadeIn = fadeOut(LeftPanel:GetDescendants()) wait(0.5) else TweenService:Create(LeftPanel, TweenInfo.new(0.5), {Size = UDim2.new(0, 131, 0, 249)}):Play() wait(0.5) if remotesFadeIn then remotesFadeIn() remotesFadeIn = nil end bringBackOnResize() end mainClosing = false end --- Expands and minimizes the sidebar (sideClosed is the toggle boolean) function toggleSideTray(override) if sideClosing and not override or maximized then return end sideClosing = true sideClosed = not sideClosed if sideClosed then rightFadeIn = fadeOut(RightPanel:GetDescendants()) wait(0.5) minimizeSize(0.5) wait(0.5) RightPanel.Visible = false else if closed then toggleMinimize(true) end RightPanel.Visible = true maximizeSize(0.5) wait(0.5) if rightFadeIn then rightFadeIn() end bringBackOnResize() end sideClosing = false end --- Expands code box to fit screen for more convenient viewing function toggleMaximize() if not sideClosed and not maximized then maximized = true local disable = Instance.new("TextButton") local prevSize = UDim2.new(0, CodeBox.AbsoluteSize.X, 0, CodeBox.AbsoluteSize.Y) local prevPos = UDim2.new(0,CodeBox.AbsolutePosition.X, 0, CodeBox.AbsolutePosition.Y) disable.Size = UDim2.new(1, 0, 1, 0) disable.BackgroundColor3 = Color3.new() disable.BorderSizePixel = 0 disable.Text = 0 disable.ZIndex = 3 disable.BackgroundTransparency = 1 disable.AutoButtonColor = false CodeBox.ZIndex = 4 CodeBox.Position = prevPos CodeBox.Size = prevSize 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() TweenService:Create(disable, TweenInfo.new(0.5), {BackgroundTransparency = 0.5}):Play() disable.MouseButton1Click:Connect(function() if UserInputService:GetMouseLocation().Y + 36 >= CodeBox.AbsolutePosition.Y and UserInputService:GetMouseLocation().Y + 36 <= CodeBox.AbsolutePosition.Y + CodeBox.AbsoluteSize.Y and UserInputService:GetMouseLocation().X >= CodeBox.AbsolutePosition.X and UserInputService:GetMouseLocation().X <= CodeBox.AbsolutePosition.X + CodeBox.AbsoluteSize.X then return end TweenService:Create(CodeBox, TweenInfo.new(0.5), {Size = prevSize, Position = prevPos}):Play() TweenService:Create(disable, TweenInfo.new(0.5), {BackgroundTransparency = 1}):Play() wait(0.5) disable:Destroy() CodeBox.Size = UDim2.new(1, 0, 0.5, 0) CodeBox.Position = UDim2.new(0, 0, 0, 0) CodeBox.ZIndex = 0 maximized = false end) end end --- Checks if cursor is within resize range --- @param p Vector2 function isInResizeRange(p) local relativeP = p - Background.AbsolutePosition local range = 5 if relativeP.X >= TopBar.AbsoluteSize.X - range and relativeP.Y >= Background.AbsoluteSize.Y - range and relativeP.X <= TopBar.AbsoluteSize.X and relativeP.Y <= Background.AbsoluteSize.Y then return true, 'B' elseif relativeP.X >= TopBar.AbsoluteSize.X - range and relativeP.X <= Background.AbsoluteSize.X then return true, 'X' elseif relativeP.Y >= Background.AbsoluteSize.Y - range and relativeP.Y <= Background.AbsoluteSize.Y then return true, 'Y' end return false end --- Checks if cursor is within dragging range --- @param p Vector2 function isInDragRange(p) local relativeP = p - Background.AbsolutePosition if relativeP.X <= TopBar.AbsoluteSize.X - CloseButton.AbsoluteSize.X * 3 and relativeP.X >= 0 and relativeP.Y <= TopBar.AbsoluteSize.Y and relativeP.Y >= 0 then return true end return false end --- Called when mouse enters SimpleSpy local customCursor = Create("ImageLabel",{Parent = SimpleSpy3,Visible = false,Size = UDim2.fromOffset(200, 200),ZIndex = 1e5,BackgroundTransparency = 1,Image = "",Parent = SimpleSpy3}) function mouseEntered() connections["SIMPLESPY_CURSOR"] = RunService.RenderStepped:Connect(function() UserInputService.MouseIconEnabled = not mouseInGui customCursor.Visible = mouseInGui if mouseInGui and getgenv().SimpleSpyExecuted then local mouseLocation = UserInputService:GetMouseLocation() - Vector2.new(0, 36) customCursor.Position = UDim2.fromOffset(mouseLocation.X - customCursor.AbsoluteSize.X / 2, mouseLocation.Y - customCursor.AbsoluteSize.Y / 2) local inRange, type = isInResizeRange(mouseLocation) if inRange and not closed then if not sideClosed then customCursor.Image = type == 'B' and "rbxassetid://6065821980" or type == 'X' and "rbxassetid://6065821086" or type == 'Y' and "rbxassetid://6065821596" elseif type == 'Y' or type == 'B' then customCursor.Image = "rbxassetid://6065821596" end elseif customCursor.Image ~= "rbxassetid://6065775281" then customCursor.Image = "rbxassetid://6065775281" end else connections["SIMPLESPY_CURSOR"]:Disconnect() end end) end --- Called when mouse moves function mouseMoved() local mousePos = UserInputService:GetMouseLocation() - Vector2.new(0, 36) if not closed and mousePos.X >= TopBar.AbsolutePosition.X and mousePos.X <= TopBar.AbsolutePosition.X + TopBar.AbsoluteSize.X and mousePos.Y >= Background.AbsolutePosition.Y and mousePos.Y <= Background.AbsolutePosition.Y + Background.AbsoluteSize.Y then if not mouseInGui then mouseInGui = true mouseEntered() end else mouseInGui = false end end --- Adjusts the ui elements to the 'Maximized' size function maximizeSize(speed) if not speed then speed = 0.05 end TweenService:Create(LeftPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play() TweenService:Create(RightPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play() TweenService:Create(TopBar, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X, TopBar.AbsoluteSize.Y) }):Play() 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() TweenService:Create(CodeBox, TweenInfo.new(speed), { Size = UDim2.fromOffset(Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play() TweenService:Create(LogList, TweenInfo.new(speed), { Size = UDim2.fromOffset(LogList.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y - 18) }):Play() end --- Adjusts the ui elements to close the side function minimizeSize(speed) if not speed then speed = 0.05 end TweenService:Create(LeftPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play() TweenService:Create(RightPanel, TweenInfo.new(speed), { Size = UDim2.fromOffset(0, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }):Play() TweenService:Create(TopBar, TweenInfo.new(speed), { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, TopBar.AbsoluteSize.Y) }):Play() TweenService:Create(ScrollingFrame, TweenInfo.new(speed), { Size = UDim2.fromOffset(0, 119), Position = UDim2.fromOffset(0, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play() TweenService:Create(CodeBox, TweenInfo.new(speed), { Size = UDim2.fromOffset(0, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }):Play() TweenService:Create(LogList, TweenInfo.new(speed), { Size = UDim2.fromOffset(LogList.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y - 18) }):Play() end --- Ensures size is within screensize limitations function validateSize() local x, y = Background.AbsoluteSize.X, Background.AbsoluteSize.Y local screenSize = CurrentCamera.ViewportSize if x + Background.AbsolutePosition.X > screenSize.X then if screenSize.X - Background.AbsolutePosition.X >= 450 then x = screenSize.X - Background.AbsolutePosition.X else x = 450 end elseif y + Background.AbsolutePosition.Y > screenSize.Y then if screenSize.X - Background.AbsolutePosition.Y >= 268 then y = screenSize.Y - Background.AbsolutePosition.Y else y = 268 end end Background.Size = UDim2.fromOffset(x, y) end --- Called on user input while mouse in 'Background' frame --- @param input InputObject function backgroundUserInput(input) local mousePos = UserInputService:GetMouseLocation() - Vector2.new(0, 36) local inResizeRange, type = isInResizeRange(mousePos) if input.UserInputType == Enum.UserInputType.MouseButton1 and inResizeRange then local lastPos = UserInputService:GetMouseLocation() local offset = Background.AbsoluteSize - lastPos local currentPos = lastPos + offset connections["SIMPLESPY_RESIZE"] = RunService.RenderStepped:Connect(function() local newPos = UserInputService:GetMouseLocation() if newPos ~= lastPos then local currentX = (newPos + offset).X local currentY = (newPos + offset).Y if currentX < 450 then currentX = 450 end if currentY < 268 then currentY = 268 end currentPos = Vector2.new(currentX, currentY) 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) validateSize() if sideClosed then minimizeSize() else maximizeSize() end lastPos = newPos end end) table.insert(connections, UserInputService.InputEnded:Connect(function(inputE) if input == inputE then connections["SIMPLESPY_RESIZE"]:Disconnect() end end)) elseif isInDragRange(mousePos) then onBarInput(input) end end --- Gets the player an instance is descended from function getPlayerFromInstance(instance) for _, v in next, Players:GetPlayers() do if v.Character and (instance:IsDescendantOf(v.Character) or instance == v.Character) then return v end end end --- Runs on MouseButton1Click of an event frame function eventSelect(frame) if selected and selected.Log then task.spawn(function() TweenService:Create(selected.Log.Button, TweenInfo.new(0.5), {BackgroundColor3 = Color3.fromRGB(0, 0, 0)}):Play() end) selected = nil end for _, v in next, logs do if frame == v.Log then selected = v end end if selected and selected.Log then task.spawn(function() TweenService:Create(frame.Button, TweenInfo.new(0.5), {BackgroundColor3 = Color3.fromRGB(92, 126, 229)}):Play() end) codebox:setRaw(selected.GenScript) end if sideClosed then toggleSideTray() end end --- Updates the canvas size to fit the current amount of function buttons function updateFunctionCanvas() ScrollingFrame.CanvasSize = UDim2.fromOffset(UIGridLayout.AbsoluteContentSize.X, UIGridLayout.AbsoluteContentSize.Y) end --- Updates the canvas size to fit the amount of current remotes function updateRemoteCanvas() LogList.CanvasSize = UDim2.fromOffset(UIListLayout.AbsoluteContentSize.X, UIListLayout.AbsoluteContentSize.Y) end --- Allows for toggling of the tooltip and easy setting of le description --- @param enable boolean --- @param text string function makeToolTip(enable, text) if enable and text then if ToolTip.Visible then ToolTip.Visible = false connections["ToolTip"]:Disconnect() end local first = true connections["ToolTip"] = RunService.RenderStepped:Connect(function() local topLeft = Vector2.new(Mouse.X + 20, Mouse.Y + 20) local bottomRight = topLeft + ToolTip.AbsoluteSize local ViewportSize = CurrentCamera.ViewportSize local ViewportSizeX = ViewportSize.X local ViewportSizeY = ViewportSize.Y if topLeft.X < 0 then topLeft = Vector2.new(0, topLeft.Y) elseif bottomRight.X > ViewportSizeX then topLeft = Vector2.new(ViewportSizeX - ToolTip.AbsoluteSize.X, topLeft.Y) end if topLeft.Y < 0 then topLeft = Vector2.new(topLeft.X, 0) elseif bottomRight.Y > ViewportSizeY - 35 then topLeft = Vector2.new(topLeft.X, ViewportSizeY - ToolTip.AbsoluteSize.Y - 35) end if topLeft.X <= Mouse.X and topLeft.Y <= Mouse.Y then topLeft = Vector2.new(Mouse.X - ToolTip.AbsoluteSize.X - 2, Mouse.Y - ToolTip.AbsoluteSize.Y - 2) end if first then ToolTip.Position = UDim2.fromOffset(topLeft.X, topLeft.Y) first = false else ToolTip:TweenPosition(UDim2.fromOffset(topLeft.X, topLeft.Y), "Out", "Linear", 0.1) end end) TextLabel.Text = text TextLabel.TextScaled = true ToolTip.Visible = true return else if ToolTip.Visible then ToolTip.Visible = false connections["ToolTip"]:Disconnect() end end end --- Creates new function button (below codebox) --- @param name string ---@param description function ---@param onClick function function newButton(name, description, onClick) local FunctionTemplate = Create("Frame",{Name = "FunctionTemplate",Parent = ScrollingFrame,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Size = UDim2.new(0, 117, 0, 23)}) local ColorBar = Create("Frame",{Name = "ColorBar",Parent = FunctionTemplate,BackgroundColor3 = Color3.new(1, 1, 1),BorderSizePixel = 0,Position = UDim2.new(0, 7, 0, 10),Size = UDim2.new(0, 7, 0, 18),ZIndex = 3}) local Text = Create("TextLabel",{Text = name,Name = "Text",Parent = FunctionTemplate,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Position = UDim2.new(0, 19, 0, 10),Size = UDim2.new(0, 69, 0, 18),ZIndex = 2,Font = Enum.Font.SourceSans,TextColor3 = Color3.new(1, 1, 1),TextSize = 14,TextStrokeColor3 = Color3.new(0.145098, 0.141176, 0.14902),TextXAlignment = Enum.TextXAlignment.Left}) local Button = Create("TextButton",{Name = "Button",Parent = FunctionTemplate,BackgroundColor3 = Color3.new(0, 0, 0),BackgroundTransparency = 0.69999998807907,BorderColor3 = Color3.new(1, 1, 1),Position = UDim2.new(0, 7, 0, 10),Size = UDim2.new(0, 80, 0, 18),AutoButtonColor = false,Font = Enum.Font.SourceSans,Text = "",TextColor3 = Color3.new(0, 0, 0),TextSize = 14}) Button.MouseEnter:Connect(function() makeToolTip(true, description()) end) Button.MouseLeave:Connect(function() makeToolTip(false) end) FunctionTemplate.AncestryChanged:Connect(function() makeToolTip(false) end) Button.MouseButton1Click:Connect(function(...) onClick(FunctionTemplate, ...) end) updateFunctionCanvas() end --- Adds new Remote to logs --- @param name string The name of the remote being logged --- @param type string The type of the remote being logged (either 'function' or 'event') --- @param args any --- @param remote any --- @param function_info string --- @param blocked any function newRemote(type, name, args, remote, function_info, blocked, src) if layoutOrderNum < 1 then layoutOrderNum = 999999999 end local RemoteTemplate = Create("Frame",{LayoutOrder = layoutOrderNum,Name = "RemoteTemplate",Parent = LogList,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Size = UDim2.new(0, 117, 0, 27)}) local ColorBar = Create("Frame",{Name = "ColorBar",Parent = RemoteTemplate,BackgroundColor3 = (type == "event" and Color3.fromRGB(255, 242, 0)) or Color3.fromRGB(99, 86, 245),BorderSizePixel = 0,Position = UDim2.new(0, 0, 0, 1),Size = UDim2.new(0, 7, 0, 18),ZIndex = 2}) local Text = Create("TextLabel",{TextTruncate = Enum.TextTruncate.AtEnd,Name = "Text",Parent = RemoteTemplate,BackgroundColor3 = Color3.new(1, 1, 1),BackgroundTransparency = 1,Position = UDim2.new(0, 12, 0, 1),Size = UDim2.new(0, 105, 0, 18),ZIndex = 2,Font = Enum.Font.SourceSans,Text = name,TextColor3 = Color3.new(1, 1, 1),TextSize = 14,TextXAlignment = Enum.TextXAlignment.Left}) local Button = Create("TextButton",{Name = "Button",Parent = RemoteTemplate,BackgroundColor3 = Color3.new(0, 0, 0),BackgroundTransparency = 0.75,BorderColor3 = Color3.new(1, 1, 1),Position = UDim2.new(0, 0, 0, 1),Size = UDim2.new(0, 117, 0, 18),AutoButtonColor = false,Font = Enum.Font.SourceSans,Text = "",TextColor3 = Color3.new(0, 0, 0),TextSize = 14}) --local id = Create("IntValue",{Name = "ID",Value = #logs + 1,Parent = RemoteTemplate}) local log = { Name = name, Function = function_info, Remote = remote, Log = RemoteTemplate, Blocked = blocked, Source = src, GenScript = "-- Generating, please wait...\n-- (If this message persists, the remote args are likely extremely long)" } if src and not DecompiledScripts[src] then DecompiledScripts[src] = nil end logs[#logs + 1] = log local connect = Button.MouseButton1Click:Connect(function() eventSelect(RemoteTemplate) log.GenScript = genScript(remote, args) if blocked then logs[#logs].GenScript = "-- THIS REMOTE WAS PREVENTED FROM FIRING TO THE SERVER BY SIMPLESPY\n\n" .. logs[#logs].GenScript end if selected == log and RemoteTemplate then eventSelect(RemoteTemplate) end end) layoutOrderNum -= 1 table.insert(remoteLogs, 1, {connect, RemoteTemplate}) clean() updateRemoteCanvas() end --- Generates a script from the provided arguments (first has to be remote path) function genScript(remote, args) prevTables = {} local gen = "" if #args > 0 then if not pcall(function() gen = v2v({args = args}) .. "\n" end) then gen = gen .. "-- TableToString failure! Reverting to legacy functionality (results may vary)\nlocal args = {" if not pcall( function() for i, v in next, args do if type(i) ~= "Instance" and type(i) ~= "userdata" then gen = gen .. "\n [object] = " elseif type(i) == "string" then gen = gen .. '\n ["' .. i .. '"] = ' elseif type(i) == "userdata" and typeof(i) ~= "Instance" then gen = gen .. "\n [" .. string.format("nil --[[%s]]", typeof(v)) .. ")] = " elseif type(i) == "userdata" then gen = gen .. "\n [game." .. i:GetFullName() .. ")] = " end if type(v) ~= "Instance" and type(v) ~= "userdata" then gen = gen .. "object" elseif type(v) == "string" then gen = gen .. '"' .. v .. '"' elseif type(v) == "userdata" and typeof(v) ~= "Instance" then gen = gen .. string.format("nil --[[%s]]", typeof(v)) elseif type(v) == "userdata" then gen = gen .. "game." .. v:GetFullName() end end gen = gen .. "\n}\n\n" end ) then gen = gen .. "}\n-- Legacy tableToString failure! Unable to decompile." end end if not remote:IsDescendantOf(game) and not getnilrequired then gen = "function getNil(name,class) for _,v in next, getnilinstances()do if v.ClassName==class and v.Name==name then return v;end end end\n\n" .. gen end if remote:IsA("RemoteEvent") then gen = gen .. v2s(remote) .. ":FireServer(unpack(args))" elseif remote:IsA("RemoteFunction") then gen = gen .. v2s(remote) .. ":InvokeServer(unpack(args))" end else if remote:IsA("RemoteEvent") then gen = gen .. v2s(remote) .. ":FireServer()" elseif remote:IsA("RemoteFunction") then gen = gen .. v2s(remote) .. ":InvokeServer()" end end prevTables = {} return gen end --- value-to-string: value, string (out), level (indentation), parent table, var name, is from tovar local ufunctions = { TweenInfo = function(u) return ("TweenInfo.new(%s, Enum.EasingStyle.%s, Enum.EasingDirection.%s, %s, %s, %s)"):format(tostring(u.Time),tostring(u.EasingStyle),tostring(u.EasingDirection),tostring(u.RepeatCount),tostring(u.Reverses),tostring(u.DelayTime)) end, Ray = function(u) return ("Ray.new(%s, %s)"):format(tostring(u.Origin),tostring(u.Direction)) end, NumberSequence = function(u) local ret = "NumberSequence.new(" for i, v in next, u.KeyPoints do ret = ret .. tostring(v) if i < #u.Keypoints then ret = ret .. ", " end end return ret .. ")" end, DockWidgetPluginGuiInfo = function(u) return ("DockWidgetPluginGuiInfo.new(Enum.InitialDockState%s)"):format(tostring(u)) end, ColorSequence = function(u) local ret = "ColorSequence.new(" for i, v in next, u.KeyPoints do ret = ret ..("Color3.new(%s)"):format(tostring(v)) if i < #u.Keypoints then ret = ret .. ", " end end return ret .. ")" end, BrickColor = function(u) return ("BrickColor.new(%s)"):format(tostring(u.Number)) end, NumberRange = function(u) return ("NumberRange.new(%s, %s)"):format(tostring(u.Min),tostring(u.Max)) end, Region3 = function(u) local center = u.CFrame.Position local size = u.CFrame.Size local vector1 = center - size / 2 local vector2 = center + size / 2 return ("Region3.new(%s, %s)"):format(vector1,vector2) end, Faces = function(u) local faces = {} if u.Top then table.insert(faces, "Top") end if u.Bottom then table.insert(faces, "Enum.NormalId.Bottom") end if u.Left then table.insert(faces, "Enum.NormalId.Left") end if u.Right then table.insert(faces, "Enum.NormalId.Right") end if u.Back then table.insert(faces, "Enum.NormalId.Back") end if u.Front then table.insert(faces, "Enum.NormalId.Front") end return ("Faces.new(%s)"):format(table.concat(faces, ", ")) end, EnumItem = function(u) return tostring(u) end, Enums = function(u) return "Enum" end, Enum = function(u) return "Enum." .. tostring(u) end, RBXScriptSignal = function(u) return "nil --[[RBXScriptSignal]]" end, Vector3 = function(u) return ("Vector3.new(%s, %s, %s)"):format(v2s(u.X), v2s(u.Y), v2s(u.Z)) end, Vector2 = function(u) return ("Vector2.new(%s, %s)"):format(v2s(u.X), v2s(u.Y)) end, CFrame = function(u) return ("CFrame.new(%s, %s)"):format(v2s(u.Position), v2s(u.LookVector)) end, DockWidgetPluginGuiInfo = function(u) ("DockWidgetPluginGuiInfo(%s, %s, %s, %s, %s, %s, %s)"):format("Enum.InitialDockState.Right", v2s(u.InitialEnabled), v2s(u.InitialEnabledShouldOverrideRestore), v2s(u.FloatingXSize), v2s(u.FloatingYSize), v2s(u.MinWidth), v2s(u.MinHeight)) end, PathWaypoint = function(u) return ("PathWaypoint.new(%s, %s)"):format(v2s(u.Position), v2s(u.Action)) end, UDim = function(u) return ("UDim.new(%s, %s)"):format(v2s(u.Scale), v2s(u.Offset)) end, UDim2 = function(u) return ("UDim2.new(%s, %s, %s, %s)"):format(v2s(u.X.Scale), v2s(u.X.Offset), v2s(u.Y.Scale), v2s(u.Y.Offset)) end, Rect = function(u) return ("Rect.new(%s, %s)"):format(v2s(u.Min), v2s(u.Max)) end, Color3 = function(u) return ("Color3.fromRGB(%s, %s, %s)"):format(tostring(round(u.r*255)),tostring(round(u.g*255)),tostring(round(u.b*255))) end } local typeofv2sfunctions = { number = function(v) if v == math.huge then return "math.huge" elseif v == -math.huge then return "-math.huge" elseif tostring(v):match("nan") then return "0/0 --[[NaN]]" end return tostring(v) end, boolean = function(v) return tostring(v) end, string = function(v,l) return formatstr(v, l) end, ["function"] = function(v) return f2s(v) end, table = function(v, l, p, n, vtv, i, pt, path, tables, tI) return t2s(v, l, p, n, vtv, i, pt, path, tables, tI) end, Instance = function(v) return i2p(SafeInstance(v)) end, userdata = function(v) return "newproxy(true)" end } local typev2sfunctions = { userdata = function(v,vtypeof) if ufunctions[vtypeof] then return ufunctions[vtypeof](v) end return ("%s(nil)"):format(vtypeof) end, vector = function(v) return string.format("Vector3.new(%s, %s, %s)", v2s(v.X), v2s(v.Y), v2s(v.Z)) end } function v2s(v, l, p, n, vtv, i, pt, path, tables, tI) local vtypeof = typeof(v) local vtype = type(v) if not tI then tI = {0} else tI[1] += 1 end if typeofv2sfunctions[vtypeof] then return typeofv2sfunctions[vtypeof](v, l, p, n, vtv, i, pt, path, tables, tI) elseif typev2sfunctions[vtype] then return typev2sfunctions[vtype](v,vtypeof) end return "nil --[[" .. vtypeof .. "]]" end --- value-to-variable --- @param t any function v2v(t) topstr = "" bottomstr = "" getnilrequired = false local ret = "" local count = 1 for i, v in next, t do if type(i) == "string" and i:match("^[%a_]+[%w_]*$") then ret = ret .. "local " .. i .. " = " .. v2s(v, nil, nil, i, true) .. "\n" elseif tostring(i):match("^[%a_]+[%w_]*$") then ret = ret .. "local " .. lower(tostring(i)) .. "_" .. tostring(count) .. " = " .. v2s(v, nil, nil, lower(tostring(i)) .. "_" .. tostring(count), true) .. "\n" else ret = ret .. "local " .. type(v) .. "_" .. tostring(count) .. " = " .. v2s(v, nil, nil, type(v) .. "_" .. tostring(count), true) .. "\n" end count = count + 1 end if getnilrequired then topstr = "function getNil(name,class) for _,v in next, getnilinstances() do if v.ClassName==class and v.Name==name then return v;end end end\n" .. topstr end if #topstr > 0 then ret = topstr .. "\n" .. ret end if #bottomstr > 0 then ret = ret .. bottomstr end return ret end --- table-to-string --- @param t table --- @param l number --- @param p table --- @param n string --- @param vtv boolean --- @param i any --- @param pt table --- @param path string --- @param tables table --- @param tI table function t2s(t, l, p, n, vtv, i, pt, path, tables, tI) local globalIndex = table.find(getgenv(), t) -- checks if table is a global if type(globalIndex) == "string" then return globalIndex end if not tI then tI = {0} end if not path then -- sets path to empty string (so it doesn't have to manually provided every time) path = "" end if not l then -- sets the level to 0 (for indentation) and tables for logging tables it already serialized l = 0 tables = {} end if not p then -- p is the previous table but doesn't really matter if it's the first p = t end for _, v in next, tables do -- checks if the current table has been serialized before if n and rawequal(v, t) then bottomstr = bottomstr .. "\n" .. tostring(n) .. tostring(path) .. " = " .. tostring(n) .. tostring(({v2p(v, p)})[2]) return "{} --[[DUPLICATE]]" end end table.insert(tables, t) -- logs table to past tables local s = "{" -- start of serialization local size = 0 l = l + indent -- set indentation level for k, v in next, t do -- iterates over table size = size + 1 -- changes size for max limit if size > (getgenv().SimpleSpyMaxTableSize or 1000) then s = s .. "\n" .. string.rep(" ", l) .. "-- MAXIMUM TABLE SIZE REACHED, CHANGE 'getgenv().SimpleSpyMaxTableSize' TO ADJUST MAXIMUM SIZE " break end if rawequal(k, t) then -- checks if the table being iterated over is being used as an index within itself (yay, lua) 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)) size -= 1 continue end local currentPath = "" -- initializes the path of 'v' within 't' if type(k) == "string" and k:match("^[%a_]+[%w_]*$") then -- cleanly handles table path generation (for the first half) currentPath = "." .. k else currentPath = "[" .. v2s(k, l, p, n, vtv, k, t, path .. currentPath, tables, tI) .. "]" end if size % 100 == 0 then scheduleWait() end -- actually serializes the member of the table s = s .. "\n" .. string.rep(" ", l) .. "[" .. v2s(k, l, p, n, vtv, k, t, path .. currentPath, tables, tI) .. "] = " .. v2s(v, l, p, n, vtv, k, t, path .. currentPath, tables, tI) .. "," end 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...) s = s:sub(1, #s - 1) end if size > 0 then -- cleanly indents the last curly bracket s = s .. "\n" .. string.rep(" ", l - indent) end return s .. "}" end --- function-to-string function f2s(f) for k, x in next, getgenv() do local isgucci, gpath if rawequal(x, f) then isgucci, gpath = true, "" elseif type(x) == "table" then isgucci, gpath = v2p(f, x) end if isgucci and type(k) ~= "function" then if type(k) == "string" and k:match("^[%a_]+[%w_]*$") then return k .. gpath else return "getgenv()[" .. v2s(k) .. "]" .. gpath end end end if configs.funcEnabled then local funcinfo = getinfo(f) if funcinfo then local funcinfoname = funcinfo.name if funcinfoname and funcinfoname:match("^[%a_]+[%w_]*$") then return ("function() %s end"):format(funcinfoname) end end end return ("function() %s end"):format(tostring(f)) end --- instance-to-path --- @param i userdata function i2p(i) local player = getplayer(i) local parent = i local out = "" if parent == nil then return "nil" elseif player then while true do if parent and parent == player.Character then if player == Players.LocalPlayer then return 'game:GetService("Players").LocalPlayer.Character' .. out else return i2p(player) .. ".Character" .. out end else if parent.Name:match("[%a_]+[%w+]*") ~= parent.Name then out = ':FindFirstChild(' .. formatstr(parent.Name) .. ')' .. out else out = "." .. parent.Name .. out end end parent = parent.Parent end elseif parent ~= game then while true do if parent and parent.Parent == game then if SafeGetService(parent.ClassName) then if lower(parent.ClassName) == "workspace" then return "workspace" .. out else return 'game:GetService("' .. parent.ClassName .. '")' .. out end else if parent.Name:match("[%a_]+[%w_]*") then return "game." .. parent.Name .. out else return 'game:FindFirstChild(' .. formatstr(parent.Name) .. ')' .. out end end elseif parent.Parent == nil then getnilrequired = true return 'getNil(' .. formatstr(parent.Name) .. ', "' .. parent.ClassName .. '")' .. out elseif parent == Players.LocalPlayer then out = ".LocalPlayer" .. out else if parent.Name:match("[%a_]+[%w_]*") ~= parent.Name then out = ':FindFirstChild(' .. formatstr(parent.Name) .. ')' .. out else out = "." .. parent.Name .. out end end parent = parent.Parent end else return "game" end end --- Gets the player an instance is descended from function getplayer(instance) for _, v in next, Players:GetPlayers() do if v.Character and (instance:IsDescendantOf(v.Character) or instance == v.Character) then return v end end end --- value-to-path (in table) function v2p(x, t, path, prev) if not path then path = "" end if not prev then prev = {} end if rawequal(x, t) then return true, "" end for i, v in next, t do if rawequal(v, x) then if type(i) == "string" and i:match("^[%a_]+[%w_]*$") then return true, (path .. "." .. i) else return true, (path .. "[" .. v2s(i) .. "]") end end if type(v) == "table" then local duplicate = false for _, y in next, prev do if rawequal(y, v) then duplicate = true end end if not duplicate then table.insert(prev, t) local found found, p = v2p(x, v, path, prev) if found then if type(i) == "string" and i:match("^[%a_]+[%w_]*$") then return true, "." .. i .. p else return true, "[" .. v2s(i) .. "]" .. p end end end end end return false, "" end --- format s: string, byte encrypt (for weird symbols) function formatstr(s, indentation) if not indentation then indentation = 0 end local handled, reachedMax = handlespecials(s, indentation) return '"' .. handled .. '"' .. (reachedMax and " --[[ MAXIMUM STRING SIZE REACHED, CHANGE 'getgenv().SimpleSpyMaxStringSize' TO ADJUST MAXIMUM SIZE ]]" or "") end --- Adds \'s to the text as a replacement to whitespace chars and other things because string.format can't yayeet local function isFinished(tableinquestion) for _, v in next, tableinquestion do if status(v) == "running" then return false end end return true end function handlespecials(s, indentation) local i = 0 local n = 1 local coroutines = {} local coroutineFunc = function(i, r) s = s:sub(0, i - 1) .. r .. s:sub(i + 1, -1) end repeat i = i + 1 local char = s:sub(i, i) if string.byte(char) then local c = create(coroutineFunc) table.insert(coroutines, c) if char == "\n" then resume(c, i, "\\n") -- s = s:sub(0, i - 1) .. "\\n" .. s:sub(i + 1, -1) i = i + 1 elseif char == "\t" then resume(c, i, "\\t") -- s = s:sub(0, i - 1) .. "\\t" .. s:sub(i + 1, -1) i = i + 1 elseif char == "\\" then resume(c, i, "\\\\") -- s = s:sub(0, i - 1) .. "\\\\" .. s:sub(i + 1, -1) i = i + 1 elseif char == '"' then resume(c, i, "\\\"") -- s = s:sub(0, i - 1) .. '\\"' .. s:sub(i + 1, -1) i = i + 1 elseif string.byte(char) > 126 or string.byte(char) < 32 then resume(c, i, "\\" .. string.byte(char)) -- s = s:sub(0, i - 1) .. "\\" .. string.byte(char) .. s:sub(i + 1, -1) i = i + #tostring(string.byte(char)) end if i >= n * 100 then local extra = string.format('" ..\n%s"', string.rep(" ", indentation + indent)) s = s:sub(0, i) .. extra .. s:sub(i + 1, -1) i += #extra n += 1 scheduleWait() end end until char == "" or i > (getgenv().SimpleSpyMaxStringSize or 10000) while not isFinished(coroutines) do RunService.Heartbeat:Wait() end if i > (getgenv().SimpleSpyMaxStringSize or 10000) then s = string.sub(s, 0, getgenv().SimpleSpyMaxStringSize or 10000) return s, true end return s, false end --- finds script from 'src' from getinfo, returns nil if not found --- @param src string function getScriptFromSrc(src) local realPath local runningTest --- @type number local s, e local match = false if src:sub(1, 1) == "=" then realPath = game s = 2 else runningTest = src:sub(2, e and e - 1 or -1) for _, v in next, getnilinstances() do if v.Name == runningTest then realPath = v break end end s = #runningTest + 1 end if realPath then e = src:sub(s, -1):find("%.") local i = 0 repeat i += 1 if not e then runningTest = src:sub(s, -1) local test = realPath.FindFirstChild(realPath, runningTest) if test then realPath = test end match = true else runningTest = src:sub(s, e) local test = realPath.FindFirstChild(realPath, runningTest) local yeOld = e if test then realPath = test s = e + 2 e = src:sub(e + 2, -1):find("%.") e = e and e + yeOld or e else e = src:sub(e + 2, -1):find("%.") e = e and e + yeOld or e end end until match or i >= 50 end return realPath end --- schedules the provided function (and calls it with any args after) function schedule(f, ...) table.insert(scheduled, {f, ...}) end --- yields the current thread until the scheduler gives the ok function scheduleWait() local thread = running() schedule(function() resume(thread) end) yield() end --- the big (well tbh small now) boi task scheduler himself, handles p much anything as quicc as possible function taskscheduler() if not toggle then scheduled = {} return end if #scheduled > 1000 then table.remove(scheduled, #scheduled) end if #scheduled > 0 then local currentf = scheduled[1] table.remove(scheduled, 1) if type(currentf) == "table" and type(currentf[1]) == "function" then pcall(unpack(currentf)) end end end --- Handles remote logs function remoteHandler(hookfunction, methodName, remote, args, func, calling,metamethod) if remote:IsA("RemoteEvent") or remote:IsA("RemoteFunction") then if configs.funcEnabled and not calling then _, calling = pcall(getScriptFromSrc, getinfo(func).source) end wrap(function() if remoteSignals[remote] then remoteSignals[remote]:Fire(args) end end)() if configs.autoblock then if excluding[remote] then return end if not history[remote] then history[remote] = {badOccurances = 0, lastCall = tick()} end if tick() - history[remote].lastCall < 1 then history[remote].badOccurances += 1 return else history[remote].badOccurances = 0 end if history[remote].badOccurances > 3 then excluding[remote] = true return end history[remote].lastCall = tick() end local functionInfoStr = "--Function Info is disabled" local src if func and islclosure(func) then functionInfoStr = { info = getinfo(func), constants = getconstants(func), upvalues = getupvalues(func) } if configs.logmetamethod then functionInfoStr["metamethod"] = metamethod end if type(calling) == "userdata" then src = calling end end if lower(methodName) == "fireserver" then newRemote("event", Dehashed_Remotes[remote.Name], args, remote, functionInfoStr, (blocklist[remote] or blocklist[Dehashed_Remotes[remote.Name]]), src) elseif lower(methodName) == "invokeserver" then newRemote("function", Dehashed_Remotes[remote.Name], args, remote, functionInfoStr, (blocklist[remote] or blocklist[Dehashed_Remotes[remote.Name]]), src) end end end local newindex = function(method,originalfunction,remote,...) if not configs.logcheckcaller and checkcaller and checkcaller() then return originalfunction(remote,...) end local args = {...} local methodName = lower(method) if methodtypes[methodName] then if not (blacklist[remote] or blacklist[Dehashed_Remotes[remote.Name]]) then local func local calling if configs.funcEnabled then func = getinfo(getinfolevel+1).func-- or funcInfo calling = (getcallingscript and getcallingscript()) or nil end wrap(function() schedule(remoteHandler, false, methodName, remote, args, func, calling,"__index") end)() end if typeof(remote) == "Instance" and (blocklist[remote] or blocklist[Dehashed_Remotes[remote.Name]]) then return end end return originalfunction(remote,...) end local newnamecall = newcclosure(function(remote, ...) if not configs.logcheckcaller and checkcaller and checkcaller() then return originalnamecall(remote, ...) end local args = {...} local methodName = lower(getnamecallmethod()) if methodtypes[methodName] then if not (blacklist[remote] or blacklist[Dehashed_Remotes[remote.Name]]) then local func local calling if configs.funcEnabled then func = getinfo(getinfolevel).func-- or funcInfo calling = getcallingscript() or nil end wrap(function() schedule(remoteHandler, false, methodName, remote, args, func, calling,"__namecall") end)() end if typeof(remote) == "Instance" and (blocklist[remote] or blocklist[Dehashed_Remotes[remote.Name]]) then return end end return originalnamecall(remote, ...) end) local newFireServer = newcclosure(function(...) return newindex("FireServer",originalEvent,...) end) local newInvokeServer = newcclosure(function(...) return newindex("InvokeServer",originalFunction,...) end) --- Toggles on and off the remote spy function toggleSpy() if not toggle then if hookmetamethod then local oldNamecall = hookmetamethod(game, "__namecall", newnamecall) originalnamecall = originalnamecall or function(...) return oldNamecall(...) end end originalEvent = hookfunction(remoteEvent.FireServer, newFireServer) originalFunction = hookfunction(remoteFunction.InvokeServer, newInvokeServer) else if hookmetamethod then if originalnamecall then hookmetamethod(game, "__namecall", originalnamecall) end end hookfunction(remoteEvent.FireServer, originalEvent) hookfunction(remoteFunction.InvokeServer, originalFunction) end end --- Toggles between the two remotespy methods (hookfunction currently = disabled) function toggleSpyMethod() toggleSpy() toggle = not toggle end --- Shuts down the remote spy function shutdown() if schedulerconnect then schedulerconnect:Disconnect() end for _, connection in next, connections do wrap(function() connection:Disconnect() end)() end if originalnamecall then hookmetamethod(game, "__namecall", originalnamecall) end hookfunction(remoteEvent.FireServer, originalEvent) hookfunction(remoteFunction.InvokeServer, originalFunction) SimpleSpy3:Destroy() UserInputService.MouseIconEnabled = true getgenv().SimpleSpyExecuted = false writefiletoggle = false end -- main if not getgenv().SimpleSpyExecuted then local succeeded, err = pcall(function() if not RunService:IsClient() then error("SimpleSpy cannot run on the server!") end getgenv().SimpleSpyShutdown = shutdown ContentProvider:PreloadAsync({"rbxassetid://6065821980", "rbxassetid://6065774948", "rbxassetid://6065821086", "rbxassetid://6065821596", ImageLabel, ImageLabel_2, ImageLabel_3}) -- if gethui then configs.funcEnabled = false end onToggleButtonClick() if not hookmetamethod then ErrorPrompt("Simple Spy v3 will not function to it's fullest capablity due to your executor not supporting hookmetamethod.",true) end codebox = Highlight.new(CodeBox) wrap(function() local suc,err = pcall(game.HttpGet,game,"https://raw.githubusercontent.com/78n/SimpleSpy/main/UpdateLog.lua") codebox:setRaw((suc and err) or "") end)() getgenv().SimpleSpy = SimpleSpy getgenv().getNil = function(name,class) for _,v in next, getnilinstances() do if v.ClassName == class and v.Name == name then return v; end end end TextLabel:GetPropertyChangedSignal("Text"):Connect(scaleToolTip) -- TopBar.InputBegan:Connect(onBarInput) MinimizeButton.MouseButton1Click:Connect(toggleMinimize) MaximizeButton.MouseButton1Click:Connect(toggleSideTray) Simple.MouseButton1Click:Connect(onToggleButtonClick) CloseButton.MouseEnter:Connect(onXButtonHover) CloseButton.MouseLeave:Connect(onXButtonUnhover) Simple.MouseEnter:Connect(onToggleButtonHover) Simple.MouseLeave:Connect(onToggleButtonUnhover) CloseButton.MouseButton1Click:Connect(shutdown) table.insert(connections, UserInputService.InputBegan:Connect(backgroundUserInput)) connectResize() SimpleSpy3.Enabled = true wrap(function() delay(1,onToggleButtonUnhover) end)() schedulerconnect = RunService.Heartbeat:Connect(taskscheduler) bringBackOnResize() SimpleSpy3.Parent = (gethui and gethui()) or (syn and syn.protect_gui and syn.protect_gui(SimpleSpy3)) or CoreGui if not Players.LocalPlayer then Players:GetPropertyChangedSignal("LocalPlayer"):Wait() end Mouse = Players.LocalPlayer:GetMouse() oldIcon = Mouse.Icon table.insert(connections, Mouse.Move:Connect(mouseMoved)) end) if succeeded then getgenv().SimpleSpyExecuted = true writefiletoggle = true else if hookmetamethod and original then hookmetamethod(game, "__namecall", original) end if hookfunction then hookfunction(remoteEvent.FireServer, originalEvent) hookfunction(remoteFunction.InvokeServer, originalFunction) end SimpleSpy3:Destroy() ErrorPrompt("An error has occured:\n"..tostring(err)) return end else SimpleSpy3:Destroy() return end function SimpleSpy:newButton(name, description, onClick) return newButton(name, description, onClick) end ----- ADD ONS ----- (easily add or remove additonal functionality to the RemoteSpy!) --[[ Some helpful things: - add your function in here, and create buttons for them through the 'newButton' function - the first argument provided is the TextButton the player clicks to run the function - generated scripts are generated when the namecall is initially fired and saved in remoteFrame objects - blacklisted remotes will be ignored directly in namecall (less lag) - the properties of a 'remoteFrame' object: { Name: (string) The name of the Remote GenScript: (string) The generated script that appears in the codebox (generated when namecall fired) Source: (Instance (LocalScript)) The script that fired/invoked the remote Remote: (Instance (RemoteEvent) | Instance (RemoteFunction)) The remote that was fired/invoked Log: (Instance (TextButton)) The button being used for the remote (same as 'selected.Log') } - globals list: (contact @exx#9394 for more information or if you have suggestions for more to be added) - closed: (boolean) whether or not the GUI is currently minimized - logs: (table[remoteFrame]) full of remoteFrame objects (properties listed above) - selected: (remoteFrame) the currently selected remoteFrame (properties listed above) - blacklist: (string[] | Instance[] (RemoteEvent) | Instance[] (RemoteFunction)) an array of blacklisted names and remotes - codebox: (Instance (TextBox)) the textbox that holds all the code- cleared often ]] -- Copies the contents of the codebox newButton( "Copy Code", function() return "Click to copy code" end, function() setclipboard(codebox:getString()) TextLabel.Text = "Copied successfully!" end ) --- Copies the source script (that fired the remote) newButton( "Copy Remote", function() return "Click to copy the path of the remote" end, function() if selected and selected.Remote then setclipboard(v2s(selected.Remote)) TextLabel.Text = "Copied!" end end ) -- Executes the contents of the codebox through loadstring newButton( "Run Code", function() return "Click to execute code" end, function() if selected and selected.GenScript then TextLabel.Text = "Executing..." local succeeded,Error = pcall(function() return loadstring(selected.GenScript)() end) if succeeded then TextLabel.Text = "Executed successfully!" else TextLabel.Text = ("Execution error!\n[[%s]]"):format(Error) end return end TextLabel.Text = "Source not found" end ) --- Gets the calling script (not super reliable but w/e) newButton( "Get Script", function() return "Click to copy calling script to clipboard\nWARNING: Not super reliable, nil == could not find" end, function() if selected and selected.Source then setclipboard(v2s(selected.Source)) TextLabel.Text = "Done!" end end ) --- Decompiles the script that fired the remote and puts it in the code box newButton( "Function Info", function() return "Click to view calling function information" end, function() if selected then if selected.Function then if typeof(selected.Function) ~= 'string' then codebox:setRaw("--[[Generating Function Info please wait]]") RunService.Heartbeat:Wait() selected.Function = tostring(v2v({functionInfo = selected.Function})) end codebox:setRaw("-- Calling function info\n-- Generated by the SimpleSpy serializer\n\n"..selected.Function) TextLabel.Text = "Done! Function info generated by the SimpleSpy Serializer." else TextLabel.Text = "Error! Selected function was not found." end end end ) --- Clears the Remote logs newButton( "Clr Logs", function() return "Click to clear logs" end, function() TextLabel.Text = "Clearing..." logs = {} for i,v in next, LogList:GetChildren() do if not v:IsA("UIListLayout") then v:Destroy() end end codebox:setRaw("") selected = nil TextLabel.Text = "Logs cleared!" end ) --- Excludes the selected.Log Remote from the RemoteSpy newButton( "Exclude (i)", function() return "Click to exclude this Remote.\nExcluding a remote makes SimpleSpy ignore it, but it will continue to be usable." end, function() if selected then blacklist[selected.Remote] = true TextLabel.Text = "Excluded!" end end ) --- Excludes all Remotes that share the same name as the selected.Log remote from the RemoteSpy newButton( "Exclude (n)", 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, function() if selected then blacklist[selected.Name] = true TextLabel.Text = "Excluded!" end end ) --- clears blacklist newButton("Clr Blacklist", function() return "Click to clear the blacklist.\nExcluding a remote makes SimpleSpy ignore it, but it will continue to be usable." end, function() blacklist = {} TextLabel.Text = "Blacklist cleared!" end) --- Prevents the selected.Log Remote from firing the server (still logged) newButton( "Block (i)", 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, function() if selected then blocklist[selected.Remote] = true TextLabel.Text = "Excluded!" end end ) --- Prevents all remotes from firing that share the same name as the selected.Log remote from the RemoteSpy (still logged) newButton("Block (n)",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, function() if selected then blocklist[selected.Name] = true TextLabel.Text = "Excluded!" end end ) --- clears blacklist newButton( "Clr Blocklist", 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, function() blocklist = {} TextLabel.Text = "Blocklist cleared!" end ) --- Attempts to decompile the source script newButton("Decompile", function() return "Decompile source script" end, function() if selected and selected.Source and decompile then local Source = selected.Source if not DecompiledScripts[Source] then codebox:setRaw("--[[Decompiling]]") local suc,err = pcall(function() DecompiledScripts[Source] = decompile(Source):gsub("-- Decompiled with the Synapse X Luau decompiler.","") end) if suc then if lower(DecompiledScripts[Source]):find("script") and v2s(Source) then DecompiledScripts[Source] = ("local script = %s\n%s"):format(v2s(Source),DecompiledScripts[Source]) end else return codebox:setRaw(("--[[\nAn error has occured\n%s\n]]"):format(err)) end end codebox:setRaw(DecompiledScripts[Source]) TextLabel.Text = "Done!" else TextLabel.Text = "Source not found!" end end) newButton( "Disable Info", function() return string.format("[%s] Toggle function info (because it can cause lag in some games)", configs.funcEnabled and "ENABLED" or "DISABLED") end, function() configs.funcEnabled = not configs.funcEnabled TextLabel.Text = string.format("[%s] Toggle function info (because it can cause lag in some games)", configs.funcEnabled and "ENABLED" or "DISABLED") end ) newButton( "Autoblock", function() return string.format("[%s] [BETA] Intelligently detects and excludes spammy remote calls from logs", configs.autoblock and "ENABLED" or "DISABLED") end, function() configs.autoblock = not configs.autoblock TextLabel.Text = string.format("[%s] [BETA] Intelligently detects and excludes spammy remote calls from logs", configs.autoblock and "ENABLED" or "DISABLED") history = {} excluding = {} end ) newButton("Logcheckcaller",function() return ("[%s] Log remotes fired by the client"):format(configs.logcheckcaller and "ENABLED" or "DISABLED") end, function() configs.logcheckcaller = not configs.logcheckcaller TextLabel.Text = ("[%s] Log remotes fired by the client"):format(configs.logcheckcaller and "ENABLED" or "DISABLED") end) newButton("Log metamethod",function() return ("[%s] Display remote's metamethod in Function Info"):format(configs.logmetamethod and "ENABLED" or "DISABLED") end, function() configs.logmetamethod = not configs.logmetamethod TextLabel.Text = ("[%s] Display remote's metamethod in Function Info"):format(configs.logmetamethod and "ENABLED" or "DISABLED") end) if syn and syn.request then request = syn.request end newButton("Join Discord",function() return "Joins The Simple Spy Discord" end, function() setclipboard("https://discord.com/invite/AWS6ez9") TextLabel.Text = "Copied invite to your clipboard" if request then request({Url = 'http://127.0.0.1:6463/rpc?v=1',Method = 'POST',Headers = {['Content-Type'] = 'application/json', Origin = 'https://discord.com'},Body = http:JSONEncode({cmd = 'INVITE_BROWSER',nonce = http:GenerateGUID(false),args = {code = 'AWS6ez9'}})}) end end) if configs.supersecretdevtoggle then newButton("Load SSV2.2",function() return "Load's Simple Spy V2.2" end, function() loadstring(game:HttpGet("https://raw.githubusercontent.com/exxtremestuffs/SimpleSpySource/master/SimpleSpy.lua"))() end) newButton("Load SSV3",function() return "Load's Simple Spy V3" end, function() loadstring(game:HttpGet("https://raw.githubusercontent.com/78n/SimpleSpy/main/SimpleSpySource.lua"))() end) local SuperSecretFolder = Create("Folder",{Parent = SimpleSpy3}) local sounds = {} newButton("SUPER SECRET BUTTON",function() return "You dont need a discription you already know what it does" end, function() if #sounds > 0 then for i,v in sounds do i.Volume = 0 i:Stop() end end local random = listfiles("Music") local NotSound = Create("Sound",{Parent = SuperSecretFolder,Looped = false,Volume = math.random(1,5),SoundId = getsynasset(random[math.random(1,#random)])}) NotSound:Play() sounds[NotSound] = "This is not a sound" end) end