Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- if not game:IsLoaded() then game.Loaded:Wait() end
- if getgenv().SignalSpyExecuted and type(getgenv().SignalSpyShutdown) == "function" then
- getgenv().SignalSpyShutdown()
- end
- local function missing(t, f, fallback)
- if type(f) == t then return f end
- return fallback
- end
- local cloneref = missing("function", cloneref, function(...) return ... end)
- local hookfunction = missing("function", hookfunction or replaceclosure)
- local hookmetamethod = missing("function", hookmetamethod)
- local getnamecallmethod = missing("function", getnamecallmethod or get_namecall_method)
- local setnamecallmethod = missing("function", setnamecallmethod or set_namecall_method)
- local checkcaller = missing("function", checkcaller, function() return false end)
- local newcclosure = missing("function", newcclosure, function(f) return f end)
- local clonefunction = missing("function", clonefunction, function(f) return f end)
- local restorefunction = missing("function", restorefunction)
- local replicatesignal = missing("function", replicatesignal)
- local getconnections = missing("function", getconnections or get_signal_cons)
- local firesignal = missing("function", firesignal or fire_signal)
- local getgenv = missing("function", getgenv, function() return _G end)
- local getcallingscript = missing("function", getcallingscript, function() return nil end)
- local everyClipboard = missing("function", setclipboard or toclipboard or set_clipboard or (Clipboard and Clipboard.set))
- local iscclosure = missing("function", iscclosure, function() return false end)
- local islclosure = missing("function", islclosure or is_l_closure, function() return false end)
- local getconstants = missing("function", debug.getconstants or getconstants)
- local getupvalues = missing("function", debug.getupvalues or getupvalues)
- local getprotos = missing("function", getprotos or debug.getprotos)
- local getinfo = missing("function", debug.info or getinfo)
- local getnilinstances = missing("function", getnilinstances or get_nil_instances, function() return {} end)
- local getrawmetatable = missing("function", getrawmetatable, function() return nil end)
- local setrawmetatable = missing("function", setrawmetatable)
- local isreadonly = missing("function", isreadonly or table.isfrozen, function() return false end)
- local setreadonly = missing("function", setreadonly or makewriteable)
- local makewriteable = missing("function", makewriteable or function(t) if setreadonly then setreadonly(t, false) end end)
- local makereadonly = missing("function", makereadonly or function(t) if setreadonly then setreadonly(t, true) end end)
- local gethui = missing("function", gethui or get_hidden_gui)
- local protect_gui = missing("function", protect_gui or (syn and syn.protect_gui))
- local getthreadidentity = missing("function", getthreadidentity or getidentity or (syn and syn.get_thread_identity))
- local setthreadidentity = missing("function", setthreadidentity or setidentity or (syn and syn.set_thread_identity))
- local getgc = missing("function", getgc or get_gc_objects, function() return {} end)
- local getreg = missing("function", getreg or debug.getregistry, function() return {} end)
- local getrunningscripts = missing("function", getrunningscripts, function() return {} end)
- local getloadedmodules = missing("function", getloadedmodules, function() return {} end)
- local getinstances = missing("function", getinstances, function() return {} end)
- local getscripthash = missing("function", getscripthash)
- local getscriptclosure = missing("function", getscriptclosure or getscriptfunction)
- local getsenv = missing("function", getsenv or getscriptenv)
- local getcallbackvalue = missing("function", getcallbackvalue or getcallbackmember)
- local getthreadcontext = missing("function", getthreadcontext or getthreadidentity)
- local isexecutorclosure = missing("function", isexecutorclosure or checkclosure)
- local getscriptbytecode = missing("function", getscriptbytecode)
- local dumpstring = missing("function", dumpstring)
- local decompile = missing("function", decompile)
- local disassemble = missing("function", disassemble)
- local oth = syn and syn.oth
- local unhook = oth and oth.unhook
- local othook = oth and oth.hook
- local synv3 = false
- if syn and identifyexecutor then
- local success, result = pcall(identifyexecutor)
- if success then
- local _, version = result, select(2, identifyexecutor())
- if version and type(version) == "string" and version:sub(1, 2) == "v3" then
- synv3 = true
- end
- end
- end
- local isfile = missing("function", isfile, function() return false end)
- local isfolder = missing("function", isfolder, function() return false end)
- local readfile = missing("function", readfile, function() return "" end)
- local writefile = missing("function", writefile)
- local makefolder = missing("function", makefolder)
- local delfile = missing("function", delfile)
- local listfiles = missing("function", listfiles, function() return {} end)
- local appendfile = missing("function", appendfile)
- local isFsSupported = type(writefile) == "function" and type(readfile) == "function"
- local Services = setmetatable({}, {
- __index = function(self, name)
- local success, cache = pcall(function()
- return cloneref(game:GetService(name))
- end)
- if success and cache then
- rawset(self, name, cache)
- return cache
- end
- return nil
- end
- })
- local HttpService = Services.HttpService
- local TweenService = Services.TweenService
- local UserInputService = Services.UserInputService
- local RunService = Services.RunService
- local Players = Services.Players
- local CoreGui = Services.CoreGui
- local TextService = Services.TextService
- local LocalPlayer = Players and Players.LocalPlayer
- local MAX_DISPLAY_ORDER = 2147483647
- local function randomString()
- local length = math.random(10, 20)
- local array = {}
- for i = 1, length do
- array[i] = string.char(math.random(32, 126))
- end
- return table.concat(array)
- end
- local CONFIG = {
- Enabled = true,
- LogRemotes = false,
- LogSignals = true,
- LogRequests = false,
- LogCheckcaller = true,
- FilterSpammy = true,
- SpamThreshold = 3,
- SpamTimeWindow = 1,
- MaxLogs = 500,
- CheckLocalPlayer = true,
- UseHookmetamethod = true,
- Blacklist = {},
- Blocklist = {},
- IgnoredSignals = {},
- BlockedSignals = {},
- SpoofedSignals = {},
- }
- local Logs = {}
- local LogFrames = {}
- local Selected = nil
- local LayoutOrder = 999999999
- local SpamHistory = {}
- local HookedSignals = {}
- local HookedConnections = {}
- local OriginalFunctions = {}
- local Connections = {}
- local Running = true
- local SearchQuery = ""
- local CachedAPIEvents = {}
- local function SafePcall(func, ...)
- local args = {...}
- local success, result = xpcall(function()
- return func(table.unpack(args))
- end, function(err)
- if getgenv().SignalSpyDEBUG then
- warn("[SignalSpy][ERROR]", err)
- end
- return nil
- end)
- return success, result
- end
- local function JSONEncode(data)
- local success, result = pcall(function()
- return HttpService:JSONEncode(data)
- end)
- return success and result or "{}"
- end
- local function JSONDecode(str)
- local success, result = pcall(function()
- return HttpService:JSONDecode(str)
- end)
- return success and result or {}
- end
- local function CheckIsLocalPlayer(instance)
- if not CONFIG.CheckLocalPlayer then return true end
- if not LocalPlayer then return true end
- if not instance then return true end
- local success, result = pcall(function()
- if instance == LocalPlayer then return true end
- if instance == LocalPlayer.Character then return true end
- if LocalPlayer.Character and instance:IsDescendantOf(LocalPlayer.Character) then return true end
- if typeof(instance) == "Instance" and instance:IsA("Player") then
- return instance == LocalPlayer or
- instance.UserId == LocalPlayer.UserId or
- instance.Name == LocalPlayer.Name or
- instance.DisplayName == LocalPlayer.DisplayName
- end
- if typeof(instance) == "Instance" and (instance:IsA("Humanoid") or instance:IsA("BasePart")) then
- local character = instance:FindFirstAncestorOfClass("Model")
- if character then
- local player = Players:GetPlayerFromCharacter(character)
- if player then
- return player == LocalPlayer or player.UserId == LocalPlayer.UserId
- end
- end
- end
- return true
- end)
- return success and result or true
- end
- local function CheckArgsForLocalPlayer(args)
- if not CONFIG.CheckLocalPlayer then return true end
- if not LocalPlayer then return true end
- if not args or #args == 0 then return true end
- for _, arg in ipairs(args) do
- if typeof(arg) == "Instance" then
- if arg:IsA("Player") then
- if arg ~= LocalPlayer and arg.UserId ~= LocalPlayer.UserId then
- return false
- end
- elseif arg:IsA("BasePart") or arg:IsA("Humanoid") then
- local character = arg:FindFirstAncestorOfClass("Model")
- if character then
- local player = Players:GetPlayerFromCharacter(character)
- if player and player ~= LocalPlayer then
- return false
- end
- end
- end
- end
- end
- return true
- end
- local function deepClone(args, copies)
- copies = copies or {}
- local copy
- if type(args) == "table" then
- if copies[args] then
- copy = copies[args]
- else
- copy = {}
- copies[args] = copy
- for k, v in next, args do
- copy[deepClone(k, copies)] = deepClone(v, copies)
- end
- end
- elseif typeof(args) == "Instance" then
- local success, cloned = pcall(cloneref, args)
- copy = success and cloned or args
- else
- copy = args
- end
- return copy
- end
- local function deepSerialize(value, depth, indent)
- depth = depth or 0
- indent = indent or 4
- if depth > 6 then return "..." end
- local t = typeof(value)
- local spacing = string.rep(" ", depth * indent)
- local nextSpacing = string.rep(" ", (depth + 1) * indent)
- if t == "nil" then
- return "nil"
- elseif t == "string" then
- if #value > 500 then
- return string.format("%q --[[...%d chars]]", value:sub(1, 500), #value)
- end
- local escaped = value:gsub("\\", "\\\\"):gsub("\n", "\\n"):gsub("\t", "\\t"):gsub('"', '\\"')
- return '"' .. escaped .. '"'
- elseif t == "number" then
- if value == math.huge then return "math.huge"
- elseif value == -math.huge then return "-math.huge"
- elseif value ~= value then return "0/0"
- else return tostring(value) end
- elseif t == "boolean" then
- return tostring(value)
- elseif t == "Instance" then
- return instanceToPath(value)
- elseif t == "Vector3" then
- if value == Vector3.zero then return "Vector3.zero"
- elseif value == Vector3.one then return "Vector3.one"
- else return string.format("Vector3.new(%s, %s, %s)", value.X, value.Y, value.Z) end
- elseif t == "Vector2" then
- if value == Vector2.zero then return "Vector2.zero"
- elseif value == Vector2.one then return "Vector2.one"
- else return string.format("Vector2.new(%s, %s)", value.X, value.Y) end
- elseif t == "CFrame" then
- if value == CFrame.identity then return "CFrame.identity" end
- local components = {value:GetComponents()}
- return string.format("CFrame.new(%s)", table.concat(components, ", "))
- elseif t == "Color3" then
- return string.format("Color3.new(%s, %s, %s)", value.R, value.G, value.B)
- elseif t == "BrickColor" then
- return string.format("BrickColor.new(%d)", value.Number)
- elseif t == "UDim" then
- return string.format("UDim.new(%s, %s)", value.Scale, value.Offset)
- elseif t == "UDim2" then
- return string.format("UDim2.new(%s, %s, %s, %s)", value.X.Scale, value.X.Offset, value.Y.Scale, value.Y.Offset)
- elseif t == "Rect" then
- return string.format("Rect.new(%s, %s, %s, %s)", value.Min.X, value.Min.Y, value.Max.X, value.Max.Y)
- elseif t == "EnumItem" then
- return tostring(value)
- elseif t == "RBXScriptSignal" then
- return "RBXScriptSignal"
- elseif t == "RBXScriptConnection" then
- return "RBXScriptConnection"
- elseif t == "function" then
- local info = ""
- pcall(function()
- local src, line, name = debug.info(value, "sln")
- info = string.format("%s:%s:%s", tostring(src or "?"), tostring(line or "?"), tostring(name or "?"))
- end)
- local closureType = "?"
- if iscclosure and iscclosure(value) then closureType = "C"
- elseif islclosure and islclosure(value) then closureType = "L" end
- return string.format("function() end --[[%s: %s]]", closureType, info)
- elseif t == "table" then
- local parts = {}
- local count = 0
- local isArray = true
- local maxIndex = 0
- for k, _ in pairs(value) do
- if type(k) ~= "number" or k < 1 or math.floor(k) ~= k then
- isArray = false
- break
- end
- maxIndex = math.max(maxIndex, k)
- end
- if isArray and maxIndex > 0 then
- for i = 1, maxIndex do
- if count >= 50 then
- table.insert(parts, nextSpacing .. "-- ..." .. (maxIndex - count) .. " more")
- break
- end
- count = count + 1
- table.insert(parts, nextSpacing .. deepSerialize(value[i], depth + 1, indent))
- end
- else
- for k, v in pairs(value) do
- if count >= 50 then
- table.insert(parts, nextSpacing .. "-- ...more entries")
- break
- end
- count = count + 1
- local keyStr
- if type(k) == "string" and k:match("^[%a_][%w_]*$") then
- keyStr = k
- else
- keyStr = "[" .. deepSerialize(k, depth + 1, indent) .. "]"
- end
- table.insert(parts, nextSpacing .. keyStr .. " = " .. deepSerialize(v, depth + 1, indent))
- end
- end
- if #parts == 0 then
- return "{}"
- end
- return "{\n" .. table.concat(parts, ",\n") .. "\n" .. spacing .. "}"
- else
- return string.format("<%s>(%s)", t, tostring(value))
- end
- end
- function instanceToPath(instance)
- if instance == nil then return "nil" end
- if instance == game then return "game" end
- if instance == workspace then return "workspace" end
- local player = nil
- for _, p in ipairs(Players:GetPlayers()) do
- if p.Character and (instance:IsDescendantOf(p.Character) or instance == p.Character) then
- player = p
- break
- end
- end
- local path = ""
- local current = instance
- if player then
- while current and current ~= player.Character do
- if current.Name:match("^[%a_][%w_]*$") then
- path = "." .. current.Name .. path
- else
- path = ':FindFirstChild("' .. current.Name:gsub('"', '\\"') .. '")' .. path
- end
- current = current.Parent
- end
- if player == Players.LocalPlayer then
- return 'game:GetService("Players").LocalPlayer.Character' .. path
- else
- return instanceToPath(player) .. ".Character" .. path
- end
- end
- while current and current.Parent ~= game do
- if current.Parent == nil then
- return string.format('getNil("%s", "%s")%s', instance.Name:gsub('"', '\\"'), instance.ClassName, path)
- end
- if current.Name:match("^[%a_][%w_]*$") then
- path = "." .. current.Name .. path
- else
- path = ':FindFirstChild("' .. current.Name:gsub('"', '\\"') .. '")' .. path
- end
- current = current.Parent
- end
- if current and current.Parent == game then
- local serviceName = current.ClassName
- if pcall(function() return game:GetService(serviceName) end) then
- return 'game:GetService("' .. serviceName .. '")' .. path
- else
- if current.Name:match("^[%a_][%w_]*$") then
- return "game." .. current.Name .. path
- else
- return 'game:FindFirstChild("' .. current.Name:gsub('"', '\\"') .. '")' .. path
- end
- end
- end
- return "game"
- end
- local function GetFullInfo(logData)
- local info = "-- ═══════════════════════════════════════════════════\n"
- info = info .. "-- FULL SIGNAL/REMOTE INFORMATION\n"
- info = info .. "-- Generated by SignalSpy Pro v2.1\n"
- info = info .. "-- ═══════════════════════════════════════════════════\n\n"
- info = info .. "-- BASIC INFO\n"
- info = info .. "Type = " .. deepSerialize(logData.Type) .. "\n"
- info = info .. "Name = " .. deepSerialize(logData.Name) .. "\n"
- info = info .. "Blocked = " .. tostring(logData.Blocked) .. "\n"
- info = info .. "Timestamp = " .. os.date("%Y-%m-%d %H:%M:%S", logData.Timestamp) .. "\n"
- info = info .. "Args Count = " .. tostring(#(logData.Args or {})) .. "\n\n"
- if logData.Remote then
- info = info .. "-- REMOTE INFO\n"
- info = info .. "RemotePath = " .. instanceToPath(logData.Remote) .. "\n"
- info = info .. "ClassName = " .. deepSerialize(logData.Remote.ClassName) .. "\n"
- info = info .. "Parent = " .. (logData.Remote.Parent and instanceToPath(logData.Remote.Parent) or "nil") .. "\n"
- local success, debugId = pcall(function() return game:GetDebugId(logData.Remote) end)
- if success then
- info = info .. "DebugId = " .. deepSerialize(debugId) .. "\n"
- end
- if getrawmetatable then
- local success, mt = pcall(getrawmetatable, logData.Remote)
- if success and mt then
- info = info .. "\n-- METATABLE INFO\n"
- info = info .. "HasMetatable = true\n"
- if isreadonly then
- local success2, readonly = pcall(isreadonly, mt)
- if success2 then
- info = info .. "IsReadonly = " .. tostring(readonly) .. "\n"
- end
- end
- info = info .. "Metatable = {\n"
- for k, v in pairs(mt) do
- if type(k) == "string" and k:sub(1, 2) == "__" then
- info = info .. " " .. k .. " = " .. deepSerialize(v, 1) .. ",\n"
- end
- end
- info = info .. "}\n"
- end
- end
- end
- if logData.Instance then
- info = info .. "-- INSTANCE INFO\n"
- info = info .. "InstancePath = " .. instanceToPath(logData.Instance) .. "\n"
- info = info .. "ClassName = " .. deepSerialize(logData.Instance.ClassName) .. "\n"
- info = info .. "SignalName = " .. deepSerialize(logData.SignalName) .. "\n"
- if logData.SignalName then
- local success, signal = pcall(function() return logData.Instance[logData.SignalName] end)
- if success and signal and typeof(signal) == "RBXScriptSignal" then
- info = info .. "\n-- SIGNAL CONNECTIONS\n"
- if getconnections then
- local success2, conns = pcall(getconnections, signal)
- if success2 and conns then
- info = info .. "ConnectionCount = " .. #conns .. "\n"
- for i, conn in ipairs(conns) do
- if i > 10 then
- info = info .. "-- ... " .. (#conns - 10) .. " more connections\n"
- break
- end
- info = info .. string.format("-- Connection[%d]:\n", i)
- info = info .. string.format("-- Enabled = %s\n", tostring(conn.Enabled))
- if conn.Function then
- local funcInfo = "?"
- pcall(function()
- local src, line, name = debug.info(conn.Function, "sln")
- funcInfo = string.format("%s:%s:%s", tostring(src), tostring(line), tostring(name))
- end)
- info = info .. string.format("-- Function = %s\n", funcInfo)
- if islclosure and islclosure(conn.Function) then
- if getupvalues then
- local success3, upvals = pcall(getupvalues, conn.Function)
- if success3 and upvals then
- info = info .. string.format("-- Upvalues = %d values\n", #upvals > 0 and #upvals or (next(upvals) and 1 or 0))
- end
- end
- if getconstants then
- local success4, consts = pcall(getconstants, conn.Function)
- if success4 and consts then
- info = info .. string.format("-- Constants = %d values\n", #consts)
- end
- end
- end
- end
- end
- end
- end
- end
- end
- end
- if logData.Source then
- info = info .. "\n-- SOURCE SCRIPT\n"
- info = info .. "SourcePath = " .. instanceToPath(logData.Source) .. "\n"
- if getscripthash and logData.Source then
- local success, hash = pcall(getscripthash, logData.Source)
- if success then
- info = info .. "ScriptHash = " .. deepSerialize(hash) .. "\n"
- end
- end
- end
- info = info .. "\n-- ARGUMENTS\n"
- info = info .. "Args = " .. deepSerialize(logData.Args or {}) .. "\n"
- info = info .. "\n-- EXECUTOR FUNCTIONS AVAILABLE\n"
- local funcs = {
- {"hookfunction", hookfunction},
- {"hookmetamethod", hookmetamethod},
- {"getconnections", getconnections},
- {"firesignal", firesignal},
- {"replicatesignal", replicatesignal},
- {"getrawmetatable", getrawmetatable},
- {"setrawmetatable", setrawmetatable},
- {"isreadonly", isreadonly},
- {"setreadonly", setreadonly},
- {"getupvalues", getupvalues},
- {"getconstants", getconstants},
- {"getprotos", getprotos},
- {"getgc", getgc},
- {"getreg", getreg},
- {"getnilinstances", getnilinstances},
- {"getrunningscripts", getrunningscripts},
- {"getloadedmodules", getloadedmodules},
- {"getcallbackvalue", getcallbackvalue},
- {"getscriptbytecode", getscriptbytecode},
- {"decompile", decompile},
- {"isexecutorclosure", isexecutorclosure},
- }
- for _, f in ipairs(funcs) do
- info = info .. string.format("-- %s = %s\n", f[1], f[2] and "YES" or "NO")
- end
- info = info .. "\n-- THREAD IDENTITY\n"
- if getthreadidentity then
- local success, identity = pcall(getthreadidentity)
- if success then
- info = info .. "ThreadIdentity = " .. tostring(identity) .. "\n"
- end
- end
- return info
- end
- local function generateScript(logData)
- local script = ""
- local needsGetNil = false
- if logData.Type == "RemoteEvent" or logData.Type == "UnreliableRemoteEvent" then
- local remotePath = instanceToPath(logData.Remote)
- if remotePath:find("getNil") then
- needsGetNil = true
- end
- if #logData.Args > 0 then
- script = "local args = " .. deepSerialize(logData.Args) .. "\n\n"
- script = script .. remotePath .. ":FireServer(unpack(args))"
- else
- script = remotePath .. ":FireServer()"
- end
- elseif logData.Type == "RemoteFunction" then
- local remotePath = instanceToPath(logData.Remote)
- if remotePath:find("getNil") then
- needsGetNil = true
- end
- if #logData.Args > 0 then
- script = "local args = " .. deepSerialize(logData.Args) .. "\n\n"
- script = script .. "local result = " .. remotePath .. ":InvokeServer(unpack(args))\nprint(result)"
- else
- script = "local result = " .. remotePath .. ":InvokeServer()\nprint(result)"
- end
- elseif logData.Type == "Signal" then
- script = "-- Signal: " .. logData.Name .. "\n"
- script = script .. "-- Instance: " .. instanceToPath(logData.Instance) .. "\n"
- script = script .. "-- Signal Name: " .. logData.SignalName .. "\n\n"
- if #logData.Args > 0 then
- script = script .. "local args = " .. deepSerialize(logData.Args) .. "\n\n"
- if replicatesignal or firesignal then
- script = script .. "-- Fire signal:\n"
- script = script .. string.format('%s(%s.%s, unpack(args))',
- replicatesignal and "replicatesignal" or "firesignal",
- instanceToPath(logData.Instance),
- logData.SignalName)
- end
- end
- end
- if needsGetNil then
- script = 'local function getNil(name, class)\n for _, v in ipairs(getnilinstances()) do\n if v.ClassName == class and v.Name == name then\n return v\n end\n end\nend\n\n' .. script
- end
- if logData.Blocked then
- script = "-- THIS CALL WAS BLOCKED BY SIGNAL SPY\n\n" .. script
- end
- return script
- end
- local function isSpammy(key)
- if not CONFIG.FilterSpammy then return false end
- local now = tick()
- if not SpamHistory[key] then
- SpamHistory[key] = {count = 1, lastTime = now, firstTime = now}
- return false
- end
- local history = SpamHistory[key]
- if now - history.lastTime > CONFIG.SpamTimeWindow then
- history.count = 1
- history.firstTime = now
- else
- history.count = history.count + 1
- end
- history.lastTime = now
- return history.count > CONFIG.SpamThreshold
- end
- local function MatchesSearch(logData)
- if SearchQuery == "" then return true end
- local query = SearchQuery:lower()
- local name = (logData.Name or ""):lower()
- local typeName = (logData.Type or ""):lower()
- return name:find(query, 1, true) or typeName:find(query, 1, true)
- end
- local function SetupFilesystem()
- if not isFsSupported then return false end
- local success = SafePcall(function()
- local folders = {
- "SignalSpy",
- "SignalSpy/Cache",
- "SignalSpy/Cache/Snapshots",
- "SignalSpy/Sessions",
- "SignalSpy/Settings"
- }
- for _, folder in ipairs(folders) do
- if not isfolder(folder) then
- makefolder(folder)
- end
- end
- end)
- return success
- end
- local function GetAPIVersion()
- local success, result = SafePcall(function()
- local version = game:HttpGet("https://raw.githubusercontent.com/MaximumADHD/Roblox-Client-Tracker/refs/heads/roblox/version.txt")
- local guid = game:HttpGet("https://raw.githubusercontent.com/MaximumADHD/Roblox-Client-Tracker/refs/heads/roblox/version-guid.txt")
- return (version or "unknown"):gsub("%s+", "") .. "-" .. (guid or "unknown"):gsub("%s+", "")
- end)
- return success and result or "unknown"
- end
- local function FetchAndCacheAPIEvents()
- if not isFsSupported then return {} end
- local version = GetAPIVersion()
- local cacheFile = "SignalSpy/Cache/Snapshots/01-" .. version .. "-Full-Events.json"
- if isfile(cacheFile) then
- local success, cached = SafePcall(function()
- return JSONDecode(readfile(cacheFile))
- end)
- if success and cached then
- print("[SignalSpy] Loaded cached events: " .. cacheFile)
- return cached
- end
- end
- local success, response = SafePcall(function()
- return game:HttpGet("https://raw.githubusercontent.com/MaximumADHD/Roblox-Client-Tracker/refs/heads/roblox/Full-API-Dump.json")
- end)
- if not success or not response then
- warn("[SignalSpy] Failed to fetch API")
- return {}
- end
- local apiData = JSONDecode(response)
- if not apiData or not apiData.Classes then
- warn("[SignalSpy] Invalid API data")
- return {}
- end
- local events = {}
- for _, class in ipairs(apiData.Classes) do
- local className = class.Name
- events[className] = {
- Superclass = class.Superclass,
- Events = {}
- }
- if class.Members then
- for _, member in ipairs(class.Members) do
- if member.MemberType == "Event" then
- table.insert(events[className].Events, {
- Name = member.Name,
- Parameters = member.Parameters or {},
- Security = member.Security,
- Tags = member.Tags or {},
- ThreadSafety = member.ThreadSafety
- })
- end
- end
- end
- end
- local oldFiles = listfiles("SignalSpy/Cache/Snapshots")
- for _, file in ipairs(oldFiles) do
- if file:find("Full%-Events%.json") then
- pcall(delfile, file)
- end
- end
- SafePcall(function()
- writefile(cacheFile, JSONEncode(events))
- print("[SignalSpy] Cached events to: " .. cacheFile)
- end)
- return events
- end
- local function ExportSession()
- if not isFsSupported then
- warn("[SignalSpy] Filesystem not supported")
- return nil
- end
- local sessionData = {
- version = "2.1",
- exportTime = os.date("%Y-%m-%d %H:%M:%S"),
- placeId = game.PlaceId,
- jobId = game.JobId,
- logsCount = #Logs,
- logs = {}
- }
- for _, log in ipairs(Logs) do
- table.insert(sessionData.logs, {
- id = log.id or 0,
- name = log.Name,
- type = log.Type,
- blocked = log.Blocked,
- timestamp = log.Timestamp,
- argsCount = #(log.Args or {})
- })
- end
- local filename = string.format("SignalSpy/Sessions/session_%s_%d.json", os.date("%Y%m%d_%H%M%S"), game.PlaceId)
- local success, err = pcall(function()
- writefile(filename, JSONEncode(sessionData))
- end)
- if success then
- return filename
- else
- warn("[SignalSpy] Export failed:", err)
- return nil
- end
- end
- local function Create(className, properties, children)
- local instance = Instance.new(className)
- for k, v in pairs(properties or {}) do
- pcall(function() instance[k] = v end)
- end
- for _, child in pairs(children or {}) do
- child.Parent = instance
- end
- return instance
- end
- local ScreenGui = Create("ScreenGui", {
- Name = randomString(),
- ResetOnSpawn = false,
- ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
- DisplayOrder = MAX_DISPLAY_ORDER,
- })
- local guiParent = CoreGui
- pcall(function()
- if gethui then
- guiParent = gethui()
- elseif protect_gui then
- protect_gui(ScreenGui)
- guiParent = CoreGui
- end
- end)
- ScreenGui.Parent = guiParent
- local MainFrame = Create("Frame", {
- Name = "MainFrame",
- Parent = ScreenGui,
- BackgroundColor3 = Color3.fromRGB(37, 36, 38),
- BorderSizePixel = 0,
- Position = UDim2.new(0.5, -350, 0.5, -200),
- Size = UDim2.new(0, 700, 0, 400),
- })
- Create("UICorner", {CornerRadius = UDim.new(0, 6), Parent = MainFrame})
- local TopBar = Create("Frame", {
- Name = "TopBar",
- Parent = MainFrame,
- BackgroundColor3 = Color3.fromRGB(37, 35, 38),
- BorderSizePixel = 0,
- Size = UDim2.new(1, 0, 0, 28),
- })
- Create("UICorner", {CornerRadius = UDim.new(0, 6), Parent = TopBar})
- Create("Frame", {
- Parent = TopBar,
- BackgroundColor3 = Color3.fromRGB(37, 35, 38),
- BorderSizePixel = 0,
- Position = UDim2.new(0, 0, 1, -6),
- Size = UDim2.new(1, 0, 0, 6),
- })
- local TitleLabel = Create("TextButton", {
- Name = "Title",
- Parent = TopBar,
- BackgroundTransparency = 1,
- Position = UDim2.new(0, 8, 0, 0),
- Size = UDim2.new(0, 130, 1, 0),
- Font = Enum.Font.GothamBold,
- Text = "SignalSpy Pro",
- TextColor3 = Color3.fromRGB(255, 255, 255),
- TextSize = 14,
- TextXAlignment = Enum.TextXAlignment.Left,
- AutoButtonColor = false,
- })
- local SearchBox = Create("TextBox", {
- Name = "Search",
- Parent = TopBar,
- BackgroundColor3 = Color3.fromRGB(30, 30, 32),
- BorderSizePixel = 0,
- Position = UDim2.new(0, 145, 0.5, -10),
- Size = UDim2.new(0, 150, 0, 20),
- Font = Enum.Font.Gotham,
- PlaceholderText = "Search...",
- PlaceholderColor3 = Color3.fromRGB(100, 100, 100),
- Text = "",
- TextColor3 = Color3.fromRGB(255, 255, 255),
- TextSize = 11,
- ClearTextOnFocus = false,
- })
- Create("UICorner", {CornerRadius = UDim.new(0, 4), Parent = SearchBox})
- Create("UIPadding", {PaddingLeft = UDim.new(0, 6), Parent = SearchBox})
- local CloseBtn = Create("TextButton", {
- Name = "Close",
- Parent = TopBar,
- BackgroundColor3 = Color3.fromRGB(37, 36, 38),
- BorderSizePixel = 0,
- Position = UDim2.new(1, -28, 0, 0),
- Size = UDim2.new(0, 28, 0, 28),
- Text = "",
- AutoButtonColor = false,
- })
- Create("ImageLabel", {
- Parent = CloseBtn,
- BackgroundTransparency = 1,
- Position = UDim2.new(0.5, -5, 0.5, -5),
- Size = UDim2.new(0, 10, 0, 10),
- Image = "rbxassetid://5597086202",
- })
- local MaxBtn = Create("TextButton", {
- Name = "Maximize",
- Parent = TopBar,
- BackgroundColor3 = Color3.fromRGB(37, 36, 38),
- BorderSizePixel = 0,
- Position = UDim2.new(1, -56, 0, 0),
- Size = UDim2.new(0, 28, 0, 28),
- Text = "",
- AutoButtonColor = false,
- })
- Create("ImageLabel", {
- Parent = MaxBtn,
- BackgroundTransparency = 1,
- Position = UDim2.new(0.5, -5, 0.5, -5),
- Size = UDim2.new(0, 10, 0, 10),
- Image = "rbxassetid://5597108117",
- })
- local MinBtn = Create("TextButton", {
- Name = "Minimize",
- Parent = TopBar,
- BackgroundColor3 = Color3.fromRGB(37, 36, 38),
- BorderSizePixel = 0,
- Position = UDim2.new(1, -84, 0, 0),
- Size = UDim2.new(0, 28, 0, 28),
- Text = "",
- AutoButtonColor = false,
- })
- Create("ImageLabel", {
- Parent = MinBtn,
- BackgroundTransparency = 1,
- Position = UDim2.new(0.5, -5, 0.5, -5),
- Size = UDim2.new(0, 10, 0, 10),
- Image = "rbxassetid://5597105827",
- })
- local LeftPanel = Create("Frame", {
- Name = "LeftPanel",
- Parent = MainFrame,
- BackgroundColor3 = Color3.fromRGB(53, 52, 55),
- BorderSizePixel = 0,
- Position = UDim2.new(0, 0, 0, 28),
- Size = UDim2.new(0, 180, 1, -28),
- })
- local LogScroll = Create("ScrollingFrame", {
- Name = "LogScroll",
- Parent = LeftPanel,
- BackgroundTransparency = 1,
- BorderSizePixel = 0,
- Position = UDim2.new(0, 0, 0, 5),
- Size = UDim2.new(1, 0, 1, -10),
- CanvasSize = UDim2.new(0, 0, 0, 0),
- ScrollBarThickness = 4,
- ScrollBarImageColor3 = Color3.fromRGB(255, 100, 100),
- })
- local LogLayout = Create("UIListLayout", {
- Parent = LogScroll,
- HorizontalAlignment = Enum.HorizontalAlignment.Center,
- SortOrder = Enum.SortOrder.LayoutOrder,
- Padding = UDim.new(0, 2),
- })
- LogLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
- LogScroll.CanvasSize = UDim2.new(0, 0, 0, LogLayout.AbsoluteContentSize.Y + 10)
- end)
- local RightPanel = Create("Frame", {
- Name = "RightPanel",
- Parent = MainFrame,
- BackgroundColor3 = Color3.fromRGB(37, 36, 38),
- BorderSizePixel = 0,
- Position = UDim2.new(0, 180, 0, 28),
- Size = UDim2.new(1, -180, 1, -28),
- })
- local CodeBox = Create("Frame", {
- Name = "CodeBox",
- Parent = RightPanel,
- BackgroundColor3 = Color3.fromRGB(21, 19, 20),
- BorderSizePixel = 0,
- Size = UDim2.new(1, 0, 0.6, 0),
- })
- Create("UICorner", {CornerRadius = UDim.new(0, 4), Parent = CodeBox})
- local CodeScroll = Create("ScrollingFrame", {
- Name = "CodeScroll",
- Parent = CodeBox,
- BackgroundTransparency = 1,
- BorderSizePixel = 0,
- Position = UDim2.new(0, 5, 0, 5),
- Size = UDim2.new(1, -10, 1, -10),
- CanvasSize = UDim2.new(0, 0, 0, 0),
- ScrollBarThickness = 4,
- ScrollBarImageColor3 = Color3.fromRGB(255, 100, 100),
- })
- local CodeText = Create("TextBox", {
- Name = "CodeText",
- Parent = CodeScroll,
- BackgroundTransparency = 1,
- Size = UDim2.new(1, 0, 1, 0),
- Font = Enum.Font.Code,
- Text = "-- SignalSpy Pro v2.1\n-- Select a log entry to view",
- TextColor3 = Color3.fromRGB(200, 200, 200),
- TextSize = 12,
- TextXAlignment = Enum.TextXAlignment.Left,
- TextYAlignment = Enum.TextYAlignment.Top,
- ClearTextOnFocus = false,
- MultiLine = true,
- TextWrapped = false,
- })
- Create("UIPadding", {Parent = CodeText, PaddingLeft = UDim.new(0, 5), PaddingTop = UDim.new(0, 5)})
- CodeText:GetPropertyChangedSignal("Text"):Connect(function()
- pcall(function()
- local textSize = TextService:GetTextSize(CodeText.Text, CodeText.TextSize, CodeText.Font, Vector2.new(CodeScroll.AbsoluteSize.X - 20, math.huge))
- CodeScroll.CanvasSize = UDim2.new(0, 0, 0, textSize.Y + 20)
- end)
- end)
- local ButtonsFrame = Create("Frame", {
- Name = "Buttons",
- Parent = RightPanel,
- BackgroundColor3 = Color3.fromRGB(37, 36, 38),
- BorderSizePixel = 0,
- Position = UDim2.new(0, 0, 0.6, 0),
- Size = UDim2.new(1, 0, 0.4, 0),
- })
- local ButtonScroll = Create("ScrollingFrame", {
- Name = "ButtonScroll",
- Parent = ButtonsFrame,
- BackgroundTransparency = 1,
- BorderSizePixel = 0,
- Position = UDim2.new(0, 5, 0, 5),
- Size = UDim2.new(1, -10, 1, -10),
- CanvasSize = UDim2.new(0, 0, 0, 0),
- ScrollBarThickness = 4,
- ScrollBarImageColor3 = Color3.fromRGB(255, 100, 100),
- })
- local ButtonGrid = Create("UIGridLayout", {
- Parent = ButtonScroll,
- HorizontalAlignment = Enum.HorizontalAlignment.Center,
- SortOrder = Enum.SortOrder.LayoutOrder,
- CellPadding = UDim2.new(0, 4, 0, 4),
- CellSize = UDim2.new(0, 95, 0, 28),
- })
- ButtonGrid:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
- ButtonScroll.CanvasSize = UDim2.new(0, 0, 0, ButtonGrid.AbsoluteContentSize.Y + 10)
- end)
- local Tooltip = Create("Frame", {
- Name = "Tooltip",
- Parent = ScreenGui,
- BackgroundColor3 = Color3.fromRGB(26, 26, 26),
- BackgroundTransparency = 0.1,
- BorderColor3 = Color3.fromRGB(255, 255, 255),
- Size = UDim2.new(0, 200, 0, 50),
- ZIndex = 10,
- Visible = false,
- })
- local TooltipText = Create("TextLabel", {
- Parent = Tooltip,
- BackgroundTransparency = 1,
- Position = UDim2.new(0, 4, 0, 4),
- Size = UDim2.new(1, -8, 1, -8),
- Font = Enum.Font.SourceSans,
- Text = "",
- TextColor3 = Color3.fromRGB(255, 255, 255),
- TextSize = 12,
- TextWrapped = true,
- TextXAlignment = Enum.TextXAlignment.Left,
- TextYAlignment = Enum.TextYAlignment.Top,
- ZIndex = 10,
- })
- local function showTooltip(text)
- TooltipText.Text = text
- pcall(function()
- local textSize = TextService:GetTextSize(text, 12, Enum.Font.SourceSans, Vector2.new(196, math.huge))
- Tooltip.Size = UDim2.new(0, math.min(textSize.X + 8, 200), 0, textSize.Y + 8)
- end)
- Tooltip.Visible = true
- if Connections["Tooltip"] then Connections["Tooltip"]:Disconnect() end
- Connections["Tooltip"] = RunService.RenderStepped:Connect(function()
- local mousePos = UserInputService:GetMouseLocation()
- local viewportSize = workspace.CurrentCamera.ViewportSize
- local x = mousePos.X + 15
- local y = mousePos.Y - 10
- if x + Tooltip.AbsoluteSize.X > viewportSize.X then
- x = mousePos.X - Tooltip.AbsoluteSize.X - 5
- end
- if y + Tooltip.AbsoluteSize.Y > viewportSize.Y then
- y = viewportSize.Y - Tooltip.AbsoluteSize.Y - 5
- end
- Tooltip.Position = UDim2.new(0, x, 0, y - 36)
- end)
- end
- local function hideTooltip()
- Tooltip.Visible = false
- if Connections["Tooltip"] then
- Connections["Tooltip"]:Disconnect()
- Connections["Tooltip"] = nil
- end
- end
- local function createButton(name, tooltip, callback)
- local btn = Create("Frame", {
- Name = name,
- Parent = ButtonScroll,
- BackgroundTransparency = 1,
- })
- Create("Frame", {
- Parent = btn,
- BackgroundColor3 = Color3.fromRGB(255, 100, 100),
- BorderSizePixel = 0,
- Position = UDim2.new(0, 4, 0, 5),
- Size = UDim2.new(0, 4, 0, 18),
- })
- Create("TextLabel", {
- Parent = btn,
- BackgroundTransparency = 1,
- Position = UDim2.new(0, 12, 0, 5),
- Size = UDim2.new(1, -16, 0, 18),
- Font = Enum.Font.SourceSans,
- Text = name,
- TextColor3 = Color3.fromRGB(255, 255, 255),
- TextSize = 12,
- TextXAlignment = Enum.TextXAlignment.Left,
- TextTruncate = Enum.TextTruncate.AtEnd,
- })
- local button = Create("TextButton", {
- Parent = btn,
- BackgroundColor3 = Color3.fromRGB(0, 0, 0),
- BackgroundTransparency = 0.7,
- BorderSizePixel = 0,
- Position = UDim2.new(0, 4, 0, 5),
- Size = UDim2.new(1, -8, 0, 18),
- AutoButtonColor = false,
- Text = "",
- })
- button.MouseEnter:Connect(function()
- showTooltip(type(tooltip) == "function" and tooltip() or tooltip)
- TweenService:Create(button, TweenInfo.new(0.2), {BackgroundTransparency = 0.5}):Play()
- end)
- button.MouseLeave:Connect(function()
- hideTooltip()
- TweenService:Create(button, TweenInfo.new(0.2), {BackgroundTransparency = 0.7}):Play()
- end)
- button.MouseButton1Click:Connect(function()
- local success, err = pcall(callback)
- if not success then
- warn("[SignalSpy] Button error:", err)
- end
- end)
- return btn
- end
- local function refreshLogList()
- for _, frame in pairs(LogFrames) do
- if frame.entry then
- frame.entry.Visible = MatchesSearch(frame.data)
- end
- end
- end
- SearchBox:GetPropertyChangedSignal("Text"):Connect(function()
- SearchQuery = SearchBox.Text
- refreshLogList()
- end)
- local function createLogEntry(logData)
- if LayoutOrder < 1 then LayoutOrder = 999999999 end
- local typeColors = {
- RemoteEvent = Color3.fromRGB(255, 242, 0),
- RemoteFunction = Color3.fromRGB(99, 86, 245),
- BindableEvent = Color3.fromRGB(0, 200, 100),
- BindableFunction = Color3.fromRGB(100, 200, 200),
- UnreliableRemoteEvent = Color3.fromRGB(255, 150, 0),
- Signal = Color3.fromRGB(255, 100, 150),
- HttpRequest = Color3.fromRGB(100, 150, 255),
- }
- local entry = Create("Frame", {
- Name = "LogEntry",
- Parent = LogScroll,
- BackgroundTransparency = 1,
- Size = UDim2.new(1, -10, 0, 24),
- LayoutOrder = LayoutOrder,
- Visible = MatchesSearch(logData),
- })
- Create("Frame", {
- Parent = entry,
- BackgroundColor3 = typeColors[logData.Type] or Color3.fromRGB(150, 150, 150),
- BorderSizePixel = 0,
- Size = UDim2.new(0, 5, 0, 18),
- Position = UDim2.new(0, 0, 0, 1),
- })
- Create("TextLabel", {
- Parent = entry,
- BackgroundTransparency = 1,
- Position = UDim2.new(0, 8, 0, 1),
- Size = UDim2.new(1, -12, 0, 18),
- Font = Enum.Font.SourceSans,
- Text = logData.Name,
- TextColor3 = logData.Blocked and Color3.fromRGB(255, 100, 100) or Color3.fromRGB(255, 255, 255),
- TextSize = 12,
- TextXAlignment = Enum.TextXAlignment.Left,
- TextTruncate = Enum.TextTruncate.AtEnd,
- })
- local button = Create("TextButton", {
- Parent = entry,
- BackgroundColor3 = Color3.fromRGB(0, 0, 0),
- BackgroundTransparency = 0.75,
- BorderSizePixel = 0,
- Position = UDim2.new(0, 0, 0, 1),
- Size = UDim2.new(1, 0, 0, 18),
- AutoButtonColor = false,
- Text = "",
- })
- button.MouseButton1Click:Connect(function()
- if Selected and Selected.Button then
- TweenService:Create(Selected.Button, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(0, 0, 0)}):Play()
- end
- Selected = logData
- Selected.Button = button
- Selected.Entry = entry
- TweenService:Create(button, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(92, 126, 229)}):Play()
- logData.Script = logData.Script or generateScript(logData)
- CodeText.Text = logData.Script
- end)
- LayoutOrder = LayoutOrder - 1
- logData.id = #Logs + 1
- table.insert(Logs, logData)
- table.insert(LogFrames, {entry = entry, data = logData})
- if #Logs > CONFIG.MaxLogs then
- local oldest = table.remove(LogFrames, #LogFrames)
- if oldest and oldest.entry then
- oldest.entry:Destroy()
- end
- table.remove(Logs, #Logs)
- end
- return entry
- end
- local function logRemote(remote, method, args, blocked)
- if not CONFIG.Enabled or not CONFIG.LogRemotes then return end
- if not CONFIG.LogCheckcaller and checkcaller() then return end
- if not CheckArgsForLocalPlayer(args) then return end
- local remoteType = remote.ClassName
- local name = remote.Name
- local key = name .. "_" .. remoteType
- if CONFIG.Blacklist[name] or CONFIG.Blacklist[remote] then return end
- if isSpammy(key) then return end
- local logData = {
- Type = remoteType,
- Name = name,
- Remote = remote,
- Args = deepClone(args),
- Method = method,
- Blocked = blocked or CONFIG.Blocklist[name] or CONFIG.Blocklist[remote],
- Timestamp = os.time(),
- Source = nil,
- }
- pcall(function()
- logData.Source = getcallingscript()
- end)
- createLogEntry(logData)
- return logData.Blocked
- end
- local function logSignal(instance, signalName, args)
- if not CONFIG.Enabled or not CONFIG.LogSignals then return end
- if not CheckIsLocalPlayer(instance) then return end
- if not CheckArgsForLocalPlayer(args) then return end
- local key = tostring(instance) .. "." .. signalName
- if CONFIG.IgnoredSignals[key] then return end
- if CONFIG.BlockedSignals[key] then return true end
- if isSpammy(key) then return end
- local spoofData = CONFIG.SpoofedSignals[key]
- if spoofData then
- args = spoofData.args
- end
- local logData = {
- Type = "Signal",
- Name = signalName,
- SignalName = signalName,
- Instance = instance,
- Args = deepClone(args),
- Blocked = CONFIG.BlockedSignals[key],
- Timestamp = os.time(),
- }
- createLogEntry(logData)
- return logData.Blocked, spoofData and spoofData.args or nil
- end
- local function hookSignal(instance, signalName)
- local key = tostring(instance) .. "." .. signalName
- if HookedSignals[key] then return end
- local success, signal = pcall(function()
- return instance[signalName]
- end)
- if not success or not signal or typeof(signal) ~= "RBXScriptSignal" then return end
- if not getconnections then return end
- HookedSignals[key] = true
- local connections = {}
- pcall(function()
- connections = getconnections(signal)
- end)
- for _, conn in pairs(connections) do
- if conn and conn.Function then
- local originalFunc = conn.Function
- local wasEnabled = conn.Enabled
- pcall(function() conn:Disable() end)
- local newConn = signal:Connect(function(...)
- local args = {...}
- local blocked, spoofedArgs = logSignal(instance, signalName, args)
- if blocked then return end
- if spoofedArgs then
- return originalFunc(table.unpack(spoofedArgs))
- end
- return originalFunc(...)
- end)
- table.insert(HookedConnections, {
- Connection = newConn,
- Original = conn,
- WasEnabled = wasEnabled,
- Key = key,
- })
- end
- end
- local catchConn = signal:Connect(function(...)
- if #connections == 0 then
- logSignal(instance, signalName, {...})
- end
- end)
- table.insert(HookedConnections, {Connection = catchConn, Key = key})
- end
- local function hookRemotes()
- local RemoteEvent = Instance.new("RemoteEvent")
- local RemoteFunction = Instance.new("RemoteFunction")
- local UnreliableRemoteEvent
- pcall(function() UnreliableRemoteEvent = Instance.new("UnreliableRemoteEvent") end)
- OriginalFunctions.FireServer = RemoteEvent.FireServer
- OriginalFunctions.InvokeServer = RemoteFunction.InvokeServer
- if UnreliableRemoteEvent then
- OriginalFunctions.UnreliableFireServer = UnreliableRemoteEvent.FireServer
- end
- RemoteEvent:Destroy()
- RemoteFunction:Destroy()
- if UnreliableRemoteEvent then UnreliableRemoteEvent:Destroy() end
- if hookfunction then
- pcall(function()
- local newFireServer = newcclosure(function(self, ...)
- if typeof(self) == "Instance" and self:IsA("RemoteEvent") then
- local blocked = logRemote(self, "FireServer", {...})
- if blocked then return end
- end
- return OriginalFunctions.FireServer(self, ...)
- end)
- hookfunction(Instance.new("RemoteEvent").FireServer, newFireServer)
- end)
- pcall(function()
- local newInvokeServer = newcclosure(function(self, ...)
- if typeof(self) == "Instance" and self:IsA("RemoteFunction") then
- local blocked = logRemote(self, "InvokeServer", {...})
- if blocked then return end
- end
- return OriginalFunctions.InvokeServer(self, ...)
- end)
- hookfunction(Instance.new("RemoteFunction").InvokeServer, newInvokeServer)
- end)
- if OriginalFunctions.UnreliableFireServer then
- pcall(function()
- local newUnreliableFire = newcclosure(function(self, ...)
- if typeof(self) == "Instance" and self:IsA("UnreliableRemoteEvent") then
- local blocked = logRemote(self, "FireServer", {...})
- if blocked then return end
- end
- return OriginalFunctions.UnreliableFireServer(self, ...)
- end)
- hookfunction(Instance.new("UnreliableRemoteEvent").FireServer, newUnreliableFire)
- end)
- end
- end
- if CONFIG.UseHookmetamethod and hookmetamethod then
- local success, err = pcall(function()
- local oldNamecall
- oldNamecall = hookmetamethod(game, "__namecall", newcclosure(function(self, ...)
- if not checkcaller() then
- local method = getnamecallmethod()
- if method then
- local lmethod = method:lower()
- if lmethod == "fireserver" and typeof(self) == "Instance" then
- if self:IsA("RemoteEvent") or self:IsA("UnreliableRemoteEvent") then
- local blocked = logRemote(self, method, {...})
- if blocked then return end
- end
- elseif lmethod == "invokeserver" and typeof(self) == "Instance" and self:IsA("RemoteFunction") then
- local blocked = logRemote(self, method, {...})
- if blocked then return end
- end
- end
- end
- return oldNamecall(self, ...)
- end))
- OriginalFunctions.Namecall = oldNamecall
- end)
- if not success then
- warn("[SignalSpy] hookmetamethod failed:", err)
- CONFIG.UseHookmetamethod = false
- end
- end
- end
- local function hookSignals()
- local TARGET_SIGNALS = {}
- if Players.LocalPlayer then
- table.insert(TARGET_SIGNALS, {Players.LocalPlayer, {"SimulationRadiusChanged", "OnTeleportInternal"}})
- end
- for _, data in pairs(TARGET_SIGNALS) do
- if data[1] then
- for _, signalName in pairs(data[2]) do
- pcall(function() hookSignal(data[1], signalName) end)
- end
- end
- end
- local function scanInstance(instance)
- pcall(function()
- if instance:IsA("Humanoid") then
- hookSignal(instance, "ServerEquipTool")
- elseif instance:IsA("ClickDetector") then
- hookSignal(instance, "MouseActionReplicated")
- elseif instance:IsA("ProximityPrompt") then
- hookSignal(instance, "TriggeredActionReplicated")
- elseif instance:IsA("Tool") then
- hookSignal(instance, "Activated")
- end
- end)
- end
- for _, desc in pairs(workspace:GetDescendants()) do
- scanInstance(desc)
- end
- Connections["DescendantAdded"] = workspace.DescendantAdded:Connect(function(desc)
- task.defer(scanInstance, desc)
- end)
- end
- local dragging = false
- local dragStart, startPos
- TopBar.InputBegan:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseButton1 then
- local mousePos = UserInputService:GetMouseLocation()
- local relPos = mousePos - TopBar.AbsolutePosition
- if relPos.X < TopBar.AbsoluteSize.X - 100 then
- dragging = true
- dragStart = input.Position
- startPos = MainFrame.Position
- end
- end
- end)
- TopBar.InputEnded:Connect(function(input)
- if input.UserInputType == Enum.UserInputType.MouseButton1 then
- dragging = false
- end
- end)
- UserInputService.InputChanged:Connect(function(input)
- if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement) then
- local delta = input.Position - dragStart
- local targetPos = UDim2.new(
- startPos.X.Scale, startPos.X.Offset + delta.X,
- startPos.Y.Scale, startPos.Y.Offset + delta.Y
- )
- TweenService:Create(MainFrame, TweenInfo.new(0.1, Enum.EasingStyle.Quad), {Position = targetPos}):Play()
- end
- end)
- local minimized = false
- MinBtn.MouseButton1Click:Connect(function()
- minimized = not minimized
- local targetSize = minimized and UDim2.new(0, 700, 0, 28) or UDim2.new(0, 700, 0, 400)
- TweenService:Create(MainFrame, TweenInfo.new(0.3, Enum.EasingStyle.Quad), {Size = targetSize}):Play()
- LeftPanel.Visible = not minimized
- RightPanel.Visible = not minimized
- end)
- local sideClosed = false
- MaxBtn.MouseButton1Click:Connect(function()
- sideClosed = not sideClosed
- local targetWidth = sideClosed and 180 or 700
- local leftSize = sideClosed and UDim2.new(1, 0, 1, -28) or UDim2.new(0, 180, 1, -28)
- TweenService:Create(MainFrame, TweenInfo.new(0.3, Enum.EasingStyle.Quad), {Size = UDim2.new(0, targetWidth, 0, 400)}):Play()
- TweenService:Create(LeftPanel, TweenInfo.new(0.3, Enum.EasingStyle.Quad), {Size = leftSize}):Play()
- task.delay(sideClosed and 0 or 0.15, function()
- RightPanel.Visible = not sideClosed
- end)
- end)
- CloseBtn.MouseEnter:Connect(function()
- TweenService:Create(CloseBtn, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(255, 60, 60)}):Play()
- end)
- CloseBtn.MouseLeave:Connect(function()
- TweenService:Create(CloseBtn, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(37, 36, 38)}):Play()
- end)
- local spyEnabled = true
- TitleLabel.MouseButton1Click:Connect(function()
- spyEnabled = not spyEnabled
- CONFIG.Enabled = spyEnabled
- TweenService:Create(TitleLabel, TweenInfo.new(0.3), {
- TextColor3 = spyEnabled and Color3.fromRGB(68, 206, 91) or Color3.fromRGB(252, 51, 51)
- }):Play()
- end)
- local function shutdown()
- Running = false
- getgenv().SignalSpyExecuted = false
- for _, conn in pairs(Connections) do
- if typeof(conn) == "RBXScriptConnection" then
- pcall(function() conn:Disconnect() end)
- end
- end
- for _, data in pairs(HookedConnections) do
- if data.Connection then
- pcall(function() data.Connection:Disconnect() end)
- end
- if data.Original and data.WasEnabled then
- pcall(function() data.Original:Enable() end)
- end
- end
- TweenService:Create(MainFrame, TweenInfo.new(0.3, Enum.EasingStyle.Quad), {
- Size = UDim2.new(0, 0, 0, 0),
- Position = UDim2.new(0.5, 0, 0.5, 0),
- }):Play()
- task.delay(0.35, function()
- ScreenGui:Destroy()
- end)
- end
- CloseBtn.MouseButton1Click:Connect(shutdown)
- getgenv().SignalSpyShutdown = shutdown
- createButton("Copy Code", "Copy the generated code to clipboard", function()
- if everyClipboard then
- everyClipboard(CodeText.Text)
- showTooltip("Copied!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Execute", "Execute the code in the code box", function()
- local code = CodeText.Text
- if code and code ~= "" then
- local func, err = loadstring(code)
- if func then
- local success, execErr = pcall(func)
- showTooltip(success and "Executed!" or "Error: " .. tostring(execErr):sub(1, 50))
- else
- showTooltip("Syntax Error: " .. tostring(err):sub(1, 50))
- end
- task.delay(2, hideTooltip)
- end
- end)
- createButton("Fire Remote", "Fire the selected remote", function()
- if Selected and Selected.Remote then
- local success, err = pcall(function()
- if Selected.Type == "RemoteEvent" or Selected.Type == "UnreliableRemoteEvent" then
- Selected.Remote:FireServer(unpack(Selected.Args or {}))
- elseif Selected.Type == "RemoteFunction" then
- local result = Selected.Remote:InvokeServer(unpack(Selected.Args or {}))
- showTooltip("Result: " .. tostring(result):sub(1, 50))
- return
- end
- end)
- showTooltip(success and "Fired!" or "Error: " .. tostring(err):sub(1, 50))
- task.delay(2, hideTooltip)
- else
- showTooltip("No remote selected!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Fire Signal", "Fire signal (firesignal)", function()
- if Selected and Selected.Type == "Signal" and Selected.Instance and firesignal then
- local success, err = pcall(function()
- local signal = Selected.Instance[Selected.SignalName]
- firesignal(signal, unpack(Selected.Args or {}))
- end)
- showTooltip(success and "Signal Fired!" or "Error: " .. tostring(err):sub(1, 50))
- task.delay(2, hideTooltip)
- else
- showTooltip(firesignal and "No signal selected!" or "firesignal unavailable!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Replicate", "Replicate signal (replicatesignal)", function()
- if Selected and Selected.Type == "Signal" and Selected.Instance and replicatesignal then
- local success, err = pcall(function()
- local signal = Selected.Instance[Selected.SignalName]
- replicatesignal(signal, unpack(Selected.Args or {}))
- end)
- showTooltip(success and "Replicated!" or "Error: " .. tostring(err):sub(1, 50))
- task.delay(2, hideTooltip)
- else
- showTooltip(replicatesignal and "No signal selected!" or "replicatesignal unavailable!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("View Full", "View FULL info (metatable, connections, etc)", function()
- if Selected then
- CodeText.Text = GetFullInfo(Selected)
- showTooltip("Full info displayed!")
- task.delay(1, hideTooltip)
- else
- showTooltip("Nothing selected!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Copy Full", "Copy FULL info to clipboard", function()
- if Selected and everyClipboard then
- everyClipboard(GetFullInfo(Selected))
- showTooltip("Full info copied!")
- task.delay(1, hideTooltip)
- else
- showTooltip("Nothing selected!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Copy Path", "Copy path to clipboard", function()
- if Selected and everyClipboard then
- local path = ""
- if Selected.Remote then
- path = instanceToPath(Selected.Remote)
- elseif Selected.Instance then
- path = instanceToPath(Selected.Instance) .. "." .. Selected.SignalName
- end
- everyClipboard(path)
- showTooltip("Path Copied!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Clear Logs", "Clear all logs", function()
- for _, frame in pairs(LogFrames) do
- if frame.entry then frame.entry:Destroy() end
- end
- Logs = {}
- LogFrames = {}
- Selected = nil
- CodeText.Text = "-- Logs cleared"
- showTooltip("Cleared!")
- task.delay(1, hideTooltip)
- end)
- createButton("Export", "Export session to file", function()
- local filename = ExportSession()
- if filename then
- showTooltip("Exported: " .. filename:sub(-30))
- if everyClipboard then everyClipboard(filename) end
- else
- showTooltip("Export failed!")
- end
- task.delay(2, hideTooltip)
- end)
- createButton("Fetch Events", "Fetch & cache API events", function()
- showTooltip("Fetching API...")
- task.spawn(function()
- CachedAPIEvents = FetchAndCacheAPIEvents()
- local count = 0
- for _ in pairs(CachedAPIEvents) do count = count + 1 end
- showTooltip("Cached " .. count .. " classes!")
- task.delay(2, hideTooltip)
- end)
- end)
- createButton("Block (i)", "Block this remote/signal", function()
- if Selected then
- if Selected.Remote then
- CONFIG.Blocklist[Selected.Remote] = true
- elseif Selected.Instance and Selected.SignalName then
- CONFIG.BlockedSignals[tostring(Selected.Instance) .. "." .. Selected.SignalName] = true
- end
- showTooltip("Blocked!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Block (n)", "Block by name", function()
- if Selected then
- CONFIG.Blocklist[Selected.Name] = true
- showTooltip("Blocked by name!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Ignore (i)", "Ignore this remote/signal", function()
- if Selected then
- if Selected.Remote then
- CONFIG.Blacklist[Selected.Remote] = true
- elseif Selected.Instance and Selected.SignalName then
- CONFIG.IgnoredSignals[tostring(Selected.Instance) .. "." .. Selected.SignalName] = true
- end
- showTooltip("Ignored!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Ignore (n)", "Ignore by name", function()
- if Selected then
- CONFIG.Blacklist[Selected.Name] = true
- showTooltip("Ignored by name!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Spoof Inf", "Spoof signal args to math.huge", function()
- if Selected and Selected.Type == "Signal" and Selected.Instance and Selected.SignalName then
- local key = tostring(Selected.Instance) .. "." .. Selected.SignalName
- CONFIG.SpoofedSignals[key] = {args = {math.huge}}
- showTooltip("Spoofed to math.huge!")
- task.delay(1, hideTooltip)
- else
- showTooltip("Select a signal first!")
- task.delay(1, hideTooltip)
- end
- end)
- createButton("Clr Spoof", "Clear all spoofed signals", function()
- CONFIG.SpoofedSignals = {}
- showTooltip("Spoofs cleared!")
- task.delay(1, hideTooltip)
- end)
- createButton("Clr Blacklist", "Clear ignore list", function()
- CONFIG.Blacklist = {}
- CONFIG.IgnoredSignals = {}
- showTooltip("Blacklist cleared!")
- task.delay(1, hideTooltip)
- end)
- createButton("Clr Blocklist", "Clear block list", function()
- CONFIG.Blocklist = {}
- CONFIG.BlockedSignals = {}
- showTooltip("Blocklist cleared!")
- task.delay(1, hideTooltip)
- end)
- createButton("Filter Spam", function()
- return "[" .. (CONFIG.FilterSpammy and "ON" or "OFF") .. "] Filter spam"
- end, function()
- CONFIG.FilterSpammy = not CONFIG.FilterSpammy
- SpamHistory = {}
- showTooltip("Filter: " .. (CONFIG.FilterSpammy and "ON" or "OFF"))
- task.delay(1, hideTooltip)
- end)
- createButton("LocalPlayer", function()
- return "[" .. (CONFIG.CheckLocalPlayer and "ON" or "OFF") .. "] Check LP"
- end, function()
- CONFIG.CheckLocalPlayer = not CONFIG.CheckLocalPlayer
- showTooltip("Check LP: " .. (CONFIG.CheckLocalPlayer and "ON" or "OFF"))
- task.delay(1, hideTooltip)
- end)
- createButton("Log Remotes", function()
- return "[" .. (CONFIG.LogRemotes and "ON" or "OFF") .. "] Remotes"
- end, function()
- CONFIG.LogRemotes = not CONFIG.LogRemotes
- showTooltip("Log Remotes: " .. (CONFIG.LogRemotes and "ON" or "OFF"))
- task.delay(1, hideTooltip)
- end)
- createButton("Log Signals", function()
- return "[" .. (CONFIG.LogSignals and "ON" or "OFF") .. "] Signals"
- end, function()
- CONFIG.LogSignals = not CONFIG.LogSignals
- showTooltip("Log Signals: " .. (CONFIG.LogSignals and "ON" or "OFF"))
- task.delay(1, hideTooltip)
- end)
- createButton("Connections", "View connections", function()
- if Selected and Selected.Type == "Signal" and Selected.Instance and getconnections then
- local success, result = pcall(function()
- local signal = Selected.Instance[Selected.SignalName]
- return getconnections(signal)
- end)
- if success then
- local info = "-- Signal Connections\n-- Count: " .. #result .. "\n\n"
- for i, conn in ipairs(result) do
- info = info .. string.format("-- [%d] Enabled=%s\n", i, tostring(conn.Enabled))
- end
- CodeText.Text = info
- end
- else
- showTooltip("Select a signal!")
- task.delay(1, hideTooltip)
- end
- end)
- SetupFilesystem()
- hookRemotes()
- hookSignals()
- getgenv().SignalSpyExecuted = true
- getgenv().SignalSpy = {
- CONFIG = CONFIG,
- Logs = Logs,
- CachedAPIEvents = CachedAPIEvents,
- shutdown = shutdown,
- hookSignal = hookSignal,
- export = ExportSession,
- fetchEvents = FetchAndCacheAPIEvents,
- spoofSignal = function(instance, signalName, args)
- local key = tostring(instance) .. "." .. signalName
- CONFIG.SpoofedSignals[key] = {args = args}
- end,
- }
- print("[SignalSpy Pro v2.1] Loaded!")
- print("[SignalSpy Pro] Click title to toggle")
- print("[SignalSpy Pro] hookmetamethod: " .. (CONFIG.UseHookmetamethod and hookmetamethod and "ON" or "OFF"))
Add Comment
Please, Sign In to add comment