local CONFIG = { Name = "Drain Job", Version = "2.1.0", UniverseId = 10403437074, RayfieldUrl = "https://sirius.menu/gen2", Theme = "cobalt", Cooldown = 1.25, } local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") if game.GameId ~= CONFIG.UniverseId then warn(string.format("[%s] Unsupported game (Universe %s).", CONFIG.Name, tostring(game.GameId))) return end local LocalPlayer = Players.LocalPlayer if not LocalPlayer then error("LocalPlayer is unavailable.") end local Shared = ReplicatedStorage:WaitForChild("Shared", 15) local EconRemotes = ReplicatedStorage:WaitForChild("EconRemotes", 15) if not Shared or not EconRemotes then error("Shared or EconRemotes could not be found. The game may have updated.") end local CompleteRemote = EconRemotes:WaitForChild("Complete", 10) local GameRoleModule = Shared:WaitForChild("GameRole", 10) local JobsModule = Shared:WaitForChild("Jobs", 10) if not CompleteRemote or not GameRoleModule or not JobsModule then error("Required job components could not be found.") end local GameRole = require(GameRoleModule) local Jobs = require(JobsModule) local JobRemotes = ReplicatedStorage:FindFirstChild("JobRemotes") local executorName, executorVersion = "Unknown", "" if type(identifyexecutor) == "function" then local ok, name, version = pcall(identifyexecutor) if ok then executorName = tostring(name or "Unknown") executorVersion = tostring(version or "") end end local stateStore if type(getscriptglobals) == "function" then local ok, globals = pcall(getscriptglobals) if ok and type(globals) == "table" and type(globals.shared) == "table" then stateStore = globals.shared end end if not stateStore then stateStore = getgenv() end -- Remove older releases before starting this distribution build. for _, key in ipairs({ "__DrainJobAssistantV2", "DrainSimulatorJobCompleter" }) do local oldSession = stateStore[key] if type(oldSession) == "table" and type(oldSession.destroy) == "function" then pcall(oldSession.destroy) end stateStore[key] = nil end local stateKey = "__DrainJobAssistantV2" local session = { connections = {}, destroyed = false, } stateStore[stateKey] = session local function elevateThread() if type(setthreadidentity) == "function" then pcall(setthreadidentity, 8) end end local function connect(signal, callback) local connection = signal:Connect(callback) table.insert(session.connections, connection) return connection end local function isJobId(value) return type(value) == "string" and value ~= "" end local function detectCurrentJob() local okNow, current = pcall(GameRole.currentJobIdNow) if okNow and isJobId(current) then return current, "GameRole" end current = LocalPlayer:GetAttribute("CurrentJob") if isJobId(current) then return current, "Player.CurrentJob" end current = ReplicatedStorage:GetAttribute("CurrentJob") if isJobId(current) then return current, "ReplicatedStorage.CurrentJob" end local okJoin, joinData = pcall(LocalPlayer.GetJoinData, LocalPlayer) if okJoin and type(joinData) == "table" and type(joinData.TeleportData) == "table" then current = joinData.TeleportData.jobId if isJobId(current) then return current, "TeleportData" end end return nil, "None" end local function getJobInfo(jobId) local ok, job = pcall(Jobs.get, jobId) if not ok or type(job) ~= "table" then return jobId, nil end local name = job.displayName or job.title or job.name if type(name) ~= "string" or name == "" then name = jobId end return name, job end local function copyText(text) if type(setclipboard) ~= "function" then return false, "Clipboard access is not supported by this executor." end local ok, message = pcall(setclipboard, text) return ok, message end local okHttp, rayfieldSource = pcall(game.HttpGet, game, CONFIG.RayfieldUrl) if not okHttp or type(rayfieldSource) ~= "string" or rayfieldSource == "" then error("Could not download Rayfield Gen2: " .. tostring(rayfieldSource)) end local loader, compileError = loadstring(rayfieldSource, "@RayfieldGen2") if not loader then error("Could not compile Rayfield Gen2: " .. tostring(compileError)) end local okLibrary, Rayfield = pcall(loader) if not okLibrary or type(Rayfield) ~= "table" then error("Could not start Rayfield Gen2: " .. tostring(Rayfield)) end local Window = Rayfield:CreateWindow({ name = CONFIG.Name, subtitle = "Job Assistant v" .. CONFIG.Version, showName = "Drain Jobs", theme = CONFIG.Theme, configuration = { autoSave = false, autoLoad = false, fileName = "DrainJobAssistant", }, }) session.destroy = function() elevateThread() if session.destroyed then return end session.destroyed = true for _, connection in ipairs(session.connections) do pcall(function() connection:Disconnect() end) end table.clear(session.connections) pcall(function() Window:Unload() end) if stateStore[stateKey] == session then stateStore[stateKey] = nil end end -- One compact tag prevents top-bar overlap on smaller resolutions. local statusTag = Window:CreateTag({ text = executorName, color = Color3.fromRGB(45, 170, 255), order = 1, }) local JobsTab = Window:CreateTab({ name = "Jobs", icon = 0 }) JobsTab:CreateSection({ name = "Current Job" }) local completionCount = 0 local completionStat = JobsTab:CreateStat({ name = "Requests sent", value = completionCount, compact = true, changeMode = "absolute", }) local currentJobId local currentJobName local function refreshJobStatus(showFeedback) elevateThread() local jobId, sourceName = detectCurrentJob() currentJobId = jobId if jobId then local jobName = getJobInfo(jobId) currentJobName = jobName statusTag:Set({ text = executorName .. " • " .. jobName, color = Color3.fromRGB(80, 200, 120), }) if showFeedback then Window:Toast({ title = "Job detected", subtitle = jobName .. " • " .. jobId, position = "Top", }) end return jobId, jobName, sourceName end currentJobName = nil statusTag:Set({ text = executorName .. " • Hub", color = Color3.fromRGB(45, 170, 255), }) if showFeedback then Window:Toast({ title = "No active job", subtitle = "Start a job and try again", position = "Top", }) end return nil, nil, sourceName end local busy = false JobsTab:CreateButton({ name = "Detect & Complete Current Job", description = "Detects the active job when clicked and sends its completion request.", callback = function() elevateThread() if busy then Window:Toast({ title = "Please wait", subtitle = "A request is already running" }) return end busy = true local ok, result = pcall(function() local jobId, jobName, sourceName = refreshJobStatus(false) if not jobId then Window:Notify({ title = "No active job", content = "Join or start a job, then press the button again.", duration = 5, }) return end CompleteRemote:FireServer(jobId) completionCount += 1 completionStat:Set(completionCount) Window:Notify({ title = "Completion sent", content = string.format("%s\nID: %s\nDetected through: %s", jobName, jobId, sourceName), duration = 6, }) print(string.format("[%s] Complete(%s) sent for %s", CONFIG.Name, jobId, jobName)) end) if not ok then warn("[" .. CONFIG.Name .. "] " .. tostring(result)) Window:Notify({ title = "Completion failed", content = tostring(result), duration = 7, }) end task.delay(CONFIG.Cooldown, function() busy = false end) end, }) JobsTab:CreateButton({ name = "Refresh Job Detection", description = "Updates the status badge without completing anything.", callback = function() elevateThread() refreshJobStatus(true) end, }) JobsTab:CreateButton({ name = "Copy Current Job ID", description = "Copies the detected internal job identifier.", callback = function() elevateThread() local jobId, jobName = refreshJobStatus(false) if not jobId then Window:Toast({ title = "Nothing to copy", subtitle = "No active job detected" }) return end local ok, message = copyText(jobId) if ok then Window:Toast({ title = "Job ID copied", subtitle = jobName }) else Window:Notify({ title = "Copy failed", content = tostring(message), duration = 5 }) end end, }) local UtilitiesTab = Window:CreateTab({ name = "Utilities", icon = 0 }) UtilitiesTab:CreateSection({ name = "Navigation" }) UtilitiesTab:CreateButton({ name = "Return to Hub", description = "Uses the game's official ReturnToHub remote.", callback = function() elevateThread() local jobId = detectCurrentJob() local returnRemote = JobRemotes and JobRemotes:FindFirstChild("ReturnToHub") if not jobId then Window:Notify({ title = "Already in the hub", content = "No active job was detected.", duration = 4 }) return end if not returnRemote then Window:Notify({ title = "Return unavailable", content = "ReturnToHub is missing. The game may have updated.", duration = 5, }) return end Window:Toast({ title = "Returning to hub", subtitle = "Leaving the current job" }) returnRemote:FireServer() end, }) UtilitiesTab:CreateSection({ name = "Session" }) UtilitiesTab:CreateButton({ name = "Unload Interface", description = "Disconnects all listeners and unloads Rayfield Gen2.", callback = function() elevateThread() session.destroy() end, }) local InfoTab = Window:CreateTab({ name = "Info", icon = 0 }) InfoTab:CreateSection({ name = "Distribution" }) InfoTab:CreateButton({ name = "Version " .. CONFIG.Version, description = "Distribution build • Rayfield Gen2", callback = function() elevateThread() Window:Toast({ title = CONFIG.Name, subtitle = "Version " .. CONFIG.Version }) end, }) InfoTab:CreateButton({ name = "Executor: " .. executorName, description = executorVersion ~= "" and ("Version: " .. executorVersion) or "Version unavailable", callback = function() elevateThread() Window:Toast({ title = executorName, subtitle = executorVersion ~= "" and executorVersion or "Version unavailable" }) end, }) InfoTab:CreateButton({ name = "Player: " .. LocalPlayer.Name, description = "User ID: " .. tostring(LocalPlayer.UserId), callback = function() elevateThread() local ok, message = copyText(tostring(LocalPlayer.UserId)) if ok then Window:Toast({ title = "User ID copied", subtitle = tostring(LocalPlayer.UserId) }) else Window:Notify({ title = "Copy failed", content = tostring(message), duration = 5 }) end end, }) connect(LocalPlayer:GetAttributeChangedSignal("CurrentJob"), function() elevateThread() task.defer(refreshJobStatus, false) end) connect(ReplicatedStorage:GetAttributeChangedSignal("CurrentJob"), function() elevateThread() task.defer(refreshJobStatus, false) end) refreshJobStatus(false) Window:Notify({ title = CONFIG.Name .. " loaded", content = string.format("Executor: %s\nVersion: %s", executorName, CONFIG.Version), duration = 5, })