Dark_Agent

SignalSpy Tool 01

Jan 5th, 2026
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 68.09 KB | Cybersecurity | 0 0
  1. if not game:IsLoaded() then game.Loaded:Wait() end
  2.  
  3. if getgenv().SignalSpyExecuted and type(getgenv().SignalSpyShutdown) == "function" then
  4.     getgenv().SignalSpyShutdown()
  5. end
  6.  
  7. local function missing(t, f, fallback)
  8.     if type(f) == t then return f end
  9.     return fallback
  10. end
  11.  
  12. local cloneref = missing("function", cloneref, function(...) return ... end)
  13. local hookfunction = missing("function", hookfunction or replaceclosure)
  14. local hookmetamethod = missing("function", hookmetamethod)
  15. local getnamecallmethod = missing("function", getnamecallmethod or get_namecall_method)
  16. local setnamecallmethod = missing("function", setnamecallmethod or set_namecall_method)
  17. local checkcaller = missing("function", checkcaller, function() return false end)
  18. local newcclosure = missing("function", newcclosure, function(f) return f end)
  19. local clonefunction = missing("function", clonefunction, function(f) return f end)
  20. local restorefunction = missing("function", restorefunction)
  21. local replicatesignal = missing("function", replicatesignal)
  22. local getconnections = missing("function", getconnections or get_signal_cons)
  23. local firesignal = missing("function", firesignal or fire_signal)
  24. local getgenv = missing("function", getgenv, function() return _G end)
  25. local getcallingscript = missing("function", getcallingscript, function() return nil end)
  26. local everyClipboard = missing("function", setclipboard or toclipboard or set_clipboard or (Clipboard and Clipboard.set))
  27. local iscclosure = missing("function", iscclosure, function() return false end)
  28. local islclosure = missing("function", islclosure or is_l_closure, function() return false end)
  29. local getconstants = missing("function", debug.getconstants or getconstants)
  30. local getupvalues = missing("function", debug.getupvalues or getupvalues)
  31. local getprotos = missing("function", getprotos or debug.getprotos)
  32. local getinfo = missing("function", debug.info or getinfo)
  33. local getnilinstances = missing("function", getnilinstances or get_nil_instances, function() return {} end)
  34. local getrawmetatable = missing("function", getrawmetatable, function() return nil end)
  35. local setrawmetatable = missing("function", setrawmetatable)
  36. local isreadonly = missing("function", isreadonly or table.isfrozen, function() return false end)
  37. local setreadonly = missing("function", setreadonly or makewriteable)
  38. local makewriteable = missing("function", makewriteable or function(t) if setreadonly then setreadonly(t, false) end end)
  39. local makereadonly = missing("function", makereadonly or function(t) if setreadonly then setreadonly(t, true) end end)
  40. local gethui = missing("function", gethui or get_hidden_gui)
  41. local protect_gui = missing("function", protect_gui or (syn and syn.protect_gui))
  42. local getthreadidentity = missing("function", getthreadidentity or getidentity or (syn and syn.get_thread_identity))
  43. local setthreadidentity = missing("function", setthreadidentity or setidentity or (syn and syn.set_thread_identity))
  44. local getgc = missing("function", getgc or get_gc_objects, function() return {} end)
  45. local getreg = missing("function", getreg or debug.getregistry, function() return {} end)
  46. local getrunningscripts = missing("function", getrunningscripts, function() return {} end)
  47. local getloadedmodules = missing("function", getloadedmodules, function() return {} end)
  48. local getinstances = missing("function", getinstances, function() return {} end)
  49. local getscripthash = missing("function", getscripthash)
  50. local getscriptclosure = missing("function", getscriptclosure or getscriptfunction)
  51. local getsenv = missing("function", getsenv or getscriptenv)
  52. local getcallbackvalue = missing("function", getcallbackvalue or getcallbackmember)
  53. local getthreadcontext = missing("function", getthreadcontext or getthreadidentity)
  54. local isexecutorclosure = missing("function", isexecutorclosure or checkclosure)
  55. local getscriptbytecode = missing("function", getscriptbytecode)
  56. local dumpstring = missing("function", dumpstring)
  57. local decompile = missing("function", decompile)
  58. local disassemble = missing("function", disassemble)
  59.  
  60. local oth = syn and syn.oth
  61. local unhook = oth and oth.unhook
  62. local othook = oth and oth.hook
  63.  
  64. local synv3 = false
  65. if syn and identifyexecutor then
  66.     local success, result = pcall(identifyexecutor)
  67.     if success then
  68.         local _, version = result, select(2, identifyexecutor())
  69.         if version and type(version) == "string" and version:sub(1, 2) == "v3" then
  70.             synv3 = true
  71.         end
  72.     end
  73. end
  74.  
  75. local isfile = missing("function", isfile, function() return false end)
  76. local isfolder = missing("function", isfolder, function() return false end)
  77. local readfile = missing("function", readfile, function() return "" end)
  78. local writefile = missing("function", writefile)
  79. local makefolder = missing("function", makefolder)
  80. local delfile = missing("function", delfile)
  81. local listfiles = missing("function", listfiles, function() return {} end)
  82. local appendfile = missing("function", appendfile)
  83.  
  84. local isFsSupported = type(writefile) == "function" and type(readfile) == "function"
  85.  
  86. local Services = setmetatable({}, {
  87.     __index = function(self, name)
  88.         local success, cache = pcall(function()
  89.             return cloneref(game:GetService(name))
  90.         end)
  91.         if success and cache then
  92.             rawset(self, name, cache)
  93.             return cache
  94.         end
  95.         return nil
  96.     end
  97. })
  98.  
  99. local HttpService = Services.HttpService
  100. local TweenService = Services.TweenService
  101. local UserInputService = Services.UserInputService
  102. local RunService = Services.RunService
  103. local Players = Services.Players
  104. local CoreGui = Services.CoreGui
  105. local TextService = Services.TextService
  106.  
  107. local LocalPlayer = Players and Players.LocalPlayer
  108. local MAX_DISPLAY_ORDER = 2147483647
  109.  
  110. local function randomString()
  111.     local length = math.random(10, 20)
  112.     local array = {}
  113.     for i = 1, length do
  114.         array[i] = string.char(math.random(32, 126))
  115.     end
  116.     return table.concat(array)
  117. end
  118.  
  119. local CONFIG = {
  120.     Enabled = true,
  121.     LogRemotes = false,
  122.     LogSignals = true,
  123.     LogRequests = false,
  124.     LogCheckcaller = true,
  125.     FilterSpammy = true,
  126.     SpamThreshold = 3,
  127.     SpamTimeWindow = 1,
  128.     MaxLogs = 500,
  129.     CheckLocalPlayer = true,
  130.     UseHookmetamethod = true,
  131.     Blacklist = {},
  132.     Blocklist = {},
  133.     IgnoredSignals = {},
  134.     BlockedSignals = {},
  135.     SpoofedSignals = {},
  136. }
  137.  
  138. local Logs = {}
  139. local LogFrames = {}
  140. local Selected = nil
  141. local LayoutOrder = 999999999
  142. local SpamHistory = {}
  143. local HookedSignals = {}
  144. local HookedConnections = {}
  145. local OriginalFunctions = {}
  146. local Connections = {}
  147. local Running = true
  148. local SearchQuery = ""
  149. local CachedAPIEvents = {}
  150.  
  151. local function SafePcall(func, ...)
  152.     local args = {...}
  153.     local success, result = xpcall(function()
  154.         return func(table.unpack(args))
  155.     end, function(err)
  156.         if getgenv().SignalSpyDEBUG then
  157.             warn("[SignalSpy][ERROR]", err)
  158.         end
  159.         return nil
  160.     end)
  161.     return success, result
  162. end
  163.  
  164. local function JSONEncode(data)
  165.     local success, result = pcall(function()
  166.         return HttpService:JSONEncode(data)
  167.     end)
  168.     return success and result or "{}"
  169. end
  170.  
  171. local function JSONDecode(str)
  172.     local success, result = pcall(function()
  173.         return HttpService:JSONDecode(str)
  174.     end)
  175.     return success and result or {}
  176. end
  177.  
  178. local function CheckIsLocalPlayer(instance)
  179.     if not CONFIG.CheckLocalPlayer then return true end
  180.     if not LocalPlayer then return true end
  181.     if not instance then return true end
  182.    
  183.     local success, result = pcall(function()
  184.         if instance == LocalPlayer then return true end
  185.         if instance == LocalPlayer.Character then return true end
  186.         if LocalPlayer.Character and instance:IsDescendantOf(LocalPlayer.Character) then return true end
  187.        
  188.         if typeof(instance) == "Instance" and instance:IsA("Player") then
  189.             return instance == LocalPlayer or
  190.                    instance.UserId == LocalPlayer.UserId or
  191.                    instance.Name == LocalPlayer.Name or
  192.                    instance.DisplayName == LocalPlayer.DisplayName
  193.         end
  194.        
  195.         if typeof(instance) == "Instance" and (instance:IsA("Humanoid") or instance:IsA("BasePart")) then
  196.             local character = instance:FindFirstAncestorOfClass("Model")
  197.             if character then
  198.                 local player = Players:GetPlayerFromCharacter(character)
  199.                 if player then
  200.                     return player == LocalPlayer or player.UserId == LocalPlayer.UserId
  201.                 end
  202.             end
  203.         end
  204.        
  205.         return true
  206.     end)
  207.    
  208.     return success and result or true
  209. end
  210.  
  211. local function CheckArgsForLocalPlayer(args)
  212.     if not CONFIG.CheckLocalPlayer then return true end
  213.     if not LocalPlayer then return true end
  214.     if not args or #args == 0 then return true end
  215.    
  216.     for _, arg in ipairs(args) do
  217.         if typeof(arg) == "Instance" then
  218.             if arg:IsA("Player") then
  219.                 if arg ~= LocalPlayer and arg.UserId ~= LocalPlayer.UserId then
  220.                     return false
  221.                 end
  222.             elseif arg:IsA("BasePart") or arg:IsA("Humanoid") then
  223.                 local character = arg:FindFirstAncestorOfClass("Model")
  224.                 if character then
  225.                     local player = Players:GetPlayerFromCharacter(character)
  226.                     if player and player ~= LocalPlayer then
  227.                         return false
  228.                     end
  229.                 end
  230.             end
  231.         end
  232.     end
  233.    
  234.     return true
  235. end
  236.  
  237. local function deepClone(args, copies)
  238.     copies = copies or {}
  239.     local copy
  240.     if type(args) == "table" then
  241.         if copies[args] then
  242.             copy = copies[args]
  243.         else
  244.             copy = {}
  245.             copies[args] = copy
  246.             for k, v in next, args do
  247.                 copy[deepClone(k, copies)] = deepClone(v, copies)
  248.             end
  249.         end
  250.     elseif typeof(args) == "Instance" then
  251.         local success, cloned = pcall(cloneref, args)
  252.         copy = success and cloned or args
  253.     else
  254.         copy = args
  255.     end
  256.     return copy
  257. end
  258.  
  259. local function deepSerialize(value, depth, indent)
  260.     depth = depth or 0
  261.     indent = indent or 4
  262.     if depth > 6 then return "..." end
  263.    
  264.     local t = typeof(value)
  265.     local spacing = string.rep(" ", depth * indent)
  266.     local nextSpacing = string.rep(" ", (depth + 1) * indent)
  267.    
  268.     if t == "nil" then
  269.         return "nil"
  270.     elseif t == "string" then
  271.         if #value > 500 then
  272.             return string.format("%q --[[...%d chars]]", value:sub(1, 500), #value)
  273.         end
  274.         local escaped = value:gsub("\\", "\\\\"):gsub("\n", "\\n"):gsub("\t", "\\t"):gsub('"', '\\"')
  275.         return '"' .. escaped .. '"'
  276.     elseif t == "number" then
  277.         if value == math.huge then return "math.huge"
  278.         elseif value == -math.huge then return "-math.huge"
  279.         elseif value ~= value then return "0/0"
  280.         else return tostring(value) end
  281.     elseif t == "boolean" then
  282.         return tostring(value)
  283.     elseif t == "Instance" then
  284.         return instanceToPath(value)
  285.     elseif t == "Vector3" then
  286.         if value == Vector3.zero then return "Vector3.zero"
  287.         elseif value == Vector3.one then return "Vector3.one"
  288.         else return string.format("Vector3.new(%s, %s, %s)", value.X, value.Y, value.Z) end
  289.     elseif t == "Vector2" then
  290.         if value == Vector2.zero then return "Vector2.zero"
  291.         elseif value == Vector2.one then return "Vector2.one"
  292.         else return string.format("Vector2.new(%s, %s)", value.X, value.Y) end
  293.     elseif t == "CFrame" then
  294.         if value == CFrame.identity then return "CFrame.identity" end
  295.         local components = {value:GetComponents()}
  296.         return string.format("CFrame.new(%s)", table.concat(components, ", "))
  297.     elseif t == "Color3" then
  298.         return string.format("Color3.new(%s, %s, %s)", value.R, value.G, value.B)
  299.     elseif t == "BrickColor" then
  300.         return string.format("BrickColor.new(%d)", value.Number)
  301.     elseif t == "UDim" then
  302.         return string.format("UDim.new(%s, %s)", value.Scale, value.Offset)
  303.     elseif t == "UDim2" then
  304.         return string.format("UDim2.new(%s, %s, %s, %s)", value.X.Scale, value.X.Offset, value.Y.Scale, value.Y.Offset)
  305.     elseif t == "Rect" then
  306.         return string.format("Rect.new(%s, %s, %s, %s)", value.Min.X, value.Min.Y, value.Max.X, value.Max.Y)
  307.     elseif t == "EnumItem" then
  308.         return tostring(value)
  309.     elseif t == "RBXScriptSignal" then
  310.         return "RBXScriptSignal"
  311.     elseif t == "RBXScriptConnection" then
  312.         return "RBXScriptConnection"
  313.     elseif t == "function" then
  314.         local info = ""
  315.         pcall(function()
  316.             local src, line, name = debug.info(value, "sln")
  317.             info = string.format("%s:%s:%s", tostring(src or "?"), tostring(line or "?"), tostring(name or "?"))
  318.         end)
  319.         local closureType = "?"
  320.         if iscclosure and iscclosure(value) then closureType = "C"
  321.         elseif islclosure and islclosure(value) then closureType = "L" end
  322.         return string.format("function() end --[[%s: %s]]", closureType, info)
  323.     elseif t == "table" then
  324.         local parts = {}
  325.         local count = 0
  326.         local isArray = true
  327.         local maxIndex = 0
  328.        
  329.         for k, _ in pairs(value) do
  330.             if type(k) ~= "number" or k < 1 or math.floor(k) ~= k then
  331.                 isArray = false
  332.                 break
  333.             end
  334.             maxIndex = math.max(maxIndex, k)
  335.         end
  336.        
  337.         if isArray and maxIndex > 0 then
  338.             for i = 1, maxIndex do
  339.                 if count >= 50 then
  340.                     table.insert(parts, nextSpacing .. "-- ..." .. (maxIndex - count) .. " more")
  341.                     break
  342.                 end
  343.                 count = count + 1
  344.                 table.insert(parts, nextSpacing .. deepSerialize(value[i], depth + 1, indent))
  345.             end
  346.         else
  347.             for k, v in pairs(value) do
  348.                 if count >= 50 then
  349.                     table.insert(parts, nextSpacing .. "-- ...more entries")
  350.                     break
  351.                 end
  352.                 count = count + 1
  353.                 local keyStr
  354.                 if type(k) == "string" and k:match("^[%a_][%w_]*$") then
  355.                     keyStr = k
  356.                 else
  357.                     keyStr = "[" .. deepSerialize(k, depth + 1, indent) .. "]"
  358.                 end
  359.                 table.insert(parts, nextSpacing .. keyStr .. " = " .. deepSerialize(v, depth + 1, indent))
  360.             end
  361.         end
  362.        
  363.         if #parts == 0 then
  364.             return "{}"
  365.         end
  366.         return "{\n" .. table.concat(parts, ",\n") .. "\n" .. spacing .. "}"
  367.     else
  368.         return string.format("<%s>(%s)", t, tostring(value))
  369.     end
  370. end
  371.  
  372. function instanceToPath(instance)
  373.     if instance == nil then return "nil" end
  374.     if instance == game then return "game" end
  375.     if instance == workspace then return "workspace" end
  376.    
  377.     local player = nil
  378.     for _, p in ipairs(Players:GetPlayers()) do
  379.         if p.Character and (instance:IsDescendantOf(p.Character) or instance == p.Character) then
  380.             player = p
  381.             break
  382.         end
  383.     end
  384.    
  385.     local path = ""
  386.     local current = instance
  387.    
  388.     if player then
  389.         while current and current ~= player.Character do
  390.             if current.Name:match("^[%a_][%w_]*$") then
  391.                 path = "." .. current.Name .. path
  392.             else
  393.                 path = ':FindFirstChild("' .. current.Name:gsub('"', '\\"') .. '")' .. path
  394.             end
  395.             current = current.Parent
  396.         end
  397.         if player == Players.LocalPlayer then
  398.             return 'game:GetService("Players").LocalPlayer.Character' .. path
  399.         else
  400.             return instanceToPath(player) .. ".Character" .. path
  401.         end
  402.     end
  403.    
  404.     while current and current.Parent ~= game do
  405.         if current.Parent == nil then
  406.             return string.format('getNil("%s", "%s")%s', instance.Name:gsub('"', '\\"'), instance.ClassName, path)
  407.         end
  408.         if current.Name:match("^[%a_][%w_]*$") then
  409.             path = "." .. current.Name .. path
  410.         else
  411.             path = ':FindFirstChild("' .. current.Name:gsub('"', '\\"') .. '")' .. path
  412.         end
  413.         current = current.Parent
  414.     end
  415.    
  416.     if current and current.Parent == game then
  417.         local serviceName = current.ClassName
  418.         if pcall(function() return game:GetService(serviceName) end) then
  419.             return 'game:GetService("' .. serviceName .. '")' .. path
  420.         else
  421.             if current.Name:match("^[%a_][%w_]*$") then
  422.                 return "game." .. current.Name .. path
  423.             else
  424.                 return 'game:FindFirstChild("' .. current.Name:gsub('"', '\\"') .. '")' .. path
  425.             end
  426.         end
  427.     end
  428.    
  429.     return "game"
  430. end
  431.  
  432. local function GetFullInfo(logData)
  433.     local info = "-- ═══════════════════════════════════════════════════\n"
  434.     info = info .. "-- FULL SIGNAL/REMOTE INFORMATION\n"
  435.     info = info .. "-- Generated by SignalSpy Pro v2.1\n"
  436.     info = info .. "-- ═══════════════════════════════════════════════════\n\n"
  437.    
  438.     info = info .. "-- BASIC INFO\n"
  439.     info = info .. "Type = " .. deepSerialize(logData.Type) .. "\n"
  440.     info = info .. "Name = " .. deepSerialize(logData.Name) .. "\n"
  441.     info = info .. "Blocked = " .. tostring(logData.Blocked) .. "\n"
  442.     info = info .. "Timestamp = " .. os.date("%Y-%m-%d %H:%M:%S", logData.Timestamp) .. "\n"
  443.     info = info .. "Args Count = " .. tostring(#(logData.Args or {})) .. "\n\n"
  444.    
  445.     if logData.Remote then
  446.         info = info .. "-- REMOTE INFO\n"
  447.         info = info .. "RemotePath = " .. instanceToPath(logData.Remote) .. "\n"
  448.         info = info .. "ClassName = " .. deepSerialize(logData.Remote.ClassName) .. "\n"
  449.         info = info .. "Parent = " .. (logData.Remote.Parent and instanceToPath(logData.Remote.Parent) or "nil") .. "\n"
  450.        
  451.         local success, debugId = pcall(function() return game:GetDebugId(logData.Remote) end)
  452.         if success then
  453.             info = info .. "DebugId = " .. deepSerialize(debugId) .. "\n"
  454.         end
  455.        
  456.         if getrawmetatable then
  457.             local success, mt = pcall(getrawmetatable, logData.Remote)
  458.             if success and mt then
  459.                 info = info .. "\n-- METATABLE INFO\n"
  460.                 info = info .. "HasMetatable = true\n"
  461.                 if isreadonly then
  462.                     local success2, readonly = pcall(isreadonly, mt)
  463.                     if success2 then
  464.                         info = info .. "IsReadonly = " .. tostring(readonly) .. "\n"
  465.                     end
  466.                 end
  467.                 info = info .. "Metatable = {\n"
  468.                 for k, v in pairs(mt) do
  469.                     if type(k) == "string" and k:sub(1, 2) == "__" then
  470.                         info = info .. "    " .. k .. " = " .. deepSerialize(v, 1) .. ",\n"
  471.                     end
  472.                 end
  473.                 info = info .. "}\n"
  474.             end
  475.         end
  476.     end
  477.    
  478.     if logData.Instance then
  479.         info = info .. "-- INSTANCE INFO\n"
  480.         info = info .. "InstancePath = " .. instanceToPath(logData.Instance) .. "\n"
  481.         info = info .. "ClassName = " .. deepSerialize(logData.Instance.ClassName) .. "\n"
  482.         info = info .. "SignalName = " .. deepSerialize(logData.SignalName) .. "\n"
  483.        
  484.         if logData.SignalName then
  485.             local success, signal = pcall(function() return logData.Instance[logData.SignalName] end)
  486.             if success and signal and typeof(signal) == "RBXScriptSignal" then
  487.                 info = info .. "\n-- SIGNAL CONNECTIONS\n"
  488.                 if getconnections then
  489.                     local success2, conns = pcall(getconnections, signal)
  490.                     if success2 and conns then
  491.                         info = info .. "ConnectionCount = " .. #conns .. "\n"
  492.                         for i, conn in ipairs(conns) do
  493.                             if i > 10 then
  494.                                 info = info .. "-- ... " .. (#conns - 10) .. " more connections\n"
  495.                                 break
  496.                             end
  497.                             info = info .. string.format("-- Connection[%d]:\n", i)
  498.                             info = info .. string.format("--   Enabled = %s\n", tostring(conn.Enabled))
  499.                             if conn.Function then
  500.                                 local funcInfo = "?"
  501.                                 pcall(function()
  502.                                     local src, line, name = debug.info(conn.Function, "sln")
  503.                                     funcInfo = string.format("%s:%s:%s", tostring(src), tostring(line), tostring(name))
  504.                                 end)
  505.                                 info = info .. string.format("--   Function = %s\n", funcInfo)
  506.                                
  507.                                 if islclosure and islclosure(conn.Function) then
  508.                                     if getupvalues then
  509.                                         local success3, upvals = pcall(getupvalues, conn.Function)
  510.                                         if success3 and upvals then
  511.                                             info = info .. string.format("--   Upvalues = %d values\n", #upvals > 0 and #upvals or (next(upvals) and 1 or 0))
  512.                                         end
  513.                                     end
  514.                                     if getconstants then
  515.                                         local success4, consts = pcall(getconstants, conn.Function)
  516.                                         if success4 and consts then
  517.                                             info = info .. string.format("--   Constants = %d values\n", #consts)
  518.                                         end
  519.                                     end
  520.                                 end
  521.                             end
  522.                         end
  523.                     end
  524.                 end
  525.             end
  526.         end
  527.     end
  528.    
  529.     if logData.Source then
  530.         info = info .. "\n-- SOURCE SCRIPT\n"
  531.         info = info .. "SourcePath = " .. instanceToPath(logData.Source) .. "\n"
  532.         if getscripthash and logData.Source then
  533.             local success, hash = pcall(getscripthash, logData.Source)
  534.             if success then
  535.                 info = info .. "ScriptHash = " .. deepSerialize(hash) .. "\n"
  536.             end
  537.         end
  538.     end
  539.    
  540.     info = info .. "\n-- ARGUMENTS\n"
  541.     info = info .. "Args = " .. deepSerialize(logData.Args or {}) .. "\n"
  542.    
  543.     info = info .. "\n-- EXECUTOR FUNCTIONS AVAILABLE\n"
  544.     local funcs = {
  545.         {"hookfunction", hookfunction},
  546.         {"hookmetamethod", hookmetamethod},
  547.         {"getconnections", getconnections},
  548.         {"firesignal", firesignal},
  549.         {"replicatesignal", replicatesignal},
  550.         {"getrawmetatable", getrawmetatable},
  551.         {"setrawmetatable", setrawmetatable},
  552.         {"isreadonly", isreadonly},
  553.         {"setreadonly", setreadonly},
  554.         {"getupvalues", getupvalues},
  555.         {"getconstants", getconstants},
  556.         {"getprotos", getprotos},
  557.         {"getgc", getgc},
  558.         {"getreg", getreg},
  559.         {"getnilinstances", getnilinstances},
  560.         {"getrunningscripts", getrunningscripts},
  561.         {"getloadedmodules", getloadedmodules},
  562.         {"getcallbackvalue", getcallbackvalue},
  563.         {"getscriptbytecode", getscriptbytecode},
  564.         {"decompile", decompile},
  565.         {"isexecutorclosure", isexecutorclosure},
  566.     }
  567.    
  568.     for _, f in ipairs(funcs) do
  569.         info = info .. string.format("-- %s = %s\n", f[1], f[2] and "YES" or "NO")
  570.     end
  571.    
  572.     info = info .. "\n-- THREAD IDENTITY\n"
  573.     if getthreadidentity then
  574.         local success, identity = pcall(getthreadidentity)
  575.         if success then
  576.             info = info .. "ThreadIdentity = " .. tostring(identity) .. "\n"
  577.         end
  578.     end
  579.    
  580.     return info
  581. end
  582.  
  583. local function generateScript(logData)
  584.     local script = ""
  585.     local needsGetNil = false
  586.    
  587.     if logData.Type == "RemoteEvent" or logData.Type == "UnreliableRemoteEvent" then
  588.         local remotePath = instanceToPath(logData.Remote)
  589.         if remotePath:find("getNil") then
  590.             needsGetNil = true
  591.         end
  592.         if #logData.Args > 0 then
  593.             script = "local args = " .. deepSerialize(logData.Args) .. "\n\n"
  594.             script = script .. remotePath .. ":FireServer(unpack(args))"
  595.         else
  596.             script = remotePath .. ":FireServer()"
  597.         end
  598.     elseif logData.Type == "RemoteFunction" then
  599.         local remotePath = instanceToPath(logData.Remote)
  600.         if remotePath:find("getNil") then
  601.             needsGetNil = true
  602.         end
  603.         if #logData.Args > 0 then
  604.             script = "local args = " .. deepSerialize(logData.Args) .. "\n\n"
  605.             script = script .. "local result = " .. remotePath .. ":InvokeServer(unpack(args))\nprint(result)"
  606.         else
  607.             script = "local result = " .. remotePath .. ":InvokeServer()\nprint(result)"
  608.         end
  609.     elseif logData.Type == "Signal" then
  610.         script = "-- Signal: " .. logData.Name .. "\n"
  611.         script = script .. "-- Instance: " .. instanceToPath(logData.Instance) .. "\n"
  612.         script = script .. "-- Signal Name: " .. logData.SignalName .. "\n\n"
  613.         if #logData.Args > 0 then
  614.             script = script .. "local args = " .. deepSerialize(logData.Args) .. "\n\n"
  615.             if replicatesignal or firesignal then
  616.                 script = script .. "-- Fire signal:\n"
  617.                 script = script .. string.format('%s(%s.%s, unpack(args))',
  618.                     replicatesignal and "replicatesignal" or "firesignal",
  619.                     instanceToPath(logData.Instance),
  620.                     logData.SignalName)
  621.             end
  622.         end
  623.     end
  624.    
  625.     if needsGetNil then
  626.         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
  627.     end
  628.    
  629.     if logData.Blocked then
  630.         script = "-- THIS CALL WAS BLOCKED BY SIGNAL SPY\n\n" .. script
  631.     end
  632.    
  633.     return script
  634. end
  635.  
  636. local function isSpammy(key)
  637.     if not CONFIG.FilterSpammy then return false end
  638.    
  639.     local now = tick()
  640.     if not SpamHistory[key] then
  641.         SpamHistory[key] = {count = 1, lastTime = now, firstTime = now}
  642.         return false
  643.     end
  644.    
  645.     local history = SpamHistory[key]
  646.    
  647.     if now - history.lastTime > CONFIG.SpamTimeWindow then
  648.         history.count = 1
  649.         history.firstTime = now
  650.     else
  651.         history.count = history.count + 1
  652.     end
  653.     history.lastTime = now
  654.    
  655.     return history.count > CONFIG.SpamThreshold
  656. end
  657.  
  658. local function MatchesSearch(logData)
  659.     if SearchQuery == "" then return true end
  660.     local query = SearchQuery:lower()
  661.     local name = (logData.Name or ""):lower()
  662.     local typeName = (logData.Type or ""):lower()
  663.     return name:find(query, 1, true) or typeName:find(query, 1, true)
  664. end
  665.  
  666. local function SetupFilesystem()
  667.     if not isFsSupported then return false end
  668.    
  669.     local success = SafePcall(function()
  670.         local folders = {
  671.             "SignalSpy",
  672.             "SignalSpy/Cache",
  673.             "SignalSpy/Cache/Snapshots",
  674.             "SignalSpy/Sessions",
  675.             "SignalSpy/Settings"
  676.         }
  677.         for _, folder in ipairs(folders) do
  678.             if not isfolder(folder) then
  679.                 makefolder(folder)
  680.             end
  681.         end
  682.     end)
  683.    
  684.     return success
  685. end
  686.  
  687. local function GetAPIVersion()
  688.     local success, result = SafePcall(function()
  689.         local version = game:HttpGet("https://raw.githubusercontent.com/MaximumADHD/Roblox-Client-Tracker/refs/heads/roblox/version.txt")
  690.         local guid = game:HttpGet("https://raw.githubusercontent.com/MaximumADHD/Roblox-Client-Tracker/refs/heads/roblox/version-guid.txt")
  691.         return (version or "unknown"):gsub("%s+", "") .. "-" .. (guid or "unknown"):gsub("%s+", "")
  692.     end)
  693.     return success and result or "unknown"
  694. end
  695.  
  696. local function FetchAndCacheAPIEvents()
  697.     if not isFsSupported then return {} end
  698.    
  699.     local version = GetAPIVersion()
  700.     local cacheFile = "SignalSpy/Cache/Snapshots/01-" .. version .. "-Full-Events.json"
  701.    
  702.     if isfile(cacheFile) then
  703.         local success, cached = SafePcall(function()
  704.             return JSONDecode(readfile(cacheFile))
  705.         end)
  706.         if success and cached then
  707.             print("[SignalSpy] Loaded cached events: " .. cacheFile)
  708.             return cached
  709.         end
  710.     end
  711.    
  712.     local success, response = SafePcall(function()
  713.         return game:HttpGet("https://raw.githubusercontent.com/MaximumADHD/Roblox-Client-Tracker/refs/heads/roblox/Full-API-Dump.json")
  714.     end)
  715.    
  716.     if not success or not response then
  717.         warn("[SignalSpy] Failed to fetch API")
  718.         return {}
  719.     end
  720.    
  721.     local apiData = JSONDecode(response)
  722.     if not apiData or not apiData.Classes then
  723.         warn("[SignalSpy] Invalid API data")
  724.         return {}
  725.     end
  726.    
  727.     local events = {}
  728.    
  729.     for _, class in ipairs(apiData.Classes) do
  730.         local className = class.Name
  731.         events[className] = {
  732.             Superclass = class.Superclass,
  733.             Events = {}
  734.         }
  735.        
  736.         if class.Members then
  737.             for _, member in ipairs(class.Members) do
  738.                 if member.MemberType == "Event" then
  739.                     table.insert(events[className].Events, {
  740.                         Name = member.Name,
  741.                         Parameters = member.Parameters or {},
  742.                         Security = member.Security,
  743.                         Tags = member.Tags or {},
  744.                         ThreadSafety = member.ThreadSafety
  745.                     })
  746.                 end
  747.             end
  748.         end
  749.     end
  750.    
  751.     local oldFiles = listfiles("SignalSpy/Cache/Snapshots")
  752.     for _, file in ipairs(oldFiles) do
  753.         if file:find("Full%-Events%.json") then
  754.             pcall(delfile, file)
  755.         end
  756.     end
  757.    
  758.     SafePcall(function()
  759.         writefile(cacheFile, JSONEncode(events))
  760.         print("[SignalSpy] Cached events to: " .. cacheFile)
  761.     end)
  762.    
  763.     return events
  764. end
  765.  
  766. local function ExportSession()
  767.     if not isFsSupported then
  768.         warn("[SignalSpy] Filesystem not supported")
  769.         return nil
  770.     end
  771.    
  772.     local sessionData = {
  773.         version = "2.1",
  774.         exportTime = os.date("%Y-%m-%d %H:%M:%S"),
  775.         placeId = game.PlaceId,
  776.         jobId = game.JobId,
  777.         logsCount = #Logs,
  778.         logs = {}
  779.     }
  780.    
  781.     for _, log in ipairs(Logs) do
  782.         table.insert(sessionData.logs, {
  783.             id = log.id or 0,
  784.             name = log.Name,
  785.             type = log.Type,
  786.             blocked = log.Blocked,
  787.             timestamp = log.Timestamp,
  788.             argsCount = #(log.Args or {})
  789.         })
  790.     end
  791.    
  792.     local filename = string.format("SignalSpy/Sessions/session_%s_%d.json", os.date("%Y%m%d_%H%M%S"), game.PlaceId)
  793.     local success, err = pcall(function()
  794.         writefile(filename, JSONEncode(sessionData))
  795.     end)
  796.    
  797.     if success then
  798.         return filename
  799.     else
  800.         warn("[SignalSpy] Export failed:", err)
  801.         return nil
  802.     end
  803. end
  804.  
  805. local function Create(className, properties, children)
  806.     local instance = Instance.new(className)
  807.     for k, v in pairs(properties or {}) do
  808.         pcall(function() instance[k] = v end)
  809.     end
  810.     for _, child in pairs(children or {}) do
  811.         child.Parent = instance
  812.     end
  813.     return instance
  814. end
  815.  
  816. local ScreenGui = Create("ScreenGui", {
  817.     Name = randomString(),
  818.     ResetOnSpawn = false,
  819.     ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
  820.     DisplayOrder = MAX_DISPLAY_ORDER,
  821. })
  822.  
  823. local guiParent = CoreGui
  824. pcall(function()
  825.     if gethui then
  826.         guiParent = gethui()
  827.     elseif protect_gui then
  828.         protect_gui(ScreenGui)
  829.         guiParent = CoreGui
  830.     end
  831. end)
  832. ScreenGui.Parent = guiParent
  833.  
  834. local MainFrame = Create("Frame", {
  835.     Name = "MainFrame",
  836.     Parent = ScreenGui,
  837.     BackgroundColor3 = Color3.fromRGB(37, 36, 38),
  838.     BorderSizePixel = 0,
  839.     Position = UDim2.new(0.5, -350, 0.5, -200),
  840.     Size = UDim2.new(0, 700, 0, 400),
  841. })
  842. Create("UICorner", {CornerRadius = UDim.new(0, 6), Parent = MainFrame})
  843.  
  844. local TopBar = Create("Frame", {
  845.     Name = "TopBar",
  846.     Parent = MainFrame,
  847.     BackgroundColor3 = Color3.fromRGB(37, 35, 38),
  848.     BorderSizePixel = 0,
  849.     Size = UDim2.new(1, 0, 0, 28),
  850. })
  851. Create("UICorner", {CornerRadius = UDim.new(0, 6), Parent = TopBar})
  852. Create("Frame", {
  853.     Parent = TopBar,
  854.     BackgroundColor3 = Color3.fromRGB(37, 35, 38),
  855.     BorderSizePixel = 0,
  856.     Position = UDim2.new(0, 0, 1, -6),
  857.     Size = UDim2.new(1, 0, 0, 6),
  858. })
  859.  
  860. local TitleLabel = Create("TextButton", {
  861.     Name = "Title",
  862.     Parent = TopBar,
  863.     BackgroundTransparency = 1,
  864.     Position = UDim2.new(0, 8, 0, 0),
  865.     Size = UDim2.new(0, 130, 1, 0),
  866.     Font = Enum.Font.GothamBold,
  867.     Text = "SignalSpy Pro",
  868.     TextColor3 = Color3.fromRGB(255, 255, 255),
  869.     TextSize = 14,
  870.     TextXAlignment = Enum.TextXAlignment.Left,
  871.     AutoButtonColor = false,
  872. })
  873.  
  874. local SearchBox = Create("TextBox", {
  875.     Name = "Search",
  876.     Parent = TopBar,
  877.     BackgroundColor3 = Color3.fromRGB(30, 30, 32),
  878.     BorderSizePixel = 0,
  879.     Position = UDim2.new(0, 145, 0.5, -10),
  880.     Size = UDim2.new(0, 150, 0, 20),
  881.     Font = Enum.Font.Gotham,
  882.     PlaceholderText = "Search...",
  883.     PlaceholderColor3 = Color3.fromRGB(100, 100, 100),
  884.     Text = "",
  885.     TextColor3 = Color3.fromRGB(255, 255, 255),
  886.     TextSize = 11,
  887.     ClearTextOnFocus = false,
  888. })
  889. Create("UICorner", {CornerRadius = UDim.new(0, 4), Parent = SearchBox})
  890. Create("UIPadding", {PaddingLeft = UDim.new(0, 6), Parent = SearchBox})
  891.  
  892. local CloseBtn = Create("TextButton", {
  893.     Name = "Close",
  894.     Parent = TopBar,
  895.     BackgroundColor3 = Color3.fromRGB(37, 36, 38),
  896.     BorderSizePixel = 0,
  897.     Position = UDim2.new(1, -28, 0, 0),
  898.     Size = UDim2.new(0, 28, 0, 28),
  899.     Text = "",
  900.     AutoButtonColor = false,
  901. })
  902. Create("ImageLabel", {
  903.     Parent = CloseBtn,
  904.     BackgroundTransparency = 1,
  905.     Position = UDim2.new(0.5, -5, 0.5, -5),
  906.     Size = UDim2.new(0, 10, 0, 10),
  907.     Image = "rbxassetid://5597086202",
  908. })
  909.  
  910. local MaxBtn = Create("TextButton", {
  911.     Name = "Maximize",
  912.     Parent = TopBar,
  913.     BackgroundColor3 = Color3.fromRGB(37, 36, 38),
  914.     BorderSizePixel = 0,
  915.     Position = UDim2.new(1, -56, 0, 0),
  916.     Size = UDim2.new(0, 28, 0, 28),
  917.     Text = "",
  918.     AutoButtonColor = false,
  919. })
  920. Create("ImageLabel", {
  921.     Parent = MaxBtn,
  922.     BackgroundTransparency = 1,
  923.     Position = UDim2.new(0.5, -5, 0.5, -5),
  924.     Size = UDim2.new(0, 10, 0, 10),
  925.     Image = "rbxassetid://5597108117",
  926. })
  927.  
  928. local MinBtn = Create("TextButton", {
  929.     Name = "Minimize",
  930.     Parent = TopBar,
  931.     BackgroundColor3 = Color3.fromRGB(37, 36, 38),
  932.     BorderSizePixel = 0,
  933.     Position = UDim2.new(1, -84, 0, 0),
  934.     Size = UDim2.new(0, 28, 0, 28),
  935.     Text = "",
  936.     AutoButtonColor = false,
  937. })
  938. Create("ImageLabel", {
  939.     Parent = MinBtn,
  940.     BackgroundTransparency = 1,
  941.     Position = UDim2.new(0.5, -5, 0.5, -5),
  942.     Size = UDim2.new(0, 10, 0, 10),
  943.     Image = "rbxassetid://5597105827",
  944. })
  945.  
  946. local LeftPanel = Create("Frame", {
  947.     Name = "LeftPanel",
  948.     Parent = MainFrame,
  949.     BackgroundColor3 = Color3.fromRGB(53, 52, 55),
  950.     BorderSizePixel = 0,
  951.     Position = UDim2.new(0, 0, 0, 28),
  952.     Size = UDim2.new(0, 180, 1, -28),
  953. })
  954.  
  955. local LogScroll = Create("ScrollingFrame", {
  956.     Name = "LogScroll",
  957.     Parent = LeftPanel,
  958.     BackgroundTransparency = 1,
  959.     BorderSizePixel = 0,
  960.     Position = UDim2.new(0, 0, 0, 5),
  961.     Size = UDim2.new(1, 0, 1, -10),
  962.     CanvasSize = UDim2.new(0, 0, 0, 0),
  963.     ScrollBarThickness = 4,
  964.     ScrollBarImageColor3 = Color3.fromRGB(255, 100, 100),
  965. })
  966. local LogLayout = Create("UIListLayout", {
  967.     Parent = LogScroll,
  968.     HorizontalAlignment = Enum.HorizontalAlignment.Center,
  969.     SortOrder = Enum.SortOrder.LayoutOrder,
  970.     Padding = UDim.new(0, 2),
  971. })
  972. LogLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
  973.     LogScroll.CanvasSize = UDim2.new(0, 0, 0, LogLayout.AbsoluteContentSize.Y + 10)
  974. end)
  975.  
  976. local RightPanel = Create("Frame", {
  977.     Name = "RightPanel",
  978.     Parent = MainFrame,
  979.     BackgroundColor3 = Color3.fromRGB(37, 36, 38),
  980.     BorderSizePixel = 0,
  981.     Position = UDim2.new(0, 180, 0, 28),
  982.     Size = UDim2.new(1, -180, 1, -28),
  983. })
  984.  
  985. local CodeBox = Create("Frame", {
  986.     Name = "CodeBox",
  987.     Parent = RightPanel,
  988.     BackgroundColor3 = Color3.fromRGB(21, 19, 20),
  989.     BorderSizePixel = 0,
  990.     Size = UDim2.new(1, 0, 0.6, 0),
  991. })
  992. Create("UICorner", {CornerRadius = UDim.new(0, 4), Parent = CodeBox})
  993.  
  994. local CodeScroll = Create("ScrollingFrame", {
  995.     Name = "CodeScroll",
  996.     Parent = CodeBox,
  997.     BackgroundTransparency = 1,
  998.     BorderSizePixel = 0,
  999.     Position = UDim2.new(0, 5, 0, 5),
  1000.     Size = UDim2.new(1, -10, 1, -10),
  1001.     CanvasSize = UDim2.new(0, 0, 0, 0),
  1002.     ScrollBarThickness = 4,
  1003.     ScrollBarImageColor3 = Color3.fromRGB(255, 100, 100),
  1004. })
  1005.  
  1006. local CodeText = Create("TextBox", {
  1007.     Name = "CodeText",
  1008.     Parent = CodeScroll,
  1009.     BackgroundTransparency = 1,
  1010.     Size = UDim2.new(1, 0, 1, 0),
  1011.     Font = Enum.Font.Code,
  1012.     Text = "-- SignalSpy Pro v2.1\n-- Select a log entry to view",
  1013.     TextColor3 = Color3.fromRGB(200, 200, 200),
  1014.     TextSize = 12,
  1015.     TextXAlignment = Enum.TextXAlignment.Left,
  1016.     TextYAlignment = Enum.TextYAlignment.Top,
  1017.     ClearTextOnFocus = false,
  1018.     MultiLine = true,
  1019.     TextWrapped = false,
  1020. })
  1021. Create("UIPadding", {Parent = CodeText, PaddingLeft = UDim.new(0, 5), PaddingTop = UDim.new(0, 5)})
  1022.  
  1023. CodeText:GetPropertyChangedSignal("Text"):Connect(function()
  1024.     pcall(function()
  1025.         local textSize = TextService:GetTextSize(CodeText.Text, CodeText.TextSize, CodeText.Font, Vector2.new(CodeScroll.AbsoluteSize.X - 20, math.huge))
  1026.         CodeScroll.CanvasSize = UDim2.new(0, 0, 0, textSize.Y + 20)
  1027.     end)
  1028. end)
  1029.  
  1030. local ButtonsFrame = Create("Frame", {
  1031.     Name = "Buttons",
  1032.     Parent = RightPanel,
  1033.     BackgroundColor3 = Color3.fromRGB(37, 36, 38),
  1034.     BorderSizePixel = 0,
  1035.     Position = UDim2.new(0, 0, 0.6, 0),
  1036.     Size = UDim2.new(1, 0, 0.4, 0),
  1037. })
  1038.  
  1039. local ButtonScroll = Create("ScrollingFrame", {
  1040.     Name = "ButtonScroll",
  1041.     Parent = ButtonsFrame,
  1042.     BackgroundTransparency = 1,
  1043.     BorderSizePixel = 0,
  1044.     Position = UDim2.new(0, 5, 0, 5),
  1045.     Size = UDim2.new(1, -10, 1, -10),
  1046.     CanvasSize = UDim2.new(0, 0, 0, 0),
  1047.     ScrollBarThickness = 4,
  1048.     ScrollBarImageColor3 = Color3.fromRGB(255, 100, 100),
  1049. })
  1050.  
  1051. local ButtonGrid = Create("UIGridLayout", {
  1052.     Parent = ButtonScroll,
  1053.     HorizontalAlignment = Enum.HorizontalAlignment.Center,
  1054.     SortOrder = Enum.SortOrder.LayoutOrder,
  1055.     CellPadding = UDim2.new(0, 4, 0, 4),
  1056.     CellSize = UDim2.new(0, 95, 0, 28),
  1057. })
  1058. ButtonGrid:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
  1059.     ButtonScroll.CanvasSize = UDim2.new(0, 0, 0, ButtonGrid.AbsoluteContentSize.Y + 10)
  1060. end)
  1061.  
  1062. local Tooltip = Create("Frame", {
  1063.     Name = "Tooltip",
  1064.     Parent = ScreenGui,
  1065.     BackgroundColor3 = Color3.fromRGB(26, 26, 26),
  1066.     BackgroundTransparency = 0.1,
  1067.     BorderColor3 = Color3.fromRGB(255, 255, 255),
  1068.     Size = UDim2.new(0, 200, 0, 50),
  1069.     ZIndex = 10,
  1070.     Visible = false,
  1071. })
  1072. local TooltipText = Create("TextLabel", {
  1073.     Parent = Tooltip,
  1074.     BackgroundTransparency = 1,
  1075.     Position = UDim2.new(0, 4, 0, 4),
  1076.     Size = UDim2.new(1, -8, 1, -8),
  1077.     Font = Enum.Font.SourceSans,
  1078.     Text = "",
  1079.     TextColor3 = Color3.fromRGB(255, 255, 255),
  1080.     TextSize = 12,
  1081.     TextWrapped = true,
  1082.     TextXAlignment = Enum.TextXAlignment.Left,
  1083.     TextYAlignment = Enum.TextYAlignment.Top,
  1084.     ZIndex = 10,
  1085. })
  1086.  
  1087. local function showTooltip(text)
  1088.     TooltipText.Text = text
  1089.     pcall(function()
  1090.         local textSize = TextService:GetTextSize(text, 12, Enum.Font.SourceSans, Vector2.new(196, math.huge))
  1091.         Tooltip.Size = UDim2.new(0, math.min(textSize.X + 8, 200), 0, textSize.Y + 8)
  1092.     end)
  1093.     Tooltip.Visible = true
  1094.    
  1095.     if Connections["Tooltip"] then Connections["Tooltip"]:Disconnect() end
  1096.     Connections["Tooltip"] = RunService.RenderStepped:Connect(function()
  1097.         local mousePos = UserInputService:GetMouseLocation()
  1098.         local viewportSize = workspace.CurrentCamera.ViewportSize
  1099.         local x = mousePos.X + 15
  1100.         local y = mousePos.Y - 10
  1101.         if x + Tooltip.AbsoluteSize.X > viewportSize.X then
  1102.             x = mousePos.X - Tooltip.AbsoluteSize.X - 5
  1103.         end
  1104.         if y + Tooltip.AbsoluteSize.Y > viewportSize.Y then
  1105.             y = viewportSize.Y - Tooltip.AbsoluteSize.Y - 5
  1106.         end
  1107.         Tooltip.Position = UDim2.new(0, x, 0, y - 36)
  1108.     end)
  1109. end
  1110.  
  1111. local function hideTooltip()
  1112.     Tooltip.Visible = false
  1113.     if Connections["Tooltip"] then
  1114.         Connections["Tooltip"]:Disconnect()
  1115.         Connections["Tooltip"] = nil
  1116.     end
  1117. end
  1118.  
  1119. local function createButton(name, tooltip, callback)
  1120.     local btn = Create("Frame", {
  1121.         Name = name,
  1122.         Parent = ButtonScroll,
  1123.         BackgroundTransparency = 1,
  1124.     })
  1125.    
  1126.     Create("Frame", {
  1127.         Parent = btn,
  1128.         BackgroundColor3 = Color3.fromRGB(255, 100, 100),
  1129.         BorderSizePixel = 0,
  1130.         Position = UDim2.new(0, 4, 0, 5),
  1131.         Size = UDim2.new(0, 4, 0, 18),
  1132.     })
  1133.    
  1134.     Create("TextLabel", {
  1135.         Parent = btn,
  1136.         BackgroundTransparency = 1,
  1137.         Position = UDim2.new(0, 12, 0, 5),
  1138.         Size = UDim2.new(1, -16, 0, 18),
  1139.         Font = Enum.Font.SourceSans,
  1140.         Text = name,
  1141.         TextColor3 = Color3.fromRGB(255, 255, 255),
  1142.         TextSize = 12,
  1143.         TextXAlignment = Enum.TextXAlignment.Left,
  1144.         TextTruncate = Enum.TextTruncate.AtEnd,
  1145.     })
  1146.    
  1147.     local button = Create("TextButton", {
  1148.         Parent = btn,
  1149.         BackgroundColor3 = Color3.fromRGB(0, 0, 0),
  1150.         BackgroundTransparency = 0.7,
  1151.         BorderSizePixel = 0,
  1152.         Position = UDim2.new(0, 4, 0, 5),
  1153.         Size = UDim2.new(1, -8, 0, 18),
  1154.         AutoButtonColor = false,
  1155.         Text = "",
  1156.     })
  1157.    
  1158.     button.MouseEnter:Connect(function()
  1159.         showTooltip(type(tooltip) == "function" and tooltip() or tooltip)
  1160.         TweenService:Create(button, TweenInfo.new(0.2), {BackgroundTransparency = 0.5}):Play()
  1161.     end)
  1162.     button.MouseLeave:Connect(function()
  1163.         hideTooltip()
  1164.         TweenService:Create(button, TweenInfo.new(0.2), {BackgroundTransparency = 0.7}):Play()
  1165.     end)
  1166.     button.MouseButton1Click:Connect(function()
  1167.         local success, err = pcall(callback)
  1168.         if not success then
  1169.             warn("[SignalSpy] Button error:", err)
  1170.         end
  1171.     end)
  1172.    
  1173.     return btn
  1174. end
  1175.  
  1176. local function refreshLogList()
  1177.     for _, frame in pairs(LogFrames) do
  1178.         if frame.entry then
  1179.             frame.entry.Visible = MatchesSearch(frame.data)
  1180.         end
  1181.     end
  1182. end
  1183.  
  1184. SearchBox:GetPropertyChangedSignal("Text"):Connect(function()
  1185.     SearchQuery = SearchBox.Text
  1186.     refreshLogList()
  1187. end)
  1188.  
  1189. local function createLogEntry(logData)
  1190.     if LayoutOrder < 1 then LayoutOrder = 999999999 end
  1191.    
  1192.     local typeColors = {
  1193.         RemoteEvent = Color3.fromRGB(255, 242, 0),
  1194.         RemoteFunction = Color3.fromRGB(99, 86, 245),
  1195.         BindableEvent = Color3.fromRGB(0, 200, 100),
  1196.         BindableFunction = Color3.fromRGB(100, 200, 200),
  1197.         UnreliableRemoteEvent = Color3.fromRGB(255, 150, 0),
  1198.         Signal = Color3.fromRGB(255, 100, 150),
  1199.         HttpRequest = Color3.fromRGB(100, 150, 255),
  1200.     }
  1201.    
  1202.     local entry = Create("Frame", {
  1203.         Name = "LogEntry",
  1204.         Parent = LogScroll,
  1205.         BackgroundTransparency = 1,
  1206.         Size = UDim2.new(1, -10, 0, 24),
  1207.         LayoutOrder = LayoutOrder,
  1208.         Visible = MatchesSearch(logData),
  1209.     })
  1210.    
  1211.     Create("Frame", {
  1212.         Parent = entry,
  1213.         BackgroundColor3 = typeColors[logData.Type] or Color3.fromRGB(150, 150, 150),
  1214.         BorderSizePixel = 0,
  1215.         Size = UDim2.new(0, 5, 0, 18),
  1216.         Position = UDim2.new(0, 0, 0, 1),
  1217.     })
  1218.    
  1219.     Create("TextLabel", {
  1220.         Parent = entry,
  1221.         BackgroundTransparency = 1,
  1222.         Position = UDim2.new(0, 8, 0, 1),
  1223.         Size = UDim2.new(1, -12, 0, 18),
  1224.         Font = Enum.Font.SourceSans,
  1225.         Text = logData.Name,
  1226.         TextColor3 = logData.Blocked and Color3.fromRGB(255, 100, 100) or Color3.fromRGB(255, 255, 255),
  1227.         TextSize = 12,
  1228.         TextXAlignment = Enum.TextXAlignment.Left,
  1229.         TextTruncate = Enum.TextTruncate.AtEnd,
  1230.     })
  1231.    
  1232.     local button = Create("TextButton", {
  1233.         Parent = entry,
  1234.         BackgroundColor3 = Color3.fromRGB(0, 0, 0),
  1235.         BackgroundTransparency = 0.75,
  1236.         BorderSizePixel = 0,
  1237.         Position = UDim2.new(0, 0, 0, 1),
  1238.         Size = UDim2.new(1, 0, 0, 18),
  1239.         AutoButtonColor = false,
  1240.         Text = "",
  1241.     })
  1242.    
  1243.     button.MouseButton1Click:Connect(function()
  1244.         if Selected and Selected.Button then
  1245.             TweenService:Create(Selected.Button, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(0, 0, 0)}):Play()
  1246.         end
  1247.        
  1248.         Selected = logData
  1249.         Selected.Button = button
  1250.         Selected.Entry = entry
  1251.        
  1252.         TweenService:Create(button, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(92, 126, 229)}):Play()
  1253.        
  1254.         logData.Script = logData.Script or generateScript(logData)
  1255.         CodeText.Text = logData.Script
  1256.     end)
  1257.    
  1258.     LayoutOrder = LayoutOrder - 1
  1259.     logData.id = #Logs + 1
  1260.     table.insert(Logs, logData)
  1261.     table.insert(LogFrames, {entry = entry, data = logData})
  1262.    
  1263.     if #Logs > CONFIG.MaxLogs then
  1264.         local oldest = table.remove(LogFrames, #LogFrames)
  1265.         if oldest and oldest.entry then
  1266.             oldest.entry:Destroy()
  1267.         end
  1268.         table.remove(Logs, #Logs)
  1269.     end
  1270.    
  1271.     return entry
  1272. end
  1273.  
  1274. local function logRemote(remote, method, args, blocked)
  1275.     if not CONFIG.Enabled or not CONFIG.LogRemotes then return end
  1276.     if not CONFIG.LogCheckcaller and checkcaller() then return end
  1277.     if not CheckArgsForLocalPlayer(args) then return end
  1278.    
  1279.     local remoteType = remote.ClassName
  1280.     local name = remote.Name
  1281.     local key = name .. "_" .. remoteType
  1282.    
  1283.     if CONFIG.Blacklist[name] or CONFIG.Blacklist[remote] then return end
  1284.     if isSpammy(key) then return end
  1285.    
  1286.     local logData = {
  1287.         Type = remoteType,
  1288.         Name = name,
  1289.         Remote = remote,
  1290.         Args = deepClone(args),
  1291.         Method = method,
  1292.         Blocked = blocked or CONFIG.Blocklist[name] or CONFIG.Blocklist[remote],
  1293.         Timestamp = os.time(),
  1294.         Source = nil,
  1295.     }
  1296.    
  1297.     pcall(function()
  1298.         logData.Source = getcallingscript()
  1299.     end)
  1300.    
  1301.     createLogEntry(logData)
  1302.    
  1303.     return logData.Blocked
  1304. end
  1305.  
  1306. local function logSignal(instance, signalName, args)
  1307.     if not CONFIG.Enabled or not CONFIG.LogSignals then return end
  1308.     if not CheckIsLocalPlayer(instance) then return end
  1309.     if not CheckArgsForLocalPlayer(args) then return end
  1310.    
  1311.     local key = tostring(instance) .. "." .. signalName
  1312.    
  1313.     if CONFIG.IgnoredSignals[key] then return end
  1314.     if CONFIG.BlockedSignals[key] then return true end
  1315.     if isSpammy(key) then return end
  1316.    
  1317.     local spoofData = CONFIG.SpoofedSignals[key]
  1318.     if spoofData then
  1319.         args = spoofData.args
  1320.     end
  1321.    
  1322.     local logData = {
  1323.         Type = "Signal",
  1324.         Name = signalName,
  1325.         SignalName = signalName,
  1326.         Instance = instance,
  1327.         Args = deepClone(args),
  1328.         Blocked = CONFIG.BlockedSignals[key],
  1329.         Timestamp = os.time(),
  1330.     }
  1331.    
  1332.     createLogEntry(logData)
  1333.    
  1334.     return logData.Blocked, spoofData and spoofData.args or nil
  1335. end
  1336.  
  1337. local function hookSignal(instance, signalName)
  1338.     local key = tostring(instance) .. "." .. signalName
  1339.     if HookedSignals[key] then return end
  1340.    
  1341.     local success, signal = pcall(function()
  1342.         return instance[signalName]
  1343.     end)
  1344.    
  1345.     if not success or not signal or typeof(signal) ~= "RBXScriptSignal" then return end
  1346.     if not getconnections then return end
  1347.    
  1348.     HookedSignals[key] = true
  1349.    
  1350.     local connections = {}
  1351.     pcall(function()
  1352.         connections = getconnections(signal)
  1353.     end)
  1354.    
  1355.     for _, conn in pairs(connections) do
  1356.         if conn and conn.Function then
  1357.             local originalFunc = conn.Function
  1358.             local wasEnabled = conn.Enabled
  1359.            
  1360.             pcall(function() conn:Disable() end)
  1361.            
  1362.             local newConn = signal:Connect(function(...)
  1363.                 local args = {...}
  1364.                 local blocked, spoofedArgs = logSignal(instance, signalName, args)
  1365.                 if blocked then return end
  1366.                 if spoofedArgs then
  1367.                     return originalFunc(table.unpack(spoofedArgs))
  1368.                 end
  1369.                 return originalFunc(...)
  1370.             end)
  1371.            
  1372.             table.insert(HookedConnections, {
  1373.                 Connection = newConn,
  1374.                 Original = conn,
  1375.                 WasEnabled = wasEnabled,
  1376.                 Key = key,
  1377.             })
  1378.         end
  1379.     end
  1380.    
  1381.     local catchConn = signal:Connect(function(...)
  1382.         if #connections == 0 then
  1383.             logSignal(instance, signalName, {...})
  1384.         end
  1385.     end)
  1386.     table.insert(HookedConnections, {Connection = catchConn, Key = key})
  1387. end
  1388.  
  1389. local function hookRemotes()
  1390.     local RemoteEvent = Instance.new("RemoteEvent")
  1391.     local RemoteFunction = Instance.new("RemoteFunction")
  1392.     local UnreliableRemoteEvent
  1393.     pcall(function() UnreliableRemoteEvent = Instance.new("UnreliableRemoteEvent") end)
  1394.    
  1395.     OriginalFunctions.FireServer = RemoteEvent.FireServer
  1396.     OriginalFunctions.InvokeServer = RemoteFunction.InvokeServer
  1397.     if UnreliableRemoteEvent then
  1398.         OriginalFunctions.UnreliableFireServer = UnreliableRemoteEvent.FireServer
  1399.     end
  1400.    
  1401.     RemoteEvent:Destroy()
  1402.     RemoteFunction:Destroy()
  1403.     if UnreliableRemoteEvent then UnreliableRemoteEvent:Destroy() end
  1404.    
  1405.     if hookfunction then
  1406.         pcall(function()
  1407.             local newFireServer = newcclosure(function(self, ...)
  1408.                 if typeof(self) == "Instance" and self:IsA("RemoteEvent") then
  1409.                     local blocked = logRemote(self, "FireServer", {...})
  1410.                     if blocked then return end
  1411.                 end
  1412.                 return OriginalFunctions.FireServer(self, ...)
  1413.             end)
  1414.             hookfunction(Instance.new("RemoteEvent").FireServer, newFireServer)
  1415.         end)
  1416.        
  1417.         pcall(function()
  1418.             local newInvokeServer = newcclosure(function(self, ...)
  1419.                 if typeof(self) == "Instance" and self:IsA("RemoteFunction") then
  1420.                     local blocked = logRemote(self, "InvokeServer", {...})
  1421.                     if blocked then return end
  1422.                 end
  1423.                 return OriginalFunctions.InvokeServer(self, ...)
  1424.             end)
  1425.             hookfunction(Instance.new("RemoteFunction").InvokeServer, newInvokeServer)
  1426.         end)
  1427.        
  1428.         if OriginalFunctions.UnreliableFireServer then
  1429.             pcall(function()
  1430.                 local newUnreliableFire = newcclosure(function(self, ...)
  1431.                     if typeof(self) == "Instance" and self:IsA("UnreliableRemoteEvent") then
  1432.                         local blocked = logRemote(self, "FireServer", {...})
  1433.                         if blocked then return end
  1434.                     end
  1435.                     return OriginalFunctions.UnreliableFireServer(self, ...)
  1436.                 end)
  1437.                 hookfunction(Instance.new("UnreliableRemoteEvent").FireServer, newUnreliableFire)
  1438.             end)
  1439.         end
  1440.     end
  1441.    
  1442.     if CONFIG.UseHookmetamethod and hookmetamethod then
  1443.         local success, err = pcall(function()
  1444.             local oldNamecall
  1445.             oldNamecall = hookmetamethod(game, "__namecall", newcclosure(function(self, ...)
  1446.                 if not checkcaller() then
  1447.                     local method = getnamecallmethod()
  1448.                     if method then
  1449.                         local lmethod = method:lower()
  1450.                         if lmethod == "fireserver" and typeof(self) == "Instance" then
  1451.                             if self:IsA("RemoteEvent") or self:IsA("UnreliableRemoteEvent") then
  1452.                                 local blocked = logRemote(self, method, {...})
  1453.                                 if blocked then return end
  1454.                             end
  1455.                         elseif lmethod == "invokeserver" and typeof(self) == "Instance" and self:IsA("RemoteFunction") then
  1456.                             local blocked = logRemote(self, method, {...})
  1457.                             if blocked then return end
  1458.                         end
  1459.                     end
  1460.                 end
  1461.                 return oldNamecall(self, ...)
  1462.             end))
  1463.             OriginalFunctions.Namecall = oldNamecall
  1464.         end)
  1465.        
  1466.         if not success then
  1467.             warn("[SignalSpy] hookmetamethod failed:", err)
  1468.             CONFIG.UseHookmetamethod = false
  1469.         end
  1470.     end
  1471. end
  1472.  
  1473. local function hookSignals()
  1474.     local TARGET_SIGNALS = {}
  1475.    
  1476.     if Players.LocalPlayer then
  1477.         table.insert(TARGET_SIGNALS, {Players.LocalPlayer, {"SimulationRadiusChanged", "OnTeleportInternal"}})
  1478.     end
  1479.    
  1480.     for _, data in pairs(TARGET_SIGNALS) do
  1481.         if data[1] then
  1482.             for _, signalName in pairs(data[2]) do
  1483.                 pcall(function() hookSignal(data[1], signalName) end)
  1484.             end
  1485.         end
  1486.     end
  1487.    
  1488.     local function scanInstance(instance)
  1489.         pcall(function()
  1490.             if instance:IsA("Humanoid") then
  1491.                 hookSignal(instance, "ServerEquipTool")
  1492.             elseif instance:IsA("ClickDetector") then
  1493.                 hookSignal(instance, "MouseActionReplicated")
  1494.             elseif instance:IsA("ProximityPrompt") then
  1495.                 hookSignal(instance, "TriggeredActionReplicated")
  1496.             elseif instance:IsA("Tool") then
  1497.                 hookSignal(instance, "Activated")
  1498.             end
  1499.         end)
  1500.     end
  1501.    
  1502.     for _, desc in pairs(workspace:GetDescendants()) do
  1503.         scanInstance(desc)
  1504.     end
  1505.    
  1506.     Connections["DescendantAdded"] = workspace.DescendantAdded:Connect(function(desc)
  1507.         task.defer(scanInstance, desc)
  1508.     end)
  1509. end
  1510.  
  1511. local dragging = false
  1512. local dragStart, startPos
  1513.  
  1514. TopBar.InputBegan:Connect(function(input)
  1515.     if input.UserInputType == Enum.UserInputType.MouseButton1 then
  1516.         local mousePos = UserInputService:GetMouseLocation()
  1517.         local relPos = mousePos - TopBar.AbsolutePosition
  1518.         if relPos.X < TopBar.AbsoluteSize.X - 100 then
  1519.             dragging = true
  1520.             dragStart = input.Position
  1521.             startPos = MainFrame.Position
  1522.         end
  1523.     end
  1524. end)
  1525.  
  1526. TopBar.InputEnded:Connect(function(input)
  1527.     if input.UserInputType == Enum.UserInputType.MouseButton1 then
  1528.         dragging = false
  1529.     end
  1530. end)
  1531.  
  1532. UserInputService.InputChanged:Connect(function(input)
  1533.     if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement) then
  1534.         local delta = input.Position - dragStart
  1535.         local targetPos = UDim2.new(
  1536.             startPos.X.Scale, startPos.X.Offset + delta.X,
  1537.             startPos.Y.Scale, startPos.Y.Offset + delta.Y
  1538.         )
  1539.         TweenService:Create(MainFrame, TweenInfo.new(0.1, Enum.EasingStyle.Quad), {Position = targetPos}):Play()
  1540.     end
  1541. end)
  1542.  
  1543. local minimized = false
  1544. MinBtn.MouseButton1Click:Connect(function()
  1545.     minimized = not minimized
  1546.     local targetSize = minimized and UDim2.new(0, 700, 0, 28) or UDim2.new(0, 700, 0, 400)
  1547.     TweenService:Create(MainFrame, TweenInfo.new(0.3, Enum.EasingStyle.Quad), {Size = targetSize}):Play()
  1548.     LeftPanel.Visible = not minimized
  1549.     RightPanel.Visible = not minimized
  1550. end)
  1551.  
  1552. local sideClosed = false
  1553. MaxBtn.MouseButton1Click:Connect(function()
  1554.     sideClosed = not sideClosed
  1555.     local targetWidth = sideClosed and 180 or 700
  1556.     local leftSize = sideClosed and UDim2.new(1, 0, 1, -28) or UDim2.new(0, 180, 1, -28)
  1557.    
  1558.     TweenService:Create(MainFrame, TweenInfo.new(0.3, Enum.EasingStyle.Quad), {Size = UDim2.new(0, targetWidth, 0, 400)}):Play()
  1559.     TweenService:Create(LeftPanel, TweenInfo.new(0.3, Enum.EasingStyle.Quad), {Size = leftSize}):Play()
  1560.    
  1561.     task.delay(sideClosed and 0 or 0.15, function()
  1562.         RightPanel.Visible = not sideClosed
  1563.     end)
  1564. end)
  1565.  
  1566. CloseBtn.MouseEnter:Connect(function()
  1567.     TweenService:Create(CloseBtn, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(255, 60, 60)}):Play()
  1568. end)
  1569. CloseBtn.MouseLeave:Connect(function()
  1570.     TweenService:Create(CloseBtn, TweenInfo.new(0.2), {BackgroundColor3 = Color3.fromRGB(37, 36, 38)}):Play()
  1571. end)
  1572.  
  1573. local spyEnabled = true
  1574. TitleLabel.MouseButton1Click:Connect(function()
  1575.     spyEnabled = not spyEnabled
  1576.     CONFIG.Enabled = spyEnabled
  1577.     TweenService:Create(TitleLabel, TweenInfo.new(0.3), {
  1578.         TextColor3 = spyEnabled and Color3.fromRGB(68, 206, 91) or Color3.fromRGB(252, 51, 51)
  1579.     }):Play()
  1580. end)
  1581.  
  1582. local function shutdown()
  1583.     Running = false
  1584.     getgenv().SignalSpyExecuted = false
  1585.    
  1586.     for _, conn in pairs(Connections) do
  1587.         if typeof(conn) == "RBXScriptConnection" then
  1588.             pcall(function() conn:Disconnect() end)
  1589.         end
  1590.     end
  1591.    
  1592.     for _, data in pairs(HookedConnections) do
  1593.         if data.Connection then
  1594.             pcall(function() data.Connection:Disconnect() end)
  1595.         end
  1596.         if data.Original and data.WasEnabled then
  1597.             pcall(function() data.Original:Enable() end)
  1598.         end
  1599.     end
  1600.    
  1601.     TweenService:Create(MainFrame, TweenInfo.new(0.3, Enum.EasingStyle.Quad), {
  1602.         Size = UDim2.new(0, 0, 0, 0),
  1603.         Position = UDim2.new(0.5, 0, 0.5, 0),
  1604.     }):Play()
  1605.    
  1606.     task.delay(0.35, function()
  1607.         ScreenGui:Destroy()
  1608.     end)
  1609. end
  1610.  
  1611. CloseBtn.MouseButton1Click:Connect(shutdown)
  1612. getgenv().SignalSpyShutdown = shutdown
  1613.  
  1614. createButton("Copy Code", "Copy the generated code to clipboard", function()
  1615.     if everyClipboard then
  1616.         everyClipboard(CodeText.Text)
  1617.         showTooltip("Copied!")
  1618.         task.delay(1, hideTooltip)
  1619.     end
  1620. end)
  1621.  
  1622. createButton("Execute", "Execute the code in the code box", function()
  1623.     local code = CodeText.Text
  1624.     if code and code ~= "" then
  1625.         local func, err = loadstring(code)
  1626.         if func then
  1627.             local success, execErr = pcall(func)
  1628.             showTooltip(success and "Executed!" or "Error: " .. tostring(execErr):sub(1, 50))
  1629.         else
  1630.             showTooltip("Syntax Error: " .. tostring(err):sub(1, 50))
  1631.         end
  1632.         task.delay(2, hideTooltip)
  1633.     end
  1634. end)
  1635.  
  1636. createButton("Fire Remote", "Fire the selected remote", function()
  1637.     if Selected and Selected.Remote then
  1638.         local success, err = pcall(function()
  1639.             if Selected.Type == "RemoteEvent" or Selected.Type == "UnreliableRemoteEvent" then
  1640.                 Selected.Remote:FireServer(unpack(Selected.Args or {}))
  1641.             elseif Selected.Type == "RemoteFunction" then
  1642.                 local result = Selected.Remote:InvokeServer(unpack(Selected.Args or {}))
  1643.                 showTooltip("Result: " .. tostring(result):sub(1, 50))
  1644.                 return
  1645.             end
  1646.         end)
  1647.         showTooltip(success and "Fired!" or "Error: " .. tostring(err):sub(1, 50))
  1648.         task.delay(2, hideTooltip)
  1649.     else
  1650.         showTooltip("No remote selected!")
  1651.         task.delay(1, hideTooltip)
  1652.     end
  1653. end)
  1654.  
  1655. createButton("Fire Signal", "Fire signal (firesignal)", function()
  1656.     if Selected and Selected.Type == "Signal" and Selected.Instance and firesignal then
  1657.         local success, err = pcall(function()
  1658.             local signal = Selected.Instance[Selected.SignalName]
  1659.             firesignal(signal, unpack(Selected.Args or {}))
  1660.         end)
  1661.         showTooltip(success and "Signal Fired!" or "Error: " .. tostring(err):sub(1, 50))
  1662.         task.delay(2, hideTooltip)
  1663.     else
  1664.         showTooltip(firesignal and "No signal selected!" or "firesignal unavailable!")
  1665.         task.delay(1, hideTooltip)
  1666.     end
  1667. end)
  1668.  
  1669. createButton("Replicate", "Replicate signal (replicatesignal)", function()
  1670.     if Selected and Selected.Type == "Signal" and Selected.Instance and replicatesignal then
  1671.         local success, err = pcall(function()
  1672.             local signal = Selected.Instance[Selected.SignalName]
  1673.             replicatesignal(signal, unpack(Selected.Args or {}))
  1674.         end)
  1675.         showTooltip(success and "Replicated!" or "Error: " .. tostring(err):sub(1, 50))
  1676.         task.delay(2, hideTooltip)
  1677.     else
  1678.         showTooltip(replicatesignal and "No signal selected!" or "replicatesignal unavailable!")
  1679.         task.delay(1, hideTooltip)
  1680.     end
  1681. end)
  1682.  
  1683. createButton("View Full", "View FULL info (metatable, connections, etc)", function()
  1684.     if Selected then
  1685.         CodeText.Text = GetFullInfo(Selected)
  1686.         showTooltip("Full info displayed!")
  1687.         task.delay(1, hideTooltip)
  1688.     else
  1689.         showTooltip("Nothing selected!")
  1690.         task.delay(1, hideTooltip)
  1691.     end
  1692. end)
  1693.  
  1694. createButton("Copy Full", "Copy FULL info to clipboard", function()
  1695.     if Selected and everyClipboard then
  1696.         everyClipboard(GetFullInfo(Selected))
  1697.         showTooltip("Full info copied!")
  1698.         task.delay(1, hideTooltip)
  1699.     else
  1700.         showTooltip("Nothing selected!")
  1701.         task.delay(1, hideTooltip)
  1702.     end
  1703. end)
  1704.  
  1705. createButton("Copy Path", "Copy path to clipboard", function()
  1706.     if Selected and everyClipboard then
  1707.         local path = ""
  1708.         if Selected.Remote then
  1709.             path = instanceToPath(Selected.Remote)
  1710.         elseif Selected.Instance then
  1711.             path = instanceToPath(Selected.Instance) .. "." .. Selected.SignalName
  1712.         end
  1713.         everyClipboard(path)
  1714.         showTooltip("Path Copied!")
  1715.         task.delay(1, hideTooltip)
  1716.     end
  1717. end)
  1718.  
  1719. createButton("Clear Logs", "Clear all logs", function()
  1720.     for _, frame in pairs(LogFrames) do
  1721.         if frame.entry then frame.entry:Destroy() end
  1722.     end
  1723.     Logs = {}
  1724.     LogFrames = {}
  1725.     Selected = nil
  1726.     CodeText.Text = "-- Logs cleared"
  1727.     showTooltip("Cleared!")
  1728.     task.delay(1, hideTooltip)
  1729. end)
  1730.  
  1731. createButton("Export", "Export session to file", function()
  1732.     local filename = ExportSession()
  1733.     if filename then
  1734.         showTooltip("Exported: " .. filename:sub(-30))
  1735.         if everyClipboard then everyClipboard(filename) end
  1736.     else
  1737.         showTooltip("Export failed!")
  1738.     end
  1739.     task.delay(2, hideTooltip)
  1740. end)
  1741.  
  1742. createButton("Fetch Events", "Fetch & cache API events", function()
  1743.     showTooltip("Fetching API...")
  1744.     task.spawn(function()
  1745.         CachedAPIEvents = FetchAndCacheAPIEvents()
  1746.         local count = 0
  1747.         for _ in pairs(CachedAPIEvents) do count = count + 1 end
  1748.         showTooltip("Cached " .. count .. " classes!")
  1749.         task.delay(2, hideTooltip)
  1750.     end)
  1751. end)
  1752.  
  1753. createButton("Block (i)", "Block this remote/signal", function()
  1754.     if Selected then
  1755.         if Selected.Remote then
  1756.             CONFIG.Blocklist[Selected.Remote] = true
  1757.         elseif Selected.Instance and Selected.SignalName then
  1758.             CONFIG.BlockedSignals[tostring(Selected.Instance) .. "." .. Selected.SignalName] = true
  1759.         end
  1760.         showTooltip("Blocked!")
  1761.         task.delay(1, hideTooltip)
  1762.     end
  1763. end)
  1764.  
  1765. createButton("Block (n)", "Block by name", function()
  1766.     if Selected then
  1767.         CONFIG.Blocklist[Selected.Name] = true
  1768.         showTooltip("Blocked by name!")
  1769.         task.delay(1, hideTooltip)
  1770.     end
  1771. end)
  1772.  
  1773. createButton("Ignore (i)", "Ignore this remote/signal", function()
  1774.     if Selected then
  1775.         if Selected.Remote then
  1776.             CONFIG.Blacklist[Selected.Remote] = true
  1777.         elseif Selected.Instance and Selected.SignalName then
  1778.             CONFIG.IgnoredSignals[tostring(Selected.Instance) .. "." .. Selected.SignalName] = true
  1779.         end
  1780.         showTooltip("Ignored!")
  1781.         task.delay(1, hideTooltip)
  1782.     end
  1783. end)
  1784.  
  1785. createButton("Ignore (n)", "Ignore by name", function()
  1786.     if Selected then
  1787.         CONFIG.Blacklist[Selected.Name] = true
  1788.         showTooltip("Ignored by name!")
  1789.         task.delay(1, hideTooltip)
  1790.     end
  1791. end)
  1792.  
  1793. createButton("Spoof Inf", "Spoof signal args to math.huge", function()
  1794.     if Selected and Selected.Type == "Signal" and Selected.Instance and Selected.SignalName then
  1795.         local key = tostring(Selected.Instance) .. "." .. Selected.SignalName
  1796.         CONFIG.SpoofedSignals[key] = {args = {math.huge}}
  1797.         showTooltip("Spoofed to math.huge!")
  1798.         task.delay(1, hideTooltip)
  1799.     else
  1800.         showTooltip("Select a signal first!")
  1801.         task.delay(1, hideTooltip)
  1802.     end
  1803. end)
  1804.  
  1805. createButton("Clr Spoof", "Clear all spoofed signals", function()
  1806.     CONFIG.SpoofedSignals = {}
  1807.     showTooltip("Spoofs cleared!")
  1808.     task.delay(1, hideTooltip)
  1809. end)
  1810.  
  1811. createButton("Clr Blacklist", "Clear ignore list", function()
  1812.     CONFIG.Blacklist = {}
  1813.     CONFIG.IgnoredSignals = {}
  1814.     showTooltip("Blacklist cleared!")
  1815.     task.delay(1, hideTooltip)
  1816. end)
  1817.  
  1818. createButton("Clr Blocklist", "Clear block list", function()
  1819.     CONFIG.Blocklist = {}
  1820.     CONFIG.BlockedSignals = {}
  1821.     showTooltip("Blocklist cleared!")
  1822.     task.delay(1, hideTooltip)
  1823. end)
  1824.  
  1825. createButton("Filter Spam", function()
  1826.     return "[" .. (CONFIG.FilterSpammy and "ON" or "OFF") .. "] Filter spam"
  1827. end, function()
  1828.     CONFIG.FilterSpammy = not CONFIG.FilterSpammy
  1829.     SpamHistory = {}
  1830.     showTooltip("Filter: " .. (CONFIG.FilterSpammy and "ON" or "OFF"))
  1831.     task.delay(1, hideTooltip)
  1832. end)
  1833.  
  1834. createButton("LocalPlayer", function()
  1835.     return "[" .. (CONFIG.CheckLocalPlayer and "ON" or "OFF") .. "] Check LP"
  1836. end, function()
  1837.     CONFIG.CheckLocalPlayer = not CONFIG.CheckLocalPlayer
  1838.     showTooltip("Check LP: " .. (CONFIG.CheckLocalPlayer and "ON" or "OFF"))
  1839.     task.delay(1, hideTooltip)
  1840. end)
  1841.  
  1842. createButton("Log Remotes", function()
  1843.     return "[" .. (CONFIG.LogRemotes and "ON" or "OFF") .. "] Remotes"
  1844. end, function()
  1845.     CONFIG.LogRemotes = not CONFIG.LogRemotes
  1846.     showTooltip("Log Remotes: " .. (CONFIG.LogRemotes and "ON" or "OFF"))
  1847.     task.delay(1, hideTooltip)
  1848. end)
  1849.  
  1850. createButton("Log Signals", function()
  1851.     return "[" .. (CONFIG.LogSignals and "ON" or "OFF") .. "] Signals"
  1852. end, function()
  1853.     CONFIG.LogSignals = not CONFIG.LogSignals
  1854.     showTooltip("Log Signals: " .. (CONFIG.LogSignals and "ON" or "OFF"))
  1855.     task.delay(1, hideTooltip)
  1856. end)
  1857.  
  1858. createButton("Connections", "View connections", function()
  1859.     if Selected and Selected.Type == "Signal" and Selected.Instance and getconnections then
  1860.         local success, result = pcall(function()
  1861.             local signal = Selected.Instance[Selected.SignalName]
  1862.             return getconnections(signal)
  1863.         end)
  1864.        
  1865.         if success then
  1866.             local info = "-- Signal Connections\n-- Count: " .. #result .. "\n\n"
  1867.             for i, conn in ipairs(result) do
  1868.                 info = info .. string.format("-- [%d] Enabled=%s\n", i, tostring(conn.Enabled))
  1869.             end
  1870.             CodeText.Text = info
  1871.         end
  1872.     else
  1873.         showTooltip("Select a signal!")
  1874.         task.delay(1, hideTooltip)
  1875.     end
  1876. end)
  1877.  
  1878. SetupFilesystem()
  1879. hookRemotes()
  1880. hookSignals()
  1881.  
  1882. getgenv().SignalSpyExecuted = true
  1883. getgenv().SignalSpy = {
  1884.     CONFIG = CONFIG,
  1885.     Logs = Logs,
  1886.     CachedAPIEvents = CachedAPIEvents,
  1887.     shutdown = shutdown,
  1888.     hookSignal = hookSignal,
  1889.     export = ExportSession,
  1890.     fetchEvents = FetchAndCacheAPIEvents,
  1891.     spoofSignal = function(instance, signalName, args)
  1892.         local key = tostring(instance) .. "." .. signalName
  1893.         CONFIG.SpoofedSignals[key] = {args = args}
  1894.     end,
  1895. }
  1896.  
  1897. print("[SignalSpy Pro v2.1] Loaded!")
  1898. print("[SignalSpy Pro] Click title to toggle")
  1899. print("[SignalSpy Pro] hookmetamethod: " .. (CONFIG.UseHookmetamethod and hookmetamethod and "ON" or "OFF"))
Add Comment
Please, Sign In to add comment