if _G.SimpleSpyExecuted and type(_G.SimpleSpyShutdown) == "function" then
print(pcall(_G.SimpleSpyShutdown))
end
local Players = game:GetService("Players")
local CoreGui = game:GetService("CoreGui")
local Highlight =
loadstring(
game:HttpGet("https://raw.githubusercontent.com/yofriendfromschool1/Sky-Hub-Backup/main/SimpleSpyV3/mobilehighlight.lua")
)()
---- GENERATED (kinda sorta mostly) BY GUI to LUA ----
-- Instances:
local SimpleSpy2 = Instance.new("ScreenGui")
local Background = Instance.new("Frame")
local LeftPanel = Instance.new("Frame")
local LogList = Instance.new("ScrollingFrame")
local UIListLayout = Instance.new("UIListLayout")
local RemoteTemplate = Instance.new("Frame")
local ColorBar = Instance.new("Frame")
local Text = Instance.new("TextLabel")
local Button = Instance.new("TextButton")
local RightPanel = Instance.new("Frame")
local CodeBox = Instance.new("Frame")
local ScrollingFrame = Instance.new("ScrollingFrame")
local UIGridLayout = Instance.new("UIGridLayout")
local FunctionTemplate = Instance.new("Frame")
local ColorBar_2 = Instance.new("Frame")
local Text_2 = Instance.new("TextLabel")
local Button_2 = Instance.new("TextButton")
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")
local gui = Instance.new("ScreenGui",Background)
local nextb = Instance.new("ImageButton", gui)
local gui = Instance.new("UICorner", nextb)
--Properties:
SimpleSpy2.Name = "SimpleSpy2"
SimpleSpy2.ResetOnSpawn = false
local SpyFind = CoreGui:FindFirstChild(SimpleSpy2.Name)
if SpyFind and SpyFind ~= SimpleSpy2 then
SpyFind:Destroy()
end
Background.Name = "Background"
Background.Parent = SimpleSpy2
Background.BackgroundColor3 = Color3.new(1, 1, 1)
Background.BackgroundTransparency = 1
Background.Position = UDim2.new(0, 160, 0, 100)
Background.Size = UDim2.new(0, 450, 0, 268)
Background.Active = true
Background.Draggable = true
nextb.Position = UDim2.new(0,100,0,60)
nextb.Size = UDim2.new(0,40,0,40)
nextb.BackgroundColor3 = Color3.fromRGB(53, 52, 55)
nextb.Image = "rbxassetid://7072720870"
nextb.Active = true
nextb.Draggable = true
nextb.MouseButton1Down:connect(function()
nextb.Image = (Background.Visible and "rbxassetid://7072720870") or "rbxassetid://7072719338"
Background.Visible = not Background.Visible
end)
LeftPanel.Name = "LeftPanel"
LeftPanel.Parent = Background
LeftPanel.BackgroundColor3 = Color3.fromRGB(53, 52, 55)
LeftPanel.BorderSizePixel = 0
LeftPanel.Position = UDim2.new(0, 0, 0, 19)
LeftPanel.Size = UDim2.new(0, 131, 0, 249)
LogList.Name = "LogList"
LogList.Parent = LeftPanel
LogList.Active = true
LogList.BackgroundColor3 = Color3.new(1, 1, 1)
LogList.BackgroundTransparency = 1
LogList.BorderSizePixel = 0
LogList.Position = UDim2.new(0, 0, 0, 9)
LogList.Size = UDim2.new(0, 131, 0, 232)
LogList.CanvasSize = UDim2.new(0, 0, 0, 0)
LogList.ScrollBarThickness = 4
UIListLayout.Parent = LogList
UIListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
UIListLayout.SortOrder = Enum.SortOrder.LayoutOrder
RemoteTemplate.Name = "RemoteTemplate"
RemoteTemplate.Parent = LogList
RemoteTemplate.BackgroundColor3 = Color3.new(1, 1, 1)
RemoteTemplate.BackgroundTransparency = 1
RemoteTemplate.Size = UDim2.new(0, 117, 0, 27)
ColorBar.Name = "ColorBar"
ColorBar.Parent = RemoteTemplate
ColorBar.BackgroundColor3 = Color3.fromRGB(255, 242, 0)
ColorBar.BorderSizePixel = 0
ColorBar.Position = UDim2.new(0, 0, 0, 1)
ColorBar.Size = UDim2.new(0, 7, 0, 18)
ColorBar.ZIndex = 2
Text.Name = "Text"
Text.Parent = RemoteTemplate
Text.BackgroundColor3 = Color3.new(1, 1, 1)
Text.BackgroundTransparency = 1
Text.Position = UDim2.new(0, 12, 0, 1)
Text.Size = UDim2.new(0, 105, 0, 18)
Text.ZIndex = 2
Text.Font = Enum.Font.SourceSans
Text.Text = "TEXT"
Text.TextColor3 = Color3.new(1, 1, 1)
Text.TextSize = 14
Text.TextXAlignment = Enum.TextXAlignment.Left
Text.TextWrapped = true
Button.Name = "Button"
Button.Parent = RemoteTemplate
Button.BackgroundColor3 = Color3.new(0, 0, 0)
Button.BackgroundTransparency = 0.75
Button.BorderColor3 = Color3.new(1, 1, 1)
Button.Position = UDim2.new(0, 0, 0, 1)
Button.Size = UDim2.new(0, 117, 0, 18)
Button.AutoButtonColor = false
Button.Font = Enum.Font.SourceSans
Button.Text = ""
Button.TextColor3 = Color3.new(0, 0, 0)
Button.TextSize = 14
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)
FunctionTemplate.Name = "FunctionTemplate"
FunctionTemplate.Parent = ScrollingFrame
FunctionTemplate.BackgroundColor3 = Color3.new(1, 1, 1)
FunctionTemplate.BackgroundTransparency = 1
FunctionTemplate.Size = UDim2.new(0, 117, 0, 23)
ColorBar_2.Name = "ColorBar"
ColorBar_2.Parent = FunctionTemplate
ColorBar_2.BackgroundColor3 = Color3.new(1, 1, 1)
ColorBar_2.BorderSizePixel = 0
ColorBar_2.Position = UDim2.new(0, 7, 0, 10)
ColorBar_2.Size = UDim2.new(0, 7, 0, 18)
ColorBar_2.ZIndex = 3
Text_2.Name = "Text"
Text_2.Parent = FunctionTemplate
Text_2.BackgroundColor3 = Color3.new(1, 1, 1)
Text_2.BackgroundTransparency = 1
Text_2.Position = UDim2.new(0, 19, 0, 10)
Text_2.Size = UDim2.new(0, 69, 0, 18)
Text_2.ZIndex = 2
Text_2.Font = Enum.Font.SourceSans
Text_2.Text = "TEXT"
Text_2.TextColor3 = Color3.new(1, 1, 1)
Text_2.TextSize = 14
Text_2.TextStrokeColor3 = Color3.new(0.145098, 0.141176, 0.14902)
Text_2.TextXAlignment = Enum.TextXAlignment.Left
Text_2.TextWrapped = true
Button_2.Name = "Button"
Button_2.Parent = FunctionTemplate
Button_2.BackgroundColor3 = Color3.new(0, 0, 0)
Button_2.BackgroundTransparency = 0.69999998807907
Button_2.BorderColor3 = Color3.new(1, 1, 1)
Button_2.Position = UDim2.new(0, 7, 0, 10)
Button_2.Size = UDim2.new(0, 80, 0, 18)
Button_2.AutoButtonColor = false
Button_2.Font = Enum.Font.SourceSans
Button_2.Text = ""
Button_2.TextColor3 = Color3.new(0, 0, 0)
Button_2.TextSize = 14
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 For Mobile"
Simple.TextColor3 = Color3.new(0, 0, 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 = SimpleSpy2
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 RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local TweenService = game:GetService("TweenService")
local ContentProvider = game:GetService("ContentProvider")
local TextService = game:GetService("TextService")
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
local gm
local original
--- used to prevent recursives
local prevTables = {}
--- holds logs (for deletion)
local remoteLogs = {}
--- used for hookfunction
local remoteEvent = Instance.new("RemoteEvent")
--- used for hookfunction
local remoteFunction = Instance.new("RemoteFunction")
local originalEvent = remoteEvent.FireServer
local originalFunction = remoteFunction.InvokeServer
--- the maximum amount of remotes allowed in logs
_G.SIMPLESPYCONFIG_MaxRemotes = 500
--- how many spaces to indent
local indent = 4
--- used for task scheduler
local scheduled = {}
--- RBXScriptConnect of the task scheduler
local schedulerconnect
local SimpleSpy = {}
local topstr = ""
local bottomstr = ""
local remotesFadeIn
local rightFadeIn
local codebox
local p
local getnilrequired = false
-- autoblock variables
local autoblock = false
local history = {}
local excluding = {}
-- function info variables
local funcEnabled = true
-- remote hooking/connecting api variables
local remoteSignals = {}
local remoteHooks = {}
-- original mouse icon
local oldIcon
-- if mouse inside gui
local mouseInGui = false
-- handy array of RBXScriptConnections to disconnect on shutdown
local connections = {}
-- whether or not SimpleSpy uses 'getcallingscript()' to get the script (default is false because detection)
local useGetCallingScript = false
--- used to enable/disable SimpleSpy's keyToString for remotes
local keyToString = false
-- determines whether return values are recorded
local recordReturnValues = false
-- functions
--- Converts arguments to a string and generates code that calls the specified method with them, recommended to be used in conjunction with ValueToString (method must be a string, e.g. `game:GetService("ReplicatedStorage").Remote.remote:FireServer`)
--- @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
--- Generates the simplespy function info
--- @param func function
--- @return string
function SimpleSpy:GetFunctionInfo(func)
assert(typeof(func) == "function", "Instance expected, got " .. typeof(func))
warn("Function info currently unavailable due to crashing in Synapse X")
return v2v({ functionInfo = {
info = debug.getinfo(func),
constants = debug.getconstants(func),
} })
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
--- Allows for direct hooking of remotes **THIS CAN BE VERY DANGEROUS**
--- @param remote Instance
--- @param f function
function SimpleSpy:HookRemote(remote, f)
assert(typeof(remote) == "Instance", "Instance expected, got " .. typeof(remote))
assert(typeof(f) == "function", "function expected, got " .. typeof(f))
remoteHooks[remote] = f
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 {
Connected = true,
Disconnect = function(self)
if not connected then
warn("Signal is already closed")
end
self.Connected = false
connected[tostring(f)] = nil
end,
}
end,
Wait = function(self)
local thread = coroutine.running()
local connection
connection = self:Connect(function()
connection:Disconnect()
if coroutine.status(thread) == "suspended" then
coroutine.resume(thread)
end
end)
coroutine.yield()
end,
Fire = function(self, ...)
for _, f in pairs(connected) do
coroutine.wrap(f)(...)
end
end,
}
end
--- Prevents remote spam from causing lag (clears logs after `_G.SIMPLESPYCONFIG_MaxRemotes` or 500 remotes)
function clean()
local max = _G.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 = workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(bringBackOnResize)
workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
lastCam:Disconnect()
if workspace.CurrentCamera then
lastCam = workspace.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 = workspace.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
RunService.BindToRenderStep(RunService, "drag", 1, function()
local newPos = UserInputService.GetMouseLocation(UserInputService)
if newPos ~= lastPos then
local currentX = (offset + newPos).X
local currentY = (offset + newPos).Y
local viewportSize = workspace.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
RunService:UnbindFromRenderStep("drag")
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 pairs(elements) do
if typeof(v) == "Instance" and v:IsA("GuiObject") and v.Visible then
coroutine.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
wait(0.5)
v.Visible = false
for i, x in pairs(data[v]) do
v[i] = x
end
data[v] = true
end)()
end
end
return function()
for i, _ in pairs(data) do
coroutine.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()
maximized = false
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
end)
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 = workspace.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
--- Gets the player an instance is descended from
function getPlayerFromInstance(instance)
for _, v in pairs(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 and selected.Log.Button then
TweenService
:Create(selected.Log.Button, TweenInfo.new(0.5), { BackgroundColor3 = Color3.fromRGB(0, 0, 0) })
:Play()
selected = nil
end
for _, v in pairs(logs) do
if frame == v.Log then
selected = v
end
end
if selected and selected.Log then
TweenService
:Create(frame.Button, TweenInfo.new(0.5), { BackgroundColor3 = Color3.fromRGB(92, 126, 229) })
:Play()
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 then
if ToolTip.Visible then
ToolTip.Visible = false
RunService:UnbindFromRenderStep("ToolTip")
end
local first = true
RunService:BindToRenderStep("ToolTip", 1, function()
local topLeft = Vector2.new(Mouse.X + 20, Mouse.Y + 20)
local bottomRight = topLeft + ToolTip.AbsoluteSize
if topLeft.X < 0 then
topLeft = Vector2.new(0, topLeft.Y)
elseif bottomRight.X > workspace.CurrentCamera.ViewportSize.X then
topLeft = Vector2.new(workspace.CurrentCamera.ViewportSize.X - ToolTip.AbsoluteSize.X, topLeft.Y)
end
if topLeft.Y < 0 then
topLeft = Vector2.new(topLeft.X, 0)
elseif bottomRight.Y > workspace.CurrentCamera.ViewportSize.Y - 35 then
topLeft = Vector2.new(topLeft.X, workspace.CurrentCamera.ViewportSize.Y - 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
ToolTip.Visible = true
else
if ToolTip.Visible then
ToolTip.Visible = false
RunService:UnbindFromRenderStep("ToolTip")
end
end
end
--- Creates new function button (below codebox)
--- @param name string
---@param description function
---@param onClick function
function newButton(name, description, onClick)
local button = FunctionTemplate:Clone()
button.Text.Text = name
button.Button.MouseEnter:Connect(function()
makeToolTip(true, description())
end)
button.Button.MouseLeave:Connect(function()
makeToolTip(false)
end)
button.AncestryChanged:Connect(function()
makeToolTip(false)
end)
button.Button.MouseButton1Click:Connect(function(...)
onClick(button, ...)
end)
button.Parent = ScrollingFrame
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, returnValue)
local remoteFrame = RemoteTemplate:Clone()
remoteFrame.Text.Text = string.sub(name, 1, 50)
remoteFrame.ColorBar.BackgroundColor3 = type == "event" and Color3.new(255, 242, 0) or Color3.fromRGB(99, 86, 245)
local id = Instance.new("IntValue")
id.Name = "ID"
id.Value = #logs + 1
id.Parent = remoteFrame
local weakRemoteTable = setmetatable({ remote = remote }, { __mode = "v" })
local log = {
Name = name,
Function = function_info,
Remote = weakRemoteTable,
Log = remoteFrame,
Blocked = blocked,
Source = src,
GenScript = "-- Generating, please wait... (click to reload)\n-- (If this message persists, the remote args are likely extremely long)",
ReturnValue = returnValue,
}
logs[#logs + 1] = log
schedule(function()
log.GenScript = genScript(remote, args)
if blocked then
logs[#logs].GenScript = "-- THIS REMOTE WAS PREVENTED FROM FIRING THE SERVER BY SIMPLESPY\n\n"
.. logs[#logs].GenScript
end
end)
local connect = remoteFrame.Button.MouseButton1Click:Connect(function()
eventSelect(remoteFrame)
end)
if layoutOrderNum < 1 then
layoutOrderNum = 999999999
end
remoteFrame.LayoutOrder = layoutOrderNum
layoutOrderNum = layoutOrderNum - 1
remoteFrame.Parent = LogList
table.insert(remoteLogs, 1, { connect, remoteFrame })
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 pairs(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 pairs(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
gen = gen
prevTables = {}
return gen
end
--- value-to-string: value, string (out), level (indentation), parent table, var name, is from tovar
function v2s(v, l, p, n, vtv, i, pt, path, tables, tI)
if not tI then
tI = { 0 }
else
tI[1] += 1
end
if typeof(v) == "number" then
if v == math.huge then
return "math.huge"
elseif tostring(v):match("nan") then
return "0/0 --[[NaN]]"
end
return tostring(v)
elseif typeof(v) == "boolean" then
return tostring(v)
elseif typeof(v) == "string" then
return formatstr(v, l)
elseif typeof(v) == "function" then
return f2s(v)
elseif typeof(v) == "table" then
return t2s(v, l, p, n, vtv, i, pt, path, tables, tI)
elseif typeof(v) == "Instance" then
return i2p(v)
elseif typeof(v) == "userdata" then
return "newproxy(true)"
elseif type(v) == "userdata" then
return u2s(v)
elseif type(v) == "vector" then
return string.format("Vector3.new(%s, %s, %s)", v2s(v.X), v2s(v.Y), v2s(v.Z))
else
return "nil --[[" .. typeof(v) .. "]]"
end
end
--- value-to-variable
--- @param t any
function v2v(t)
topstr = ""
bottomstr = ""
getnilrequired = false
local ret = ""
local count = 1
for i, v in pairs(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 "
.. tostring(i):lower()
.. "_"
.. tostring(count)
.. " = "
.. v2s(v, nil, nil, tostring(i):lower() .. "_" .. 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 pairs(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 pairs(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 pairs(t) do -- iterates over table
size = size + 1 -- changes size for max limit
if size > (_G.SimpleSpyMaxTableSize or 1000) then
s = s
.. "\n"
.. string.rep(" ", l)
.. "-- MAXIMUM TABLE SIZE REACHED, CHANGE '_G.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 = "[" .. k2s(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)
.. "["
.. k2s(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
--- key-to-string
function k2s(v, ...)
if keyToString then
if typeof(v) == "userdata" and getrawmetatable(v) then
return string.format(
'"<void> (%s)" --[[Potentially hidden data (tostring in SimpleSpy:HookRemote/GetRemoteFiredSignal at your own risk)]]',
safetostring(v)
)
elseif typeof(v) == "userdata" then
return string.format('"<void> (%s)"', safetostring(v))
elseif type(v) == "userdata" and typeof(v) ~= "Instance" then
return string.format('"<%s> (%s)"', typeof(v), tostring(v))
elseif type(v) == "function" then
return string.format('"<Function> (%s)"', tostring(v))
end
end
return v2s(v, ...)
end
--- function-to-string
function f2s(f)
for k, x in pairs(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 funcEnabled and debug.getinfo(f).name:match("^[%a_]+[%w_]*$") then
return "function()end --[[" .. debug.getinfo(f).name .. "]]"
end
return "function()end --[[" .. 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
local service = game:FindService(parent.ClassName)
if service then
if parent.ClassName == "Workspace" then
return "workspace" .. out
else
return 'game:GetService("' .. service.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
--- userdata-to-string: userdata
--- @param u userdata
function u2s(u)
if typeof(u) == "TweenInfo" then
-- TweenInfo
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)
.. ")"
elseif typeof(u) == "Ray" then
-- Ray
return "Ray.new(" .. u2s(u.Origin) .. ", " .. u2s(u.Direction) .. ")"
elseif typeof(u) == "NumberSequence" then
-- NumberSequence
local ret = "NumberSequence.new("
for i, v in pairs(u.KeyPoints) do
ret = ret .. tostring(v)
if i < #u.Keypoints then
ret = ret .. ", "
end
end
return ret .. ")"
elseif typeof(u) == "DockWidgetPluginGuiInfo" then
-- DockWidgetPluginGuiInfo
return "DockWidgetPluginGuiInfo.new(Enum.InitialDockState" .. tostring(u) .. ")"
elseif typeof(u) == "ColorSequence" then
-- ColorSequence
local ret = "ColorSequence.new("
for i, v in pairs(u.KeyPoints) do
ret = ret .. "Color3.new(" .. tostring(v) .. ")"
if i < #u.Keypoints then
ret = ret .. ", "
end
end
return ret .. ")"
elseif typeof(u) == "BrickColor" then
-- BrickColor
return "BrickColor.new(" .. tostring(u.Number) .. ")"
elseif typeof(u) == "NumberRange" then
-- NumberRange
return "NumberRange.new(" .. tostring(u.Min) .. ", " .. tostring(u.Max) .. ")"
elseif typeof(u) == "Region3" then
-- Region3
local center = u.CFrame.Position
local size = u.CFrame.Size
local vector1 = center - size / 2
local vector2 = center + size / 2
return "Region3.new(" .. u2s(vector1) .. ", " .. u2s(vector2) .. ")"
elseif typeof(u) == "Faces" then
-- Faces
local faces = {}
if u.Top then
table.insert(faces, "Enum.NormalId.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(" .. table.concat(faces, ", ") .. ")"
elseif typeof(u) == "EnumItem" then
return tostring(u)
elseif typeof(u) == "Enums" then
return "Enum"
elseif typeof(u) == "Enum" then
return "Enum." .. tostring(u)
elseif typeof(u) == "RBXScriptSignal" then
return "nil --[[RBXScriptSignal]]"
elseif typeof(u) == "Vector3" then
return string.format("Vector3.new(%s, %s, %s)", v2s(u.X), v2s(u.Y), v2s(u.Z))
elseif typeof(u) == "CFrame" then
local xAngle, yAngle, zAngle = u:ToEulerAnglesXYZ()
return string.format(
"CFrame.new(%s, %s, %s) * CFrame.Angles(%s, %s, %s)",
v2s(u.X),
v2s(u.Y),
v2s(u.Z),
v2s(xAngle),
v2s(yAngle),
v2s(zAngle)
)
elseif typeof(u) == "DockWidgetPluginGuiInfo" then
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)
)
elseif typeof(u) == "PathWaypoint" then
return string.format("PathWaypoint.new(%s, %s)", v2s(u.Position), v2s(u.Action))
elseif typeof(u) == "UDim" then
return string.format("UDim.new(%s, %s)", v2s(u.Scale), v2s(u.Offset))
elseif typeof(u) == "UDim2" then
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)
)
elseif typeof(u) =Remote Script extracts any script or code
سكربت ريموت يستخرج اي سكربت او كود شي
No comments yet. Be the first to comment!
1if _G.SimpleSpyExecuted and type(_G.SimpleSpyShutdown) == "function" then
2 print(pcall(_G.SimpleSpyShutdown))
3end
4
5local Players = game:GetService("Players")
6local CoreGui = game:GetService("CoreGui")
7local Highlight =
8 loadstring(
9 game:HttpGet("https://raw.githubusercontent.com/yofriendfromschool1/Sky-Hub-Backup/main/SimpleSpyV3/mobilehighlight.lua")
10 )()
11
12---- GENERATED (kinda sorta mostly) BY GUI to LUA ----
13
14-- Instances:
15
16local SimpleSpy2 = Instance.new("ScreenGui")
17local Background = Instance.new("Frame")
18local LeftPanel = Instance.new("Frame")
19local LogList = Instance.new("ScrollingFrame")
20local UIListLayout = Instance.new("UIListLayout")
21local RemoteTemplate = Instance.new("Frame")
22local ColorBar = Instance.new("Frame")
23local Text = Instance.new("TextLabel")
24local Button = Instance.new("TextButton")
25local RightPanel = Instance.new("Frame")
26local CodeBox = Instance.new("Frame")
27local ScrollingFrame = Instance.new("ScrollingFrame")
28local UIGridLayout = Instance.new("UIGridLayout")
29local FunctionTemplate = Instance.new("Frame")
30local ColorBar_2 = Instance.new("Frame")
31local Text_2 = Instance.new("TextLabel")
32local Button_2 = Instance.new("TextButton")
33local TopBar = Instance.new("Frame")
34local Simple = Instance.new("TextButton")
35local CloseButton = Instance.new("TextButton")
36local ImageLabel = Instance.new("ImageLabel")
37local MaximizeButton = Instance.new("TextButton")
38local ImageLabel_2 = Instance.new("ImageLabel")
39local MinimizeButton = Instance.new("TextButton")
40local ImageLabel_3 = Instance.new("ImageLabel")
41local ToolTip = Instance.new("Frame")
42local TextLabel = Instance.new("TextLabel")
43local gui = Instance.new("ScreenGui",Background)
44local nextb = Instance.new("ImageButton", gui)
45local gui = Instance.new("UICorner", nextb)
46
47--Properties:
48
49SimpleSpy2.Name = "SimpleSpy2"
50SimpleSpy2.ResetOnSpawn = false
51
52local SpyFind = CoreGui:FindFirstChild(SimpleSpy2.Name)
53
54if SpyFind and SpyFind ~= SimpleSpy2 then
55 SpyFind:Destroy()
56end
57
58Background.Name = "Background"
59Background.Parent = SimpleSpy2
60Background.BackgroundColor3 = Color3.new(1, 1, 1)
61Background.BackgroundTransparency = 1
62Background.Position = UDim2.new(0, 160, 0, 100)
63Background.Size = UDim2.new(0, 450, 0, 268)
64Background.Active = true
65Background.Draggable = true
66
67nextb.Position = UDim2.new(0,100,0,60)
68nextb.Size = UDim2.new(0,40,0,40)
69nextb.BackgroundColor3 = Color3.fromRGB(53, 52, 55)
70nextb.Image = "rbxassetid://7072720870"
71nextb.Active = true
72nextb.Draggable = true
73nextb.MouseButton1Down:connect(function()
74nextb.Image = (Background.Visible and "rbxassetid://7072720870") or "rbxassetid://7072719338"
75Background.Visible = not Background.Visible
76end)
77
78LeftPanel.Name = "LeftPanel"
79LeftPanel.Parent = Background
80LeftPanel.BackgroundColor3 = Color3.fromRGB(53, 52, 55)
81LeftPanel.BorderSizePixel = 0
82LeftPanel.Position = UDim2.new(0, 0, 0, 19)
83LeftPanel.Size = UDim2.new(0, 131, 0, 249)
84
85LogList.Name = "LogList"
86LogList.Parent = LeftPanel
87LogList.Active = true
88LogList.BackgroundColor3 = Color3.new(1, 1, 1)
89LogList.BackgroundTransparency = 1
90LogList.BorderSizePixel = 0
91LogList.Position = UDim2.new(0, 0, 0, 9)
92LogList.Size = UDim2.new(0, 131, 0, 232)
93LogList.CanvasSize = UDim2.new(0, 0, 0, 0)
94LogList.ScrollBarThickness = 4
95
96UIListLayout.Parent = LogList
97UIListLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
98UIListLayout.SortOrder = Enum.SortOrder.LayoutOrder
99
100RemoteTemplate.Name = "RemoteTemplate"
101RemoteTemplate.Parent = LogList
102RemoteTemplate.BackgroundColor3 = Color3.new(1, 1, 1)
103RemoteTemplate.BackgroundTransparency = 1
104RemoteTemplate.Size = UDim2.new(0, 117, 0, 27)
105
106ColorBar.Name = "ColorBar"
107ColorBar.Parent = RemoteTemplate
108ColorBar.BackgroundColor3 = Color3.fromRGB(255, 242, 0)
109ColorBar.BorderSizePixel = 0
110ColorBar.Position = UDim2.new(0, 0, 0, 1)
111ColorBar.Size = UDim2.new(0, 7, 0, 18)
112ColorBar.ZIndex = 2
113
114Text.Name = "Text"
115Text.Parent = RemoteTemplate
116Text.BackgroundColor3 = Color3.new(1, 1, 1)
117Text.BackgroundTransparency = 1
118Text.Position = UDim2.new(0, 12, 0, 1)
119Text.Size = UDim2.new(0, 105, 0, 18)
120Text.ZIndex = 2
121Text.Font = Enum.Font.SourceSans
122Text.Text = "TEXT"
123Text.TextColor3 = Color3.new(1, 1, 1)
124Text.TextSize = 14
125Text.TextXAlignment = Enum.TextXAlignment.Left
126Text.TextWrapped = true
127
128Button.Name = "Button"
129Button.Parent = RemoteTemplate
130Button.BackgroundColor3 = Color3.new(0, 0, 0)
131Button.BackgroundTransparency = 0.75
132Button.BorderColor3 = Color3.new(1, 1, 1)
133Button.Position = UDim2.new(0, 0, 0, 1)
134Button.Size = UDim2.new(0, 117, 0, 18)
135Button.AutoButtonColor = false
136Button.Font = Enum.Font.SourceSans
137Button.Text = ""
138Button.TextColor3 = Color3.new(0, 0, 0)
139Button.TextSize = 14
140
141RightPanel.Name = "RightPanel"
142RightPanel.Parent = Background
143RightPanel.BackgroundColor3 = Color3.fromRGB(37, 36, 38)
144RightPanel.BorderSizePixel = 0
145RightPanel.Position = UDim2.new(0, 131, 0, 19)
146RightPanel.Size = UDim2.new(0, 319, 0, 249)
147
148CodeBox.Name = "CodeBox"
149CodeBox.Parent = RightPanel
150CodeBox.BackgroundColor3 = Color3.new(0.0823529, 0.0745098, 0.0784314)
151CodeBox.BorderSizePixel = 0
152CodeBox.Size = UDim2.new(0, 319, 0, 119)
153
154ScrollingFrame.Parent = RightPanel
155ScrollingFrame.Active = true
156ScrollingFrame.BackgroundColor3 = Color3.new(1, 1, 1)
157ScrollingFrame.BackgroundTransparency = 1
158ScrollingFrame.Position = UDim2.new(0, 0, 0.5, 0)
159ScrollingFrame.Size = UDim2.new(1, 0, 0.5, -9)
160ScrollingFrame.CanvasSize = UDim2.new(0, 0, 0, 0)
161ScrollingFrame.ScrollBarThickness = 4
162
163UIGridLayout.Parent = ScrollingFrame
164UIGridLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
165UIGridLayout.SortOrder = Enum.SortOrder.LayoutOrder
166UIGridLayout.CellPadding = UDim2.new(0, 0, 0, 0)
167UIGridLayout.CellSize = UDim2.new(0, 94, 0, 27)
168
169FunctionTemplate.Name = "FunctionTemplate"
170FunctionTemplate.Parent = ScrollingFrame
171FunctionTemplate.BackgroundColor3 = Color3.new(1, 1, 1)
172FunctionTemplate.BackgroundTransparency = 1
173FunctionTemplate.Size = UDim2.new(0, 117, 0, 23)
174
175ColorBar_2.Name = "ColorBar"
176ColorBar_2.Parent = FunctionTemplate
177ColorBar_2.BackgroundColor3 = Color3.new(1, 1, 1)
178ColorBar_2.BorderSizePixel = 0
179ColorBar_2.Position = UDim2.new(0, 7, 0, 10)
180ColorBar_2.Size = UDim2.new(0, 7, 0, 18)
181ColorBar_2.ZIndex = 3
182
183Text_2.Name = "Text"
184Text_2.Parent = FunctionTemplate
185Text_2.BackgroundColor3 = Color3.new(1, 1, 1)
186Text_2.BackgroundTransparency = 1
187Text_2.Position = UDim2.new(0, 19, 0, 10)
188Text_2.Size = UDim2.new(0, 69, 0, 18)
189Text_2.ZIndex = 2
190Text_2.Font = Enum.Font.SourceSans
191Text_2.Text = "TEXT"
192Text_2.TextColor3 = Color3.new(1, 1, 1)
193Text_2.TextSize = 14
194Text_2.TextStrokeColor3 = Color3.new(0.145098, 0.141176, 0.14902)
195Text_2.TextXAlignment = Enum.TextXAlignment.Left
196Text_2.TextWrapped = true
197
198Button_2.Name = "Button"
199Button_2.Parent = FunctionTemplate
200Button_2.BackgroundColor3 = Color3.new(0, 0, 0)
201Button_2.BackgroundTransparency = 0.69999998807907
202Button_2.BorderColor3 = Color3.new(1, 1, 1)
203Button_2.Position = UDim2.new(0, 7, 0, 10)
204Button_2.Size = UDim2.new(0, 80, 0, 18)
205Button_2.AutoButtonColor = false
206Button_2.Font = Enum.Font.SourceSans
207Button_2.Text = ""
208Button_2.TextColor3 = Color3.new(0, 0, 0)
209Button_2.TextSize = 14
210
211TopBar.Name = "TopBar"
212TopBar.Parent = Background
213TopBar.BackgroundColor3 = Color3.fromRGB(37, 35, 38)
214TopBar.BorderSizePixel = 0
215TopBar.Size = UDim2.new(0, 450, 0, 19)
216
217Simple.Name = "Simple"
218Simple.Parent = TopBar
219Simple.BackgroundColor3 = Color3.new(1, 1, 1)
220Simple.AutoButtonColor = false
221Simple.BackgroundTransparency = 1
222Simple.Position = UDim2.new(0, 5, 0, 0)
223Simple.Size = UDim2.new(0, 57, 0, 18)
224Simple.Font = Enum.Font.SourceSansBold
225Simple.Text = "SimpleSpy For Mobile"
226Simple.TextColor3 = Color3.new(0, 0, 1)
227Simple.TextSize = 14
228Simple.TextXAlignment = Enum.TextXAlignment.Left
229
230CloseButton.Name = "CloseButton"
231CloseButton.Parent = TopBar
232CloseButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
233CloseButton.BorderSizePixel = 0
234CloseButton.Position = UDim2.new(1, -19, 0, 0)
235CloseButton.Size = UDim2.new(0, 19, 0, 19)
236CloseButton.Font = Enum.Font.SourceSans
237CloseButton.Text = ""
238CloseButton.TextColor3 = Color3.new(0, 0, 0)
239CloseButton.TextSize = 14
240
241ImageLabel.Parent = CloseButton
242ImageLabel.BackgroundColor3 = Color3.new(1, 1, 1)
243ImageLabel.BackgroundTransparency = 1
244ImageLabel.Position = UDim2.new(0, 5, 0, 5)
245ImageLabel.Size = UDim2.new(0, 9, 0, 9)
246ImageLabel.Image = "http://www.roblox.com/asset/?id=5597086202"
247
248MaximizeButton.Name = "MaximizeButton"
249MaximizeButton.Parent = TopBar
250MaximizeButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
251MaximizeButton.BorderSizePixel = 0
252MaximizeButton.Position = UDim2.new(1, -38, 0, 0)
253MaximizeButton.Size = UDim2.new(0, 19, 0, 19)
254MaximizeButton.Font = Enum.Font.SourceSans
255MaximizeButton.Text = ""
256MaximizeButton.TextColor3 = Color3.new(0, 0, 0)
257MaximizeButton.TextSize = 14
258
259ImageLabel_2.Parent = MaximizeButton
260ImageLabel_2.BackgroundColor3 = Color3.new(1, 1, 1)
261ImageLabel_2.BackgroundTransparency = 1
262ImageLabel_2.Position = UDim2.new(0, 5, 0, 5)
263ImageLabel_2.Size = UDim2.new(0, 9, 0, 9)
264ImageLabel_2.Image = "http://www.roblox.com/asset/?id=5597108117"
265
266MinimizeButton.Name = "MinimizeButton"
267MinimizeButton.Parent = TopBar
268MinimizeButton.BackgroundColor3 = Color3.new(0.145098, 0.141176, 0.14902)
269MinimizeButton.BorderSizePixel = 0
270MinimizeButton.Position = UDim2.new(1, -57, 0, 0)
271MinimizeButton.Size = UDim2.new(0, 19, 0, 19)
272MinimizeButton.Font = Enum.Font.SourceSans
273MinimizeButton.Text = ""
274MinimizeButton.TextColor3 = Color3.new(0, 0, 0)
275MinimizeButton.TextSize = 14
276
277ImageLabel_3.Parent = MinimizeButton
278ImageLabel_3.BackgroundColor3 = Color3.new(1, 1, 1)
279ImageLabel_3.BackgroundTransparency = 1
280ImageLabel_3.Position = UDim2.new(0, 5, 0, 5)
281ImageLabel_3.Size = UDim2.new(0, 9, 0, 9)
282ImageLabel_3.Image = "http://www.roblox.com/asset/?id=5597105827"
283
284ToolTip.Name = "ToolTip"
285ToolTip.Parent = SimpleSpy2
286ToolTip.BackgroundColor3 = Color3.fromRGB(26, 26, 26)
287ToolTip.BackgroundTransparency = 0.1
288ToolTip.BorderColor3 = Color3.new(1, 1, 1)
289ToolTip.Size = UDim2.new(0, 200, 0, 50)
290ToolTip.ZIndex = 3
291ToolTip.Visible = false
292
293TextLabel.Parent = ToolTip
294TextLabel.BackgroundColor3 = Color3.new(1, 1, 1)
295TextLabel.BackgroundTransparency = 1
296TextLabel.Position = UDim2.new(0, 2, 0, 2)
297TextLabel.Size = UDim2.new(0, 196, 0, 46)
298TextLabel.ZIndex = 3
299TextLabel.Font = Enum.Font.SourceSans
300TextLabel.Text = "This is some slightly longer text."
301TextLabel.TextColor3 = Color3.new(1, 1, 1)
302TextLabel.TextSize = 14
303TextLabel.TextWrapped = true
304TextLabel.TextXAlignment = Enum.TextXAlignment.Left
305TextLabel.TextYAlignment = Enum.TextYAlignment.Top
306
307-------------------------------------------------------------------------------
308-- init
309local RunService = game:GetService("RunService")
310local UserInputService = game:GetService("UserInputService")
311local TweenService = game:GetService("TweenService")
312local ContentProvider = game:GetService("ContentProvider")
313local TextService = game:GetService("TextService")
314local Mouse
315
316local selectedColor = Color3.new(0.321569, 0.333333, 1)
317local deselectedColor = Color3.new(0.8, 0.8, 0.8)
318--- So things are descending
319local layoutOrderNum = 999999999
320--- Whether or not the gui is closing
321local mainClosing = false
322--- Whether or not the gui is closed (defaults to false)
323local closed = false
324--- Whether or not the sidebar is closing
325local sideClosing = false
326--- Whether or not the sidebar is closed (defaults to true but opens automatically on remote selection)
327local sideClosed = false
328--- Whether or not the code box is maximized (defaults to false)
329local maximized = false
330--- The event logs to be read from
331local logs = {}
332--- The event currently selected.Log (defaults to nil)
333local selected = nil
334--- The blacklist (can be a string name or the Remote Instance)
335local blacklist = {}
336--- The block list (can be a string name or the Remote Instance)
337local blocklist = {}
338--- Whether or not to add getNil function
339local getNil = false
340--- Array of remotes (and original functions) connected to
341local connectedRemotes = {}
342--- True = hookfunction, false = namecall
343local toggle = false
344local gm
345local original
346--- used to prevent recursives
347local prevTables = {}
348--- holds logs (for deletion)
349local remoteLogs = {}
350--- used for hookfunction
351local remoteEvent = Instance.new("RemoteEvent")
352--- used for hookfunction
353local remoteFunction = Instance.new("RemoteFunction")
354local originalEvent = remoteEvent.FireServer
355local originalFunction = remoteFunction.InvokeServer
356--- the maximum amount of remotes allowed in logs
357_G.SIMPLESPYCONFIG_MaxRemotes = 500
358--- how many spaces to indent
359local indent = 4
360--- used for task scheduler
361local scheduled = {}
362--- RBXScriptConnect of the task scheduler
363local schedulerconnect
364local SimpleSpy = {}
365local topstr = ""
366local bottomstr = ""
367local remotesFadeIn
368local rightFadeIn
369local codebox
370local p
371local getnilrequired = false
372
373-- autoblock variables
374local autoblock = false
375local history = {}
376local excluding = {}
377
378-- function info variables
379local funcEnabled = true
380
381-- remote hooking/connecting api variables
382local remoteSignals = {}
383local remoteHooks = {}
384
385-- original mouse icon
386local oldIcon
387
388-- if mouse inside gui
389local mouseInGui = false
390
391-- handy array of RBXScriptConnections to disconnect on shutdown
392local connections = {}
393
394-- whether or not SimpleSpy uses 'getcallingscript()' to get the script (default is false because detection)
395local useGetCallingScript = false
396
397--- used to enable/disable SimpleSpy's keyToString for remotes
398local keyToString = false
399
400-- determines whether return values are recorded
401local recordReturnValues = false
402
403-- functions
404
405--- Converts arguments to a string and generates code that calls the specified method with them, recommended to be used in conjunction with ValueToString (method must be a string, e.g. `game:GetService("ReplicatedStorage").Remote.remote:FireServer`)
406--- @param method string
407--- @param args any[]
408--- @return string
409function SimpleSpy:ArgsToString(method, args)
410 assert(typeof(method) == "string", "string expected, got " .. typeof(method))
411 assert(typeof(args) == "table", "table expected, got " .. typeof(args))
412 return v2v({ args = args }) .. "\n\n" .. method .. "(unpack(args))"
413end
414
415--- Converts a value to variables with the specified index as the variable name (if nil/invalid then the name will be assigned automatically)
416--- @param t any[]
417--- @return string
418function SimpleSpy:TableToVars(t)
419 assert(typeof(t) == "table", "table expected, got " .. typeof(t))
420 return v2v(t)
421end
422
423--- Converts a value to a variable with the specified `variablename` (if nil/invalid then the name will be assigned automatically)
424--- @param value any
425--- @return string
426function SimpleSpy:ValueToVar(value, variablename)
427 assert(variablename == nil or typeof(variablename) == "string", "string expected, got " .. typeof(variablename))
428 if not variablename then
429 variablename = 1
430 end
431 return v2v({ [variablename] = value })
432end
433
434--- Converts any value to a string, cannot preserve function contents
435--- @param value any
436--- @return string
437function SimpleSpy:ValueToString(value)
438 return v2s(value)
439end
440
441--- Generates the simplespy function info
442--- @param func function
443--- @return string
444function SimpleSpy:GetFunctionInfo(func)
445 assert(typeof(func) == "function", "Instance expected, got " .. typeof(func))
446 warn("Function info currently unavailable due to crashing in Synapse X")
447 return v2v({ functionInfo = {
448 info = debug.getinfo(func),
449 constants = debug.getconstants(func),
450 } })
451end
452
453--- Gets the ScriptSignal for a specified remote being fired
454--- @param remote Instance
455function SimpleSpy:GetRemoteFiredSignal(remote)
456 assert(typeof(remote) == "Instance", "Instance expected, got " .. typeof(remote))
457 if not remoteSignals[remote] then
458 remoteSignals[remote] = newSignal()
459 end
460 return remoteSignals[remote]
461end
462
463--- Allows for direct hooking of remotes **THIS CAN BE VERY DANGEROUS**
464--- @param remote Instance
465--- @param f function
466function SimpleSpy:HookRemote(remote, f)
467 assert(typeof(remote) == "Instance", "Instance expected, got " .. typeof(remote))
468 assert(typeof(f) == "function", "function expected, got " .. typeof(f))
469 remoteHooks[remote] = f
470end
471
472--- Blocks the specified remote instance/string
473--- @param remote any
474function SimpleSpy:BlockRemote(remote)
475 assert(
476 typeof(remote) == "Instance" or typeof(remote) == "string",
477 "Instance | string expected, got " .. typeof(remote)
478 )
479 blocklist[remote] = true
480end
481
482--- Excludes the specified remote from logs (instance/string)
483--- @param remote any
484function SimpleSpy:ExcludeRemote(remote)
485 assert(
486 typeof(remote) == "Instance" or typeof(remote) == "string",
487 "Instance | string expected, got " .. typeof(remote)
488 )
489 blacklist[remote] = true
490end
491
492--- Creates a new ScriptSignal that can be connected to and fired
493--- @return table
494function newSignal()
495 local connected = {}
496 return {
497 Connect = function(self, f)
498 assert(connected, "Signal is closed")
499 connected[tostring(f)] = f
500 return {
501 Connected = true,
502 Disconnect = function(self)
503 if not connected then
504 warn("Signal is already closed")
505 end
506 self.Connected = false
507 connected[tostring(f)] = nil
508 end,
509 }
510 end,
511 Wait = function(self)
512 local thread = coroutine.running()
513 local connection
514 connection = self:Connect(function()
515 connection:Disconnect()
516 if coroutine.status(thread) == "suspended" then
517 coroutine.resume(thread)
518 end
519 end)
520 coroutine.yield()
521 end,
522 Fire = function(self, ...)
523 for _, f in pairs(connected) do
524 coroutine.wrap(f)(...)
525 end
526 end,
527 }
528end
529
530--- Prevents remote spam from causing lag (clears logs after `_G.SIMPLESPYCONFIG_MaxRemotes` or 500 remotes)
531function clean()
532 local max = _G.SIMPLESPYCONFIG_MaxRemotes
533 if not typeof(max) == "number" and math.floor(max) ~= max then
534 max = 500
535 end
536 if #remoteLogs > max then
537 for i = 100, #remoteLogs do
538 local v = remoteLogs[i]
539 if typeof(v[1]) == "RBXScriptConnection" then
540 v[1]:Disconnect()
541 end
542 if typeof(v[2]) == "Instance" then
543 v[2]:Destroy()
544 end
545 end
546 local newLogs = {}
547 for i = 1, 100 do
548 table.insert(newLogs, remoteLogs[i])
549 end
550 remoteLogs = newLogs
551 end
552end
553
554--- Scales the ToolTip to fit containing text
555function scaleToolTip()
556 local size = TextService:GetTextSize(
557 TextLabel.Text,
558 TextLabel.TextSize,
559 TextLabel.Font,
560 Vector2.new(196, math.huge)
561 )
562 TextLabel.Size = UDim2.new(0, size.X, 0, size.Y)
563 ToolTip.Size = UDim2.new(0, size.X + 4, 0, size.Y + 4)
564end
565
566--- Executed when the toggle button (the SimpleSpy logo) is hovered over
567function onToggleButtonHover()
568 if not toggle then
569 TweenService:Create(Simple, TweenInfo.new(0.5), { TextColor3 = Color3.fromRGB(252, 51, 51) }):Play()
570 else
571 TweenService:Create(Simple, TweenInfo.new(0.5), { TextColor3 = Color3.fromRGB(68, 206, 91) }):Play()
572 end
573end
574
575--- Executed when the toggle button is unhovered over
576function onToggleButtonUnhover()
577 TweenService:Create(Simple, TweenInfo.new(0.5), { TextColor3 = Color3.fromRGB(255, 255, 255) }):Play()
578end
579
580--- Executed when the X button is hovered over
581function onXButtonHover()
582 TweenService:Create(CloseButton, TweenInfo.new(0.2), { BackgroundColor3 = Color3.fromRGB(255, 60, 60) }):Play()
583end
584
585--- Executed when the X button is unhovered over
586function onXButtonUnhover()
587 TweenService:Create(CloseButton, TweenInfo.new(0.2), { BackgroundColor3 = Color3.fromRGB(37, 36, 38) }):Play()
588end
589
590--- Toggles the remote spy method (when button clicked)
591function onToggleButtonClick()
592 if toggle then
593 TweenService:Create(Simple, TweenInfo.new(0.5), { TextColor3 = Color3.fromRGB(252, 51, 51) }):Play()
594 else
595 TweenService:Create(Simple, TweenInfo.new(0.5), { TextColor3 = Color3.fromRGB(68, 206, 91) }):Play()
596 end
597 toggleSpyMethod()
598end
599
600--- Reconnects bringBackOnResize if the current viewport changes and also connects it initially
601function connectResize()
602 local lastCam = workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(bringBackOnResize)
603 workspace:GetPropertyChangedSignal("CurrentCamera"):Connect(function()
604 lastCam:Disconnect()
605 if workspace.CurrentCamera then
606 lastCam = workspace.CurrentCamera:GetPropertyChangedSignal("ViewportSize"):Connect(bringBackOnResize)
607 end
608 end)
609end
610
611--- Brings gui back if it gets lost offscreen (connected to the camera viewport changing)
612function bringBackOnResize()
613 validateSize()
614 if sideClosed then
615 minimizeSize()
616 else
617 maximizeSize()
618 end
619 local currentX = Background.AbsolutePosition.X
620 local currentY = Background.AbsolutePosition.Y
621 local viewportSize = workspace.CurrentCamera.ViewportSize
622 if (currentX < 0) or (currentX > (viewportSize.X - (sideClosed and 131 or Background.AbsoluteSize.X))) then
623 if currentX < 0 then
624 currentX = 0
625 else
626 currentX = viewportSize.X - (sideClosed and 131 or Background.AbsoluteSize.X)
627 end
628 end
629 if (currentY < 0) or (currentY > (viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36)) then
630 if currentY < 0 then
631 currentY = 0
632 else
633 currentY = viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36
634 end
635 end
636 TweenService.Create(
637 TweenService,
638 Background,
639 TweenInfo.new(0.1),
640 { Position = UDim2.new(0, currentX, 0, currentY) }
641 ):Play()
642end
643
644--- Drags gui (so long as mouse is held down)
645--- @param input InputObject
646function onBarInput(input)
647 if input.UserInputType == Enum.UserInputType.MouseButton1 then
648 local lastPos = UserInputService.GetMouseLocation(UserInputService)
649 local mainPos = Background.AbsolutePosition
650 local offset = mainPos - lastPos
651 local currentPos = offset + lastPos
652 RunService.BindToRenderStep(RunService, "drag", 1, function()
653 local newPos = UserInputService.GetMouseLocation(UserInputService)
654 if newPos ~= lastPos then
655 local currentX = (offset + newPos).X
656 local currentY = (offset + newPos).Y
657 local viewportSize = workspace.CurrentCamera.ViewportSize
658 if
659 (currentX < 0 and currentX < currentPos.X)
660 or (
661 currentX > (viewportSize.X - (sideClosed and 131 or TopBar.AbsoluteSize.X))
662 and currentX > currentPos.X
663 )
664 then
665 if currentX < 0 then
666 currentX = 0
667 else
668 currentX = viewportSize.X - (sideClosed and 131 or TopBar.AbsoluteSize.X)
669 end
670 end
671 if
672 (currentY < 0 and currentY < currentPos.Y)
673 or (
674 currentY > (viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36)
675 and currentY > currentPos.Y
676 )
677 then
678 if currentY < 0 then
679 currentY = 0
680 else
681 currentY = viewportSize.Y - (closed and 19 or Background.AbsoluteSize.Y) - 36
682 end
683 end
684 currentPos = Vector2.new(currentX, currentY)
685 lastPos = newPos
686 TweenService.Create(
687 TweenService,
688 Background,
689 TweenInfo.new(0.1),
690 { Position = UDim2.new(0, currentPos.X, 0, currentPos.Y) }
691 ):Play()
692 end
693 -- if input.UserInputState ~= Enum.UserInputState.Begin then
694 -- RunService.UnbindFromRenderStep(RunService, "drag")
695 -- end
696 end)
697 table.insert(
698 connections,
699 UserInputService.InputEnded:Connect(function(inputE)
700 if input == inputE then
701 RunService:UnbindFromRenderStep("drag")
702 end
703 end)
704 )
705 end
706end
707
708--- Fades out the table of elements (and makes them invisible), returns a function to make them visible again
709function fadeOut(elements)
710 local data = {}
711 for _, v in pairs(elements) do
712 if typeof(v) == "Instance" and v:IsA("GuiObject") and v.Visible then
713 coroutine.wrap(function()
714 data[v] = {
715 BackgroundTransparency = v.BackgroundTransparency,
716 }
717 TweenService:Create(v, TweenInfo.new(0.5), { BackgroundTransparency = 1 }):Play()
718 if v:IsA("TextBox") or v:IsA("TextButton") or v:IsA("TextLabel") then
719 data[v].TextTransparency = v.TextTransparency
720 TweenService:Create(v, TweenInfo.new(0.5), { TextTransparency = 1 }):Play()
721 elseif v:IsA("ImageButton") or v:IsA("ImageLabel") then
722 data[v].ImageTransparency = v.ImageTransparency
723 TweenService:Create(v, TweenInfo.new(0.5), { ImageTransparency = 1 }):Play()
724 end
725 wait(0.5)
726 v.Visible = false
727 for i, x in pairs(data[v]) do
728 v[i] = x
729 end
730 data[v] = true
731 end)()
732 end
733 end
734 return function()
735 for i, _ in pairs(data) do
736 coroutine.wrap(function()
737 local properties = {
738 BackgroundTransparency = i.BackgroundTransparency,
739 }
740 i.BackgroundTransparency = 1
741 TweenService
742 :Create(i, TweenInfo.new(0.5), { BackgroundTransparency = properties.BackgroundTransparency })
743 :Play()
744 if i:IsA("TextBox") or i:IsA("TextButton") or i:IsA("TextLabel") then
745 properties.TextTransparency = i.TextTransparency
746 i.TextTransparency = 1
747 TweenService
748 :Create(i, TweenInfo.new(0.5), { TextTransparency = properties.TextTransparency })
749 :Play()
750 elseif i:IsA("ImageButton") or i:IsA("ImageLabel") then
751 properties.ImageTransparency = i.ImageTransparency
752 i.ImageTransparency = 1
753 TweenService
754 :Create(i, TweenInfo.new(0.5), { ImageTransparency = properties.ImageTransparency })
755 :Play()
756 end
757 i.Visible = true
758 end)()
759 end
760 end
761end
762
763--- Expands and minimizes the gui (closed is the toggle boolean)
764function toggleMinimize(override)
765 if mainClosing and not override or maximized then
766 return
767 end
768 mainClosing = true
769 closed = not closed
770 if closed then
771 if not sideClosed then
772 toggleSideTray(true)
773 end
774 LeftPanel.Visible = true
775 TweenService:Create(LeftPanel, TweenInfo.new(0.5), { Size = UDim2.new(0, 131, 0, 0) }):Play()
776 wait(0.5)
777 remotesFadeIn = fadeOut(LeftPanel:GetDescendants())
778 wait(0.5)
779 else
780 TweenService:Create(LeftPanel, TweenInfo.new(0.5), { Size = UDim2.new(0, 131, 0, 249) }):Play()
781 wait(0.5)
782 if remotesFadeIn then
783 remotesFadeIn()
784 remotesFadeIn = nil
785 end
786 bringBackOnResize()
787 end
788 mainClosing = false
789end
790
791--- Expands and minimizes the sidebar (sideClosed is the toggle boolean)
792function toggleSideTray(override)
793 if sideClosing and not override or maximized then
794 return
795 end
796 sideClosing = true
797 sideClosed = not sideClosed
798 if sideClosed then
799 rightFadeIn = fadeOut(RightPanel:GetDescendants())
800 wait(0.5)
801 minimizeSize(0.5)
802 wait(0.5)
803 RightPanel.Visible = false
804 else
805 if closed then
806 toggleMinimize(true)
807 end
808 RightPanel.Visible = true
809 maximizeSize(0.5)
810 wait(0.5)
811 if rightFadeIn then
812 rightFadeIn()
813 end
814 bringBackOnResize()
815 end
816 sideClosing = false
817end
818
819--- Expands code box to fit screen for more convenient viewing
820function toggleMaximize()
821 if not sideClosed and not maximized then
822 maximized = true
823 local disable = Instance.new("TextButton")
824 local prevSize = UDim2.new(0, CodeBox.AbsoluteSize.X, 0, CodeBox.AbsoluteSize.Y)
825 local prevPos = UDim2.new(0, CodeBox.AbsolutePosition.X, 0, CodeBox.AbsolutePosition.Y)
826 disable.Size = UDim2.new(1, 0, 1, 0)
827 disable.BackgroundColor3 = Color3.new()
828 disable.BorderSizePixel = 0
829 disable.Text = 0
830 disable.ZIndex = 3
831 disable.BackgroundTransparency = 1
832 disable.AutoButtonColor = false
833 CodeBox.ZIndex = 4
834 CodeBox.Position = prevPos
835 CodeBox.Size = prevSize
836 TweenService
837 :Create(
838 CodeBox,
839 TweenInfo.new(0.5),
840 { Size = UDim2.new(0.5, 0, 0.5, 0), Position = UDim2.new(0.25, 0, 0.25, 0) }
841 )
842 :Play()
843 TweenService:Create(disable, TweenInfo.new(0.5), { BackgroundTransparency = 0.5 }):Play()
844 disable.MouseButton1Click:Connect(function()
845 if
846 UserInputService:GetMouseLocation().Y + 36 >= CodeBox.AbsolutePosition.Y
847 and UserInputService:GetMouseLocation().Y + 36 <= CodeBox.AbsolutePosition.Y + CodeBox.AbsoluteSize.Y
848 and UserInputService:GetMouseLocation().X >= CodeBox.AbsolutePosition.X
849 and UserInputService:GetMouseLocation().X <= CodeBox.AbsolutePosition.X + CodeBox.AbsoluteSize.X
850 then
851 return
852 end
853 TweenService:Create(CodeBox, TweenInfo.new(0.5), { Size = prevSize, Position = prevPos }):Play()
854 TweenService:Create(disable, TweenInfo.new(0.5), { BackgroundTransparency = 1 }):Play()
855 maximized = false
856 wait(0.5)
857 disable:Destroy()
858 CodeBox.Size = UDim2.new(1, 0, 0.5, 0)
859 CodeBox.Position = UDim2.new(0, 0, 0, 0)
860 CodeBox.ZIndex = 0
861 end)
862 end
863end
864
865--- Adjusts the ui elements to the 'Maximized' size
866function maximizeSize(speed)
867 if not speed then
868 speed = 0.05
869 end
870 TweenService
871 :Create(
872 LeftPanel,
873 TweenInfo.new(speed),
874 { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }
875 )
876 :Play()
877 TweenService
878 :Create(RightPanel, TweenInfo.new(speed), {
879 Size = UDim2.fromOffset(
880 Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X,
881 Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y
882 ),
883 })
884 :Play()
885 TweenService
886 :Create(
887 TopBar,
888 TweenInfo.new(speed),
889 { Size = UDim2.fromOffset(Background.AbsoluteSize.X, TopBar.AbsoluteSize.Y) }
890 )
891 :Play()
892 TweenService
893 :Create(ScrollingFrame, TweenInfo.new(speed), {
894 Size = UDim2.fromOffset(Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X, 110),
895 Position = UDim2.fromOffset(0, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y),
896 })
897 :Play()
898 TweenService
899 :Create(CodeBox, TweenInfo.new(speed), {
900 Size = UDim2.fromOffset(
901 Background.AbsoluteSize.X - LeftPanel.AbsoluteSize.X,
902 Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y
903 ),
904 })
905 :Play()
906 TweenService
907 :Create(
908 LogList,
909 TweenInfo.new(speed),
910 { Size = UDim2.fromOffset(LogList.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y - 18) }
911 )
912 :Play()
913end
914
915--- Adjusts the ui elements to close the side
916function minimizeSize(speed)
917 if not speed then
918 speed = 0.05
919 end
920 TweenService
921 :Create(
922 LeftPanel,
923 TweenInfo.new(speed),
924 { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }
925 )
926 :Play()
927 TweenService
928 :Create(
929 RightPanel,
930 TweenInfo.new(speed),
931 { Size = UDim2.fromOffset(0, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y) }
932 )
933 :Play()
934 TweenService
935 :Create(
936 TopBar,
937 TweenInfo.new(speed),
938 { Size = UDim2.fromOffset(LeftPanel.AbsoluteSize.X, TopBar.AbsoluteSize.Y) }
939 )
940 :Play()
941 TweenService
942 :Create(ScrollingFrame, TweenInfo.new(speed), {
943 Size = UDim2.fromOffset(0, 119),
944 Position = UDim2.fromOffset(0, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y),
945 })
946 :Play()
947 TweenService
948 :Create(
949 CodeBox,
950 TweenInfo.new(speed),
951 { Size = UDim2.fromOffset(0, Background.AbsoluteSize.Y - 119 - TopBar.AbsoluteSize.Y) }
952 )
953 :Play()
954 TweenService
955 :Create(
956 LogList,
957 TweenInfo.new(speed),
958 { Size = UDim2.fromOffset(LogList.AbsoluteSize.X, Background.AbsoluteSize.Y - TopBar.AbsoluteSize.Y - 18) }
959 )
960 :Play()
961end
962
963--- Ensures size is within screensize limitations
964function validateSize()
965 local x, y = Background.AbsoluteSize.X, Background.AbsoluteSize.Y
966 local screenSize = workspace.CurrentCamera.ViewportSize
967 if x + Background.AbsolutePosition.X > screenSize.X then
968 if screenSize.X - Background.AbsolutePosition.X >= 450 then
969 x = screenSize.X - Background.AbsolutePosition.X
970 else
971 x = 450
972 end
973 elseif y + Background.AbsolutePosition.Y > screenSize.Y then
974 if screenSize.X - Background.AbsolutePosition.Y >= 268 then
975 y = screenSize.Y - Background.AbsolutePosition.Y
976 else
977 y = 268
978 end
979 end
980 Background.Size = UDim2.fromOffset(x, y)
981end
982
983--- Gets the player an instance is descended from
984function getPlayerFromInstance(instance)
985 for _, v in pairs(Players:GetPlayers()) do
986 if v.Character and (instance:IsDescendantOf(v.Character) or instance == v.Character) then
987 return v
988 end
989 end
990end
991
992--- Runs on MouseButton1Click of an event frame
993function eventSelect(frame)
994 if selected and selected.Log and selected.Log.Button then
995 TweenService
996 :Create(selected.Log.Button, TweenInfo.new(0.5), { BackgroundColor3 = Color3.fromRGB(0, 0, 0) })
997 :Play()
998 selected = nil
999 end
1000 for _, v in pairs(logs) do
1001 if frame == v.Log then
1002 selected = v
1003 end
1004 end
1005 if selected and selected.Log then
1006 TweenService
1007 :Create(frame.Button, TweenInfo.new(0.5), { BackgroundColor3 = Color3.fromRGB(92, 126, 229) })
1008 :Play()
1009 codebox:setRaw(selected.GenScript)
1010 end
1011 if sideClosed then
1012 toggleSideTray()
1013 end
1014end
1015
1016--- Updates the canvas size to fit the current amount of function buttons
1017function updateFunctionCanvas()
1018 ScrollingFrame.CanvasSize = UDim2.fromOffset(UIGridLayout.AbsoluteContentSize.X, UIGridLayout.AbsoluteContentSize.Y)
1019end
1020
1021--- Updates the canvas size to fit the amount of current remotes
1022function updateRemoteCanvas()
1023 LogList.CanvasSize = UDim2.fromOffset(UIListLayout.AbsoluteContentSize.X, UIListLayout.AbsoluteContentSize.Y)
1024end
1025
1026--- Allows for toggling of the tooltip and easy setting of le description
1027--- @param enable boolean
1028--- @param text string
1029function makeToolTip(enable, text)
1030 if enable then
1031 if ToolTip.Visible then
1032 ToolTip.Visible = false
1033 RunService:UnbindFromRenderStep("ToolTip")
1034 end
1035 local first = true
1036 RunService:BindToRenderStep("ToolTip", 1, function()
1037 local topLeft = Vector2.new(Mouse.X + 20, Mouse.Y + 20)
1038 local bottomRight = topLeft + ToolTip.AbsoluteSize
1039 if topLeft.X < 0 then
1040 topLeft = Vector2.new(0, topLeft.Y)
1041 elseif bottomRight.X > workspace.CurrentCamera.ViewportSize.X then
1042 topLeft = Vector2.new(workspace.CurrentCamera.ViewportSize.X - ToolTip.AbsoluteSize.X, topLeft.Y)
1043 end
1044 if topLeft.Y < 0 then
1045 topLeft = Vector2.new(topLeft.X, 0)
1046 elseif bottomRight.Y > workspace.CurrentCamera.ViewportSize.Y - 35 then
1047 topLeft = Vector2.new(topLeft.X, workspace.CurrentCamera.ViewportSize.Y - ToolTip.AbsoluteSize.Y - 35)
1048 end
1049 if topLeft.X <= Mouse.X and topLeft.Y <= Mouse.Y then
1050 topLeft = Vector2.new(Mouse.X - ToolTip.AbsoluteSize.X - 2, Mouse.Y - ToolTip.AbsoluteSize.Y - 2)
1051 end
1052 if first then
1053 ToolTip.Position = UDim2.fromOffset(topLeft.X, topLeft.Y)
1054 first = false
1055 else
1056 ToolTip:TweenPosition(UDim2.fromOffset(topLeft.X, topLeft.Y), "Out", "Linear", 0.1)
1057 end
1058 end)
1059 TextLabel.Text = text
1060 ToolTip.Visible = true
1061 else
1062 if ToolTip.Visible then
1063 ToolTip.Visible = false
1064 RunService:UnbindFromRenderStep("ToolTip")
1065 end
1066 end
1067end
1068
1069--- Creates new function button (below codebox)
1070--- @param name string
1071---@param description function
1072---@param onClick function
1073function newButton(name, description, onClick)
1074 local button = FunctionTemplate:Clone()
1075 button.Text.Text = name
1076 button.Button.MouseEnter:Connect(function()
1077 makeToolTip(true, description())
1078 end)
1079 button.Button.MouseLeave:Connect(function()
1080 makeToolTip(false)
1081 end)
1082 button.AncestryChanged:Connect(function()
1083 makeToolTip(false)
1084 end)
1085 button.Button.MouseButton1Click:Connect(function(...)
1086 onClick(button, ...)
1087 end)
1088 button.Parent = ScrollingFrame
1089 updateFunctionCanvas()
1090end
1091
1092--- Adds new Remote to logs
1093--- @param name string The name of the remote being logged
1094--- @param type string The type of the remote being logged (either 'function' or 'event')
1095--- @param args any
1096--- @param remote any
1097--- @param function_info string
1098--- @param blocked any
1099function newRemote(type, name, args, remote, function_info, blocked, src, returnValue)
1100 local remoteFrame = RemoteTemplate:Clone()
1101 remoteFrame.Text.Text = string.sub(name, 1, 50)
1102 remoteFrame.ColorBar.BackgroundColor3 = type == "event" and Color3.new(255, 242, 0) or Color3.fromRGB(99, 86, 245)
1103 local id = Instance.new("IntValue")
1104 id.Name = "ID"
1105 id.Value = #logs + 1
1106 id.Parent = remoteFrame
1107 local weakRemoteTable = setmetatable({ remote = remote }, { __mode = "v" })
1108 local log = {
1109 Name = name,
1110 Function = function_info,
1111 Remote = weakRemoteTable,
1112 Log = remoteFrame,
1113 Blocked = blocked,
1114 Source = src,
1115 GenScript = "-- Generating, please wait... (click to reload)\n-- (If this message persists, the remote args are likely extremely long)",
1116 ReturnValue = returnValue,
1117 }
1118 logs[#logs + 1] = log
1119 schedule(function()
1120 log.GenScript = genScript(remote, args)
1121 if blocked then
1122 logs[#logs].GenScript = "-- THIS REMOTE WAS PREVENTED FROM FIRING THE SERVER BY SIMPLESPY\n\n"
1123 .. logs[#logs].GenScript
1124 end
1125 end)
1126 local connect = remoteFrame.Button.MouseButton1Click:Connect(function()
1127 eventSelect(remoteFrame)
1128 end)
1129 if layoutOrderNum < 1 then
1130 layoutOrderNum = 999999999
1131 end
1132 remoteFrame.LayoutOrder = layoutOrderNum
1133 layoutOrderNum = layoutOrderNum - 1
1134 remoteFrame.Parent = LogList
1135 table.insert(remoteLogs, 1, { connect, remoteFrame })
1136 clean()
1137 updateRemoteCanvas()
1138end
1139
1140--- Generates a script from the provided arguments (first has to be remote path)
1141function genScript(remote, args)
1142 prevTables = {}
1143 local gen = ""
1144 if #args > 0 then
1145 if not pcall(function()
1146 gen = v2v({ args = args }) .. "\n"
1147 end) then
1148 gen = gen
1149 .. "-- TableToString failure! Reverting to legacy functionality (results may vary)\nlocal args = {"
1150 if
1151 not pcall(function()
1152 for i, v in pairs(args) do
1153 if type(i) ~= "Instance" and type(i) ~= "userdata" then
1154 gen = gen .. "\n [object] = "
1155 elseif type(i) == "string" then
1156 gen = gen .. '\n ["' .. i .. '"] = '
1157 elseif type(i) == "userdata" and typeof(i) ~= "Instance" then
1158 gen = gen .. "\n [" .. string.format("nil --[[%s]]", typeof(v)) .. ")] = "
1159 elseif type(i) == "userdata" then
1160 gen = gen .. "\n [game." .. i:GetFullName() .. ")] = "
1161 end
1162 if type(v) ~= "Instance" and type(v) ~= "userdata" then
1163 gen = gen .. "object"
1164 elseif type(v) == "string" then
1165 gen = gen .. '"' .. v .. '"'
1166 elseif type(v) == "userdata" and typeof(v) ~= "Instance" then
1167 gen = gen .. string.format("nil --[[%s]]", typeof(v))
1168 elseif type(v) == "userdata" then
1169 gen = gen .. "game." .. v:GetFullName()
1170 end
1171 end
1172 gen = gen .. "\n}\n\n"
1173 end)
1174 then
1175 gen = gen .. "}\n-- Legacy tableToString failure! Unable to decompile."
1176 end
1177 end
1178 if not remote:IsDescendantOf(game) and not getnilrequired then
1179 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"
1180 .. gen
1181 end
1182 if remote:IsA("RemoteEvent") then
1183 gen = gen .. v2s(remote) .. ":FireServer(unpack(args))"
1184 elseif remote:IsA("RemoteFunction") then
1185 gen = gen .. v2s(remote) .. ":InvokeServer(unpack(args))"
1186 end
1187 else
1188 if remote:IsA("RemoteEvent") then
1189 gen = gen .. v2s(remote) .. ":FireServer()"
1190 elseif remote:IsA("RemoteFunction") then
1191 gen = gen .. v2s(remote) .. ":InvokeServer()"
1192 end
1193 end
1194 gen = gen
1195 prevTables = {}
1196 return gen
1197end
1198
1199--- value-to-string: value, string (out), level (indentation), parent table, var name, is from tovar
1200function v2s(v, l, p, n, vtv, i, pt, path, tables, tI)
1201 if not tI then
1202 tI = { 0 }
1203 else
1204 tI[1] += 1
1205 end
1206 if typeof(v) == "number" then
1207 if v == math.huge then
1208 return "math.huge"
1209 elseif tostring(v):match("nan") then
1210 return "0/0 --[[NaN]]"
1211 end
1212 return tostring(v)
1213 elseif typeof(v) == "boolean" then
1214 return tostring(v)
1215 elseif typeof(v) == "string" then
1216 return formatstr(v, l)
1217 elseif typeof(v) == "function" then
1218 return f2s(v)
1219 elseif typeof(v) == "table" then
1220 return t2s(v, l, p, n, vtv, i, pt, path, tables, tI)
1221 elseif typeof(v) == "Instance" then
1222 return i2p(v)
1223 elseif typeof(v) == "userdata" then
1224 return "newproxy(true)"
1225 elseif type(v) == "userdata" then
1226 return u2s(v)
1227 elseif type(v) == "vector" then
1228 return string.format("Vector3.new(%s, %s, %s)", v2s(v.X), v2s(v.Y), v2s(v.Z))
1229 else
1230 return "nil --[[" .. typeof(v) .. "]]"
1231 end
1232end
1233
1234--- value-to-variable
1235--- @param t any
1236function v2v(t)
1237 topstr = ""
1238 bottomstr = ""
1239 getnilrequired = false
1240 local ret = ""
1241 local count = 1
1242 for i, v in pairs(t) do
1243 if type(i) == "string" and i:match("^[%a_]+[%w_]*$") then
1244 ret = ret .. "local " .. i .. " = " .. v2s(v, nil, nil, i, true) .. "\n"
1245 elseif tostring(i):match("^[%a_]+[%w_]*$") then
1246 ret = ret
1247 .. "local "
1248 .. tostring(i):lower()
1249 .. "_"
1250 .. tostring(count)
1251 .. " = "
1252 .. v2s(v, nil, nil, tostring(i):lower() .. "_" .. tostring(count), true)
1253 .. "\n"
1254 else
1255 ret = ret
1256 .. "local "
1257 .. type(v)
1258 .. "_"
1259 .. tostring(count)
1260 .. " = "
1261 .. v2s(v, nil, nil, type(v) .. "_" .. tostring(count), true)
1262 .. "\n"
1263 end
1264 count = count + 1
1265 end
1266 if getnilrequired then
1267 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"
1268 .. topstr
1269 end
1270 if #topstr > 0 then
1271 ret = topstr .. "\n" .. ret
1272 end
1273 if #bottomstr > 0 then
1274 ret = ret .. bottomstr
1275 end
1276 return ret
1277end
1278
1279--- table-to-string
1280--- @param t table
1281--- @param l number
1282--- @param p table
1283--- @param n string
1284--- @param vtv boolean
1285--- @param i any
1286--- @param pt table
1287--- @param path string
1288--- @param tables table
1289--- @param tI table
1290function t2s(t, l, p, n, vtv, i, pt, path, tables, tI)
1291 local globalIndex = table.find(getgenv(), t) -- checks if table is a global
1292 if type(globalIndex) == "string" then
1293 return globalIndex
1294 end
1295 if not tI then
1296 tI = { 0 }
1297 end
1298 if not path then -- sets path to empty string (so it doesn't have to manually provided every time)
1299 path = ""
1300 end
1301 if not l then -- sets the level to 0 (for indentation) and tables for logging tables it already serialized
1302 l = 0
1303 tables = {}
1304 end
1305 if not p then -- p is the previous table but doesn't really matter if it's the first
1306 p = t
1307 end
1308 for _, v in pairs(tables) do -- checks if the current table has been serialized before
1309 if n and rawequal(v, t) then
1310 bottomstr = bottomstr
1311 .. "\n"
1312 .. tostring(n)
1313 .. tostring(path)
1314 .. " = "
1315 .. tostring(n)
1316 .. tostring(({ v2p(v, p) })[2])
1317 return "{} --[[DUPLICATE]]"
1318 end
1319 end
1320 table.insert(tables, t) -- logs table to past tables
1321 local s = "{" -- start of serialization
1322 local size = 0
1323 l = l + indent -- set indentation level
1324 for k, v in pairs(t) do -- iterates over table
1325 size = size + 1 -- changes size for max limit
1326 if size > (_G.SimpleSpyMaxTableSize or 1000) then
1327 s = s
1328 .. "\n"
1329 .. string.rep(" ", l)
1330 .. "-- MAXIMUM TABLE SIZE REACHED, CHANGE '_G.SimpleSpyMaxTableSize' TO ADJUST MAXIMUM SIZE "
1331 break
1332 end
1333 if rawequal(k, t) then -- checks if the table being iterated over is being used as an index within itself (yay, lua)
1334 bottomstr = bottomstr
1335 .. "\n"
1336 .. tostring(n)
1337 .. tostring(path)
1338 .. "["
1339 .. tostring(n)
1340 .. tostring(path)
1341 .. "]"
1342 .. " = "
1343 .. (
1344 rawequal(v, k) and tostring(n) .. tostring(path)
1345 or v2s(v, l, p, n, vtv, k, t, path .. "[" .. tostring(n) .. tostring(path) .. "]", tables)
1346 )
1347 size -= 1
1348 continue
1349 end
1350 local currentPath = "" -- initializes the path of 'v' within 't'
1351 if type(k) == "string" and k:match("^[%a_]+[%w_]*$") then -- cleanly handles table path generation (for the first half)
1352 currentPath = "." .. k
1353 else
1354 currentPath = "[" .. k2s(k, l, p, n, vtv, k, t, path .. currentPath, tables, tI) .. "]"
1355 end
1356 if size % 100 == 0 then
1357 scheduleWait()
1358 end
1359 -- actually serializes the member of the table
1360 s = s
1361 .. "\n"
1362 .. string.rep(" ", l)
1363 .. "["
1364 .. k2s(k, l, p, n, vtv, k, t, path .. currentPath, tables, tI)
1365 .. "] = "
1366 .. v2s(v, l, p, n, vtv, k, t, path .. currentPath, tables, tI)
1367 .. ","
1368 end
1369 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...)
1370 s = s:sub(1, #s - 1)
1371 end
1372 if size > 0 then -- cleanly indents the last curly bracket
1373 s = s .. "\n" .. string.rep(" ", l - indent)
1374 end
1375 return s .. "}"
1376end
1377
1378--- key-to-string
1379function k2s(v, ...)
1380 if keyToString then
1381 if typeof(v) == "userdata" and getrawmetatable(v) then
1382 return string.format(
1383 '"<void> (%s)" --[[Potentially hidden data (tostring in SimpleSpy:HookRemote/GetRemoteFiredSignal at your own risk)]]',
1384 safetostring(v)
1385 )
1386 elseif typeof(v) == "userdata" then
1387 return string.format('"<void> (%s)"', safetostring(v))
1388 elseif type(v) == "userdata" and typeof(v) ~= "Instance" then
1389 return string.format('"<%s> (%s)"', typeof(v), tostring(v))
1390 elseif type(v) == "function" then
1391 return string.format('"<Function> (%s)"', tostring(v))
1392 end
1393 end
1394 return v2s(v, ...)
1395end
1396
1397--- function-to-string
1398function f2s(f)
1399 for k, x in pairs(getgenv()) do
1400 local isgucci, gpath
1401 if rawequal(x, f) then
1402 isgucci, gpath = true, ""
1403 elseif type(x) == "table" then
1404 isgucci, gpath = v2p(f, x)
1405 end
1406 if isgucci and type(k) ~= "function" then
1407 if type(k) == "string" and k:match("^[%a_]+[%w_]*$") then
1408 return k .. gpath
1409 else
1410 return "getgenv()[" .. v2s(k) .. "]" .. gpath
1411 end
1412 end
1413 end
1414 if funcEnabled and debug.getinfo(f).name:match("^[%a_]+[%w_]*$") then
1415 return "function()end --[[" .. debug.getinfo(f).name .. "]]"
1416 end
1417 return "function()end --[[" .. tostring(f) .. "]]"
1418end
1419
1420--- instance-to-path
1421--- @param i userdata
1422function i2p(i)
1423 local player = getplayer(i)
1424 local parent = i
1425 local out = ""
1426 if parent == nil then
1427 return "nil"
1428 elseif player then
1429 while true do
1430 if parent and parent == player.Character then
1431 if player == Players.LocalPlayer then
1432 return 'game:GetService("Players").LocalPlayer.Character' .. out
1433 else
1434 return i2p(player) .. ".Character" .. out
1435 end
1436 else
1437 if parent.Name:match("[%a_]+[%w+]*") ~= parent.Name then
1438 out = ":FindFirstChild(" .. formatstr(parent.Name) .. ")" .. out
1439 else
1440 out = "." .. parent.Name .. out
1441 end
1442 end
1443 parent = parent.Parent
1444 end
1445 elseif parent ~= game then
1446 while true do
1447 if parent and parent.Parent == game then
1448 local service = game:FindService(parent.ClassName)
1449 if service then
1450 if parent.ClassName == "Workspace" then
1451 return "workspace" .. out
1452 else
1453 return 'game:GetService("' .. service.ClassName .. '")' .. out
1454 end
1455 else
1456 if parent.Name:match("[%a_]+[%w_]*") then
1457 return "game." .. parent.Name .. out
1458 else
1459 return "game:FindFirstChild(" .. formatstr(parent.Name) .. ")" .. out
1460 end
1461 end
1462 elseif parent.Parent == nil then
1463 getnilrequired = true
1464 return "getNil(" .. formatstr(parent.Name) .. ', "' .. parent.ClassName .. '")' .. out
1465 elseif parent == Players.LocalPlayer then
1466 out = ".LocalPlayer" .. out
1467 else
1468 if parent.Name:match("[%a_]+[%w_]*") ~= parent.Name then
1469 out = ":FindFirstChild(" .. formatstr(parent.Name) .. ")" .. out
1470 else
1471 out = "." .. parent.Name .. out
1472 end
1473 end
1474 parent = parent.Parent
1475 end
1476 else
1477 return "game"
1478 end
1479end
1480
1481--- userdata-to-string: userdata
1482--- @param u userdata
1483function u2s(u)
1484 if typeof(u) == "TweenInfo" then
1485 -- TweenInfo
1486 return "TweenInfo.new("
1487 .. tostring(u.Time)
1488 .. ", Enum.EasingStyle."
1489 .. tostring(u.EasingStyle)
1490 .. ", Enum.EasingDirection."
1491 .. tostring(u.EasingDirection)
1492 .. ", "
1493 .. tostring(u.RepeatCount)
1494 .. ", "
1495 .. tostring(u.Reverses)
1496 .. ", "
1497 .. tostring(u.DelayTime)
1498 .. ")"
1499 elseif typeof(u) == "Ray" then
1500 -- Ray
1501 return "Ray.new(" .. u2s(u.Origin) .. ", " .. u2s(u.Direction) .. ")"
1502 elseif typeof(u) == "NumberSequence" then
1503 -- NumberSequence
1504 local ret = "NumberSequence.new("
1505 for i, v in pairs(u.KeyPoints) do
1506 ret = ret .. tostring(v)
1507 if i < #u.Keypoints then
1508 ret = ret .. ", "
1509 end
1510 end
1511 return ret .. ")"
1512 elseif typeof(u) == "DockWidgetPluginGuiInfo" then
1513 -- DockWidgetPluginGuiInfo
1514 return "DockWidgetPluginGuiInfo.new(Enum.InitialDockState" .. tostring(u) .. ")"
1515 elseif typeof(u) == "ColorSequence" then
1516 -- ColorSequence
1517 local ret = "ColorSequence.new("
1518 for i, v in pairs(u.KeyPoints) do
1519 ret = ret .. "Color3.new(" .. tostring(v) .. ")"
1520 if i < #u.Keypoints then
1521 ret = ret .. ", "
1522 end
1523 end
1524 return ret .. ")"
1525 elseif typeof(u) == "BrickColor" then
1526 -- BrickColor
1527 return "BrickColor.new(" .. tostring(u.Number) .. ")"
1528 elseif typeof(u) == "NumberRange" then
1529 -- NumberRange
1530 return "NumberRange.new(" .. tostring(u.Min) .. ", " .. tostring(u.Max) .. ")"
1531 elseif typeof(u) == "Region3" then
1532 -- Region3
1533 local center = u.CFrame.Position
1534 local size = u.CFrame.Size
1535 local vector1 = center - size / 2
1536 local vector2 = center + size / 2
1537 return "Region3.new(" .. u2s(vector1) .. ", " .. u2s(vector2) .. ")"
1538 elseif typeof(u) == "Faces" then
1539 -- Faces
1540 local faces = {}
1541 if u.Top then
1542 table.insert(faces, "Enum.NormalId.Top")
1543 end
1544 if u.Bottom then
1545 table.insert(faces, "Enum.NormalId.Bottom")
1546 end
1547 if u.Left then
1548 table.insert(faces, "Enum.NormalId.Left")
1549 end
1550 if u.Right then
1551 table.insert(faces, "Enum.NormalId.Right")
1552 end
1553 if u.Back then
1554 table.insert(faces, "Enum.NormalId.Back")
1555 end
1556 if u.Front then
1557 table.insert(faces, "Enum.NormalId.Front")
1558 end
1559 return "Faces.new(" .. table.concat(faces, ", ") .. ")"
1560 elseif typeof(u) == "EnumItem" then
1561 return tostring(u)
1562 elseif typeof(u) == "Enums" then
1563 return "Enum"
1564 elseif typeof(u) == "Enum" then
1565 return "Enum." .. tostring(u)
1566 elseif typeof(u) == "RBXScriptSignal" then
1567 return "nil --[[RBXScriptSignal]]"
1568 elseif typeof(u) == "Vector3" then
1569 return string.format("Vector3.new(%s, %s, %s)", v2s(u.X), v2s(u.Y), v2s(u.Z))
1570 elseif typeof(u) == "CFrame" then
1571 local xAngle, yAngle, zAngle = u:ToEulerAnglesXYZ()
1572 return string.format(
1573 "CFrame.new(%s, %s, %s) * CFrame.Angles(%s, %s, %s)",
1574 v2s(u.X),
1575 v2s(u.Y),
1576 v2s(u.Z),
1577 v2s(xAngle),
1578 v2s(yAngle),
1579 v2s(zAngle)
1580 )
1581 elseif typeof(u) == "DockWidgetPluginGuiInfo" then
1582 return string.format(
1583 "DockWidgetPluginGuiInfo(%s, %s, %s, %s, %s, %s, %s)",
1584 "Enum.InitialDockState.Right",
1585 v2s(u.InitialEnabled),
1586 v2s(u.InitialEnabledShouldOverrideRestore),
1587 v2s(u.FloatingXSize),
1588 v2s(u.FloatingYSize),
1589 v2s(u.MinWidth),
1590 v2s(u.MinHeight)
1591 )
1592 elseif typeof(u) == "PathWaypoint" then
1593 return string.format("PathWaypoint.new(%s, %s)", v2s(u.Position), v2s(u.Action))
1594 elseif typeof(u) == "UDim" then
1595 return string.format("UDim.new(%s, %s)", v2s(u.Scale), v2s(u.Offset))
1596 elseif typeof(u) == "UDim2" then
1597 return string.format(
1598 "UDim2.new(%s, %s, %s, %s)",
1599 v2s(u.X.Scale),
1600 v2s(u.X.Offset),
1601 v2s(u.Y.Scale),
1602 v2s(u.Y.Offset)
1603 )
1604 elseif typeof(u) =