local ClonedFunctions = {}
do
local functionsToClone = {
"pcall", "xpcall", "type", "typeof", "tostring", "tonumber",
"pairs", "ipairs", "next", "select", "unpack", "rawget", "rawset",
"rawequal", "rawlen", "setmetatable", "getmetatable", "assert", "error"
}
for _, name in ipairs(functionsToClone) do
if getgenv()[name] then
ClonedFunctions[name] = clonefunction(getgenv()[name])
end
end
if not ClonedFunctions.unpack then
ClonedFunctions.unpack = clonefunction(table.unpack or unpack)
end
ClonedFunctions.tableClone = clonefunction(table.clone)
ClonedFunctions.tableInsert = clonefunction(table.insert)
ClonedFunctions.tableRemove = clonefunction(table.remove)
ClonedFunctions.tableConcat = clonefunction(table.concat)
ClonedFunctions.tableFind = clonefunction(table.find)
ClonedFunctions.tableClear = clonefunction(table.clear)
ClonedFunctions.tableSort = clonefunction(table.sort)
ClonedFunctions.stringFormat = clonefunction(string.format)
ClonedFunctions.stringMatch = clonefunction(string.match)
ClonedFunctions.stringFind = clonefunction(string.find)
ClonedFunctions.stringGsub = clonefunction(string.gsub)
ClonedFunctions.stringSub = clonefunction(string.sub)
ClonedFunctions.stringLower = clonefunction(string.lower)
ClonedFunctions.stringUpper = clonefunction(string.upper)
ClonedFunctions.stringLen = clonefunction(string.len)
ClonedFunctions.stringRep = clonefunction(string.rep)
ClonedFunctions.stringSplit = clonefunction(string.split)
ClonedFunctions.stringByte = clonefunction(string.byte)
ClonedFunctions.mathFloor = clonefunction(math.floor)
ClonedFunctions.mathMax = clonefunction(math.max)
ClonedFunctions.mathMin = clonefunction(math.min)
ClonedFunctions.mathAbs = clonefunction(math.abs)
ClonedFunctions.coroutineCreate = clonefunction(coroutine.create)
ClonedFunctions.coroutineResume = clonefunction(coroutine.resume)
ClonedFunctions.coroutineYield = clonefunction(coroutine.yield)
ClonedFunctions.coroutineWrap = clonefunction(coroutine.wrap)
ClonedFunctions.coroutineRunning = clonefunction(coroutine.running)
ClonedFunctions.coroutineClose = clonefunction(coroutine.close)
ClonedFunctions.taskSpawn = clonefunction(task.spawn)
ClonedFunctions.taskDefer = clonefunction(task.defer)
ClonedFunctions.taskDelay = clonefunction(task.delay)
ClonedFunctions.taskWait = clonefunction(task.wait)
ClonedFunctions.taskCancel = clonefunction(task.cancel)
ClonedFunctions.osTime = clonefunction(os.time)
ClonedFunctions.osDate = clonefunction(os.date)
ClonedFunctions.osClock = clonefunction(os.clock)
end
local pcall = ClonedFunctions.pcall
local xpcall = ClonedFunctions.xpcall
local type = ClonedFunctions.type
local typeof = ClonedFunctions.typeof
local tostring = ClonedFunctions.tostring
local tonumber = ClonedFunctions.tonumber
local pairs = ClonedFunctions.pairs
local ipairs = ClonedFunctions.ipairs
local next = ClonedFunctions.next
local select = ClonedFunctions.select
local rawget = ClonedFunctions.rawget
local rawset = ClonedFunctions.rawset
local rawequal = ClonedFunctions.rawequal
local setmetatable = ClonedFunctions.setmetatable
local getmetatable = ClonedFunctions.getmetatable
local unpack = ClonedFunctions.unpack
local Globals = getgenv()
local AdonisBypassed = false
local ActorInterceptionEnabled = false
local CacheAPI = {}
function CacheAPI.IsAvailable()
return cache and cache.invalidate and cache.iscached and cache.replace
end
function CacheAPI.Invalidate(object)
if not CacheAPI.IsAvailable() then return false end
local success = pcall(function()
cache.invalidate(object)
end)
return success
end
function CacheAPI.IsCached(object)
if not CacheAPI.IsAvailable() then return nil end
local success, result = pcall(function()
return cache.iscached(object)
end)
return success and result or nil
end
function CacheAPI.Replace(object, newObject)
if not CacheAPI.IsAvailable() then return false end
local success = pcall(function()
cache.replace(object, newObject)
end)
return success
end
local function PatchAdonisDetections()
pcall(function()
for _, v in getgc(true) do
if type(v) == "table" and rawget(v, "indexInstance") then
for k, det in pairs(v) do
if type(det) == "table" and type(det[2]) == "function" then
hookfunction(det[2], newcclosure(function()
return false
end))
end
end
AdonisBypassed = true
break
end
end
end)
end
local sc = cloneref(game:GetService("ScriptContext"))
for _, c in getconnections(sc.Error) do
c:Disconnect()
end
if Globals.BlatantSpyLoaded then
if Globals.BlatantSpyInstance then
pcall(function()
Globals.BlatantSpyInstance:Destroy()
end)
end
end
Globals.BlatantSpyLoaded = true
local RequiredFunctions = {
"hookmetamethod", "newcclosure", "getgc", "getnilinstances",
"getcallingscript", "cloneref", "getnamecallmethod", "checkcaller",
"setclipboard", "clonefunction"
}
local MissingFunctions = {}
for _, funcName in ipairs(RequiredFunctions) do
local found = false
if Globals[funcName] or getgenv()[funcName] or getfenv()[funcName] then
found = true
end
if not found and funcName == "getinfo" then
if debug and debug.getinfo then
found = true
end
end
if not found and funcName ~= "getnilinstances" then
ClonedFunctions.tableInsert(MissingFunctions, funcName)
end
end
local function GetExecutorName()
local success, name = pcall(function()
if identifyexecutor then
return identifyexecutor()
elseif getexecutorname then
return getexecutorname()
end
return "Unknown"
end)
return success and name or "Unknown"
end
if #MissingFunctions > 0 then
local ErrorGui = Instance.new("ScreenGui")
ErrorGui.Name = "SKRSpyError"
ErrorGui.ResetOnSpawn = false
ErrorGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
local MainFrame = Instance.new("Frame")
MainFrame.Size = UDim2.new(0, 400, 0, 160)
MainFrame.Position = UDim2.new(0.5, -200, 0.5, -80)
MainFrame.BackgroundColor3 = Color3.fromRGB(15, 20, 30)
MainFrame.BackgroundTransparency = 0.05
MainFrame.BorderSizePixel = 0
MainFrame.Parent = ErrorGui
local Corner = Instance.new("UICorner")
Corner.CornerRadius = UDim.new(0, 6)
Corner.Parent = MainFrame
local Stroke = Instance.new("UIStroke")
Stroke.Color = Color3.fromRGB(200, 50, 50)
Stroke.Thickness = 1
Stroke.Transparency = 0.5
Stroke.Parent = MainFrame
local Title = Instance.new("TextLabel")
Title.Size = UDim2.new(1, -30, 0, 30)
Title.Position = UDim2.new(0, 15, 0, 15)
Title.BackgroundTransparency = 1
Title.Text = "SK RSpy - COMPATIBILITY ERROR"
Title.TextColor3 = Color3.fromRGB(200, 50, 50)
Title.TextSize = 16
Title.Font = Enum.Font.GothamBold
Title.TextXAlignment = Enum.TextXAlignment.Left
Title.Parent = MainFrame
local Desc = Instance.new("TextLabel")
Desc.Size = UDim2.new(1, -30, 0, 25)
Desc.Position = UDim2.new(0, 15, 0, 45)
Desc.BackgroundTransparency = 1
Desc.Text = GetExecutorName() .. " does not support required functions:"
Desc.TextColor3 = Color3.fromRGB(180, 180, 180)
Desc.TextSize = 14
Desc.Font = Enum.Font.Gotham
Desc.TextXAlignment = Enum.TextXAlignment.Left
Desc.Parent = MainFrame
local Missing = Instance.new("TextLabel")
Missing.Size = UDim2.new(1, -30, 0, 40)
Missing.Position = UDim2.new(0, 15, 0, 70)
Missing.BackgroundTransparency = 1
Missing.Text = ClonedFunctions.tableConcat(MissingFunctions, ", ")
Missing.TextColor3 = Color3.fromRGB(120, 120, 120)
Missing.TextSize = 13
Missing.Font = Enum.Font.RobotoMono
Missing.TextXAlignment = Enum.TextXAlignment.Left
Missing.TextWrapped = true
Missing.Parent = MainFrame
local CloseBtn = Instance.new("TextButton")
CloseBtn.Size = UDim2.new(0, 80, 0, 28)
CloseBtn.Position = UDim2.new(0.5, -40, 1, -40)
CloseBtn.BackgroundColor3 = Color3.fromRGB(200, 50, 50)
CloseBtn.BackgroundTransparency = 0.2
CloseBtn.Text = "CLOSE"
CloseBtn.TextColor3 = Color3.fromRGB(255, 255, 255)
CloseBtn.TextSize = 13
CloseBtn.Font = Enum.Font.GothamBold
CloseBtn.BorderSizePixel = 0
CloseBtn.Parent = MainFrame
local CloseBtnCorner = Instance.new("UICorner")
CloseBtnCorner.CornerRadius = UDim.new(0, 4)
CloseBtnCorner.Parent = CloseBtn
CloseBtn.MouseButton1Click:Connect(function()
ErrorGui:Destroy()
end)
if syn and syn.protect_gui then
syn.protect_gui(ErrorGui)
ErrorGui.Parent = cloneref(game:GetService("CoreGui"))
elseif gethui then
ErrorGui.Parent = gethui()
else
ErrorGui.Parent = cloneref(game:GetService("CoreGui"))
end
return
end
local GameRef = cloneref(game)
local Services = {}
do
local serviceNames = {
"Players", "TweenService", "UserInputService",
"RunService", "HttpService", "CoreGui", "ReplicatedStorage"
}
for _, name in ipairs(serviceNames) do
local success, service = pcall(function()
return cloneref(GameRef:GetService(name))
end)
if success then
Services[name] = service
end
end
end
local LocalPlayer = Services.Players.LocalPlayer
-- 最初のUIプロンプトを自動化(UI表示を削除し自動でYes判定)
local function ShowAdonisPrompt(callback)
PatchAdonisDetections()
callback()
end
local function ShowActorPrompt(callback)
if not getactors then
callback(false)
return
end
local actors = {}
pcall(function()
actors = getactors()
end)
if #actors == 0 then
callback(false)
return
end
local PromptGui = Instance.new("ScreenGui")
PromptGui.Name = "SKRSpyActorPrompt"
PromptGui.ResetOnSpawn = false
PromptGui.ZIndexBehavior = Enum.ZIndexBehavior.Global
PromptGui.DisplayOrder = 9999
local MainFrame = Instance.new("Frame")
MainFrame.Size = UDim2.new(0, 400, 0, 160)
MainFrame.Position = UDim2.new(0.5, -200, 0.5, -80)
MainFrame.BackgroundColor3 = Color3.fromRGB(15, 20, 30)
MainFrame.BackgroundTransparency = 0.05
MainFrame.BorderSizePixel = 0
MainFrame.Parent = PromptGui
local Corner = Instance.new("UICorner")
Corner.CornerRadius = UDim.new(0, 8)
Corner.Parent = MainFrame
local Stroke = Instance.new("UIStroke")
Stroke.Color = Color3.fromRGB(255, 165, 0)
Stroke.Thickness = 1
Stroke.Transparency = 0.5
Stroke.Parent = MainFrame
local Title = Instance.new("TextLabel")
Title.Size = UDim2.new(1, -20, 0, 30)
Title.Position = UDim2.new(0, 10, 0, 15)
Title.BackgroundTransparency = 1
Title.Text = "SK RSpy - ACTOR DETECTED"
Title.TextColor3 = Color3.fromRGB(255, 165, 0)
Title.TextSize = 18
Title.Font = Enum.Font.GothamBold
Title.TextXAlignment = Enum.TextXAlignment.Center
Title.Parent = MainFrame
local Question = Instance.new("TextLabel")
Question.Size = UDim2.new(1, -20, 0, 25)
Question.Position = UDim2.new(0, 10, 0, 50)
Question.BackgroundTransparency = 1
Question.Text = "Intercept Actor-Based events? (" .. #actors .. " actors found)"
Question.TextColor3 = Color3.fromRGB(220, 220, 220)
Question.TextSize = 15
Question.Font = Enum.Font.Gotham
Question.TextXAlignment = Enum.TextXAlignment.Center
Question.Parent = MainFrame
local SubText = Instance.new("TextLabel")
SubText.Size = UDim2.new(1, -20, 0, 20)
SubText.Position = UDim2.new(0, 10, 0, 72)
SubText.BackgroundTransparency = 1
SubText.Text = "Actor events will be marked with [ActorCall] prefix"
SubText.TextColor3 = Color3.fromRGB(150, 150, 150)
SubText.TextSize = 12
SubText.Font = Enum.Font.Gotham
SubText.TextXAlignment = Enum.TextXAlignment.Center
SubText.Parent = MainFrame
local ButtonContainer = Instance.new("Frame")
ButtonContainer.Size = UDim2.new(1, -40, 0, 36)
ButtonContainer.Position = UDim2.new(0, 20, 0, 105)
ButtonContainer.BackgroundTransparency = 1
ButtonContainer.Parent = MainFrame
local YesBtn = Instance.new("TextButton")
YesBtn.Size = UDim2.new(0, 140, 0, 36)
YesBtn.Position = UDim2.new(0, 0, 0, 0)
YesBtn.BackgroundColor3 = Color3.fromRGB(87, 181, 106)
YesBtn.BackgroundTransparency = 0.2
YesBtn.Text = "YES"
YesBtn.TextColor3 = Color3.fromRGB(255, 255, 255)
YesBtn.TextSize = 14
YesBtn.Font = Enum.Font.GothamBold
YesBtn.BorderSizePixel = 0
YesBtn.Parent = ButtonContainer
local YesBtnCorner = Instance.new("UICorner")
YesBtnCorner.CornerRadius = UDim.new(0, 6)
YesBtnCorner.Parent = YesBtn
local NoBtn = Instance.new("TextButton")
NoBtn.Size = UDim2.new(0, 140, 0, 36)
NoBtn.Position = UDim2.new(1, -140, 0, 0)
NoBtn.BackgroundColor3 = Color3.fromRGB(219, 75, 75)
NoBtn.BackgroundTransparency = 0.2
NoBtn.Text = "NO"
NoBtn.TextColor3 = Color3.fromRGB(255, 255, 255)
NoBtn.TextSize = 14
NoBtn.Font = Enum.Font.GothamBold
NoBtn.BorderSizePixel = 0
NoBtn.Parent = ButtonContainer
local NoBtnCorner = Instance.new("UICorner")
NoBtnCorner.CornerRadius = UDim.new(0, 6)
NoBtnCorner.Parent = NoBtn
if syn and syn.protect_gui then
syn.protect_gui(PromptGui)
PromptGui.Parent = cloneref(game:GetService("CoreGui"))
elseif gethui then
PromptGui.Parent = gethui()
else
PromptGui.Parent = cloneref(game:GetService("CoreGui"))
end
YesBtn.MouseButton1Click:Connect(function()
PromptGui:Destroy()
ActorInterceptionEnabled = true
callback(true)
end)
NoBtn.MouseButton1Click:Connect(function()
PromptGui:Destroy()
callback(false)
end)
end
-- 全体的なUIを暗い青色に変更
local Theme = {
Primary = Color3.fromRGB(13, 17, 25),
Secondary = Color3.fromRGB(20, 26, 38),
Tertiary = Color3.fromRGB(28, 38, 55),
Quaternary = Color3.fromRGB(38, 52, 75),
Accent = Color3.fromRGB(60, 130, 240),
AccentDark = Color3.fromRGB(40, 100, 200),
Text = Color3.fromRGB(240, 240, 240),
TextDim = Color3.fromRGB(180, 180, 180),
TextMuted = Color3.fromRGB(120, 120, 120),
Success = Color3.fromRGB(87, 181, 106),
Warning = Color3.fromRGB(220, 160, 40),
Error = Color3.fromRGB(219, 75, 75),
RemoteEvent = Color3.fromRGB(214, 157, 133),
RemoteFunction = Color3.fromRGB(78, 201, 176),
BindableEvent = Color3.fromRGB(181, 206, 168),
BindableFunction = Color3.fromRGB(206, 145, 120),
UnreliableRemote = Color3.fromRGB(220, 220, 170),
IncomingEvent = Color3.fromRGB(197, 134, 192),
ActorCall = Color3.fromRGB(255, 165, 0),
Transparency = 0.05,
TransparencyLight = 0.1,
CornerSmall = UDim.new(0, 4),
CornerMedium = UDim.new(0, 6),
CornerLarge = UDim.new(0, 8)
}
local Utils = {}
function Utils.ToHex(color)
local r = math.floor(color.R * 255)
local g = math.floor(color.G * 255)
local b = math.floor(color.B * 255)
return string.format("#%02X%02X%02X", r, g, b)
end
function Utils.HighlightLua(code)
code = code:gsub("&", "&")
code = code:gsub("<", "<")
code = code:gsub(">", ">")
local patterns = {
{Pattern = "%-%-[^\n]*", Color = "#6A9955"},
{Pattern = "\"[^\"]*\"", Color = "#CE9178"},
{Pattern = "'[^']*'", Color = "#CE9178"},
{Pattern = "%[%[.*%]%]", Color = "#CE9178"},
{Pattern = "%f[%w]local%f[%W]", Color = "#569CD6"},
{Pattern = "%f[%w]function%f[%W]", Color = "#569CD6"},
{Pattern = "%f[%w]end%f[%W]", Color = "#569CD6"},
{Pattern = "%f[%w]if%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]then%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]else%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]elseif%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]return%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]do%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]while%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]for%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]in%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]repeat%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]until%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]break%f[%W]", Color = "#C586C0"},
{Pattern = "%f[%w]true%f[%W]", Color = "#569CD6"},
{Pattern = "%f[%w]false%f[%W]", Color = "#569CD6"},
{Pattern = "%f[%w]nil%f[%W]", Color = "#569CD6"},
{Pattern = "%f[%w]and%f[%W]", Color = "#569CD6"},
{Pattern = "%f[%w]or%f[%W]", Color = "#569CD6"},
{Pattern = "%f[%w]not%f[%W]", Color = "#569CD6"},
{Pattern = "%f[%d]%d[%d%.]*", Color = "#B5CEA8"},
{Pattern = "%f[%w][%a_][%w_]*%s*%(", Color = "#DCDCAA", Offset = 1}
}
local replacements = {}
local function addReplacement(startPos, endPos, color, text)
table.insert(replacements, {s = startPos, e = endPos, c = color, t = text})
end
for _, p in ipairs(patterns) do
local offset = p.Offset or 0
local pat = p.Pattern
local currentIdx = 1
while true do
local s, e = string.find(code, pat, currentIdx)
if not s then break end
local captured = string.sub(code, s, e - offset)
addReplacement(s, e - offset, p.Color, captured)
currentIdx = s + 1
end
end
table.sort(replacements, function(a, b) return a.s < b.s end)
local result = {}
local lastPos = 1
for _, r in ipairs(replacements) do
if r.s >= lastPos then
if r.s > lastPos then
table.insert(result, string.sub(code, lastPos, r.s - 1))
end
table.insert(result, '' .. r.t .. '')
lastPos = r.e + 1
end
end
if lastPos <= #code then
table.insert(result, string.sub(code, lastPos))
end
return table.concat(result)
end
function Utils.SafeSet(instance, property, value)
pcall(function()
instance[property] = value
end)
end
function Utils.Create(className, props)
local success, instance = pcall(function()
return Instance.new(className)
end)
if not success or not instance then
return nil
end
local parent = props.Parent
props.Parent = nil
local text = props.Text
props.Text = nil
if props.RichText ~= nil then
pcall(function()
instance.RichText = props.RichText
end)
props.RichText = nil
end
for prop, value in pairs(props) do
pcall(function()
instance[prop] = value
end)
end
if text ~= nil then
pcall(function()
instance.Text = text
end)
end
if parent then
pcall(function()
instance.Parent = parent
end)
end
return instance
end
function Utils.Corner(parent, radius)
if not parent then return nil end
return Utils.Create("UICorner", {
CornerRadius = radius or Theme.CornerMedium,
Parent = parent
})
end
function Utils.Stroke(parent, color, thickness, transparency)
if not parent then return nil end
return Utils.Create("UIStroke", {
Color = color or Theme.Accent,
Thickness = thickness or 1,
Transparency = transparency or 0.7,
Parent = parent
})
end
function Utils.Padding(parent, padding)
if not parent then return nil end
return Utils.Create("UIPadding", {
PaddingTop = UDim.new(0, padding),
PaddingBottom = UDim.new(0, padding),
PaddingLeft = UDim.new(0, padding),
PaddingRight = UDim.new(0, padding),
Parent = parent
})
end
function Utils.Tween(instance, props, duration, style, direction)
if not instance then return nil end
local success, tween = pcall(function()
return Services.TweenService:Create(
instance,
TweenInfo.new(
duration or 0.2,
style or Enum.EasingStyle.Quad,
direction or Enum.EasingDirection.Out
),
props
)
end)
if success and tween then
pcall(function()
tween:Play()
end)
return tween
end
return nil
end
function Utils.GetPath(instance)
if not instance then return "nil" end
local function IsGame(obj)
return obj == game or (pcall(function() return obj.ClassName end) and obj.ClassName == "DataModel")
end
if IsGame(instance) then return "game" end
local parts = {}
local current = instance
local service = nil
while current do
local parent = nil
pcall(function() parent = current.Parent end)
if parent and IsGame(parent) then
service = current
break
end
if not parent then break end
local name = current.Name
if ClonedFunctions.stringMatch(name, "^[%a_][%w_]*$") then
ClonedFunctions.tableInsert(parts, 1, "." .. name)
else
local escaped = ClonedFunctions.stringGsub(name, '"', '\\"')
ClonedFunctions.tableInsert(parts, 1, '["' .. escaped .. '"]')
end
current = parent
end
if service then
return 'game:GetService("' .. service.ClassName .. '")' .. ClonedFunctions.tableConcat(parts, "")
elseif #parts > 0 and current then
return current.Name .. ClonedFunctions.tableConcat(parts, "")
else
return instance.Name or "nil"
end
end
function Utils.Serialize(value, depth, visited)
depth = depth or 0
visited = visited or {}
if depth > 10 then
return '"[MAX_DEPTH]"'
end
local valueType = typeof(value)
if valueType == "nil" then
return "nil"
elseif valueType == "string" then
local escaped = value
escaped = ClonedFunctions.stringGsub(escaped, '\\', '\\\\')
escaped = ClonedFunctions.stringGsub(escaped, '"', '\\"')
escaped = ClonedFunctions.stringGsub(escaped, '\n', '\\n')
escaped = ClonedFunctions.stringGsub(escaped, '\r', '\\r')
escaped = ClonedFunctions.stringGsub(escaped, '\t', '\\t')
return '"' .. escaped .. '"'
elseif valueType == "number" then
if value == math.huge then return "math.huge" end
if value == -math.huge then return "-math.huge" end
if value ~= value then return "0/0" end
return tostring(value)
elseif valueType == "boolean" then
return tostring(value)
elseif valueType == "Instance" then
return Utils.GetPath(value)
elseif valueType == "Vector3" then
return ClonedFunctions.stringFormat("Vector3.new(%s, %s, %s)", tostring(value.X), tostring(value.Y), tostring(value.Z))
elseif valueType == "Vector2" then
return ClonedFunctions.stringFormat("Vector2.new(%s, %s)", tostring(value.X), tostring(value.Y))
elseif valueType == "CFrame" then
local c = {value:GetComponents()}
local parts = {}
for _, v in ipairs(c) do
ClonedFunctions.tableInsert(parts, tostring(v))
end
return "CFrame.new(" .. ClonedFunctions.tableConcat(parts, ", ") .. ")"
elseif valueType == "Color3" then
return ClonedFunctions.stringFormat("Color3.new(%s, %s, %s)", tostring(value.R), tostring(value.G), tostring(value.B))
elseif valueType == "BrickColor" then
return 'BrickColor.new("' .. tostring(value) .. '")'
elseif valueType == "UDim" then
return ClonedFunctions.stringFormat("UDim.new(%s, %s)", tostring(value.Scale), tostring(value.Offset))
elseif valueType == "UDim2" then
return ClonedFunctions.stringFormat(
"UDim2.new(%s, %s, %s, %s)",
tostring(value.X.Scale), tostring(value.X.Offset), tostring(value.Y.Scale), tostring(value.Y.Offset)
)
elseif valueType == "Ray" then
return ClonedFunctions.stringFormat(
"Ray.new(%s, %s)",
Utils.Serialize(value.Origin, depth + 1, visited),
Utils.Serialize(value.Direction, depth + 1, visited)
)
elseif valueType == "Rect" then
return ClonedFunctions.stringFormat(
"Rect.new(%s, %s, %s, %s)",
tostring(value.Min.X), tostring(value.Min.Y), tostring(value.Max.X), tostring(value.Max.Y)
)
elseif valueType == "NumberSequence" then
local kps = {}
for _, kp in ipairs(value.Keypoints) do
ClonedFunctions.tableInsert(kps, ClonedFunctions.stringFormat(
"NumberSequenceKeypoint.new(%s, %s, %s)",
tostring(kp.Time), tostring(kp.Value), tostring(kp.Envelope)
))
end
return "NumberSequence.new({" .. ClonedFunctions.tableConcat(kps, ", ") .. "})"
elseif valueType == "ColorSequence" then
local kps = {}
for _, kp in ipairs(value.Keypoints) do
ClonedFunctions.tableInsert(kps, ClonedFunctions.stringFormat(
"ColorSequenceKeypoint.new(%s, %s)",
tostring(kp.Time), Utils.Serialize(kp.Value, depth + 1, visited)
))
end
return "ColorSequence.new({" .. ClonedFunctions.tableConcat(kps, ", ") .. "})"
elseif valueType == "EnumItem" then
return tostring(value)
elseif valueType == "table" then
if visited[value] then return '"[Cyclic Reference]"' end
visited[value] = true
local isArray = true
local count = 0
for k, _ in pairs(value) do
count = count + 1
if type(k) ~= "number" or k < 1 or k ~= ClonedFunctions.mathFloor(k) then
isArray = false
end
end
if isArray and count ~= #value then isArray = false end
if count == 0 then return "{}" end
local parts = {}
local indent = ClonedFunctions.stringRep(" ", depth + 1)
local closeIndent = ClonedFunctions.stringRep(" ", depth)
if isArray then
for _, v in ipairs(value) do
ClonedFunctions.tableInsert(parts, indent .. Utils.Serialize(v, depth + 1, visited))
end
else
local keys = {}
for k in pairs(value) do ClonedFunctions.tableInsert(keys, k) end
pcall(function() ClonedFunctions.tableSort(keys, function(a, b) return tostring(a) < tostring(b) end) end)
for _, k in ipairs(keys) do
local v = value[k]
local keyStr = (type(k) == "string" and ClonedFunctions.stringMatch(k, "^[%a_][%w_]*$"))
and (k .. " = ")
or ("[" .. Utils.Serialize(k, depth + 1, visited) .. "] = ")
ClonedFunctions.tableInsert(parts, indent .. keyStr .. Utils.Serialize(v, depth + 1, visited))
end
end
visited[value] = nil
return "{\n" .. ClonedFunctions.tableConcat(parts, ",\n") .. "\n" .. closeIndent .. "}"
elseif valueType == "function" then
local name = "anonymous"
local source = "unknown"
local line = 0
pcall(function()
if debug and debug.getinfo then
local info = debug.getinfo(value)
if info then
name = info.name or name
source = info.source or source
line = info.currentline or line
end
end
end)
return ClonedFunctions.stringFormat('function() --[[ Name: %s | Source: %s:%d ]] end', name, source, line)
elseif valueType == "userdata" then
return '"[userdata]"'
elseif valueType == "thread" then
local status = "unknown"
pcall(function() status = coroutine.status(value) end)
return ClonedFunctions.stringFormat('coroutine.create(function() --[[ Status: %s ]] end)', status)
elseif valueType == "buffer" then
local size = buffer.len(value)
if size == 0 then return "buffer.create(0)" end
local parts = {}
for i = 0, size - 1 do
local b = buffer.readu8(value, i)
if b >= 32 and b <= 126 and b ~= 34 and b ~= 92 then
ClonedFunctions.tableInsert(parts, string.char(b))
else
ClonedFunctions.tableInsert(parts, ClonedFunctions.stringFormat("\\x%02X", b))
end
end
return 'buffer.fromstring("' .. ClonedFunctions.tableConcat(parts) .. '")'
end
return '"[' .. valueType .. ']"'
end
function Utils.GenerateScript(remoteType, remotePath, args)
local serializedArgs = {}
for _, arg in ipairs(args) do
ClonedFunctions.tableInsert(serializedArgs, Utils.Serialize(arg))
end
local argsStr = ClonedFunctions.tableConcat(serializedArgs, ", ")
local methods = {
RemoteEvent = ":FireServer",
RemoteFunction = ":InvokeServer",
BindableEvent = ":Fire",
BindableFunction = ":Invoke",
UnreliableRemoteEvent = ":FireServer",
OnClientEvent = "[OnClientEvent]",
ActorCall_RemoteEvent = ":FireServer",
ActorCall_RemoteFunction = ":InvokeServer",
ActorCall_BindableEvent = ":Fire",
ActorCall_BindableFunction = ":Invoke",
ActorCall_UnreliableRemoteEvent = ":FireServer"
}
local method = methods[remoteType] or ":FireServer"
if remoteType == "OnClientEvent" then
return remotePath .. ".OnClientEvent:Connect(function(" .. argsStr .. ") end)"
end
if ClonedFunctions.stringFind(remoteType, "ActorCall_", 1, true) then
return remotePath .. method .. "(" .. argsStr .. ")"
end
return remotePath .. method .. "(" .. argsStr .. ")"
end
function Utils.GetCallerInfo(level)
local info = {
Source = "[Unknown]",
Name = "[Anonymous]",
Line = 0,
FunctionType = "Unknown",
ScriptPath = "[Unknown]",
ScriptInstance = nil,
Arity = 0,
IsVararg = false,
CurrentLine = 0,
NumUpvalues = 0,
NumParams = 0
}
level = level or 4
pcall(function()
local script = getcallingscript()
if script and typeof(script) == "Instance" then
info.ScriptInstance = script
info.ScriptPath = Utils.GetPath(script)
info.Source = script:GetFullName()
end
end)
pcall(function()
if debug and debug.getinfo then
local dinfo = debug.getinfo(level)
if dinfo then
info.Name = dinfo.name or info.Name
info.Source = dinfo.source or info.Source
info.Line = dinfo.currentline or info.Line
info.NumParams = dinfo.nparams or 0
info.IsVararg = dinfo.isvararg and true or false
info.FunctionType = dinfo.what or "Unknown"
end
end
end)
if not info.ScriptInstance and getnilinstances and info.Source ~= "[Unknown]" then
pcall(function()
local nilInst = getnilinstances()
for _, v in ipairs(nilInst) do
if v:IsA("LocalScript") or v:IsA("ModuleScript") then
if v.Name == info.Name or ClonedFunctions.stringFind(info.Source, v.Name) then
info.ScriptInstance = v
info.ScriptPath = "[Nil] " .. v:GetFullName()
break
end
end
end
end)
end
pcall(function()
info.StackTrace = {}
for i = 1, 10 do
if debug and debug.getinfo then
local f = debug.getinfo(level + i)
if f then
ClonedFunctions.tableInsert(info.StackTrace, {
Source = f.source or "?",
Name = f.name or "?",
Line = f.currentline or 0
})
end
end
end
end)
return info
end
local LogEntry = {}
LogEntry.__index = LogEntry
function LogEntry.new(data)
local self = setmetatable({}, LogEntry)
self.Id = data.Id or 0
self.Remote = data.Remote
self.RemoteType = data.RemoteType or "Unknown"
self.RemotePath = data.RemotePath or "Unknown"
self.Arguments = data.Arguments or {}
self.CallerInfo = data.CallerInfo or {}
self.HookType = data.HookType or "__namecall"
self.Method = data.Method or "Unknown"
self.Blocked = data.Blocked or false
self.ActorScript = data.ActorScript or nil
return self
end
function LogEntry:GetColor()
local colors = {
RemoteEvent = Theme.RemoteEvent,
RemoteFunction = Theme.RemoteFunction,
BindableEvent = Theme.BindableEvent,
BindableFunction = Theme.BindableFunction,
UnreliableRemoteEvent = Theme.UnreliableRemote,
OnClientEvent = Theme.IncomingEvent,
ActorCall_RemoteEvent = Theme.ActorCall,
ActorCall_RemoteFunction = Theme.ActorCall,
ActorCall_BindableEvent = Theme.ActorCall,
ActorCall_BindableFunction = Theme.ActorCall,
ActorCall_UnreliableRemoteEvent = Theme.ActorCall
}
return colors[self.RemoteType] or Theme.Accent
end
function LogEntry:GetTypeShort()
local shorts = {
RemoteEvent = "RE",
RemoteFunction = "RF",
BindableEvent = "BE",
BindableFunction = "BF",
UnreliableRemoteEvent = "URE",
OnClientEvent = "IN",
ActorCall_RemoteEvent = "ACT",
ActorCall_RemoteFunction = "ACT",
ActorCall_BindableEvent = "ACT",
ActorCall_BindableFunction = "ACT",
ActorCall_UnreliableRemoteEvent = "ACT"
}
return shorts[self.RemoteType] or "?"
end
function LogEntry:GetScript()
return Utils.GenerateScript(self.RemoteType, self.RemotePath, self.Arguments)
end
function LogEntry:GetDetailedInfo()
local lines = {}
local H = Utils.ToHex
local function Escape(text)
text = ClonedFunctions.stringGsub(tostring(text), "&", "&")
text = ClonedFunctions.stringGsub(text, "<", "<")
text = ClonedFunctions.stringGsub(text, ">", ">")
return text
end
local function Header(text)
return '' .. Escape(text) .. ''
end
local function Key(text)
return '' .. Escape(text) .. ''
end
local function Value(text)
return '' .. Escape(text) .. ''
end
ClonedFunctions.tableInsert(lines, Header("REMOTE INFORMATION"))
ClonedFunctions.tableInsert(lines, Key("Type: ") .. Value(self.RemoteType))
ClonedFunctions.tableInsert(lines, Key("Name: ") .. Value(self.Remote.Name))
ClonedFunctions.tableInsert(lines, Key("Path: ") .. Value(self.RemotePath))
ClonedFunctions.tableInsert(lines, Key("Hook: ") .. Value(self.HookType))
ClonedFunctions.tableInsert(lines, Key("Method: ") .. Value(self.Method))
local blockedStatus = self.Blocked and "TRUE" or "false"
local blockedColor = self.Blocked and Theme.Error or Theme.Text
ClonedFunctions.tableInsert(lines, Key("Blocked: ") .. '' .. blockedStatus .. '')
if CacheAPI.IsAvailable() then
local isCached = CacheAPI.IsCached(self.Remote)
if isCached ~= nil then
ClonedFunctions.tableInsert(lines, Key("Cached: ") .. Value(tostring(isCached)))
end
end
ClonedFunctions.tableInsert(lines, "")
ClonedFunctions.tableInsert(lines, Header("CALLER INFORMATION"))
if self.RemoteType == "OnClientEvent" then
ClonedFunctions.tableInsert(lines, Value("Source: Server (Incoming Network)"))
elseif ClonedFunctions.stringFind(self.RemoteType, "ActorCall_", 1, true) then
ClonedFunctions.tableInsert(lines, Value("Source: Actor Thread (Parallel Execution)"))
ClonedFunctions.tableInsert(lines, Key("[s] Actor Script: ") .. Value(self.CallerInfo.Source or "[Unknown]"))
if self.ActorScript then
ClonedFunctions.tableInsert(lines, Key("[s] Actor Script Path: ") .. Value(Utils.GetPath(self.ActorScript)))
end
else
ClonedFunctions.tableInsert(lines, Key("[s] Source: ") .. Value(self.CallerInfo.Source or "[Unknown]"))
ClonedFunctions.tableInsert(lines, Key("[s] Script Path: ") .. Value(self.CallerInfo.ScriptPath or "[Unknown]"))
ClonedFunctions.tableInsert(lines, Key("[n] Function Name: ") .. Value(self.CallerInfo.Name or "[Anonymous]"))
ClonedFunctions.tableInsert(lines, Key("[l] Line: ") .. Value(tostring(self.CallerInfo.Line or 0)))
ClonedFunctions.tableInsert(lines, Key("[f] Function Type: ") .. Value(self.CallerInfo.FunctionType or "Unknown"))
ClonedFunctions.tableInsert(lines, Key("[a] Arity: ") .. Value(tostring(self.CallerInfo.NumParams or 0)))
ClonedFunctions.tableInsert(lines, Key("[a] Is Vararg: ") .. Value(tostring(self.CallerInfo.IsVararg or false)))
ClonedFunctions.tableInsert(lines, "")
if self.CallerInfo.StackTrace and #self.CallerInfo.StackTrace > 0 then
ClonedFunctions.tableInsert(lines, Header("STACK TRACE"))
for i, frame in ipairs(self.CallerInfo.StackTrace) do
local frameLine = Key("[" .. i .. "] ") .. Value((frame.Source or "?") .. " : " .. (frame.Name or "?") .. " @ line " .. (frame.Line or 0))
ClonedFunctions.tableInsert(lines, frameLine)
end
ClonedFunctions.tableInsert(lines, "")
end
end
ClonedFunctions.tableInsert(lines, Header("ARGUMENTS (" .. #self.Arguments .. ")"))
if #self.Arguments == 0 then
ClonedFunctions.tableInsert(lines, Value("(no arguments)"))
else
for i, arg in ipairs(self.Arguments) do
local argType = typeof(arg)
local argValue = Utils.Serialize(arg)
ClonedFunctions.tableInsert(lines, Key("[" .. i .. "] <" .. argType .. ">"))
ClonedFunctions.tableInsert(lines, " " .. Value(argValue))
end
end
ClonedFunctions.tableInsert(lines, "")
ClonedFunctions.tableInsert(lines, Header("GENERATED SCRIPT"))
local script = self:GetScript()
ClonedFunctions.tableInsert(lines, '' .. Value(script) .. '')
return ClonedFunctions.tableConcat(lines, "
")
end
function LogEntry:GetDetailedInfoPlain()
local lines = {}
ClonedFunctions.tableInsert(lines, "=== REMOTE INFORMATION ===")
ClonedFunctions.tableInsert(lines, "Type: " .. self.RemoteType)
ClonedFunctions.tableInsert(lines, "Name: " .. self.Remote.Name)
ClonedFunctions.tableInsert(lines, "Path: " .. self.RemotePath)
ClonedFunctions.tableInsert(lines, "Hook: " .. self.HookType)
ClonedFunctions.tableInsert(lines, "Method: " .. self.Method)
ClonedFunctions.tableInsert(lines, "Blocked: " .. (self.Blocked and "TRUE" or "false"))
if CacheAPI.IsAvailable() then
local isCached = CacheAPI.IsCached(self.Remote)
if isCached ~= nil then
ClonedFunctions.tableInsert(lines, "Cached: " .. tostring(isCached))
end
end
ClonedFunctions.tableInsert(lines, "")
ClonedFunctions.tableInsert(lines, "=== CALLER INFORMATION ===")
if self.RemoteType == "OnClientEvent" then
ClonedFunctions.tableInsert(lines, "Source: Server (Incoming Network)")
elseif ClonedFunctions.stringFind(self.RemoteType, "ActorCall_", 1, true) then
ClonedFunctions.tableInsert(lines, "Source: Actor Thread (Parallel Execution)")
ClonedFunctions.tableInsert(lines, "[s] Actor Script: " .. (self.CallerInfo.Source or "[Unknown]"))
if self.ActorScript then
ClonedFunctions.tableInsert(lines, "[s] Actor Script Path: " .. Utils.GetPath(self.ActorScript))
end
else
ClonedFunctions.tableInsert(lines, "[s] Source: " .. (self.CallerInfo.Source or "[Unknown]"))
ClonedFunctions.tableInsert(lines, "[s] Script Path: " .. (self.CallerInfo.ScriptPath or "[Unknown]"))
ClonedFunctions.tableInsert(lines, "[n] Function Name: " .. (self.CallerInfo.Name or "[Anonymous]"))
ClonedFunctions.tableInsert(lines, "[l] Line: " .. tostring(self.CallerInfo.Line or 0))
ClonedFunctions.tableInsert(lines, "[f] Function Type: " .. (self.CallerInfo.FunctionType or "Unknown"))
ClonedFunctions.tableInsert(lines, "[a] Arity: " .. tostring(self.CallerInfo.NumParams or 0))
ClonedFunctions.tableInsert(lines, "[a] Is Vararg: " .. tostring(self.CallerInfo.IsVararg or false))
ClonedFunctions.tableInsert(lines, "")
if self.CallerInfo.StackTrace and #self.CallerInfo.StackTrace > 0 then
ClonedFunctions.tableInsert(lines, "--- STACK TRACE ---")
for i, frame in ipairs(self.CallerInfo.StackTrace) do
ClonedFunctions.tableInsert(lines, "[" .. i .. "] " .. (frame.Source or "?") .. " : " .. (frame.Name or "?") .. " @ line " .. (frame.Line or 0))
end
ClonedFunctions.tableInsert(lines, "")
end
end
ClonedFunctions.tableInsert(lines, "=== ARGUMENTS (" .. #self.Arguments .. ") ===")
if #self.Arguments == 0 then
ClonedFunctions.tableInsert(lines, "(no arguments)")
else
for i, arg in ipairs(self.Arguments) do
local argType = typeof(arg)
local argValue = Utils.Serialize(arg)
ClonedFunctions.tableInsert(lines, "[" .. i .. "] <" .. argType .. ">")
ClonedFunctions.tableInsert(lines, " " .. argValue)
end
end
ClonedFunctions.tableInsert(lines, "")
ClonedFunctions.tableInsert(lines, "=== GENERATED SCRIPT ===")
ClonedFunctions.tableInsert(lines, self:GetScript())
return ClonedFunctions.tableConcat(lines, "\n")
end
function LogEntry:CanDecompile()
if self.CallerInfo.ScriptInstance then
return true
end
if self.ActorScript then
return true
end
return false
end
function LogEntry:GetDecompilableScript()
if self.CallerInfo.ScriptInstance then
return self.CallerInfo.ScriptInstance
end
if self.ActorScript then
return self.ActorScript
end
return nil
end
local BlockList = {}
BlockList.__index = BlockList
function BlockList.new()
local self = setmetatable({}, BlockList)
self.Blocked = {}
return self
end
function BlockList:Add(remote)
local path = Utils.GetPath(remote)
self.Blocked[path] = true
self.Blocked[remote] = true
end
function BlockList:Remove(remote)
local path = Utils.GetPath(remote)
self.Blocked[path] = nil
self.Blocked[remote] = nil
end
function BlockList:IsBlocked(remote)
local path = Utils.GetPath(remote)
return self.Blocked[path] == true or self.Blocked[remote] == true
end
local Logger = {}
Logger.__index = Logger
function Logger.new()
local self = setmetatable({}, Logger)
self.Entries = {}
self.Groups = {}
self.EntryId = 0
self.GroupId = 0
self.MaxEntries = 1000
self.MaxEntriesPerGroup = 200
self.Paused = false
self.Filter = ""
self.TypeFilter = "All"
self.OnGroupUpdated = nil
return self
end
function Logger:Add(data)
if self.Paused then return nil end
self.EntryId = self.EntryId + 1
data.Id = self.EntryId
local entry = LogEntry.new(data)
local groupKey = data.RemotePath
if not self.Groups[groupKey] then
self.GroupId = self.GroupId + 1
self.Groups[groupKey] = {
Id = self.GroupId,
RemotePath = data.RemotePath,
Remote = data.Remote,
RemoteType = data.RemoteType,
Entries = {},
Count = 0,
LastEntry = nil,
Expanded = false
}
end
local group = self.Groups[groupKey]
group.Count = group.Count + 1
group.LastEntry = entry
ClonedFunctions.tableInsert(group.Entries, 1, entry)
while #group.Entries > self.MaxEntriesPerGroup do
ClonedFunctions.tableRemove(group.Entries)
end
ClonedFunctions.tableInsert(self.Entries, 1, entry)
while #self.Entries > self.MaxEntries do
ClonedFunctions.tableRemove(self.Entries)
end
if self.OnGroupUpdated then
self.OnGroupUpdated(group, entry)
end
return entry, group
end
function Logger:Clear()
ClonedFunctions.tableClear(self.Entries)
ClonedFunctions.tableClear(self.Groups)
self.GroupId = 0
end
function Logger:GetFilteredGroups()
local result = {}
for _, group in pairs(self.Groups) do
local passType = self.TypeFilter == "All" or group.RemoteType == self.TypeFilter
if self.TypeFilter == "RemoteEvent" and group.RemoteType == "OnClientEvent" then
passType = false
end
if self.TypeFilter == "All" and group.RemoteType == "OnClientEvent" then
passType = true
end
if self.TypeFilter == "All" and ClonedFunctions.stringFind(group.RemoteType, "ActorCall_", 1, true) then
passType = true
end
local passText = self.Filter == "" or
ClonedFunctions.stringFind(ClonedFunctions.stringLower(group.RemotePath), ClonedFunctions.stringLower(self.Filter), 1, true) or
ClonedFunctions.stringFind(ClonedFunctions.stringLower(group.Remote.Name), ClonedFunctions.stringLower(self.Filter), 1, true)
if passType and passText then
ClonedFunctions.tableInsert(result, group)
end
end
ClonedFunctions.tableSort(result, function(a, b)
if a.LastEntry and b.LastEntry then
return a.LastEntry.Id > b.LastEntry.Id
end
return false
end)
return result
end
local Decompiler = {}
Decompiler.__index = Decompiler
function Decompiler.new()
return setmetatable({}, Decompiler)
end
function Decompiler:Process(scriptInstance)
if not scriptInstance then
return "No script instance provided"
end
local result = "-- Script: " .. Utils.GetPath(scriptInstance) .. "\n"
result = result .. "-- Class: " .. scriptInstance.ClassName .. "\n\n"
if decompile then
local success, source = pcall(decompile, scriptInstance)
if success and source then
return result .. source
end
end
if getscriptbytecode then
local success, bytecode = pcall(getscriptbytecode, scriptInstance)
if success and bytecode then
if disassemble then
local disSuccess, disResult = pcall(disassemble, bytecode)
if disSuccess then
return result .. "-- Disassembled bytecode:\n\n" .. disResult
end
end
return result .. "-- Bytecode retrieved but decompilation unavailable"
end
end
return result .. "-- Decompilation not supported by executor"
end
local UI = {}
UI.__index = UI
function UI.new(logger, blockList, decompiler)
local self = setmetatable({}, UI)
self.Logger = logger
self.BlockList = blockList
self.Decompiler = decompiler
self.Gui = nil
self.Main = nil
self.LogList = nil
self.ContentFrame = nil
self.Toolbar = nil
self.GroupItems = {}
self.SelectedEntry = nil
self.SelectedGroup = nil
self.SubWindows = {}
self.Minimized = false
self.MinWindowWidth = 400
self.MinWindowHeight = 300
self.ExpandedHeight = 500
self.PendingGroups = {}
self.UpdateConnection = nil
return self
end
function UI:Build()
if self.Gui then
pcall(function()
self.Gui:Destroy()
end)
end
self.Gui = Utils.Create("ScreenGui", {
Name = "SK RSpy",
ResetOnSpawn = false,
ZIndexBehavior = Enum.ZIndexBehavior.Global,
DisplayOrder = 999
})
if not self.Gui then return end
if syn and syn.protect_gui then
pcall(function()
syn.protect_gui(self.Gui)
end)
pcall(function()
self.Gui.Parent = Services.CoreGui
end)
elseif gethui then
pcall(function()
self.Gui.Parent = gethui()
end)
else
pcall(function()
self.Gui.Parent = Services.CoreGui
end)
end
Globals.SKRSpyInstance = self.Gui
self:SetupLoggerCallback()
self:BuildMain()
self:BuildHeader()
self:BuildToolbar()
self:BuildLogArea()
self:BuildResizeHandle()
self:SetupDrag()
self:AnimateIn()
self:SetMaxZIndex()
if self.UpdateConnection then
self.UpdateConnection:Disconnect()
end
self.UpdateConnection = Services.RunService.Heartbeat:Connect(function()
self:ProcessPendingUpdates()
end)
end
function UI:SetMaxZIndex()
local function applyZIndex(instance)
pcall(function()
if instance:IsA("GuiObject") then
instance.ZIndex = 999
end
end)
end
pcall(function()
if self.Main then
applyZIndex(self.Main)
for _, desc in ipairs(self.Main:GetDescendants()) do
applyZIndex(desc)
end
self.Main.DescendantAdded:Connect(function(desc)
applyZIndex(desc)
end)
end
end)
pcall(function()
for _, window in pairs(self.SubWindows) do
applyZIndex(window)
for _, desc in ipairs(window:GetDescendants()) do
applyZIndex(desc)
end
end
end)
end
function UI:BuildMain()
self.Main = Utils.Create("Frame", {
Name = "Main",
Size = UDim2.new(0, 750, 0, 500),
Position = UDim2.new(0.5, -375, 0.5, -250),
BackgroundColor3 = Theme.Primary,
BackgroundTransparency = Theme.Transparency,
ClipsDescendants = true,
Parent = self.Gui
})
if not self.Main then return end
Utils.Corner(self.Main, Theme.CornerMedium)
Utils.Stroke(self.Main, Theme.Accent, 1, 0.8)
end
function UI:BuildHeader()
if not self.Main then return end
local header = Utils.Create("Frame", {
Name = "Header",
Size = UDim2.new(1, 0, 0, 40),
BackgroundColor3 = Theme.Secondary,
BackgroundTransparency = 0.3,
Parent = self.Main
})
if not header then return end
Utils.Corner(header, Theme.CornerMedium)
Utils.Create("Frame", {
Size = UDim2.new(1, 0, 0, 8),
Position = UDim2.new(0, 0, 1, -8),
BackgroundColor3 = Theme.Secondary,
BackgroundTransparency = 0.3,
BorderSizePixel = 0,
Parent = header
})
Utils.Create("TextLabel", {
Name = "Title",
Size = UDim2.new(0, 150, 1, 0),
Position = UDim2.new(0, 14, 0, 0),
BackgroundTransparency = 1,
Text = "SK RSpy",
TextColor3 = Theme.Text,
TextSize = 16,
Font = Enum.Font.GothamBold,
TextXAlignment = Enum.TextXAlignment.Left,
Parent = header
})
Utils.Create("TextLabel", {
Name = "Executor",
Size = UDim2.new(0, 120, 1, 0),
Position = UDim2.new(0, 130, 0, 0),
BackgroundTransparency = 1,
Text = GetExecutorName(),
TextColor3 = Theme.TextMuted,
TextSize = 12,
Font = Enum.Font.Gotham,
TextXAlignment = Enum.TextXAlignment.Left,
Parent = header
})
local btnContainer = Utils.Create("Frame", {
Name = "Buttons",
Size = UDim2.new(0, 80, 0, 28),
Position = UDim2.new(1, -90, 0.5, -14),
BackgroundTransparency = 1,
Parent = header
})
if btnContainer then
Utils.Create("UIListLayout", {
FillDirection = Enum.FillDirection.Horizontal,
HorizontalAlignment = Enum.HorizontalAlignment.Right,
Padding = UDim.new(0, 8),
Parent = btnContainer
})
self:CreateHeaderButton("_", btnContainer, function()
self:ToggleMinimize()
end)
local closeBtn = self:CreateHeaderButton("X", btnContainer, function()
self:Close()
end)
if closeBtn then
Utils.SafeSet(closeBtn, "BackgroundColor3", Theme.Error)
end
end
end
function UI:CreateHeaderButton(text, parent, callback)
local btn = Utils.Create("TextButton", {
Size = UDim2.new(0, 28, 0, 28),
BackgroundColor3 = Theme.Tertiary,
BackgroundTransparency = 0.3,
Text = text,
TextColor3 = Theme.Text,
TextSize = 14,
Font = Enum.Font.GothamBold,
Parent = parent
})
if not btn then return nil end
Utils.Corner(btn, Theme.CornerSmall)
pcall(function()
btn.MouseEnter:Connect(function()
Utils.Tween(btn, {BackgroundTransparency = 0}, 0.1)
end)
btn.MouseLeave:Connect(function()
Utils.Tween(btn, {BackgroundTransparency = 0.3}, 0.1)
end)
btn.MouseButton1Click:Connect(callback)
end)
return btn
end
function UI:BuildToolbar()
if not self.Main then return end
self.Toolbar = Utils.Create("Frame", {
Name = "Toolbar",
Size = UDim2.new(1, -24, 0, 36),
Position = UDim2.new(0, 12, 0, 46),
BackgroundTransparency = 1,
Parent = self.Main
})
if not self.Toolbar then return end
local searchBox = Utils.Create("TextBox", {
Name = "Search",
Size = UDim2.new(0, 200, 0, 32),
Position = UDim2.new(0, 0, 0.5, -16),
BackgroundColor3 = Theme.Tertiary,
BackgroundTransparency = 0.5,
Text = "",
PlaceholderText = "Search...",
PlaceholderColor3 = Theme.TextMuted,
TextColor3 = Theme.Text,
TextSize = 14,
Font = Enum.Font.Gotham,
ClearTextOnFocus = false,
Parent = self.Toolbar
})
if searchBox then
Utils.Corner(searchBox, Theme.CornerSmall)
Utils.Padding(searchBox, 10)
pcall(function()
searchBox:GetPropertyChangedSignal("Text"):Connect(function()
self.Logger.Filter = searchBox.Text
self:RefreshList()
end)
end)
end
local filterContainer = Utils.Create("Frame", {
Name = "Filters",
Size = UDim2.new(0, 300, 0, 32),
Position = UDim2.new(0, 210, 0.5, -16),
BackgroundTransparency = 1,
Parent = self.Toolbar
})
if filterContainer then
Utils.Create("UIListLayout", {
FillDirection = Enum.FillDirection.Horizontal,
Padding = UDim.new(0, 6),
Parent = filterContainer
})
local filters = {"All", "RemoteEvent", "RemoteFunction", "BindableEvent"}
for _, filterType in ipairs(filters) do
self:CreateFilterButton(filterType, filterContainer)
end
end
local actionContainer = Utils.Create("Frame", {
Name = "Actions",
Size = UDim2.new(0, 90, 0, 32),
Position = UDim2.new(1, -90, 0.5, -16),
BackgroundTransparency = 1,
Parent = self.Toolbar
})
if actionContainer then
Utils.Create("UIListLayout", {
FillDirection = Enum.FillDirection.Horizontal,
HorizontalAlignment = Enum.HorizontalAlignment.Right,
Padding = UDim.new(0, 6),
Parent = actionContainer
})
self:CreateActionButton("||", actionContainer, function(btn)
self.Logger.Paused = not self.Logger.Paused
if btn then
Utils.SafeSet(btn, "Text", self.Logger.Paused and ">" or "||")
end
end)
self:CreateActionButton("C", actionContainer, function()
self.Logger:Clear()
self:RefreshList()
end)
end
end
function UI:CreateFilterButton(filterType, parent)
local colors = {
All = Theme.Accent,
RemoteEvent = Theme.RemoteEvent,
RemoteFunction = Theme.RemoteFunction,
BindableEvent = Theme.BindableEvent
}
local short = filterType == "All" and "ALL" or
(filterType == "RemoteEvent" and "RE" or
(filterType == "RemoteFunction" and "RF" or
(filterType == "BindableEvent" and "BE" or "?")))
local isActive = self.Logger.TypeFilter == filterType
local btn = Utils.Create("TextButton", {
Name = filterType,
Size = UDim2.new(0, 0, 1, 0),
AutomaticSize = Enum.AutomaticSize.X,
BackgroundColor3 = isActive and (colors[filterType] or Theme.Accent) or Theme.Tertiary,
BackgroundTransparency = isActive and 0.3 or 0.6,
Text = " " .. short .. " ",
TextColor3 = Theme.Text,
TextSize = 13,
Font = Enum.Font.GothamBold,
Parent = parent
})
if not btn then return nil end
Utils.Corner(btn, Theme.CornerSmall)
Utils.Padding(btn, 6)
pcall(function()
btn.MouseButton1Click:Connect(function()
self.Logger.TypeFilter = filterType
for _, child in ipairs(parent:GetChildren()) do
if child:IsA("TextButton") then
local col = colors[child.Name] or Theme.Accent
local active = child.Name == filterType
Utils.SafeSet(child, "BackgroundColor3", active and col or Theme.Tertiary)
Utils.SafeSet(child, "BackgroundTransparency", active and 0.3 or 0.6)
end
end
self:RefreshList()
end)
end)
return btn
end
function UI:CreateActionButton(text, parent, callback)
local btn = Utils.Create("TextButton", {
Size = UDim2.new(0, 32, 0, 32),
BackgroundColor3 = Theme.Tertiary,
BackgroundTransparency = 0.5,
Text = text,
TextColor3 = Theme.Text,
TextSize = 14,
Font = Enum.Font.GothamBold,
Parent = parent
})
if not btn then return nil end
Utils.Corner(btn, Theme.CornerSmall)
pcall(function()
btn.MouseEnter:Connect(function()
Utils.Tween(btn, {BackgroundTransparency = 0.2}, 0.1)
end)
btn.MouseLeave:Connect(function()
Utils.Tween(btn, {BackgroundTransparency = 0.5}, 0.1)
end)
btn.MouseButton1Click:Connect(function()
callback(btn)
end)
end)
return btn
end
function UI:BuildLogArea()
if not self.Main then return end
self.ContentFrame = Utils.Create("Frame", {
Name = "LogFrame",
Size = UDim2.new(1, -24, 1, -100),
Position = UDim2.new(0, 12, 0, 88),
BackgroundColor3 = Theme.Secondary,
BackgroundTransparency = 0.6,
ClipsDescendants = true,
Parent = self.Main
})
if not self.ContentFrame then return end
Utils.Corner(self.ContentFrame, Theme.CornerSmall)
self.LogList = Utils.Create("ScrollingFrame", {
Name = "LogList",
Size = UDim2.new(1, 0, 1, 0),
BackgroundTransparency = 1,
ScrollBarThickness = 4,
ScrollBarImageColor3 = Theme.Accent,
ScrollBarImageTransparency = 0.5,
CanvasSize = UDim2.new(0, 0, 0, 0),
AutomaticCanvasSize = Enum.AutomaticSize.Y,
Parent = self.ContentFrame
})
if self.LogList then
Utils.Create("UIListLayout", {
Padding = UDim.new(0, 3),
SortOrder = Enum.SortOrder.LayoutOrder,
Parent = self.LogList
})
Utils.Padding(self.LogList, 6)
end
end
function UI:BuildResizeHandle()
if not self.Main then return end
local resizeHandle = Utils.Create("TextButton", {
Name = "ResizeHandle",
Size = UDim2.new(0, 20, 0, 20),
Position = UDim2.new(1, -20, 1, -20),
BackgroundColor3 = Theme.Accent,
BackgroundTransparency = 0.7,
Text = "",
Parent = self.Main
})
if not resizeHandle then return end
Utils.Corner(resizeHandle, UDim.new(0, 3))
local resizing = false
local startPos
local startSize
pcall(function()
resizeHandle.MouseEnter:Connect(function()
Utils.Tween(resizeHandle, {BackgroundTransparency = 0.3}, 0.1)
end)
resizeHandle.MouseLeave:Connect(function()
if not resizing then
Utils.Tween(resizeHandle, {BackgroundTransparency = 0.7}, 0.1)
end
end)
resizeHandle.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or
input.UserInputType == Enum.UserInputType.Touch then
resizing = true
startPos = input.Position
startSize = self.Main.Size
end
end)
resizeHandle.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or
input.UserInputType == Enum.UserInputType.Touch then
resizing = false
end
end)
Services.UserInputService.InputChanged:Connect(function(input)
if resizing and (input.UserInputType == Enum.UserInputType.MouseMovement or
input.UserInputType == Enum.UserInputType.Touch) then
local delta = input.Position - startPos
local newWidth = ClonedFunctions.mathMax(self.MinWindowWidth, startSize.X.Offset + delta.X)
local newHeight = ClonedFunctions.mathMax(self.MinWindowHeight, startSize.Y.Offset + delta.Y)
Utils.SafeSet(self.Main, "Size", UDim2.new(0, newWidth, 0, newHeight))
self.ExpandedHeight = newHeight
end
end)
Services.UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or
input.UserInputType == Enum.UserInputType.Touch then
resizing = false
end
end)
end)
end
function UI:CreateGroupItem(group)
if not self.LogList then return nil end
local existingItem = self.GroupItems[group.RemotePath]
if existingItem and existingItem.Frame then
local parentCheck = pcall(function() return existingItem.Frame.Parent end)
if parentCheck then
self:UpdateGroupItem(group)
return existingItem.Frame
end
end
local entry = group.LastEntry
if not entry then return nil end
local item = Utils.Create("Frame", {
Name = "Group_" .. tostring(group.Id),
Size = UDim2.new(1, -10, 0, 50),
BackgroundColor3 = Theme.Tertiary,
BackgroundTransparency = 0.7,
LayoutOrder = -entry.Id,
ClipsDescendants = true,
Parent = self.LogList
})
if not item then return nil end
Utils.Corner(item, Theme.CornerSmall)
local colorBar = Utils.Create("Frame", {
Name = "ColorBar",
Size = UDim2.new(0, 4, 1, -8),
Position = UDim2.new(0, 4, 0, 4),
BackgroundColor3 = entry:GetColor(),
Parent = item
})
if colorBar then
Utils.Corner(colorBar, UDim.new(0, 2))
end
local typeLabel = Utils.Create("TextLabel", {
Name = "TypeLabel",
Size = UDim2.new(0, 36, 0, 20),
Position = UDim2.new(0, 14, 0, 5),
BackgroundColor3 = entry:GetColor(),
BackgroundTransparency = 0.7,
Text = entry:GetTypeShort(),
TextColor3 = Theme.Text,
TextSize = 12,
Font = Enum.Font.GothamBold,
Parent = item
})
if typeLabel then
Utils.Corner(typeLabel, UDim.new(0, 3))
end
local countLabel = Utils.Create("TextLabel", {
Name = "CountLabel",
Size = UDim2.new(0, 40, 0, 20),
Position = UDim2.new(0, 54, 0, 5),
BackgroundColor3 = Theme.Accent,
BackgroundTransparency = 0.5,
Text = "x" .. tostring(group.Count),
TextColor3 = Theme.Text,
TextSize = 12,
Font = Enum.Font.GothamBold,
Parent = item
})
if countLabel then
Utils.Corner(countLabel, UDim.new(0, 3))
end
local isBlocked = self.BlockList:IsBlocked(group.Remote)
local blockedLabel = Utils.Create("TextLabel", {
Name = "BlockedLabel",
Size = UDim2.new(0, 60, 0, 20),
Position = UDim2.new(1, -100, 0, 5),
BackgroundColor3 = Theme.Error,
BackgroundTransparency = 0.3,
Text = "BLOCKED",
TextColor3 = Theme.Text,
TextSize = 10,
Font = Enum.Font.GothamBold,
Visible = isBlocked,
Parent = item
})
if blockedLabel then
Utils.Corner(blockedLabel, UDim.new(0, 3))
end
Utils.Create("TextLabel", {
Name = "NameLabel",
Size = UDim2.new(1, -180, 0, 20),
Position = UDim2.new(0, 100, 0, 5),
BackgroundTransparency = 1,
Text = entry.Remote.Name,
TextColor3 = Theme.Text,
TextSize = 14,
Font = Enum.Font.GothamBold,
TextXAlignment = Enum.TextXAlignment.Left,
TextTruncate = Enum.TextTruncate.AtEnd,
Parent = item
})
Utils.Create("TextLabel", {
Name = "PathLabel",
Size = UDim2.new(1, -70, 0, 16),
Position = UDim2.new(0, 14, 0, 28),
BackgroundTransparency = 1,
Text = entry.RemotePath,
TextColor3 = Theme.TextMuted,
TextSize = 11,
Font = Enum.Font.RobotoMono,
TextXAlignment = Enum.TextXAlignment.Left,
TextTruncate = Enum.TextTruncate.AtEnd,
Parent = item
})
local expandBtn = Utils.Create("TextButton", {
Name = "ExpandBtn",
Size = UDim2.new(0, 24, 0, 24),
Position = UDim2.new(1, -32, 0, 13),
BackgroundColor3 = Theme.Quaternary,
BackgroundTransparency = 0.5,
Text = "▼",
TextColor3 = Theme.Text,
TextSize = 10,
Font = Enum.Font.GothamBold,
Parent = item
})
if expandBtn then
Utils.Corner(expandBtn, Theme.CornerSmall)
end
local entriesContainer = Utils.Create("Frame", {
Name = "EntriesContainer",
Size = UDim2.new(1, -20, 0, 0),
Position = UDim2.new(0, 10, 0, 50),
BackgroundTransparency = 1,
ClipsDescendants = true,
Visible = false,
Parent = item
})
if entriesContainer then
Utils.Create("UIListLayout", {
Padding = UDim.new(0, 2),
SortOrder = Enum.SortOrder.LayoutOrder,
Parent = entriesContainer
})
end
local clickBtn = Utils.Create("TextButton", {
Name = "ClickBtn",
Size = UDim2.new(1, -40, 0, 50),
Position = UDim2.new(0, 0, 0, 0),
BackgroundTransparency = 1,
Text = "",
Parent = item
})
if clickBtn then
pcall(function()
clickBtn.MouseEnter:Connect(function()
Utils.Tween(item, {BackgroundTransparency = 0.5}, 0.08)
end)
clickBtn.MouseLeave:Connect(function()
if self.SelectedGroup ~= group then
Utils.Tween(item, {BackgroundTransparency = 0.7}, 0.08)
end
end)
clickBtn.MouseButton1Click:Connect(function()
self:SelectEntry(entry, item)
end)
end)
end
if expandBtn then
pcall(function()
expandBtn.MouseButton1Click:Connect(function()
group.Expanded = not group.Expanded
self:ToggleGroupExpansion(group, item, entriesContainer, expandBtn)
end)
end)
end
self.GroupItems[group.RemotePath] = {
Frame = item,
CountLabel = countLabel,
BlockedLabel = blockedLabel,
EntriesContainer = entriesContainer,
ExpandBtn = expandBtn,
Group = group
}
return item
end
function UI:UpdateGroupItem(group)
local itemData = self.GroupItems[group.RemotePath]
if not itemData then return end
pcall(function()
if itemData.CountLabel then
itemData.CountLabel.Text = "x" .. tostring(group.Count)
end
end)
pcall(function()
if itemData.BlockedLabel then
local isBlocked = self.BlockList:IsBlocked(group.Remote)
itemData.BlockedLabel.Visible = isBlocked
end
end)
pcall(function()
if itemData.Frame and group.LastEntry then
itemData.Frame.LayoutOrder = -group.LastEntry.Id
local typeLabel = itemData.Frame:FindFirstChild("TypeLabel")
if typeLabel then
typeLabel.BackgroundColor3 = group.LastEntry:GetColor()
end
local colorBar = itemData.Frame:FindFirstChild("ColorBar")
if colorBar then
colorBar.BackgroundColor3 = group.LastEntry:GetColor()
end
end
end)
if group.Expanded and itemData.EntriesContainer then
self:PopulateGroupEntries(group, itemData.EntriesContainer)
local entryHeight = 36
local containerHeight = #group.Entries * (entryHeight + 2)
Utils.SafeSet(itemData.EntriesContainer, "Size", UDim2.new(1, -20, 0, containerHeight))
Utils.Tween(itemData.Frame, {Size = UDim2.new(1, -10, 0, 50 + containerHeight + 10)}, 0.2)
end
end
function UI:ToggleGroupExpansion(group, item, container, expandBtn)
if not item or not container or not expandBtn then return end
if group.Expanded then
Utils.SafeSet(expandBtn, "Text", "▲")
Utils.SafeSet(container, "Visible", true)
self:PopulateGroupEntries(group, container)
local entryHeight = 36
local containerHeight = #group.Entries * (entryHeight + 2)
Utils.SafeSet(container, "Size", UDim2.new(1, -20, 0, containerHeight))
Utils.Tween(item, {Size = UDim2.new(1, -10, 0, 50 + containerHeight + 10)}, 0.2)
else
Utils.SafeSet(expandBtn, "Text", "▼")
Utils.Tween(item, {Size = UDim2.new(1, -10, 0, 50)}, 0.2)
ClonedFunctions.taskDelay(0.2, function()
if not group.Expanded then
Utils.SafeSet(container, "Visible", false)
pcall(function()
for _, child in ipairs(container:GetChildren()) do
if child:IsA("Frame") then
child:Destroy()
end
end
end)
end
end)
end
end
function UI:PopulateGroupEntries(group, container)
if not container then return end
pcall(function()
for _, child in ipairs(container:GetChildren()) do
if child:IsA("Frame") or child:IsA("TextLabel") then
child:Destroy()
end
end
end)
for i, entry in ipairs(group.Entries) do
if entry then
self:CreateSubEntryItem(entry, container, i)
end
end
end
function UI:CreateSubEntryItem(entry, parent, index)
if not parent or not entry then return nil end
local subItem = Utils.Create("Frame", {
Name = "Entry_" .. tostring(entry.Id),
Size = UDim2.new(1, 0, 0, 36),
BackgroundColor3 = Theme.Secondary,
BackgroundTransparency = 0.5,
LayoutOrder = index,
Parent = parent
})
if not subItem then return nil end
Utils.Corner(subItem, Theme.CornerSmall)
local colorIndicator = Utils.Create("Frame", {
Size = UDim2.new(0, 3, 1, -6),
Position = UDim2.new(0, 3, 0, 3),
BackgroundColor3 = entry:GetColor(),
Parent = subItem
})
if colorIndicator then
Utils.Corner(colorIndicator, UDim.new(0, 1))
end
Utils.Create("TextLabel", {
Size = UDim2.new(0, 30, 1, 0),
Position = UDim2.new(0, 10, 0, 0),
BackgroundTransparency = 1,
Text = "#" .. tostring(index),
TextColor3 = Theme.TextDim,
TextSize = 11,
Font = Enum.Font.GothamBold,
TextXAlignment = Enum.TextXAlignment.Left,
Parent = subItem
})
Utils.Create("TextLabel", {
Size = UDim2.new(0, 60, 1, 0),
Position = UDim2.new(0, 45, 0, 0),
BackgroundTransparency = 1,
Text = tostring(#entry.Arguments) .. " args",
TextColor3 = Theme.TextMuted,
TextSize = 11,
Font = Enum.Font.Gotham,
TextXAlignment = Enum.TextXAlignment.Left,
Parent = subItem
})
local callerName = "[Anonymous]"
if entry.RemoteType == "OnClientEvent" then
callerName = "Server"
elseif ClonedFunctions.stringFind(entry.RemoteType, "ActorCall_", 1, true) then
callerName = "[ActorCall]"
else
callerName = entry.CallerInfo.Name or "[Anonymous]"
end
Utils.Create("TextLabel", {
Size = UDim2.new(1, -180, 1, 0),
Position = UDim2.new(0, 110, 0, 0),
BackgroundTransparency = 1,
Text = callerName .. (entry.RemoteType ~= "OnClientEvent" and not ClonedFunctions.stringFind(entry.RemoteType, "ActorCall_", 1, true) and (" @ line " .. tostring(entry.CallerInfo.Line or 0)) or ""),
TextColor3 = Theme.TextDim,
TextSize = 10,
Font = Enum.Font.RobotoMono,
TextXAlignment = Enum.TextXAlignment.Left,
TextTruncate = Enum.TextTruncate.AtEnd,
Parent = subItem
})
if entry.Blocked then
Utils.Create("TextLabel", {
Size = UDim2.new(0, 20, 1, 0),
Position = UDim2.new(1, -25, 0, 0),
BackgroundTransparency = 1,
Text = "B",
TextColor3 = Theme.Error,
TextSize = 11,
Font = Enum.Font.GothamBold,
Parent = subItem
})
end
local clickBtn = Utils.Create("TextButton", {
Size = UDim2.new(1, 0, 1, 0),
BackgroundTransparency = 1,
Text = "",
Parent = subItem
})
if clickBtn then
pcall(function()
clickBtn.MouseEnter:Connect(function()
Utils.Tween(subItem, {BackgroundTransparency = 0.3}, 0.08)
end)
clickBtn.MouseLeave:Connect(function()
Utils.Tween(subItem, {BackgroundTransparency = 0.5}, 0.08)
end)
clickBtn.MouseButton1Click:Connect(function()
self:OpenDetailWindow(entry)
end)
end)
end
return subItem
end
function UI:SelectEntry(entry, item)
for _, groupData in pairs(self.GroupItems) do
if groupData.Frame then
Utils.Tween(groupData.Frame, {BackgroundTransparency = 0.7}, 0.08)
end
end
self.SelectedEntry = entry
Utils.Tween(item, {BackgroundTransparency = 0.4}, 0.08)
self:OpenDetailWindow(entry)
end
function UI:OpenDetailWindow(entry)
if not entry then return end
local currentBlockedStatus = self.BlockList:IsBlocked(entry.Remote)
entry.Blocked = currentBlockedStatus
local windowId = "Detail_" .. tostring(entry.Id)
if self.SubWindows[windowId] then
pcall(function()
self.SubWindows[windowId]:Destroy()
end)
end
local window = Utils.Create("Frame", {
Name = windowId,
Size = UDim2.new(0, 600, 0, 500),
Position = UDim2.new(0.5, -300, 0.5, -250),
BackgroundColor3 = Theme.Primary,
BackgroundTransparency = Theme.Transparency,
Parent = self.Gui
})
if not window then return end
Utils.Corner(window, Theme.CornerMedium)
Utils.Stroke(window, entry:GetColor(), 1, 0.6)
self.SubWindows[windowId] = window
local header = Utils.Create("Frame", {
Size = UDim2.new(1, 0, 0, 36),
BackgroundColor3 = entry:GetColor(),
BackgroundTransparency = 0.7,
Parent = window
})
if header then
Utils.Corner(header, Theme.CornerMedium)
Utils.Create("Frame", {
Size = UDim2.new(1, 0, 0, 8),
Position = UDim2.new(0, 0, 1, -8),
BackgroundColor3 = entry:GetColor(),
BackgroundTransparency = 0.7,
BorderSizePixel = 0,
Parent = header
})
Utils.Create("TextLabel", {
Size = UDim2.new(1, -70, 1, 0),
Position = UDim2.new(0, 12, 0, 0),
BackgroundTransparency = 1,
Text = entry:GetTypeShort() .. " | " .. tostring(entry.Remote.Name) .. " | ID: " .. tostring(entry.Id),
TextColor3 = Theme.Text,
TextSize = 15,
Font = Enum.Font.GothamBold,
TextXAlignment = Enum.TextXAlignment.Left,
Parent = header
})
local closeBtn = Utils.Create("TextButton", {
Size = UDim2.new(0, 28, 0, 28),
Position = UDim2.new(1, -36, 0.5, -14),
BackgroundColor3 = Theme.Error,
BackgroundTransparency = 0.3,
Text = "X",
TextColor3 = Theme.Text,
TextSize = 14,
Font = Enum.Font.GothamBold,
Parent = header
})
if closeBtn then
Utils.Corner(closeBtn, Theme.CornerSmall)
pcall(function()
closeBtn.MouseButton1Click:Connect(function()
window:Destroy()
self.SubWindows[windowId] = nil
end)
end)
end
self:SetupWindowDrag(window, header)
end
local btnFrame = Utils.Create("Frame", {
Size = UDim2.new(1, -24, 0, 32),
Position = UDim2.new(0, 12, 0, 42),
BackgroundTransparency = 1,
Parent = window
})
if btnFrame then
Utils.Create("UIListLayout", {
FillDirection = Enum.FillDirection.Horizontal,
Padding = UDim.new(0, 8),
Parent = btnFrame
})
self:CreateDetailButton("COPY SCRIPT", btnFrame, function()
pcall(function()
setclipboard(entry:GetScript())
end)
self:ShowNotification("Script copied", Theme.Success)
end)
self:CreateDetailButton("COPY INFO", btnFrame, function()
pcall(function()
setclipboard(entry:GetDetailedInfoPlain())
end)
self:ShowNotification("Info copied", Theme.Success)
end)
if entry:CanDecompile() then
self:CreateDetailButton("DECOMPILE", btnFrame, function()
self:OpenDecompileWindow(entry)
end)
end
local isBlocked = self.BlockList:IsBlocked(entry.Remote)
self:CreateDetailButton(isBlocked and "UNBLOCK" or "BLOCK", btnFrame, function(btn)
if self.BlockList:IsBlocked(entry.Remote) then
self.BlockList:Remove(entry.Remote)
Utils.SafeSet(btn, "Text", "BLOCK")
self:ShowNotification("Unblocked", Theme.Success)
else
self.BlockList:Add(entry.Remote)
Utils.SafeSet(btn, "Text", "UNBLOCK")
self:ShowNotification("Blocked", Theme.Warning)
end
pcall(function()
if self.GroupItems[entry.RemotePath] then
self:UpdateGroupItem(self.GroupItems[entry.RemotePath].Group)
end
end)
end)
self:CreateDetailButton("FIRE REMOTE", btnFrame, function()
ClonedFunctions.taskSpawn(function()
local args = entry.Arguments
local rem = entry.Remote
if entry.RemoteType == "OnClientEvent" then
if firesignal then
pcall(function()
firesignal(rem.OnClientEvent, unpack(args))
end)
self:ShowNotification("Signal Fired!", Theme.Success)
elseif replicatesignal then
pcall(function()
replicatesignal(rem.OnClientEvent, unpack(args))
end)
self:ShowNotification("Signal Replicated!", Theme.Success)
else
self:ShowNotification("firesignal not available", Theme.Error)
end
elseif rem:IsA("RemoteEvent") or rem:IsA("UnreliableRemoteEvent") then
rem:FireServer(unpack(args))
self:ShowNotification("Remote Fired!", Theme.Success)
elseif rem:IsA("RemoteFunction") then
rem:InvokeServer(unpack(args))
self:ShowNotification("Remote Fired!", Theme.Success)
elseif rem:IsA("BindableEvent") then
rem:Fire(unpack(args))
self:ShowNotification("Remote Fired!", Theme.Success)
elseif rem:IsA("BindableFunction") then
rem:Invoke(unpack(args))
self:ShowNotification("Remote Fired!", Theme.Success)
end
end)
end)
if CacheAPI.IsAvailable() then
self:CreateDetailButton("INVALIDATE", btnFrame, function()
if CacheAPI.Invalidate(entry.Remote) then
self:ShowNotification("Cache invalidated", Theme.Success)
else
self:ShowNotification("Failed to invalidate", Theme.Error)
end
end)
end
end
local contentFrame = Utils.Create("Frame", {
Size = UDim2.new(1, -24, 1, -90),
Position = UDim2.new(0, 12, 0, 80),
BackgroundColor3 = Theme.Secondary,
BackgroundTransparency = 0.5,
ClipsDescendants = true,
Parent = window
})
if contentFrame then
Utils.Corner(contentFrame, Theme.CornerSmall)
local contentScroll = Utils.Create("ScrollingFrame", {
Size = UDim2.new(1,0, 1, 0),
BackgroundTransparency = 1,
ScrollBarThickness = 5,
ScrollBarImageColor3 = Theme.Accent,
ScrollBarImageTransparency = 0.3,
CanvasSize = UDim2.new(0, 0, 0, 0),
AutomaticCanvasSize = Enum.AutomaticSize.Y,
Parent = contentFrame
})
if contentScroll then
Utils.Padding(contentScroll, 10)
local detailLabel = Instance.new("TextLabel")
detailLabel.Name = "DetailText"
detailLabel.Size = UDim2.new(1, -20, 0, 0)
detailLabel.AutomaticSize = Enum.AutomaticSize.Y
detailLabel.BackgroundTransparency = 1
detailLabel.TextColor3 = Theme.Text
detailLabel.TextSize = 13
detailLabel.Font = Enum.Font.RobotoMono
detailLabel.TextXAlignment = Enum.TextXAlignment.Left
detailLabel.TextYAlignment = Enum.TextYAlignment.Top
detailLabel.TextWrapped = true
detailLabel.RichText = true
detailLabel.Text = entry:GetDetailedInfo()
detailLabel.Parent = contentScroll
end
end
self:SetupSubWindowResize(window)
Utils.SafeSet(window, "Size", UDim2.new(0, 600, 0, 0))
Utils.Tween(window, {Size = UDim2.new(0, 600, 0, 500)}, 0.25, Enum.EasingStyle.Back)
end
function UI:OpenDecompileWindow(entry)
if not entry then
self:ShowNotification("No entry provided", Theme.Error)
return
end
local scriptToDecompile = entry:GetDecompilableScript()
if not scriptToDecompile then
self:ShowNotification("No script to decompile", Theme.Error)
return
end
local windowId = "Decompile_" .. tostring(entry.Id)
if self.SubWindows[windowId] then
pcall(function()
self.SubWindows[windowId]:Destroy()
end)
end
local window = Utils.Create("Frame", {
Name = windowId,
Size = UDim2.new(0, 700, 0, 550),
Position = UDim2.new(0.5, -350, 0.5, -275),
BackgroundColor3 = Theme.Primary,
BackgroundTransparency = Theme.Transparency,
Parent = self.Gui
})
if not window then return end
Utils.Corner(window, Theme.CornerMedium)
Utils.Stroke(window, Theme.Accent, 1, 0.6)
self.SubWindows[windowId] = window
local header = Utils.Create("Frame", {
Size = UDim2.new(1, 0, 0, 36),
BackgroundColor3 = Theme.Accent,
BackgroundTransparency = 0.7,
Parent = window
})
if header then
Utils.Corner(header, Theme.CornerMedium)
Utils.Create("Frame", {
Size = UDim2.new(1, 0, 0, 8),
Position = UDim2.new(0, 0, 1, -8),
BackgroundColor3 = Theme.Accent,
BackgroundTransparency = 0.7,
BorderSizePixel = 0,
Parent = header
})
local titleText = "DECOMPILE | " .. tostring(scriptToDecompile.Name)
if entry.ActorScript then
titleText = "DECOMPILE [ACTOR] | " .. tostring(scriptToDecompile.Name)
end
Utils.Create("TextLabel", {
Size = UDim2.new(1, -70, 1, 0),
Position = UDim2.new(0, 12, 0, 0),
BackgroundTransparency = 1,
Text = titleText,
TextColor3 = Theme.Text,
TextSize = 15,
Font = Enum.Font.GothamBold,
TextXAlignment = Enum.TextXAlignment.Left,
Parent = header
})
local closeBtn = Utils.Create("TextButton", {
Size = UDim2.new(0, 28, 0, 28),
Position = UDim2.new(1, -36, 0.5, -14),
BackgroundColor3 = Theme.Error,
BackgroundTransparency = 0.3,
Text = "X",
TextColor3 = Theme.Text,
TextSize = 14,
Font = Enum.Font.GothamBold,
Parent = header
})
if closeBtn then
Utils.Corner(closeBtn, Theme.CornerSmall)
pcall(function()
closeBtn.MouseButton1Click:Connect(function()
window:Destroy()
self.SubWindows[windowId] = nil
end)
end)
end
self:SetupWindowDrag(window, header)
end
local decompiled = self.Decompiler:Process(scriptToDecompile)
local copyBtn = Utils.Create("TextButton", {
Size = UDim2.new(0, 90, 0, 28),
Position = UDim2.new(0, 12, 0, 42),
BackgroundColor3 = Theme.Accent,
BackgroundTransparency = 0.3,
Text = "COPY",
TextColor3 = Theme.Text,
TextSize = 13,
Font = Enum.Font.GothamBold,
Parent = window
})
if copyBtn then
Utils.Corner(copyBtn, Theme.CornerSmall)
pcall(function()
copyBtn.MouseButton1Click:Connect(function()
pcall(function()
setclipboard(decompiled)
end)
self:ShowNotification("Decompiled script copied", Theme.Success)
end)
end)
end
local contentFrame = Utils.Create("Frame", {
Size = UDim2.new(1, -24, 1, -90),
Position = UDim2.new(0, 12, 0, 76),
BackgroundColor3 = Theme.Secondary,
BackgroundTransparency = 0.5,
ClipsDescendants = true,
Parent = window
})
if contentFrame then
Utils.Corner(contentFrame, Theme.CornerSmall)
local contentScroll = Utils.Create("ScrollingFrame", {
Size = UDim2.new(1, 0, 1, 0),
BackgroundTransparency = 1,
ScrollBarThickness = 6,
ScrollBarImageColor3 = Theme.Accent,
ScrollBarImageTransparency = 0.3,
CanvasSize = UDim2.new(0, 0, 0, 0),
AutomaticCanvasSize = Enum.AutomaticSize.XY,
ScrollingDirection = Enum.ScrollingDirection.XY,
Parent = contentFrame
})
if contentScroll then
Utils.Padding(contentScroll, 10)
Utils.Create("UIListLayout", {
SortOrder = Enum.SortOrder.LayoutOrder,
Parent = contentScroll
})
local lines = ClonedFunctions.stringSplit(decompiled, "\n")
local totalLines = #lines
local CHUNK_SIZE = 50
for i = 1, totalLines, CHUNK_SIZE do
local chunkEnd = ClonedFunctions.mathMin(i + CHUNK_SIZE - 1, totalLines)
local codeChunk = {}
local numChunk = {}
for j = i, chunkEnd do
ClonedFunctions.tableInsert(codeChunk, lines[j])
ClonedFunctions.tableInsert(numChunk, tostring(j))
end
local codeStr = ClonedFunctions.tableConcat(codeChunk, "\n")
local highlightedStr = Utils.HighlightLua(codeStr)
local numStr = ClonedFunctions.tableConcat(numChunk, "\n")
local rowFrame = Utils.Create("Frame", {
Size = UDim2.new(1, 0, 0, 0),
AutomaticSize = Enum.AutomaticSize.Y,
BackgroundTransparency = 1,
LayoutOrder = i,
Parent = contentScroll
})
if rowFrame then
local numLabel = Utils.Create("TextLabel", {
Size = UDim2.new(0, 40, 1, 0),
Position = UDim2.new(0, 0, 0, 0),
BackgroundTransparency = 1,
Text = numStr,
TextColor3 = Theme.TextMuted,
TextSize = 13,
Font = Enum.Font.RobotoMono,
TextXAlignment = Enum.TextXAlignment.Right,
TextYAlignment = Enum.TextYAlignment.Top,
TextWrapped = false,
Parent = rowFrame
})
local codeLabel = Utils.Create("TextLabel", {
Size = UDim2.new(1, -50, 0, 0),
Position = UDim2.new(0, 50, 0, 0),
AutomaticSize = Enum.AutomaticSize.XY,
BackgroundTransparency = 1,
Text = highlightedStr,
RichText = true,
TextColor3 = Theme.Text,
TextSize = 13,
Font = Enum.Font.RobotoMono,
TextXAlignment = Enum.TextXAlignment.Left,
TextYAlignment = Enum.TextYAlignment.Top,
TextWrapped = false,
Parent = rowFrame
})
end
end
end
end
self:SetupSubWindowResize(window)
Utils.SafeSet(window, "Size", UDim2.new(0, 700, 0, 0))
Utils.Tween(window, {Size = UDim2.new(0, 700, 0, 550)}, 0.25, Enum.EasingStyle.Back)
end
function UI:SetupSubWindowResize(window)
if not window then return end
local resizeHandle = Utils.Create("TextButton", {
Name = "ResizeHandle",
Size = UDim2.new(0, 18, 0, 18),
Position = UDim2.new(1, -18, 1, -18),
BackgroundColor3 = Theme.Accent,
BackgroundTransparency = 0.7,
Text = "",
Parent = window
})
if not resizeHandle then return end
Utils.Corner(resizeHandle, UDim.new(0, 3))
local resizing = false
local startPos
local startSize
pcall(function()
resizeHandle.MouseEnter:Connect(function()
Utils.Tween(resizeHandle, {BackgroundTransparency = 0.3}, 0.1)
end)
resizeHandle.MouseLeave:Connect(function()
if not resizing then
Utils.Tween(resizeHandle, {BackgroundTransparency = 0.7}, 0.1)
end
end)
resizeHandle.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or
input.UserInputType == Enum.UserInputType.Touch then
resizing = true
startPos = input.Position
startSize = window.Size
end
end)
resizeHandle.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or
input.UserInputType == Enum.UserInputType.Touch then
resizing = false
end
end)
local connection
connection = Services.UserInputService.InputChanged:Connect(function(input)
local parentExists = pcall(function() return window.Parent end)
if not parentExists then
connection:Disconnect()
return
end
if resizing and (input.UserInputType == Enum.UserInputType.MouseMovement or
input.UserInputType == Enum.UserInputType.Touch) then
local delta = input.Position - startPos
local newWidth = ClonedFunctions.mathMax(300, startSize.X.Offset + delta.X)
local newHeight = ClonedFunctions.mathMax(200, startSize.Y.Offset + delta.Y)
Utils.SafeSet(window, "Size", UDim2.new(0, newWidth, 0, newHeight))
end
end)
local endConnection
endConnection = Services.UserInputService.InputEnded:Connect(function(input)
local parentExists = pcall(function() return window.Parent end)
if not parentExists then
endConnection:Disconnect()
return
end
if input.UserInputType == Enum.UserInputType.MouseButton1 or
input.UserInputType == Enum.UserInputType.Touch then
resizing = false
end
end)
end)
end
function UI:CreateDetailButton(text, parent, callback)
local btn = Utils.Create("TextButton", {
Size = UDim2.new(0, 0, 1, 0),
AutomaticSize = Enum.AutomaticSize.X,
BackgroundColor3 = Theme.Tertiary,
BackgroundTransparency = 0.4,
Text = text,
TextColor3 = Theme.Text,
TextSize = 13,
Font = Enum.Font.GothamBold,
Parent = parent
})
if not btn then return nil end
Utils.Corner(btn, Theme.CornerSmall)
Utils.Padding(btn, 10)
pcall(function()
btn.MouseEnter:Connect(function()
Utils.Tween(btn, {BackgroundColor3 = Theme.Accent, BackgroundTransparency = 0.2}, 0.1)
end)
btn.MouseLeave:Connect(function()
Utils.Tween(btn, {BackgroundColor3 = Theme.Tertiary, BackgroundTransparency = 0.4}, 0.1)
end)
btn.MouseButton1Click:Connect(function()
callback(btn)
end)
end)
return btn
end
function UI:ShowNotification(message, color)
local notification = Utils.Create("Frame", {
Size = UDim2.new(0, 220, 0, 40),
Position = UDim2.new(1, -230, 1, 10),
BackgroundColor3 = color or Theme.Accent,
BackgroundTransparency = 0.15,
Parent = self.Gui
})
if not notification then return end
Utils.Corner(notification, Theme.CornerSmall)
Utils.Create("TextLabel", {
Size = UDim2.new(1, -20, 1, 0),
Position = UDim2.new(0, 10, 0, 0),
BackgroundTransparency = 1,
Text = message,
TextColor3 = Theme.Text,
TextSize = 14,
Font = Enum.Font.GothamBold,
TextXAlignment = Enum.TextXAlignment.Left,
Parent = notification
})
Utils.Tween(notification, {Position = UDim2.new(1, -230, 1, -50)}, 0.2, Enum.EasingStyle.Back)
ClonedFunctions.taskDelay(1.5, function()
Utils.Tween(notification, {Position = UDim2.new(1, -230, 1, 10)}, 0.15)
ClonedFunctions.taskWait(0.15)
pcall(function()
notification:Destroy()
end)
end)
end
function UI:RefreshList()
for _, itemData in pairs(self.GroupItems) do
if itemData.Frame then
pcall(function()
itemData.Frame:Destroy()
end)
end
end
self.GroupItems = {}
local filteredGroups = self.Logger:GetFilteredGroups()
for _, group in ipairs(filteredGroups) do
self:CreateGroupItem(group)
end
end
function UI:SetupLoggerCallback()
local selfRef = self
self.Logger.OnGroupUpdated = function(group, entry)
selfRef.PendingGroups[group] = true
end
end
function UI:ProcessPendingUpdates()
if not self.PendingGroups or not next(self.PendingGroups) then return end
local processed = {}
for group, _ in pairs(self.PendingGroups) do
processed[group] = true
pcall(function()
local passType = self.Logger.TypeFilter == "All" or group.RemoteType == self.Logger.TypeFilter
if self.Logger.TypeFilter == "RemoteEvent" and group.RemoteType == "OnClientEvent" then passType = false end
if self.Logger.TypeFilter == "All" and group.RemoteType == "OnClientEvent" then passType = true end
if self.Logger.TypeFilter == "All" and ClonedFunctions.stringFind(group.RemoteType, "ActorCall_", 1, true) then passType = true end
local passText = self.Logger.Filter == "" or
ClonedFunctions.stringFind(ClonedFunctions.stringLower(group.RemotePath), ClonedFunctions.stringLower(self.Logger.Filter), 1, true) or
ClonedFunctions.stringFind(ClonedFunctions.stringLower(group.Remote.Name), ClonedFunctions.stringLower(self.Logger.Filter), 1, true)
if passType and passText then
if self.GroupItems[group.RemotePath] then
self:UpdateGroupItem(group)
else
self:CreateGroupItem(group)
end
end
end)
end
for group, _ in pairs(processed) do
self.PendingGroups[group] = nil
end
end
function UI:SetupDrag()
local header = self.Main and self.Main:FindFirstChild("Header")
if not header then return end
local dragging = false
local dragInput
local dragStart
local startPos
pcall(function()
header.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or
input.UserInputType == Enum.UserInputType.Touch then
dragging = true
dragStart = input.Position
startPos = self.Main.Position
input.Changed:Connect(function()
if input.UserInputState == Enum.UserInputState.End then
dragging = false
end
end)
end
end)
header.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement or
input.UserInputType == Enum.UserInputType.Touch then
dragInput = input
end
end)
Services.UserInputService.InputChanged:Connect(function(input)
if input == dragInput and dragging then
local delta = input.Position - dragStart
Utils.SafeSet(self.Main, "Position", UDim2.new(
startPos.X.Scale,
startPos.X.Offset + delta.X,
startPos.Y.Scale,
startPos.Y.Offset + delta.Y
))
end
end)
end)
end
function UI:SetupWindowDrag(window, header)
if not window or not header then return end
local dragging = false
local dragInput
local dragStart
local startPos
pcall(function()
header.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or
input.UserInputType == Enum.UserInputType.Touch then
dragging = true
dragStart = input.Position
startPos = window.Position
input.Changed:Connect(function()
if input.UserInputState == Enum.UserInputState.End then
dragging = false
end
end)
end
end)
header.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement or
input.UserInputType == Enum.UserInputType.Touch then
dragInput = input
end
end)
local connection
connection = Services.UserInputService.InputChanged:Connect(function(input)
local parentExists = pcall(function() return window.Parent end)
if not parentExists then
connection:Disconnect()
return
end
if input == dragInput and dragging then
local delta = input.Position - dragStart
Utils.SafeSet(window, "Position", UDim2.new(
startPos.X.Scale,
startPos.X.Offset + delta.X,
startPos.Y.Scale,
startPos.Y.Offset + delta.Y
))
end
end)
end)
end
function UI:ToggleMinimize()
self.Minimized = not self.Minimized
if self.Minimized then
if self.Toolbar then
Utils.SafeSet(self.Toolbar, "Visible", false)
end
if self.ContentFrame then
Utils.SafeSet(self.ContentFrame, "Visible", false)
end
local resizeHandle = self.Main and self.Main:FindFirstChild("ResizeHandle")
if resizeHandle then
Utils.SafeSet(resizeHandle, "Visible", false)
end
Utils.Tween(self.Main, {Size = UDim2.new(0, self.Main.Size.X.Offset, 0, 40)}, 0.2)
else
Utils.Tween(self.Main, {Size = UDim2.new(0, self.Main.Size.X.Offset, 0, self.ExpandedHeight)}, 0.2)
ClonedFunctions.taskDelay(0.2, function()
if not self.Minimized then
if self.Toolbar then
Utils.SafeSet(self.Toolbar, "Visible", true)
end
if self.ContentFrame then
Utils.SafeSet(self.ContentFrame, "Visible", true)
end
local resizeHandle = self.Main and self.Main:FindFirstChild("ResizeHandle")
if resizeHandle then
Utils.SafeSet(resizeHandle, "Visible", true)
end
end
end)
end
end
function UI:AnimateIn()
if not self.Main then return end
Utils.SafeSet(self.Main, "BackgroundTransparency", 1)
Utils.SafeSet(self.Main, "Size", UDim2.new(0, 750, 0, 0))
Utils.Tween(self.Main, {
Size = UDim2.new(0, 750, 0, 500),
BackgroundTransparency = Theme.Transparency
}, 0.3, Enum.EasingStyle.Back)
end
function UI:Close()
if self.UpdateConnection then
self.UpdateConnection:Disconnect()
self.UpdateConnection = nil
end
for _, subWindow in pairs(self.SubWindows) do
pcall(function()
subWindow:Destroy()
end)
end
if self.Main then
Utils.Tween(self.Main, {
Size = UDim2.new(0, 750, 0, 0),
BackgroundTransparency = 1
}, 0.2)
end
ClonedFunctions.taskWait(0.2)
if self.Gui then
pcall(function()
self.Gui:Destroy()
end)
Globals.SKRSpyInstance = nil
end
end
local Core = {}
Core.__index = Core
function Core.new()
local self = setmetatable({}, Core)
self.Logger = Logger.new()
self.BlockList = BlockList.new()
self.Decompiler = Decompiler.new()
self.UI = nil
self.OriginalNamecall = nil
self.InHook = false
self.Active = true
self.IncomingConnections = {}
self.ActorHooked = false
self.ActorChannel = nil
self.ActorChannelId = nil
self.ActorScripts = {}
return self
end
function Core:Init()
self:HookRemotes()
self:HookIncoming()
if ActorInterceptionEnabled then
self:HookActors()
end
self.UI = UI.new(self.Logger, self.BlockList, self.Decompiler)
self.UI:Build()
if AdonisBypassed then
ClonedFunctions.taskDelay(0.5, function()
if self.UI then
self.UI:ShowNotification("Adonis detections patched!", Theme.Success)
end
end)
end
if ActorInterceptionEnabled then
ClonedFunctions.taskDelay(0.8, function()
if self.UI then
self.UI:ShowNotification("Actor interception enabled!", Theme.Warning)
end
end)
end
if CacheAPI.IsAvailable() then
ClonedFunctions.taskDelay(1.1, function()
if self.UI then
self.UI:ShowNotification("Cache API available!", Theme.Success)
end
end)
end
end
function Core:HookActors()
if not getactors or not run_on_actor or not create_comm_channel or not get_comm_channel then
return
end
local selfRef = self
local r1, r2 = create_comm_channel()
local channel, channelId
if typeof(r1) == "Instance" and r1:IsA("BindableEvent") then
channel = r1
channelId = r2
elseif typeof(r2) == "Instance" and r2:IsA("BindableEvent") then
channel = r2
channelId = r1
elseif type(r1) == "number" then
channelId = r1
channel = r2
elseif type(r2) == "number" then
channelId = r2
channel = r1
end
if not channel or not channelId then
return
end
if type(channelId) ~= "number" then
return
end
selfRef.ActorChannel = channel
selfRef.ActorChannelId = channelId
local function handleActorData(data)
if not selfRef.Active then return end
if type(data) ~= "table" then return end
local remote = data.Remote
local remoteType = data.RemoteType
local args = data.Arguments or {}
local actorScript = data.ActorScript
if not remote or typeof(remote) ~= "Instance" then return end
local isBlocked = selfRef.BlockList:IsBlocked(remote)
if isBlocked then return end
local actorRemoteType = "ActorCall_" .. remoteType
local sanitizedArgs = {}
for i, v in ipairs(args) do
if typeof(v) == "userdata" then
sanitizedArgs[i] = tostring(v)
else
sanitizedArgs[i] = v
end
end
local actorScriptInstance = nil
if actorScript and typeof(actorScript) == "Instance" then
actorScriptInstance = actorScript
selfRef.ActorScripts[remote] = actorScript
end
selfRef.Logger:Add({
Remote = remote,
RemoteType = actorRemoteType,
RemotePath = Utils.GetPath(remote),
Arguments = sanitizedArgs,
CallerInfo = { Source = "[Actor Thread]", Name = "[ActorCall]" },
HookType = "Actor",
Method = data.Method or "Unknown",
Blocked = false,
ActorScript = actorScriptInstance
})
end
if typeof(channel) == "Instance" and channel:IsA("BindableEvent") then
channel.Event:Connect(handleActorData)
else
return
end
local actorHookScript = string.format([[
local channelId = %d
local channel = get_comm_channel(channelId)
if not channel then
return
end
if getgenv()._BlatantSpyActorHooked then
return
end
getgenv()._BlatantSpyActorHooked = true
local firing = false
local oldNamecall
oldNamecall = hookmetamethod(game, "__namecall", newcclosure(function(self, ...)
local method = getnamecallmethod()
if checkcaller() or firing then
return oldNamecall(self, ...)
end
if method == "FireServer" or method == "InvokeServer" then
if typeof(self) == "Instance" then
local class = self.ClassName
local remoteType = nil
if method == "FireServer" and class == "RemoteEvent" then
remoteType = "RemoteEvent"
elseif method == "FireServer" and class == "UnreliableRemoteEvent" then
remoteType = "UnreliableRemoteEvent"
elseif method == "InvokeServer" and class == "RemoteFunction" then
remoteType = "RemoteFunction"
end
if remoteType then
local args = {...}
local callingScript = nil
pcall(function()
callingScript = getcallingscript()
end)
task.defer(function()
firing = true
pcall(function()
channel:Fire({
Remote = self,
RemoteType = remoteType,
Arguments = args,
Method = method,
ActorScript = callingScript
})
end)
firing = false
end)
end
end
end
return oldNamecall(self, ...)
end))
]], channelId)
local actors = getactors()
for _, actor in ipairs(actors) do
pcall(function()
run_on_actor(actor, actorHookScript)
end)
end
selfRef.ActorHooked = true
GameRef.DescendantAdded:Connect(function(desc)
if desc:IsA("Actor") then
ClonedFunctions.taskDelay(0.5, function()
pcall(function()
run_on_actor(desc, actorHookScript)
end)
end)
end
end)
end
function Core:HookIncoming()
local selfRef = self
local function ConnectRemote(remote)
if not remote then return end
if selfRef.IncomingConnections[remote] then return end
selfRef.IncomingConnections[remote] = true
pcall(function()
remote.OnClientEvent:Connect(function(...)
if not selfRef.Active then return end
local args = {...}
ClonedFunctions.taskSpawn(function()
local isBlocked = selfRef.BlockList:IsBlocked(remote)
if isBlocked then return end
local sanitizedArgs = {}
for i, v in ipairs(args) do
if typeof(v) == "userdata" then
sanitizedArgs[i] = tostring(v)
else
sanitizedArgs[i] = v
end
end
selfRef.Logger:Add({
Remote = remote,
RemoteType = "OnClientEvent",
RemotePath = Utils.GetPath(remote),
Arguments = sanitizedArgs,
CallerInfo = { Name = "Server" },
HookType = "OnClientEvent",
Method = "OnClientEvent",
Blocked = false
})
end)
end)
end)
end
for _, v in ipairs(GameRef:GetDescendants()) do
if v:IsA("RemoteEvent") or v:IsA("UnreliableRemoteEvent") then
ConnectRemote(v)
end
end
GameRef.DescendantAdded:Connect(function(v)
if v:IsA("RemoteEvent") or v:IsA("UnreliableRemoteEvent") then
ConnectRemote(v)
end
end)
end
function Core:HookRemotes()
local selfRef = self
self.OriginalNamecall = hookmetamethod(game, "__namecall", newcclosure(function(self, ...)
local method = getnamecallmethod()
if selfRef.InHook or checkcaller() then
return selfRef.OriginalNamecall(self, ...)
end
if method == "FireServer" or method == "InvokeServer" or method == "Fire" or method == "Invoke" then
if typeof(self) == "Instance" then
local class = self.ClassName
local isEvent = (method == "FireServer" and (class == "RemoteEvent" or class == "UnreliableRemoteEvent"))
local isFunc = (method == "InvokeServer" and class == "RemoteFunction")
local isBindEvent = (method == "Fire" and class == "BindableEvent")
local isBindFunc = (method == "Invoke" and class == "BindableFunction")
if isEvent or isFunc or isBindEvent or isBindFunc then
if selfRef.Active then
selfRef.InHook = true
local isBlocked = selfRef.BlockList:IsBlocked(self)
if isBlocked then
selfRef.InHook = false
return
end
local args = {...}
ClonedFunctions.taskSpawn(function()
local remoteType = "Unknown"
if isEvent then remoteType = "RemoteEvent" end
if isFunc then remoteType = "RemoteFunction" end
if isBindEvent then remoteType = "BindableEvent" end
if isBindFunc then remoteType = "BindableFunction" end
if class == "UnreliableRemoteEvent" then remoteType = "UnreliableRemoteEvent" end
local callerInfo = Utils.GetCallerInfo(4)
local sanitizedArgs = {}
for i, v in ipairs(args) do
if typeof(v) == "userdata" then
sanitizedArgs[i] = tostring(v)
else
sanitizedArgs[i] = v
end
end
pcall(function()
selfRef.Logger:Add({
Remote = self,
RemoteType = remoteType,
RemotePath = Utils.GetPath(self),
Arguments = sanitizedArgs,
CallerInfo = callerInfo,
HookType = "__namecall",
Method = method,
Blocked = false
})
end)
end)
selfRef.InHook = false
end
end
end
end
return selfRef.OriginalNamecall(self, ...)
end))
end
function Core:Shutdown()
self.Active = false
getgenv()._BlatantSpyActorCallback = nil
getgenv()._BlatantSpyActorHooked = nil
if self.UI then
self.UI:Close()
end
end
local function StartBlatantSpy()
local BlatantSpy = Core.new()
BlatantSpy:Init()
Globals.BlatantSpy = BlatantSpy
return BlatantSpy
end
-- 起動処理
ShowAdonisPrompt(function()
ShowActorPrompt(function(actorEnabled)
StartBlatantSpy()
end)
end)