--[[ Enhanced Spy Utility Script Version: 4.1.0 Author: Sergeant Date: 09/06/2025 --// CHANGELOG (v4.1.0) //-- - Added 'HTTP Spy' tab to log HTTP requests, with its own log-clearing functionality. --// CHANGELOG (v4.0.1) //-- - Fixed a bug where the unread message counter would not appear when a new message was received while the GUI was collapsed and on the chat tab. --// CHANGELOG (v4.0.0) //-- - The unread message counter is now visible even when the GUI is collapsed. - Clicking the message counter while collapsed will now uncollapse the GUI and navigate to the new messages. --// CHANGELOG (v3.9.9) //-- - Added 'Event Spy' tab to log and fire BindableEvents and BindableFunctions. --// CHANGELOG (v3.9.8) //-- - Updated Spectate and Teleport lists to show player DisplayName and Username. --// CHANGELOG (v3.9.7) //-- - Fixed a warning related to GuiService that could appear on death by preventing a conflict with the default respawn camera handling. --// CHANGELOG (v3.9.6) //-- - Added a handler to automatically untoggle spectate and teleport functions when the local player's character dies. --// CHANGELOG (v3.9.5) //-- - Added a toggle for the teleport function. Clicking a player teleports you, and clicking them again returns you to your original position. - The teleport target is now highlighted in red, similar to spectating. --// CHANGELOG (v3.9.4) //-- - Added a small amount of bottom padding to the Spectate, Teleport, and Remote Spy lists to prevent the last item from being visually cut off when scrolling. --// CHANGELOG (v3.9.3) //-- - Fixed a bug where new messages would be marked as unread after deleting all previous messages while on the chat tab. --// CHANGELOG (v3.9.2) //-- - Messages received while on another tab are now correctly counted as unread, even if the chat log is scrolled to the bottom. --// CHANGELOG (v3.9.1) //-- - The message counter is now a badge on the bottom-left of the mail icon. - Clicking the mail icon with unread messages now navigates to the first unread message. - Clicking the mail icon with no unread messages clears the log. --// CHANGELOG (v3.9.0) //-- - Replaced the 'New Messages' button with a message counter next to the 'Clear Logs' icon. --// CHANGELOG (v3.8.1) //-- - Fixed a bug where the 'New Messages' indicator would appear incorrectly after clearing logs while scrolled up. --// CHANGELOG (v3.8) //-- - Removed the background and border from individual chat log delete buttons for a cleaner look. - Adjusted delete button text color and size for better visibility and easier interaction. --// CHANGELOG (v3.7) //-- - Aligned chat log delete buttons to the top of each message frame for consistent spacing, regardless of message length. - Set text to also align to the top within its frame for a cleaner look. --// CHANGELOG (v3.6) //-- - Added a button to the top bar to clear all chat logs. - Added an 'x' button to each individual chat log message to delete it. - Adjusted text wrapping to ensure delete buttons are always visible. ]] --// Services //-- local Players = game:GetService("Players") local UserInputService = game:GetService("UserInputService") local TextService = game:GetService("TextService") local TextChatService = game:GetService("TextChatService") local TweenService = game:GetService("TweenService") local RunService = game:GetService("RunService") local HttpService = game:GetService("HttpService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local Debris = game:GetService("Debris") local GuiService = game:GetService("GuiService") --// Globals for HTTP Spy local GlobalENV = getgenv() local Typeof = typeof --// Configuration //-- local GUI_TITLE = "Spy Utility | RCTRL - Toggle | V4.1.0" -- Reduced width to eliminate empty space local GUI_WIDTH = 395 local GUI_HEIGHT = 420 local TOPBAR_HEIGHT = 30 local TOOLBAR_HEIGHT = 35 --// Create the main screen GUI //-- local screenGui = Instance.new("ScreenGui") screenGui.Name = "SpyUtilityGui" screenGui.Parent = Players.LocalPlayer:WaitForChild("PlayerGui") screenGui.ZIndexBehavior = Enum.ZIndexBehavior.Global screenGui.ResetOnSpawn = false --// Main Frame //-- local mainFrame = Instance.new("Frame") mainFrame.Name = "MainFrame" mainFrame.Parent = screenGui mainFrame.Size = UDim2.new(0, GUI_WIDTH, 0, GUI_HEIGHT) mainFrame.Position = UDim2.new(0.5, -GUI_WIDTH / 2, 0.5, -GUI_HEIGHT / 2) mainFrame.BackgroundColor3 = Color3.fromRGB(35, 35, 45) mainFrame.BorderColor3 = Color3.fromRGB(80, 80, 100) mainFrame.BorderSizePixel = 2 mainFrame.Active = true mainFrame.Draggable = true mainFrame.ClipsDescendants = true --// Top Bar //-- local topBar = Instance.new("Frame") topBar.Name = "TopBar" topBar.Parent = mainFrame topBar.Size = UDim2.new(1, 0, 0, TOPBAR_HEIGHT) topBar.BackgroundColor3 = Color3.fromRGB(50, 50, 65) topBar.BorderColor3 = Color3.fromRGB(80, 80, 100) topBar.BorderSizePixel = 0 local titleLabel = Instance.new("TextLabel") titleLabel.Name = "TitleLabel" titleLabel.Parent = topBar titleLabel.Size = UDim2.new(1, -TOPBAR_HEIGHT*3, 1, 0) -- Adjusted for new button titleLabel.Position = UDim2.new(0, 5, 0, 0) titleLabel.BackgroundTransparency = 1 titleLabel.Font = Enum.Font.SourceSansBold titleLabel.TextColor3 = Color3.fromRGB(220, 220, 220) titleLabel.Text = GUI_TITLE titleLabel.TextSize = 18 titleLabel.TextXAlignment = Enum.TextXAlignment.Left local toggleVisibilityButton = Instance.new("TextButton") toggleVisibilityButton.Name = "ToggleVisibilityButton" toggleVisibilityButton.Parent = topBar toggleVisibilityButton.Size = UDim2.new(0, TOPBAR_HEIGHT, 1, 0) toggleVisibilityButton.Position = UDim2.new(1, -TOPBAR_HEIGHT*3, 0, 0) -- Adjusted for new button toggleVisibilityButton.BackgroundTransparency = 1 toggleVisibilityButton.Font = Enum.Font.SourceSansBold toggleVisibilityButton.TextColor3 = Color3.fromRGB(220, 220, 220) toggleVisibilityButton.Text = "◐" toggleVisibilityButton.TextSize = 16 local collapseButton = Instance.new("TextButton") collapseButton.Name = "CollapseButton" collapseButton.Parent = topBar collapseButton.Size = UDim2.new(0, TOPBAR_HEIGHT, 1, 0) collapseButton.Position = UDim2.new(1, -TOPBAR_HEIGHT, 0, 0) -- Swapped position collapseButton.BackgroundTransparency = 1 collapseButton.Font = Enum.Font.SourceSansBold collapseButton.TextColor3 = Color3.fromRGB(220, 220, 220) collapseButton.Text = "▼" collapseButton.TextSize = 16 -- New Clear Logs Button local clearLogsButton = Instance.new("TextButton") clearLogsButton.Name = "ClearLogsButton" clearLogsButton.Parent = topBar clearLogsButton.Size = UDim2.new(0, TOPBAR_HEIGHT, 1, 0) clearLogsButton.Position = UDim2.new(1, -TOPBAR_HEIGHT*2, 0, 0) -- Swapped position clearLogsButton.BackgroundTransparency = 1 clearLogsButton.Font = Enum.Font.SourceSansBold clearLogsButton.TextColor3 = Color3.fromRGB(220, 220, 220) clearLogsButton.Text = "✉" -- Mail icon clearLogsButton.TextSize = 16 --// Unread Message Badge //-- local unreadBadge = Instance.new("TextLabel") unreadBadge.Name = "UnreadBadge" unreadBadge.Parent = clearLogsButton unreadBadge.Size = UDim2.new(0, 14, 0, 14) unreadBadge.AnchorPoint = Vector2.new(0, 1) unreadBadge.Position = UDim2.new(0, 2, 1, -2) unreadBadge.BackgroundColor3 = Color3.fromRGB(220, 50, 50) unreadBadge.BorderColor3 = Color3.fromRGB(255, 255, 255) unreadBadge.BorderSizePixel = 1 unreadBadge.Font = Enum.Font.SourceSansBold unreadBadge.TextColor3 = Color3.fromRGB(255, 255, 255) unreadBadge.Text = "0" unreadBadge.TextSize = 9 unreadBadge.ZIndex = 2 unreadBadge.Visible = false local unreadBadgeCorner = Instance.new("UICorner") unreadBadgeCorner.CornerRadius = UDim.new(0.5, 0) unreadBadgeCorner.Parent = unreadBadge --// Tool Bar (Scrollable) //-- local toolBar = Instance.new("ScrollingFrame") toolBar.Name = "ToolBar" toolBar.Parent = mainFrame toolBar.Size = UDim2.new(1, 0, 0, TOOLBAR_HEIGHT) toolBar.Position = UDim2.new(0, 0, 0, TOPBAR_HEIGHT) toolBar.BackgroundColor3 = Color3.fromRGB(45, 45, 55) toolBar.BorderSizePixel = 0 toolBar.ScrollingDirection = Enum.ScrollingDirection.X toolBar.ScrollBarThickness = 4 toolBar.ScrollBarImageColor3 = Color3.fromRGB(160, 160, 180) toolBar.ScrollBarImageTransparency = 1 local toolBarLayout = Instance.new("UIListLayout") toolBarLayout.Parent = toolBar toolBarLayout.FillDirection = Enum.FillDirection.Horizontal toolBarLayout.SortOrder = Enum.SortOrder.LayoutOrder toolBarLayout.Padding = UDim.new(0, 5) toolBarLayout.VerticalAlignment = Enum.VerticalAlignment.Center local toolBarPadding = Instance.new("UIPadding") toolBarPadding.Parent = toolBar toolBarPadding.PaddingLeft = UDim.new(0, 5) local function createToolbarButton(name, text, width) local button = Instance.new("TextButton") button.Name = name button.Parent = toolBar button.Size = UDim2.new(0, width, 0, 28) button.BackgroundColor3 = Color3.fromRGB(70, 70, 90) button.BorderColor3 = Color3.fromRGB(100, 100, 120) button.BorderSizePixel = 1 button.Font = Enum.Font.SourceSansBold button.TextColor3 = Color3.fromRGB(220, 220, 220) button.Text = text button.TextSize = 14 return button end local chatButton = createToolbarButton("ChatButton", "Chat Log", 90) local spectateButton = createToolbarButton("SpectateButton", "Spectate", 90) local teleportButton = createToolbarButton("TeleportButton", "Teleport", 90) local remoteSpyButton = createToolbarButton("RemoteSpyButton", "Remote Spy", 100) local eventSpyButton = createToolbarButton("EventSpyButton", "Event Spy", 100) local httpSpyButton = createToolbarButton("HttpSpyButton", "HTTP Spy", 100) toolBar.CanvasSize = UDim2.new(0, toolBarLayout.AbsoluteContentSize.X + 10, 0, 0) --// Pages Container //-- local pagesFrame = Instance.new("Frame") pagesFrame.Name = "PagesFrame" pagesFrame.Parent = mainFrame pagesFrame.Size = UDim2.new(1, 0, 1, -TOPBAR_HEIGHT - TOOLBAR_HEIGHT) pagesFrame.Position = UDim2.new(0, 0, 0, TOPBAR_HEIGHT + TOOLBAR_HEIGHT) pagesFrame.BackgroundTransparency = 1 pagesFrame.ClipsDescendants = true local function createPage(name) local scrollingFrame = Instance.new("ScrollingFrame") scrollingFrame.Name = name scrollingFrame.Parent = pagesFrame scrollingFrame.Size = UDim2.new(1, 0, 1, 0) scrollingFrame.Position = UDim2.new(0, 0, 0, 0) scrollingFrame.BackgroundColor3 = Color3.fromRGB(40, 40, 55) scrollingFrame.BorderSizePixel = 0 scrollingFrame.Visible = false scrollingFrame.ScrollBarImageColor3 = Color3.fromRGB(160, 160, 180) scrollingFrame.ScrollBarThickness = 5 scrollingFrame.ScrollBarImageTransparency = 1 local layout = Instance.new("UIListLayout") layout.Parent = scrollingFrame layout.Padding = UDim.new(0, 2) local padding = Instance.new("UIPadding") padding.Parent = scrollingFrame padding.PaddingLeft = UDim.new(0, 5) padding.PaddingRight = UDim.new(0, 5) padding.PaddingTop = UDim.new(0, 5) padding.PaddingBottom = UDim.new(0, 5) return scrollingFrame, layout end --// Create all pages //-- local logContainer, uiListLayout = createPage("LogContainer") local dropdownList, dropdownLayout = createPage("DropdownList") -- For Spectate/Teleport local remoteSpyList, remoteSpyLayout = createPage("RemoteSpyList") local eventSpyList, eventSpyLayout = createPage("EventSpyList") local httpSpyPage, httpSpyLayout = createPage("HttpSpyPage") --// HTTP Spy Page Setup //-- local httpClearButton = Instance.new("TextButton") httpClearButton.Name = "HttpClearButton" httpClearButton.Parent = httpSpyPage httpClearButton.Size = UDim2.new(1, 0, 0, 25) httpClearButton.BackgroundColor3 = Color3.fromRGB(140, 70, 70) httpClearButton.BorderColor3 = Color3.fromRGB(170, 100, 100) httpClearButton.BorderSizePixel = 1 httpClearButton.Font = Enum.Font.SourceSansBold httpClearButton.TextColor3 = Color3.fromRGB(220, 220, 220) httpClearButton.Text = "Clear HTTP Logs" httpClearButton.TextSize = 14 httpClearButton.LayoutOrder = -1 -- To keep it at the top httpClearButton.MouseButton1Click:Connect(function() for _, child in ipairs(httpSpyPage:GetChildren()) do if child.Name == "HttpLogEntry" then child:Destroy() end end task.wait() httpSpyPage.CanvasSize = UDim2.new(0, 0, 0, httpSpyLayout.AbsoluteContentSize.Y + 9) end) --// Variables //-- local isCollapsed = false local isVisible = true local dropdownMode = nil -- "spectate" or "teleport" local spectatingPlayer = nil local originalCameraSubject = nil local unreadMessages = 0 local isAtBottom = true -- Changed variable name for clarity local activePage = "chat" local spectateCharConn = nil local firstUnreadMessageFrame = nil local teleportingToPlayer = nil local originalPosition = nil local pages = { chat = logContainer, spectate = dropdownList, teleport = dropdownList, remote = remoteSpyList, event = eventSpyList, http = httpSpyPage } local buttons = { chat = chatButton, spectate = spectateButton, teleport = teleportButton, remote = remoteSpyButton, event = eventSpyButton, http = httpSpyButton } --// Functions //-- local function clearAllLogs() for _, child in ipairs(logContainer:GetChildren()) do if child.Name == "MsgFrame" then child:Destroy() end end -- Reset canvas size and unread messages logContainer.CanvasSize = UDim2.new(0, 0, 0, 0) unreadMessages = 0 unreadBadge.Visible = false firstUnreadMessageFrame = nil -- BUG FIX: Manually set isAtBottom to true as the log is now empty. isAtBottom = true end local function toggleCollapse(onComplete) isCollapsed = not isCollapsed local targetHeight = isCollapsed and TOPBAR_HEIGHT or GUI_HEIGHT collapseButton.Text = isCollapsed and "►" or "▼" local tween = TweenService:Create(mainFrame, TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {Size = UDim2.new(0, GUI_WIDTH, 0, targetHeight)}) if onComplete then tween.Completed:Once(onComplete) end tween:Play() end local function toggleVisibility() isVisible = not isVisible mainFrame.Visible = isVisible toggleVisibilityButton.Text = isVisible and "◐" or "◑" end --// Page and List Update Functions //-- local function updateDropdownList() for _, child in ipairs(dropdownList:GetChildren()) do if child:IsA("TextButton") then child:Destroy() end end local players = Players:GetPlayers() table.sort(players, function(a, b) return a.Name:lower() < b.Name:lower() end) for _, player in ipairs(players) do if player ~= Players.LocalPlayer then local playerButton = Instance.new("TextButton") playerButton.Name = player.Name playerButton.Parent = dropdownList playerButton.Size = UDim2.new(1, 0, 0, 25) playerButton.BackgroundColor3 = Color3.fromRGB(60, 60, 75) playerButton.BorderColor3 = Color3.fromRGB(80, 80, 100) playerButton.BorderSizePixel = 1 playerButton.Font = Enum.Font.SourceSans playerButton.TextColor3 = Color3.fromRGB(220, 220, 220) playerButton.Text = string.format("%s (%s)", player.DisplayName, player.Name) playerButton.TextSize = 14 if (dropdownMode == "spectate" and spectatingPlayer and spectatingPlayer.Name == player.Name) or (dropdownMode == "teleport" and teleportingToPlayer and teleportingToPlayer.Name == player.Name) then playerButton.BackgroundColor3 = Color3.fromRGB(180, 50, 50) end playerButton.MouseButton1Click:Connect(function() if dropdownMode == "spectate" then if spectatingPlayer and spectatingPlayer == player then if spectateCharConn then spectateCharConn:Disconnect(); spectateCharConn = nil end if originalCameraSubject then workspace.CurrentCamera.CameraSubject = originalCameraSubject end spectatingPlayer, originalCameraSubject = nil, nil playerButton.BackgroundColor3 = Color3.fromRGB(60, 60, 75) return end if not spectatingPlayer and not originalCameraSubject then originalCameraSubject = workspace.CurrentCamera.CameraSubject end if spectatingPlayer then local oldButton = dropdownList:FindFirstChild(spectatingPlayer.Name) if oldButton then oldButton.BackgroundColor3 = Color3.fromRGB(60, 60, 75) end end spectatingPlayer = player if spectateCharConn then spectateCharConn:Disconnect(); spectateCharConn = nil end local function setCamToChar(char) local hum = char:FindFirstChildOfClass("Humanoid") or char workspace.CurrentCamera.CameraSubject = hum end if player.Character then setCamToChar(player.Character) end spectateCharConn = player.CharacterAdded:Connect(setCamToChar) playerButton.BackgroundColor3 = Color3.fromRGB(180, 50, 50) elseif dropdownMode == "teleport" then local localChar = Players.LocalPlayer.Character if not localChar or not localChar:FindFirstChild("HumanoidRootPart") then return end local localHRP = localChar.HumanoidRootPart if teleportingToPlayer and teleportingToPlayer == player then if originalPosition then localHRP.CFrame = originalPosition end teleportingToPlayer, originalPosition = nil, nil playerButton.BackgroundColor3 = Color3.fromRGB(60, 60, 75) return end local targetChar = player.Character if targetChar and targetChar:FindFirstChild("HumanoidRootPart") then local targetHRP = targetChar.HumanoidRootPart if teleportingToPlayer then local oldButton = dropdownList:FindFirstChild(teleportingToPlayer.Name) if oldButton then oldButton.BackgroundColor3 = Color3.fromRGB(60, 60, 75) end end if not originalPosition then originalPosition = localHRP.CFrame end localHRP.CFrame = targetHRP.CFrame teleportingToPlayer = player playerButton.BackgroundColor3 = Color3.fromRGB(180, 50, 50) end end end) end end dropdownList.CanvasSize = UDim2.new(0, 0, 0, dropdownLayout.AbsoluteContentSize.Y + 9) end local function updateRemoteSpyList() for _, child in ipairs(remoteSpyList:GetChildren()) do if child:IsA("Frame") then child:Destroy() end end local allRemotes = {} for _, remote in ipairs(game:GetDescendants()) do if remote:IsA("RemoteEvent") or remote:IsA("RemoteFunction") then table.insert(allRemotes, remote) end end table.sort(allRemotes, function(a, b) return a:GetFullName() < b:GetFullName() end) for _, remote in ipairs(allRemotes) do local remoteFrame = Instance.new("Frame") remoteFrame.Name = remote.Name; remoteFrame.Parent = remoteSpyList remoteFrame.Size = UDim2.new(1, 0, 0, 30) remoteFrame.BackgroundColor3 = Color3.fromRGB(60, 60, 75) remoteFrame.BorderColor3 = Color3.fromRGB(80, 80, 100); remoteFrame.BorderSizePixel = 1 local remotePath = remote:GetFullName() local remoteType = remote:IsA("RemoteEvent") and "RE" or "RF" local pathLabel = Instance.new("TextLabel") pathLabel.Parent = remoteFrame; pathLabel.Size = UDim2.new(1, -150, 1, 0) pathLabel.Position = UDim2.new(0, 5, 0, 0) pathLabel.BackgroundTransparency = 1; pathLabel.Font = Enum.Font.Code pathLabel.TextColor3 = Color3.fromRGB(200, 200, 210); pathLabel.TextSize = 12 pathLabel.TextXAlignment = Enum.TextXAlignment.Left pathLabel.Text = string.format("[%s] %s", remoteType, remotePath) pathLabel.TextTruncate = Enum.TextTruncate.AtEnd local fireButton = Instance.new("TextButton") fireButton.Parent = remoteFrame; fireButton.Size = UDim2.new(0, 50, 1, -6) fireButton.Position = UDim2.new(1, -55, 0, 3) fireButton.BackgroundColor3 = Color3.fromRGB(140, 70, 70) fireButton.BorderColor3 = Color3.fromRGB(170, 100, 100); fireButton.BorderSizePixel = 1 fireButton.Font = Enum.Font.SourceSansBold; fireButton.TextColor3 = Color3.fromRGB(220, 220, 220) fireButton.Text = "Fire"; fireButton.TextSize = 12 fireButton.MouseButton1Click:Connect(function() pcall(function() if remote:IsA("RemoteEvent") then remote:FireServer() else remote:InvokeServer() end end) end) local copyPathButton = Instance.new("TextButton") copyPathButton.Parent = remoteFrame; copyPathButton.Size = UDim2.new(0, 80, 1, -6) copyPathButton.Position = UDim2.new(1, -140, 0, 3) copyPathButton.BackgroundColor3 = Color3.fromRGB(70, 100, 140) copyPathButton.BorderColor3 = Color3.fromRGB(100, 130, 170); copyPathButton.BorderSizePixel = 1 copyPathButton.Font = Enum.Font.SourceSansBold; copyPathButton.TextColor3 = Color3.fromRGB(220, 220, 220) copyPathButton.Text = "Copy Path"; copyPathButton.TextSize = 12 copyPathButton.MouseButton1Click:Connect(function() setclipboard(remotePath) end) end remoteSpyList.CanvasSize = UDim2.new(0, 0, 0, remoteSpyLayout.AbsoluteContentSize.Y + 9) end local function updateEventSpyList() for _, child in ipairs(eventSpyList:GetChildren()) do if child:IsA("Frame") then child:Destroy() end end local allEvents = {} for _, event in ipairs(game:GetDescendants()) do if event:IsA("BindableEvent") or event:IsA("BindableFunction") then table.insert(allEvents, event) end end table.sort(allEvents, function(a, b) return a:GetFullName() < b:GetFullName() end) for _, event in ipairs(allEvents) do local eventFrame = Instance.new("Frame") eventFrame.Name = event.Name; eventFrame.Parent = eventSpyList eventFrame.Size = UDim2.new(1, 0, 0, 30) eventFrame.BackgroundColor3 = Color3.fromRGB(60, 60, 75) eventFrame.BorderColor3 = Color3.fromRGB(80, 80, 100); eventFrame.BorderSizePixel = 1 local eventPath = event:GetFullName() local eventType = event:IsA("BindableEvent") and "BE" or "BF" local pathLabel = Instance.new("TextLabel") pathLabel.Parent = eventFrame; pathLabel.Size = UDim2.new(1, -150, 1, 0) pathLabel.Position = UDim2.new(0, 5, 0, 0) pathLabel.BackgroundTransparency = 1; pathLabel.Font = Enum.Font.Code pathLabel.TextColor3 = Color3.fromRGB(200, 200, 210); pathLabel.TextSize = 12 pathLabel.TextXAlignment = Enum.TextXAlignment.Left pathLabel.Text = string.format("[%s] %s", eventType, eventPath) pathLabel.TextTruncate = Enum.TextTruncate.AtEnd local fireButton = Instance.new("TextButton") fireButton.Parent = eventFrame; fireButton.Size = UDim2.new(0, 50, 1, -6) fireButton.Position = UDim2.new(1, -55, 0, 3) fireButton.BackgroundColor3 = Color3.fromRGB(140, 70, 70) fireButton.BorderColor3 = Color3.fromRGB(170, 100, 100); fireButton.BorderSizePixel = 1 fireButton.Font = Enum.Font.SourceSansBold; fireButton.TextColor3 = Color3.fromRGB(220, 220, 220) fireButton.Text = "Fire"; fireButton.TextSize = 12 fireButton.MouseButton1Click:Connect(function() pcall(function() if event:IsA("BindableEvent") then event:Fire() else event:Invoke() end end) end) local copyPathButton = Instance.new("TextButton") copyPathButton.Parent = eventFrame; copyPathButton.Size = UDim2.new(0, 80, 1, -6) copyPathButton.Position = UDim2.new(1, -140, 0, 3) copyPathButton.BackgroundColor3 = Color3.fromRGB(70, 100, 140) copyPathButton.BorderColor3 = Color3.fromRGB(100, 130, 170); copyPathButton.BorderSizePixel = 1 copyPathButton.Font = Enum.Font.SourceSansBold; copyPathButton.TextColor3 = Color3.fromRGB(220, 220, 220) copyPathButton.Text = "Copy Path"; copyPathButton.TextSize = 12 copyPathButton.MouseButton1Click:Connect(function() setclipboard(eventPath) end) end eventSpyList.CanvasSize = UDim2.new(0, 0, 0, eventSpyLayout.AbsoluteContentSize.Y + 9) end function setActivePage(pageName) if pageName == "spectate" or pageName == "teleport" then dropdownMode = pageName; updateDropdownList() end if pageName == "remote" then updateRemoteSpyList() end if pageName == "event" then updateEventSpyList() end activePage = pageName for name, page in pairs(pages) do page.Visible = (page.Name == pages[pageName].Name) end for name, button in pairs(buttons) do button.BackgroundColor3 = (name == pageName) and Color3.fromRGB(90, 110, 140) or Color3.fromRGB(70, 70, 90) end if pageName == "chat" and isAtBottom then unreadMessages = 0 unreadBadge.Visible = false firstUnreadMessageFrame = nil elseif unreadMessages > 0 then unreadBadge.Visible = true else unreadBadge.Visible = false end end --// Logging Functions //-- local function logMessage(player, message) local DELETE_BTN_WIDTH = 20 local PADDING = 5 local msgFrame = Instance.new("Frame") msgFrame.Name = "MsgFrame"; msgFrame.Parent = logContainer msgFrame.Size = UDim2.new(1, 0, 0, 0); msgFrame.BackgroundTransparency = 1 msgFrame.AutomaticSize = Enum.AutomaticSize.Y local deleteButton = Instance.new("TextButton") deleteButton.Name = "DeleteButton" deleteButton.Parent = msgFrame deleteButton.Size = UDim2.new(0, DELETE_BTN_WIDTH, 0, DELETE_BTN_WIDTH) deleteButton.AnchorPoint = Vector2.new(1, 0) deleteButton.Position = UDim2.new(1, 0, 0, 0) deleteButton.BackgroundTransparency = 1 deleteButton.BorderSizePixel = 0 deleteButton.Font = Enum.Font.SourceSansBold deleteButton.TextColor3 = Color3.fromRGB(200, 90, 90) deleteButton.Text = "x" deleteButton.TextSize = 16 local combinedLabel = Instance.new("TextLabel") combinedLabel.Name = "CombinedLabel"; combinedLabel.Parent = msgFrame combinedLabel.Size = UDim2.new(1, -(DELETE_BTN_WIDTH + PADDING), 0, 0) combinedLabel.AutomaticSize = Enum.AutomaticSize.Y combinedLabel.BackgroundTransparency = 1; combinedLabel.Font = Enum.Font.SourceSans combinedLabel.TextColor3 = Color3.fromRGB(230, 230, 230); combinedLabel.TextSize = 14 combinedLabel.TextWrapped = true; combinedLabel.TextXAlignment = Enum.TextXAlignment.Left combinedLabel.TextYAlignment = Enum.TextYAlignment.Top combinedLabel.RichText = true combinedLabel.Text = string.format("%s: %s", player.Name:gsub("<", "<"), message:gsub("<", "<")) deleteButton.MouseButton1Click:Connect(function() msgFrame:Destroy() task.wait() logContainer.CanvasSize = UDim2.new(0, 0, 0, uiListLayout.AbsoluteContentSize.Y + 9) if logContainer.CanvasSize.Y.Offset <= logContainer.AbsoluteSize.Y then isAtBottom = true if unreadMessages > 0 then unreadMessages = 0 unreadBadge.Visible = false firstUnreadMessageFrame = nil end end end) msgFrame.Parent = logContainer msgFrame.LayoutOrder = tick() logContainer.CanvasSize = UDim2.new(0, 0, 0, uiListLayout.AbsoluteContentSize.Y + 9) if not isCollapsed and isAtBottom and activePage == "chat" then logContainer.CanvasPosition = Vector2.new(0, logContainer.CanvasSize.Y.Offset) firstUnreadMessageFrame = nil else if not firstUnreadMessageFrame or not firstUnreadMessageFrame.Parent then firstUnreadMessageFrame = msgFrame end unreadMessages = unreadMessages + 1 unreadBadge.Text = tostring(unreadMessages) unreadBadge.Visible = true end end local function logHttpRequest(...) local parts = {...} local fullMessage = table.concat(parts, " ") local logLabel = Instance.new("TextLabel") logLabel.Name = "HttpLogEntry" logLabel.Parent = httpSpyPage logLabel.Size = UDim2.new(1, 0, 0, 0) logLabel.AutomaticSize = Enum.AutomaticSize.Y logLabel.BackgroundTransparency = 1 logLabel.Font = Enum.Font.Code logLabel.TextColor3 = Color3.fromRGB(220, 220, 220) logLabel.Text = fullMessage logLabel.TextSize = 12 logLabel.TextWrapped = true logLabel.TextXAlignment = Enum.TextXAlignment.Left task.wait() httpSpyPage.CanvasSize = UDim2.new(0, 0, 0, httpSpyLayout.AbsoluteContentSize.Y + 9) end --// HTTP SPY CORE LOGIC //-- local Hook = {} local Http = {} --// Config local UrlIntercepts = { ["http://127.0.0.1:6463/rpc?v=1"] = { Callback = function() warn("Blocked discord inivite!") return "" end, }, } local function HttpCallback(OldFunc, ...) local Args = {...} local Request = Http:ScanHTTPRequest(Args) if not Request then return end local IsPost = Request.IsPost local IsTable = Request.IsTable local Url = Request.Url local Body = Request.Body local Headers = Request.Headers if not Url then return OldFunc(...) end logHttpRequest(string.format("[%s]: %s", IsPost and "POST" or "GET", Url)) if Body then logHttpRequest(string.format("> [Body] %s", tostring(Body))) end if Headers then logHttpRequest(string.format("> [Headers] %s", HttpService:JSONEncode(Headers))) end local Responce = nil local Intercept = Http:FindIntercept(Url) if not Intercept or Intercept.PassResponce then local s, r = pcall(OldFunc, ...) if not s then warn("HTTP Error:", r) end Responce = r end if not Intercept then return Responce end local Spoofed = Intercept.Callback if Typeof(Spoofed) == "function" then if Intercept.PassResponce then Spoofed = Spoofed(Responce, Request) else Spoofed = Spoofed(Request) end end if IsTable then local Base = Responce or {} return Hook:Hook(Base, { ["Body"] = Spoofed }) end return Spoofed end function Http:ScanHTTPRequest(Args: {}) local Request = {} for Index: number, Arg in next, Args do if Typeof(Arg) == "string" then Request.Url = Arg break elseif Typeof(Arg) == "table" then local Url = Arg.Url or Arg.url if not Url then continue end local Body = Arg.Body or Arg.body Request.Url = Url Request.Body = Body Request.IsPost = Body and true or false Request.IsTable = true Request.Headers = Arg.Headers break end end return Request end function Http:FindIntercept(Url: string) for UrlMatch, Data in next, UrlIntercepts do if Url:match(UrlMatch) then return Data end end return end Hook.Hooks = {} Hook.Cache = setmetatable({}, {__mode = "k"}) Hook.Alliases = { ["HTTP_HOOK"] = HttpCallback } function Hook:GetHooks() return self.Hooks end function Hook:IsObject(Object: Instance?) return Typeof(Object) == "Instance" end function Hook:GetHooksForObject(Instance) return self.Hooks[Instance] end function Hook:AddRefernce(Instance, Hooks) if not Instance then return end self.Hooks[Instance] = Hooks end function Hook:GetCached(Instance) return self.Cache[Instance] end function Hook:AddCached(Instance, Proxy) self.Cache[Instance] = Proxy end function Hook:Hook(Object: Instance, Hooks: table) local Cached = self:GetCached(Object) if Cached then return Cached end local Proxy = newproxy(true) local Meta = getmetatable(Proxy) Meta.__index = function(self, Key: string) local Hook = Hooks[Key] if Hook then return Hook end local Value = Object[Key] if type(Value) == "function" then return function(self, ...) return Value(Object, ...) end end return Value end Meta.__newindex = function(self, Key: string, New) Object[Key] = New end Meta.__tostring = function() return tostring(Object) end Meta.__metatable = getmetatable(Object) self:AddCached(Object, Proxy) return Proxy end function Hook:ApplyHooks() local AllHooks = self:GetHooks() local Alliases = self.Alliases for Object, Data in next, AllHooks do local IsObject = self:IsObject(Object) local Hooks = Data.Hooks local Globals = Data.Globals local IsReadOnly = false if typeof(Object) == "table" then IsReadOnly = table.isfrozen(Object) end if IsReadOnly then setreadonly(Object, false) end for Key: string, Value in next, Hooks do local Success, OldValue = pcall(function() return Object[Key] end) if not Success then continue end if Typeof(OldValue) == "function" then if IsObject then local OldFunc = OldValue OldValue = function(self, ...) return OldFunc(Object, ...) end end if iscclosure(OldValue) then OldValue = newcclosure(OldValue) end end if typeof(Value) == "string" then local Callback = Alliases[Value] if Callback then Value = function(...) return Callback(OldValue, ...) end end end Hooks[Key] = Value if not IsObject then Object[Key] = Value end end if IsObject then local Proxy = self:Hook(Object, Hooks) if Globals then for _, Global: string in next, Globals do GlobalENV[Global] = Proxy end end elseif IsReadOnly then setreadonly(Object, true) end end end local function AddHooks() Hook:AddRefernce(game, { Globals = {"game", "Game"}, Hooks = { ["HttpGet"] = "HTTP_HOOK", ["HttpGetAsync"] = "HTTP_HOOK", ["HttpPost"] = "HTTP_HOOK", ["HttpPostAsync"] = "HTTP_HOOK" } }) Hook:AddRefernce(GlobalENV, { Hooks = { ["http_request"] = "HTTP_HOOK", ["request"] = "HTTP_HOOK" } }) Hook:AddRefernce(http, { Hooks = { ["request"] = "HTTP_HOOK" } }) Hook:AddRefernce(syn, { Hooks = { ["request"] = "HTTP_HOOK" } }) end --// Setup Hooks & Connections //-- TextChatService.OnIncomingMessage = function(message) if message.TextSource then local p = Players:GetPlayerByUserId(message.TextSource.UserId) if p and p ~= Players.LocalPlayer then logMessage(p, message.Text) end end end TextChatService.SendingMessage:Connect(function(msg) logMessage(Players.LocalPlayer, msg.Text) end) --// Draggable Top Bar //-- topBar.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then local startPos, frameStartPos = input.Position, mainFrame.Position local moveConn, upConn moveConn = UserInputService.InputChanged:Connect(function(c) if c.UserInputType == Enum.UserInputType.MouseMovement or c.UserInputType == Enum.UserInputType.Touch then local d = c.Position - startPos; mainFrame.Position = UDim2.new(frameStartPos.X.Scale, frameStartPos.X.Offset + d.X, frameStartPos.Y.Scale, frameStartPos.Y.Offset + d.Y) end end) upConn = UserInputService.InputEnded:Connect(function(e) if e.UserInputType == Enum.UserInputType.MouseButton1 or e.UserInputType == Enum.UserInputType.Touch then moveConn:Disconnect(); upConn:Disconnect() end end) end end) --// Main Button Connections //-- collapseButton.MouseButton1Click:Connect(function() toggleCollapse() end) toggleVisibilityButton.MouseButton1Click:Connect(toggleVisibility) clearLogsButton.MouseButton1Click:Connect(function() if unreadMessages > 0 then local function scrollToMessage() setActivePage("chat") if firstUnreadMessageFrame and firstUnreadMessageFrame.Parent then task.wait() -- Allow UI to update before calculating position local targetY = firstUnreadMessageFrame.AbsolutePosition.Y - logContainer.AbsolutePosition.Y - 5 TweenService:Create(logContainer, TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {CanvasPosition = Vector2.new(0, targetY)}):Play() end end if isCollapsed then toggleCollapse(scrollToMessage) else scrollToMessage() end else clearAllLogs() end end) chatButton.MouseButton1Click:Connect(function() setActivePage("chat") end) spectateButton.MouseButton1Click:Connect(function() setActivePage("spectate") end) teleportButton.MouseButton1Click:Connect(function() setActivePage("teleport") end) remoteSpyButton.MouseButton1Click:Connect(function() setActivePage("remote") end) eventSpyButton.MouseButton1Click:Connect(function() setActivePage("event") end) httpSpyButton.MouseButton1Click:Connect(function() setActivePage("http") end) --// Input Handling //-- UserInputService.InputBegan:Connect(function(input, processed) if not processed and input.KeyCode == Enum.KeyCode.RightControl then toggleVisibility() end end) --// Handle Local Player Death to reset states //-- local function onCharacterAdded(character) local humanoid = character:WaitForChild("Humanoid") humanoid.Died:Connect(function() if spectatingPlayer then if spectateCharConn then spectateCharConn:Disconnect(); spectateCharConn = nil end spectatingPlayer, originalCameraSubject = nil, nil end if teleportingToPlayer then teleportingToPlayer, originalPosition = nil, nil end if activePage == "spectate" or activePage == "teleport" then updateDropdownList() end end) end if Players.LocalPlayer.Character then onCharacterAdded(Players.LocalPlayer.Character) end Players.LocalPlayer.CharacterAdded:Connect(onCharacterAdded) Players.PlayerAdded:Connect(function() if activePage == "spectate" or activePage == "teleport" then updateDropdownList() end end) Players.PlayerRemoving:Connect(function(player) if spectatingPlayer == player then if originalCameraSubject then workspace.CurrentCamera.CameraSubject = originalCameraSubject end spectatingPlayer, originalCameraSubject = nil, nil end if teleportingToPlayer == player then if originalPosition and Players.LocalPlayer.Character and Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart") then Players.LocalPlayer.Character.HumanoidRootPart.CFrame = originalPosition end teleportingToPlayer, originalPosition = nil, nil end if activePage == "spectate" or activePage == "teleport" then updateDropdownList() end end) logContainer:GetPropertyChangedSignal("CanvasPosition"):Connect(function() local scrollPos = logContainer.CanvasPosition.Y isAtBottom = (scrollPos + logContainer.AbsoluteSize.Y) >= (logContainer.CanvasSize.Y.Offset - 5) if isAtBottom then unreadMessages = 0 unreadBadge.Visible = false firstUnreadMessageFrame = nil end end) --// Initial State //-- AddHooks() Hook:ApplyHooks() logHttpRequest("HTTP Spy loaded successfully!") setActivePage("chat")