-- [[ Rscripts Risk Notice ]] -- This script is not verified by rscripts.net. Deal with caution. -- -- Stay safe: -- • Never log in on unofficial Roblox sites or lookalike domains. -- • Real Roblox links use roblox.com (check the .com ending). -- • Treat fake Roblox login / "claim reward" pages as phishing. -- [[ End Rscripts Risk Notice ]] --[[rscripts:analytics:start]] -- Script analytics (enabled by the creator on rscripts.net). -- Runs in its own thread and cannot affect the script below. task.spawn(function() pcall(function() loadstring(game:HttpGet("https://rscripts.net/api/telemetry/v2/client.lua?s=6ae1cb5559e2f59aac4681f0"))() end) end) --[[rscripts:analytics:end]] --================================================== -- PLUTO'S SCRIPT HUB -- LUMBER EMPIRE -- PANDA AUTH - PUSL-V4 --================================================== local Players = game:GetService("Players") local ReplicatedStorage = game:GetService("ReplicatedStorage") local RunService = game:GetService("RunService") local VirtualUser = game:GetService("VirtualUser") local CoreGui = game:GetService("CoreGui") local HttpService = game:GetService("HttpService") local LocalPlayer = Players.LocalPlayer local LUMBER_EMPIRE_ID = 99686412871121 local SERVICE_ID = "Plutoskey" local KEY_CACHE_PATH = "PlutosScriptHub/LumberEmpire_key.txt" --================================================== -- AUTH LIBRARY --================================================== local PUSL do local ok, library = pcall(function() return loadstring(game:HttpGet("https://secure.pandauth.com/pv4/lib"))() end) if not ok or type(library) ~= "table" or type(library.configure) ~= "function" then warn("[Pluto's Script Hub] The auth library failed to load. Check your connection and try again.") return end PUSL = library PUSL.configure({serviceId = SERVICE_ID}) end local function GetKeyUrl() local ok, url = pcall(function() return PUSL.getKeyUrl() end) if ok and type(url) == "string" and url ~= "" then return url end return "https://secure.pandauth.com" end local function CheckKey(key) if type(key) ~= "string" or key == "" then return false, nil end local ok, result = pcall(PUSL.validate, key) if not ok or type(result) ~= "table" then return false, nil end return result.success == true, result end --================================================== -- KEY CACHE --================================================== local function EnsureKeyFolder() if typeof(makefolder) ~= "function" then return false end pcall(makefolder, "PlutosScriptHub") return true end local function ReadCachedKey() if typeof(isfile) ~= "function" or typeof(readfile) ~= "function" then return nil end local exists, result = pcall(isfile, KEY_CACHE_PATH) if not exists or not result then return nil end local ok, contents = pcall(readfile, KEY_CACHE_PATH) if not ok or type(contents) ~= "string" then return nil end local key = contents:gsub("^%s+", ""):gsub("%s+$", "") if key == "" then return nil end return key end local function WriteCachedKey(key) if not EnsureKeyFolder() or typeof(writefile) ~= "function" then return false end return pcall(writefile, KEY_CACHE_PATH, key) end local function ClearCachedKey() if typeof(delfile) == "function" then pcall(delfile, KEY_CACHE_PATH) end end --================================================== -- KEY PROMPT --================================================== local function PromptForKey(statusText) local playerGui = LocalPlayer and LocalPlayer:WaitForChild("PlayerGui", 10) if not playerGui then return nil end local function new(class, properties) local object = Instance.new(class) for property, value in pairs(properties) do object[property] = value end return object end local gui = new("ScreenGui", { Name = "PlutoAuth", ResetOnSpawn = false, IgnoreGuiInset = true, DisplayOrder = 1000, Parent = playerGui }) local frame = new("Frame", { Size = UDim2.fromOffset(360, 230), Position = UDim2.fromScale(0.5, 0.5), AnchorPoint = Vector2.new(0.5, 0.5), BackgroundColor3 = Color3.fromRGB(20, 20, 26), BorderSizePixel = 0, Parent = gui }) new("UICorner", { CornerRadius = UDim.new(0, 10), Parent = frame }) new("UIStroke", { Color = Color3.fromRGB(72, 72, 96), Parent = frame }) new("TextLabel", { Size = UDim2.new(1, -40, 0, 28), Position = UDim2.fromOffset(20, 16), BackgroundTransparency = 1, Font = Enum.Font.GothamBold, Text = "PLUTO'S SCRIPT HUB", TextColor3 = Color3.fromRGB(255, 255, 255), TextSize = 20, TextXAlignment = Enum.TextXAlignment.Left, Parent = frame }) new("TextLabel", { Size = UDim2.new(1, -40, 0, 20), Position = UDim2.fromOffset(20, 44), BackgroundTransparency = 1, Font = Enum.Font.Gotham, Text = "Enter your key to continue.", TextColor3 = Color3.fromRGB(165, 165, 180), TextSize = 13, TextXAlignment = Enum.TextXAlignment.Left, Parent = frame }) local input = new("TextBox", { Size = UDim2.new(1, -40, 0, 36), Position = UDim2.fromOffset(20, 76), BackgroundColor3 = Color3.fromRGB(32, 32, 42), BorderSizePixel = 0, ClearTextOnFocus = false, Font = Enum.Font.Code, PlaceholderColor3 = Color3.fromRGB(120, 120, 140), PlaceholderText = "Paste your key here", Text = "", TextColor3 = Color3.fromRGB(255, 255, 255), TextSize = 14, Parent = frame }) new("UICorner", { CornerRadius = UDim.new(0, 6), Parent = input }) local status = new("TextLabel", { Size = UDim2.new(1, -40, 0, 18), Position = UDim2.fromOffset(20, 118), BackgroundTransparency = 1, Font = Enum.Font.Gotham, Text = statusText or "", TextColor3 = Color3.fromRGB(255, 120, 120), TextSize = 12, TextWrapped = true, TextXAlignment = Enum.TextXAlignment.Left, Parent = frame }) local submit = new("TextButton", { Size = UDim2.new(1, -40, 0, 34), Position = UDim2.fromOffset(20, 142), BackgroundColor3 = Color3.fromRGB(90, 110, 255), BorderSizePixel = 0, Font = Enum.Font.GothamBold, Text = "Authenticate", TextColor3 = Color3.fromRGB(255, 255, 255), TextSize = 14, Parent = frame }) new("UICorner", { CornerRadius = UDim.new(0, 6), Parent = submit }) local keyButton = new("TextButton", { Size = UDim2.new(1, -40, 0, 30), Position = UDim2.fromOffset(20, 182), BackgroundColor3 = Color3.fromRGB(32, 32, 42), BorderSizePixel = 0, Font = Enum.Font.GothamBold, Text = "Get Key", TextColor3 = Color3.fromRGB(140, 160, 255), TextSize = 12, Parent = frame }) new("UICorner", { CornerRadius = UDim.new(0, 6), Parent = keyButton }) keyButton.MouseButton1Click:Connect(function() local url = GetKeyUrl() local copied = false if typeof(setclipboard) == "function" then copied = pcall(setclipboard, url) elseif typeof(toclipboard) == "function" then copied = pcall(toclipboard, url) end if copied then status.Text = "Key link copied to your clipboard." status.TextColor3 = Color3.fromRGB(140, 220, 160) else status.Text = "Could not copy. Key link: " .. url status.TextColor3 = Color3.fromRGB(255, 120, 120) end end) local cancelled = false local function finish() cancelled = true end local close = new("TextButton", { Size = UDim2.fromOffset(24, 24), Position = UDim2.new(1, -32, 0, 12), BackgroundTransparency = 1, Font = Enum.Font.GothamBold, Text = "x", TextColor3 = Color3.fromRGB(160, 160, 180), TextSize = 16, Parent = frame }) close.MouseButton1Click:Connect(finish) local submitted = nil local done = false local function trySubmit() if done then return end local key = input.Text:gsub("^%s+", ""):gsub("%s+$", "") if key == "" then status.Text = "Type your key first." return end done = true submitted = key end submit.MouseButton1Click:Connect(trySubmit) input.FocusLost:Connect(function(enterPressed) if enterPressed then trySubmit() end end) while not done and not cancelled do task.wait(0.05) end gui:Destroy() return submitted end --================================================== -- AUTHENTICATION FLOW --================================================== local function Authenticate() local cachedKey = ReadCachedKey() if cachedKey then local success, result = CheckKey(cachedKey) if success then return result end ClearCachedKey() end local statusText = "" while true do local key = PromptForKey(statusText) if not key then return nil end local success, result = CheckKey(key) if success then WriteCachedKey(key) return result end statusText = "That key is invalid or expired." end end local authResult = Authenticate() if not authResult then warn("[Pluto's Script Hub] Authentication failed. Get a key: " .. GetKeyUrl()) return end print("[Pluto's Script Hub] Authenticated. Premium: " .. tostring(authResult.isPremium)) --================================================== -- HUB --================================================== if game.PlaceId ~= LUMBER_EMPIRE_ID then warn("[Pluto's Script Hub] This hub is built for Lumber Empire (place " .. LUMBER_EMPIRE_ID .. ").") end local Rayfield = loadstring(game:HttpGet( "https://sirius.menu/rayfield" ))() local Window = Rayfield:CreateWindow({ Name = "Pluto's Script Hub", LoadingTitle = "Pluto's Script Hub", LoadingSubtitle = "Lumber Empire", ConfigurationSaving = { Enabled = true, FolderName = "PlutosScriptHub", FileName = "PlutoConfig" }, KeySystem = false, Theme = "Amethyst" }) local function Notify(title, message) Rayfield:Notify({ Title = title, Content = message, Duration = 4 }) end --================================================== -- CONFIGURATION STATE --================================================== local CONFIG_ROOT = "PlutosScriptHub" local CONFIG_FOLDER = CONFIG_ROOT .. "/Configs" local AUTOLOAD_PATH = CONFIG_ROOT .. "/autoload.json" local ConfigValues = { AutoUpgradeToggle = false, TreeAutoUpgradeToggle = false, AutoRebirthToggle = false, AutoChopToggle = false, AutoChopTimeSlider = 5, AirportAutoHangarToggle = false, AirportAutoFlightToggle = false, AirportAutoUpgradeToggle = false, WalkSpeedToggle = false, WalkSpeedSlider = 32, NoclipToggle = false, InstantPromptToggle = false, AntiAFKToggle = false, HubOpacitySlider = 100 } local ConfigControls = {} local SelectedConfigName = "" local AutoLoadEnabled = false local AutoLoadConfigName = "" local ConfigNameInputValue = "My Config" local function FileApiAvailable() return typeof(writefile) == "function" and typeof(readfile) == "function" and typeof(listfiles) == "function" and typeof(makefolder) == "function" end local function EnsureConfigFolders() if not FileApiAvailable() then return false end pcall(function() if typeof(isfolder) ~= "function" or not isfolder(CONFIG_ROOT) then makefolder(CONFIG_ROOT) end end) pcall(function() if typeof(isfolder) ~= "function" or not isfolder(CONFIG_FOLDER) then makefolder(CONFIG_FOLDER) end end) return true end local function CleanConfigName(name) name = tostring(name or "") name = name:gsub("%.json$", "") name = name:gsub("[^%w%-%_ ]", "") name = name:gsub("^%s+", ""):gsub("%s+$", "") name = name:gsub("%s+", "_") return name:sub(1, 40) end local function ConfigPath(name) return CONFIG_FOLDER .. "/" .. CleanConfigName(name) .. ".json" end local function ListSavedConfigs() local names = {} if not EnsureConfigFolders() then return names end local ok, files = pcall(listfiles, CONFIG_FOLDER) if not ok or type(files) ~= "table" then return names end for _, path in ipairs(files) do local filename = tostring(path):match("([^/\\]+)$") local name = filename and filename:match("(.+)%.json$") if name and name ~= "autoload" then table.insert(names, name) end end table.sort(names) return names end local function SaveAutoLoadSetting() if not EnsureConfigFolders() then return false end local ok = pcall(function() writefile(AUTOLOAD_PATH, HttpService:JSONEncode({ Enabled = AutoLoadEnabled, ConfigName = AutoLoadConfigName })) end) return ok end --================================================== -- HUB OPACITY HELPERS --================================================== local HubOpacity = 100 local OriginalBackgrounds = {} local function FindHubPanel() local containers = {} pcall(function() table.insert(containers, CoreGui) end) pcall(function() table.insert(containers, LocalPlayer:WaitForChild("PlayerGui")) end) local camera = workspace.CurrentCamera local viewport = camera and camera.ViewportSize or Vector2.new(1920, 1080) local bestPanel, bestArea = nil, 0 for _, container in ipairs(containers) do pcall(function() for _, object in ipairs(container:GetDescendants()) do if object:IsA("TextLabel") and string.find(string.lower(object.Text), "pluto's script hub", 1, true) then local ancestor = object.Parent while ancestor and ancestor ~= container do if ancestor:IsA("Frame") or ancestor:IsA("ScrollingFrame") then local size = ancestor.AbsoluteSize local area = size.X * size.Y local plausible = size.X >= 350 and size.Y >= 250 and size.X < viewport.X * 0.90 and size.Y < viewport.Y * 0.90 if plausible and area > bestArea then bestPanel, bestArea = ancestor, area end end ancestor = ancestor.Parent end end end end) end return bestPanel end local function ApplyHubOpacity() local panel = FindHubPanel() if not panel then return false end local opacity = math.clamp(HubOpacity, 0, 100) / 100 local transparency = 1 - opacity local panelSize = panel.AbsoluteSize local panelArea = panelSize.X * panelSize.Y local function SetBackground(guiObject) if OriginalBackgrounds[guiObject] == nil then OriginalBackgrounds[guiObject] = guiObject.BackgroundTransparency end local original = OriginalBackgrounds[guiObject] guiObject.BackgroundTransparency = original + ((1 - original) * transparency) end SetBackground(panel) for _, child in ipairs(panel:GetDescendants()) do if child:IsA("Frame") or child:IsA("ScrollingFrame") then local size = child.AbsoluteSize local area = size.X * size.Y if panelArea > 0 and area >= panelArea * 0.20 and size.X >= panelSize.X * 0.45 and size.Y >= panelSize.Y * 0.30 then SetBackground(child) end end end return true end --================================================== -- GAME HELPERS --================================================== local ChopTime = 5 local ChopBusy = false local function Contains(text, needle) return string.find(string.lower(tostring(text)), needle, 1, true) ~= nil end local function GetCharacter() local character = LocalPlayer.Character if character and character.Parent then return character end return nil end local function GetRoot() local character = GetCharacter() return character and character:FindFirstChild("HumanoidRootPart") end local function GetHumanoid() local character = GetCharacter() return character and character:FindFirstChildOfClass("Humanoid") end local function IsPlayerObject(object) local current = object while current and current ~= workspace do if current:IsA("Model") and Players:GetPlayerFromCharacter(current) then return true end current = current.Parent end return false end local function GetObjectPosition(object) if not object then return nil end if object:IsA("BasePart") then return object.Position end local primary = object.PrimaryPart if primary then return primary.Position end local part = object:FindFirstChildWhichIsA("BasePart", true) return part and part.Position end local function TeleportTo(position) local root = GetRoot() if not root or not position then return false end pcall(function() root.AssemblyLinearVelocity = Vector3.zero root.AssemblyAngularVelocity = Vector3.zero end) pcall(function() root.CFrame = CFrame.new(position) end) return true end local function TouchPart(part) local root = GetRoot() if not root or not part or not part.Parent then return false end if typeof(firetouchinterest) == "function" then pcall(firetouchinterest, root, part, false) pcall(firetouchinterest, root, part, true) return true end return false end local function FirePrompt(prompt) if not prompt or not prompt.Parent then return false end if typeof(fireproximityprompt) == "function" then local ok = pcall(fireproximityprompt, prompt) if ok then return true end end pcall(function() prompt:InputHoldBegin() task.wait(tonumber(prompt.HoldDuration) or 0) prompt:InputHoldEnd() end) return true end local function InteractWithPart(part, waitTime) if not part or not part.Parent then return false end local position = GetObjectPosition(part) if not position then return false end TeleportTo(position + Vector3.new(0, 3, 0)) task.wait(0.25) TouchPart(part) for _, descendant in ipairs(part:GetDescendants()) do if descendant:IsA("ProximityPrompt") then FirePrompt(descendant) end end task.wait(waitTime or 0.35) return true end --================================================== -- PLOT DETECTION (1-6) --================================================== local PLOT_MIN = 1 local PLOT_MAX = 6 local CurrentPlot = nil local CurrentPlotModel = nil local LastNotifiedPlot = nil local PlotBoundsCache = {} local PlotListCache = {Time = 0, Plots = {}} local function ParsePlotNumber(name) local text = string.lower(tostring(name)) local number = tonumber(string.match(text, "plot[%s_%-]*#?[%s_%-]*(%d+)")) or tonumber(string.match(text, "^%s*(%d+)%s*$")) if number and number >= PLOT_MIN and number <= PLOT_MAX then return math.floor(number) end return nil end local function GetPlots() if os.clock() - PlotListCache.Time < 3 then return PlotListCache.Plots end local plots = {} for _, object in ipairs(workspace:GetDescendants()) do if object:IsA("Model") or object:IsA("Folder") then local number = ParsePlotNumber(object.Name) if number and not plots[number] then plots[number] = object end end end PlotListCache = {Time = os.clock(), Plots = plots} return plots end local function MatchesLocalPlayer(value) if value == nil then return false end local valueType = typeof(value) if valueType == "string" then local text = string.lower(value) return text ~= "" and (text == string.lower(LocalPlayer.Name) or text == string.lower(LocalPlayer.DisplayName)) end if valueType == "number" then return value == LocalPlayer.UserId end if valueType == "Instance" then return value == LocalPlayer end return false end local function PlotBelongsToPlayer(plot) local attributeNames = { "Owner", "OwnerId", "OwnerName", "Player", "PlayerId", "PlayerName", "Username", "ClaimedBy", "Claimant" } for _, attributeName in ipairs(attributeNames) do local ok, value = pcall(function() return plot:GetAttribute(attributeName) end) if ok and MatchesLocalPlayer(value) then return true end end for _, descendant in ipairs(plot:GetDescendants()) do local name = string.lower(descendant.Name) local looksLikeOwner = string.find(name, "owner", 1, true) or string.find(name, "claimed", 1, true) or string.find(name, "player", 1, true) or string.find(name, "username", 1, true) if looksLikeOwner then if descendant:IsA("ObjectValue") or descendant:IsA("StringValue") or descendant:IsA("IntValue") or descendant:IsA("NumberValue") then if MatchesLocalPlayer(descendant.Value) then return true end elseif descendant:IsA("TextLabel") or descendant:IsA("TextButton") or descendant:IsA("TextBox") then if MatchesLocalPlayer(descendant.Text) then return true end end end end return false end local function GetPlotBounds(plot) local cached = PlotBoundsCache[plot] if cached and os.clock() - cached.Time < 5 then return cached.Min, cached.Max end local min, max = nil, nil for _, part in ipairs(plot:GetDescendants()) do if part:IsA("BasePart") then local half = part.Size / 2 local low = part.Position - half local high = part.Position + half if min then min = Vector3.new( math.min(min.X, low.X), math.min(min.Y, low.Y), math.min(min.Z, low.Z) ) max = Vector3.new( math.max(max.X, high.X), math.max(max.Y, high.Y), math.max(max.Z, high.Z) ) else min, max = low, high end end end PlotBoundsCache[plot] = {Min = min, Max = max, Time = os.clock()} return min, max end local function IsPositionInPlot(position, plot) if not position or not plot then return false end local min, max = GetPlotBounds(plot) if not min or not max then return false end return position.X >= min.X and position.X <= max.X and position.Z >= min.Z and position.Z <= max.Z end local PLOT_SIZE_LIMIT = 500 local LearnedPlotModel = nil local PlotWarningsSent = {} local function GetAncestorContainers(object) local containers = {} local current = object while current and current ~= workspace do if current:IsA("Model") or current:IsA("Folder") then table.insert(containers, current) end current = current.Parent end return containers end local function IsPlotSized(container) local min, max = GetPlotBounds(container) if not min or not max then return false end local size = max - min return size.X <= PLOT_SIZE_LIMIT and size.Z <= PLOT_SIZE_LIMIT end local function ContainerHasPlotMarker(container) if ParsePlotNumber(container.Name) then return true end for _, descendant in ipairs(container:GetDescendants()) do local name = string.lower(descendant.Name) if descendant:IsA("SpawnLocation") then return true end if descendant:IsA("BasePart") then if string.find(name, "sell", 1, true) or string.find(name, "plot", 1, true) then return true end end end return false end local function FindContainerAt(position) local nearestPart, nearestDistance = nil, math.huge for _, object in ipairs(workspace:GetDescendants()) do if object:IsA("BasePart") and not IsPlayerObject(object) then local distance = (object.Position - position).Magnitude if distance < nearestDistance then nearestPart, nearestDistance = object, distance end end end if not nearestPart then return nil end local candidates = {} for _, container in ipairs(GetAncestorContainers(nearestPart)) do if IsPlotSized(container) and ContainerHasPlotMarker(container) then table.insert(candidates, container) end end if #candidates == 0 then return nil end local innermost = {} for _, container in ipairs(candidates) do local containsAnother = false for _, other in ipairs(candidates) do if other ~= container and other:IsDescendantOf(container) then containsAnother = true break end end if not containsAnother then table.insert(innermost, container) end end for _, container in ipairs(innermost) do if ParsePlotNumber(container.Name) then return container end end return innermost[1] end local function LearnPlotFromPosition() local root = GetRoot() if not root then return nil end local container = FindContainerAt(root.Position) if container then LearnedPlotModel = container end return container end local function PlotFromPlayerState() for _, attributeName in ipairs({"Plot", "PlotNumber", "PlotId", "PlotID"}) do local ok, value = pcall(function() return LocalPlayer:GetAttribute(attributeName) end) if ok and value ~= nil then local number = tonumber(value) if not number and typeof(value) == "string" then number = ParsePlotNumber(value) end if number and number >= PLOT_MIN and number <= PLOT_MAX then return math.floor(number) end end end local leaderstats = LocalPlayer:FindFirstChild("leaderstats") if leaderstats then for _, child in ipairs(leaderstats:GetChildren()) do if string.find(string.lower(child.Name), "plot", 1, true) then local number = tonumber(child.Value) if number and number >= PLOT_MIN and number <= PLOT_MAX then return math.floor(number) end end end end return nil end local function DetectPlot() local plots = GetPlots() for plotNumber, candidate in pairs(plots) do if PlotBelongsToPlayer(candidate) then LearnedPlotModel = candidate CurrentPlot = plotNumber CurrentPlotModel = candidate return CurrentPlot, CurrentPlotModel end end local assignedNumber = PlotFromPlayerState() if assignedNumber and plots[assignedNumber] then LearnedPlotModel = plots[assignedNumber] CurrentPlot = assignedNumber CurrentPlotModel = LearnedPlotModel return CurrentPlot, CurrentPlotModel end if not LearnedPlotModel or not LearnedPlotModel.Parent then LearnedPlotModel = LearnPlotFromPosition() end if not LearnedPlotModel or not LearnedPlotModel.Parent then CurrentPlot = nil CurrentPlotModel = nil return nil, nil end CurrentPlot = assignedNumber for plotNumber, candidate in pairs(plots) do if candidate == LearnedPlotModel then CurrentPlot = plotNumber break end end CurrentPlotModel = LearnedPlotModel return CurrentPlot, CurrentPlotModel end local function WarnNoPlot(key) if PlotWarningsSent[key] then return end PlotWarningsSent[key] = true Notify( "Plot", key .. " is paused because your plot was not detected. Stand on your own plot or press Detect My Plot." ) end -- SELL PAD local function FindSellPad() local plot = CurrentPlotModel if not plot then return nil end local namedPad, anySell = nil, nil for _, object in ipairs(workspace:GetDescendants()) do if object:IsA("BasePart") and string.find(string.lower(object.Name), "sell", 1, true) and IsPositionInPlot(object.Position, plot) then local name = string.lower(object.Name) if string.find(name, "sellpad", 1, true) then namedPad = namedPad or object else anySell = anySell or object end end end return namedPad or anySell end -- TREES local function IsTreeCandidate(object) if not object:IsA("Model") and not object:IsA("BasePart") then return false end if IsPlayerObject(object) then return false end local name = string.lower(object.Name) if not string.find(name, "tree", 1, true) then return false end if string.find(name, "pad", 1, true) or string.find(name, "upgrade", 1, true) or string.find(name, "luck", 1, true) or string.find(name, "regrow", 1, true) then return false end return GetObjectPosition(object) ~= nil end local function FindNearestTree() local root = GetRoot() local plot = CurrentPlotModel if not root or not plot then return nil end local nearest, nearestDistance = nil, math.huge for _, object in ipairs(workspace:GetDescendants()) do if IsTreeCandidate(object) then local position = GetObjectPosition(object) if position and IsPositionInPlot(position, plot) then local distance = (position - root.Position).Magnitude if distance < nearestDistance then nearest, nearestDistance = object, distance end end end end return nearest, nearestDistance end local function GetTreePart(tree) if tree:IsA("BasePart") then return tree end local preferred = tree:FindFirstChild("Trunk", true) or tree:FindFirstChild("Wood", true) or tree:FindFirstChild("Log", true) if preferred and preferred:IsA("BasePart") then return preferred end return tree:FindFirstChildWhichIsA("BasePart", true) end -- AXE local function FindAxe() local character = GetCharacter() if character then for _, child in ipairs(character:GetChildren()) do if child:IsA("Tool") and Contains(child.Name, "axe") then return child end end end local backpack = LocalPlayer:FindFirstChildOfClass("Backpack") if backpack then for _, child in ipairs(backpack:GetChildren()) do if child:IsA("Tool") and Contains(child.Name, "axe") then return child end end end return nil end local function EquipAxe() local character = GetCharacter() local humanoid = GetHumanoid() local tool = FindAxe() if not character or not humanoid or not tool then return nil end if tool.Parent ~= character then pcall(function() humanoid:EquipTool(tool) end) task.wait(0.2) tool = FindAxe() end return tool end local function ChopTree(tree) local treePosition = GetObjectPosition(tree) if not treePosition then return false end local root = GetRoot() if not root then return false end TeleportTo(treePosition + Vector3.new(0, 3, 2.5)) task.wait(0.2) local tool = EquipAxe() local deadline = os.clock() + math.clamp(ChopTime, 1, 30) while os.clock() < deadline do if not ConfigValues.AutoChopToggle then return false end if not tree.Parent then break end root = GetRoot() if not root then return false end pcall(function() root.CFrame = CFrame.lookAt( root.Position, Vector3.new(treePosition.X, root.Position.Y, treePosition.Z) ) end) if not tool or not tool.Parent then tool = EquipAxe() end if tool and tool.Parent then pcall(function() tool:Activate() end) end local treePart = GetTreePart(tree) if treePart then TouchPart(treePart) end for _, descendant in ipairs(tree:GetDescendants()) do if descendant:IsA("ProximityPrompt") then FirePrompt(descendant) end end task.wait(0.25) end return true end -- LOGS local function IsLogObject(object) local name = string.lower(tostring(object.Name)) if not string.find(name, "log", 1, true) then return false end return not string.find(name, "logo", 1, true) and not string.find(name, "login", 1, true) and not string.find(name, "dialog", 1, true) and not string.find(name, "catalog", 1, true) end local function GetLogs(origin, range) local logs = {} range = range or 250 for _, object in ipairs(workspace:GetDescendants()) do local isPart = object:IsA("BasePart") local isTool = object:IsA("Tool") if (isPart or isTool) and IsLogObject(object) and not IsPlayerObject(object) then local part = isPart and object or object:FindFirstChild("Handle") if not part and isTool then part = object:FindFirstChildWhichIsA("BasePart", true) end if part and part.Parent then local position = part.Position local withinRange = true if origin then withinRange = (position - origin).Magnitude <= range end if withinRange then table.insert(logs, part) end end end end return logs end local function PickupLogs(origin) local plot = CurrentPlotModel if not plot then return end for _, part in ipairs(GetLogs(origin)) do if not ConfigValues.AutoChopToggle then return end if part and part.Parent and IsPositionInPlot(part.Position, plot) then TeleportTo(part.Position + Vector3.new(0, 2, 0)) task.wait(0.12) TouchPart(part) task.wait(0.12) end end end local function SellLogs() local sellPad = FindSellPad() if not sellPad then return false end InteractWithPart(sellPad, 0.5) return true end local function RunChopCycle() if ChopBusy then return end if not CurrentPlotModel then DetectPlot() if not CurrentPlotModel then WarnNoPlot("Auto Chop") return end end PlotWarningsSent["Auto Chop"] = nil ChopBusy = true local ok, err = pcall(function() local tree = FindNearestTree() if not tree then return end local treePosition = GetObjectPosition(tree) ChopTree(tree) if treePosition then PickupLogs(treePosition) else PickupLogs(nil) end if ConfigValues.AutoChopToggle then SellLogs() end end) ChopBusy = false if not ok then warn("[Pluto's Script Hub] Auto Chop: " .. tostring(err)) end end --================================================== -- LUMBER EMPIRE TAB --================================================== local LumberTab = Window:CreateTab( "🪓 Lumber Empire", 4483362458 ) LumberTab:CreateParagraph({ Title = "Lumber Empire", Content = "Chop, haul, and sell automatically." }) local LumberLoopTokens = {} local function StartLumberLoop(key, interval, action) LumberLoopTokens[key] = (LumberLoopTokens[key] or 0) + 1 local token = LumberLoopTokens[key] task.spawn(function() while ConfigValues[key] and LumberLoopTokens[key] == token do local ok, err = pcall(action) if not ok then warn("[Pluto's Script Hub] " .. key .. ": " .. tostring(err)) end task.wait(interval) end end) end local function StopLumberLoop(key) LumberLoopTokens[key] = (LumberLoopTokens[key] or 0) + 1 end local function BuyLumberUpgrade(upgradeName) ReplicatedStorage :WaitForChild("Remotes") :WaitForChild("BuyUpgrade") :FireServer(upgradeName) end -- PLOT LumberTab:CreateSection("Plot") local PlotParagraph = LumberTab:CreateParagraph({ Title = "Plot Detection", Content = "Detecting which plot (1-6) belongs to you..." }) LumberTab:CreateButton({ Name = "Detect My Plot", Callback = function() LearnedPlotModel = nil LearnPlotFromPosition() local number = DetectPlot() if number then Notify("Plot", "You are on Plot " .. number .. ".") elseif CurrentPlotModel then Notify("Plot", "Your plot was found. Farm tools stay inside it.") else Notify("Plot", "Could not detect your plot. Stand on your own plot and try again.") end end }) local function RefreshPlotParagraph() if PlotParagraph and type(PlotParagraph.Set) == "function" then pcall(function() PlotParagraph:Set({ Title = "Plot Detection", Content = CurrentPlot and ("You are on Plot " .. CurrentPlot .. ". Farm tools stay on this plot.") or "Plot not detected, so farm tools stay paused until it is found." }) end) end end DetectPlot() RefreshPlotParagraph() LocalPlayer.CharacterAdded:Connect(function() task.wait(2) LearnedPlotModel = nil DetectPlot() RefreshPlotParagraph() end) task.spawn(function() while task.wait(2) do local ok = pcall(DetectPlot) if not ok then CurrentPlot = nil CurrentPlotModel = nil end RefreshPlotParagraph() if CurrentPlot and CurrentPlot ~= LastNotifiedPlot then LastNotifiedPlot = CurrentPlot Notify("Plot", "You are on Plot " .. CurrentPlot) end end end) -- AUTO CHOP / SELL LumberTab:CreateSection("Auto Chop & Sell") ConfigControls.AutoChopToggle = LumberTab:CreateToggle({ Name = "Auto Chop Trees", CurrentValue = false, Flag = "AutoChopToggle", Callback = function(value) ConfigValues.AutoChopToggle = value if value then StartLumberLoop("AutoChopToggle", 1, RunChopCycle) else StopLumberLoop("AutoChopToggle") end end }) ConfigControls.AutoChopTimeSlider = LumberTab:CreateSlider({ Name = "Chop Time Per Tree", Range = {2, 15}, Increment = 1, Suffix = "s", CurrentValue = 5, Flag = "AutoChopTimeSlider", Callback = function(value) ConfigValues.AutoChopTimeSlider = value ChopTime = value end }) LumberTab:CreateParagraph({ Title = "Auto Chop Trees", Content = "Walks up to the nearest tree on your plot, equips the axe from your inventory, chops it, picks up the dropped logs, then sells at your plot's SellPad." }) -- REMOTE UPGRADES LumberTab:CreateSection("Worker & Truck Auto Upgrade") ConfigControls.AutoUpgradeToggle = LumberTab:CreateToggle({ Name = "Worker & Truck Auto Upgrade", CurrentValue = false, Flag = "AutoUpgradeToggle", Callback = function(value) ConfigValues.AutoUpgradeToggle = value if value then StartLumberLoop("AutoUpgradeToggle", 1, function() ReplicatedStorage :WaitForChild("Remotes") :WaitForChild("HireWorker") :FireServer() for _, upgradeName in ipairs({ "TruckLevel", "TruckSpeed", "WorkerPower", "WorkerCarry", "WorkerSpeed" }) do if not ConfigValues.AutoUpgradeToggle then break end BuyLumberUpgrade(upgradeName) task.wait(1) end end) else StopLumberLoop("AutoUpgradeToggle") end end }) LumberTab:CreateSection("Tree & Event Tree Auto Upgrade") ConfigControls.TreeAutoUpgradeToggle = LumberTab:CreateToggle({ Name = "Tree & Event Tree Auto Upgrade", CurrentValue = false, Flag = "TreeAutoUpgradeToggle", Callback = function(value) ConfigValues.TreeAutoUpgradeToggle = value if value then StartLumberLoop("TreeAutoUpgradeToggle", 1, function() for _, upgradeName in ipairs({ "TreeLuck", "TreeRegrow", "HauntTime", "HauntTrees" }) do if not ConfigValues.TreeAutoUpgradeToggle then break end BuyLumberUpgrade(upgradeName) task.wait(1) end end) else StopLumberLoop("TreeAutoUpgradeToggle") end end }) LumberTab:CreateSection("Worker & Rebirth") LumberTab:CreateButton({ Name = "Hire Worker", Callback = function() local success, err = pcall(function() ReplicatedStorage :WaitForChild("Remotes") :WaitForChild("HireWorker") :FireServer() end) if success then Notify("Lumber Empire", "Request sent.") else Notify("Error", tostring(err)) end end }) ConfigControls.AutoRebirthToggle = LumberTab:CreateToggle({ Name = "Auto Rebirth", CurrentValue = false, Flag = "AutoRebirthToggle", Callback = function(value) ConfigValues.AutoRebirthToggle = value if value then StartLumberLoop("AutoRebirthToggle", 1, function() ReplicatedStorage :WaitForChild("Remotes") :WaitForChild("Rebirth") :FireServer() end) else StopLumberLoop("AutoRebirthToggle") end end }) --================================================== -- AIRPORT TAB --================================================== local AirportTab = Window:CreateTab( "✈️ Airport", 4483362458 ) AirportTab:CreateParagraph({ Title = "Airport Automation", Content = "Automate hangars, flights, and airport upgrades." }) local AirportLoopTokens = {} local function StartAirportLoop(key, action) AirportLoopTokens[key] = (AirportLoopTokens[key] or 0) + 1 local token = AirportLoopTokens[key] task.spawn(function() while ConfigValues[key] and AirportLoopTokens[key] == token do local ok, err = pcall(action) if not ok then warn("[Pluto's Script Hub] " .. key .. ": " .. tostring(err)) end task.wait(1) end end) end local function StopAirportLoop(key) AirportLoopTokens[key] = (AirportLoopTokens[key] or 0) + 1 end local function GetAirportRemote(remoteName) return ReplicatedStorage :WaitForChild("Remotes") :WaitForChild(remoteName) end ConfigControls.AirportAutoHangarToggle = AirportTab:CreateToggle({ Name = "Auto Hangar", CurrentValue = false, Flag = "AirportAutoHangarToggle", Callback = function(value) ConfigValues.AirportAutoHangarToggle = value if value then StartAirportLoop("AirportAutoHangarToggle", function() local airportBuy = GetAirportRemote("AirportBuy") for _, hangarId in ipairs({1, 2, 3}) do if not ConfigValues.AirportAutoHangarToggle then break end airportBuy:FireServer(hangarId) task.wait(0.35) end end) else StopAirportLoop("AirportAutoHangarToggle") end end }) ConfigControls.AirportAutoFlightToggle = AirportTab:CreateToggle({ Name = "Auto Flight", CurrentValue = false, Flag = "AirportAutoFlightToggle", Callback = function(value) ConfigValues.AirportAutoFlightToggle = value if value then StartAirportLoop("AirportAutoFlightToggle", function() GetAirportRemote("SendPlane"):FireServer("MapleRidge") end) else StopAirportLoop("AirportAutoFlightToggle") end end }) ConfigControls.AirportAutoUpgradeToggle = AirportTab:CreateToggle({ Name = "Auto Airport Upgrade", CurrentValue = false, Flag = "AirportAutoUpgradeToggle", Callback = function(value) ConfigValues.AirportAutoUpgradeToggle = value if value then StartAirportLoop("AirportAutoUpgradeToggle", function() local buyUpgrade = GetAirportRemote("BuyUpgrade") for _, upgradeName in ipairs({ "FlightSpeed", "CargoHold", "LogDiscount" }) do if not ConfigValues.AirportAutoUpgradeToggle then break end buyUpgrade:FireServer(upgradeName) task.wait(0.35) end end) else StopAirportLoop("AirportAutoUpgradeToggle") end end }) --================================================== -- UNIVERSAL TAB --================================================== local UniversalTab = Window:CreateTab( "Universal", 4483362458 ) UniversalTab:CreateParagraph({ Title = "Universal Features", Content = "Player utilities available from the Universal tab." }) UniversalTab:CreateSection("External Script") UniversalTab:CreateParagraph({ Title = "Infinite Yield", Content = "Load Infinite Yield separately from the player utilities below." }) UniversalTab:CreateButton({ Name = "Load Infinite Yield", Callback = function() local success, err = pcall(function() loadstring(game:HttpGet( "https://raw.githubusercontent.com/EdgeIY/infiniteyield/master/source" ))() end) if not success then Notify("Error", tostring(err)) end end }) UniversalTab:CreateSection("Player Configurations") -- WALK SPEED local WalkSpeedEnabled = false local WalkSpeedValue = 32 local function ApplyWalkSpeed() local character = LocalPlayer.Character local humanoid = character and character:FindFirstChildOfClass("Humanoid") if humanoid and WalkSpeedEnabled then humanoid.WalkSpeed = WalkSpeedValue end end ConfigControls.WalkSpeedToggle = UniversalTab:CreateToggle({ Name = "Walk Speed", CurrentValue = false, Flag = "WalkSpeedToggle", Callback = function(value) ConfigValues.WalkSpeedToggle = value WalkSpeedEnabled = value ApplyWalkSpeed() end }) ConfigControls.WalkSpeedSlider = UniversalTab:CreateSlider({ Name = "Walk Speed Amount", Range = {16, 200}, Increment = 1, Suffix = "Speed", CurrentValue = 32, Flag = "WalkSpeedSlider", Callback = function(value) ConfigValues.WalkSpeedSlider = value WalkSpeedValue = value ApplyWalkSpeed() end }) -- NOCLIP local NoclipConnection local function SetNoclip(value) if NoclipConnection then NoclipConnection:Disconnect() NoclipConnection = nil end if value then NoclipConnection = RunService.Stepped:Connect(function() local character = LocalPlayer.Character if not character then return end for _, part in ipairs(character:GetDescendants()) do if part:IsA("BasePart") then part.CanCollide = false end end end) else local character = LocalPlayer.Character if character then for _, part in ipairs(character:GetDescendants()) do if part:IsA("BasePart") then part.CanCollide = true end end end end end ConfigControls.NoclipToggle = UniversalTab:CreateToggle({ Name = "Noclip", CurrentValue = false, Flag = "NoclipToggle", Callback = function(value) ConfigValues.NoclipToggle = value SetNoclip(value) end }) -- INSTANT PROXIMITY PROMPT local InstantPromptEnabled = false ConfigControls.InstantPromptToggle = UniversalTab:CreateToggle({ Name = "Instant Proximity Prompt", CurrentValue = false, Flag = "InstantPromptToggle", Callback = function(value) ConfigValues.InstantPromptToggle = value InstantPromptEnabled = value if value then Notify("Prompts", "Instant prompt enabled.") end end }) local function UpdatePrompt(prompt) if InstantPromptEnabled and prompt:IsA("ProximityPrompt") then pcall(function() prompt.HoldDuration = 0 end) end end for _, object in ipairs(workspace:GetDescendants()) do UpdatePrompt(object) end workspace.DescendantAdded:Connect(function(object) UpdatePrompt(object) end) RunService.Heartbeat:Connect(function() if not InstantPromptEnabled then return end for _, object in ipairs(workspace:GetDescendants()) do if object:IsA("ProximityPrompt") then pcall(function() object.HoldDuration = 0 end) end end end) -- ANTI-AFK local AntiAFKEnabled = false ConfigControls.AntiAFKToggle = UniversalTab:CreateToggle({ Name = "Anti-AFK", CurrentValue = false, Flag = "AntiAFKToggle", Callback = function(value) ConfigValues.AntiAFKToggle = value AntiAFKEnabled = value end }) LocalPlayer.Idled:Connect(function() if AntiAFKEnabled then pcall(function() VirtualUser:CaptureController() VirtualUser:ClickButton2(Vector2.new(0, 0)) end) end end) --================================================== -- SETTINGS TAB: NAMED CONFIGS + AUTO-LOAD --================================================== local SettingsTab = Window:CreateTab("Settings", 4483362458) local ConfigDropdown local AutoLoadToggle SettingsTab:CreateParagraph({ Title = "Configuration Manager", Content = "Save named presets of your hub toggles and slider values, then load them later or enable auto-load. Configs are stored locally by your executor." }) SettingsTab:CreateInput({ Name = "Config Name", CurrentValue = "My Config", PlaceholderText = "Enter a config name", RemoveTextAfterFocusLost = false, Flag = "ConfigNameInput", Callback = function(value) ConfigNameInputValue = tostring(value or "") end }) local function RefreshConfigDropdown() local names = ListSavedConfigs() local options = #names > 0 and names or {"No saved configs"} if ConfigDropdown and type(ConfigDropdown.Refresh) == "function" then pcall(function() ConfigDropdown:Refresh(options, true) end) end if SelectedConfigName ~= "" then local found = false for _, name in ipairs(names) do if name == SelectedConfigName then found = true break end end if not found then SelectedConfigName = "" end end return names end local function SaveCurrentConfig(name) name = CleanConfigName(name) if name == "" then Notify("Configs", "Enter a name before saving.") return false end if not EnsureConfigFolders() then Notify("Configs", "Your executor does not support the required file APIs.") return false end local ok, err = pcall(function() writefile(ConfigPath(name), HttpService:JSONEncode(ConfigValues)) end) if not ok then Notify("Config Error", tostring(err)) return false end SelectedConfigName = name RefreshConfigDropdown() Notify("Configs", "Saved config: " .. name) return true end local function LoadConfig(name, silent) name = CleanConfigName(name) if name == "" then if not silent then Notify("Configs", "Select a saved config first.") end return false end if not EnsureConfigFolders() then if not silent then Notify("Configs", "Your executor does not support the required file APIs.") end return false end local path = ConfigPath(name) local exists = false if typeof(isfile) == "function" then local ok, result = pcall(isfile, path) exists = ok and result else local ok = pcall(readfile, path) exists = ok end if not exists then if not silent then Notify("Configs", "Config not found: " .. name) end return false end local readOk, decoded = pcall(function() return HttpService:JSONDecode(readfile(path)) end) if not readOk or type(decoded) ~= "table" then if not silent then Notify("Config Error", "That config file is invalid.") end return false end for key, control in pairs(ConfigControls) do local value = decoded[key] if value ~= nil then local setOk = false if control and type(control.Set) == "function" then setOk = pcall(function() control:Set(value) end) end if not setOk then ConfigValues[key] = value end end end if decoded.HubOpacitySlider ~= nil then HubOpacity = math.clamp( tonumber(decoded.HubOpacitySlider) or 100, 0, 100 ) ConfigValues.HubOpacitySlider = HubOpacity task.spawn(function() for _ = 1, 20 do if ApplyHubOpacity() then break end task.wait(0.25) end end) end SelectedConfigName = name if not silent then Notify("Configs", "Loaded config: " .. name) end return true end local InitialConfigNames = ListSavedConfigs() local InitialConfigOptions = #InitialConfigNames > 0 and InitialConfigNames or {"No saved configs"} if #InitialConfigNames > 0 then SelectedConfigName = InitialConfigNames[1] end ConfigDropdown = SettingsTab:CreateDropdown({ Name = "Saved Configs", Options = InitialConfigOptions, CurrentOption = {InitialConfigOptions[1]}, MultipleOptions = false, Flag = "SavedConfigDropdown", Callback = function(option) if type(option) == "table" then SelectedConfigName = tostring(option[1] or "") else SelectedConfigName = tostring(option or "") end if SelectedConfigName == "No saved configs" then SelectedConfigName = "" end if AutoLoadEnabled and SelectedConfigName ~= "" then AutoLoadConfigName = SelectedConfigName SaveAutoLoadSetting() end end }) SettingsTab:CreateButton({ Name = "Save Config", Callback = function() SaveCurrentConfig(ConfigNameInputValue) end }) SettingsTab:CreateButton({ Name = "Load Selected Config", Callback = function() LoadConfig(SelectedConfigName, false) end }) SettingsTab:CreateButton({ Name = "Refresh Config List", Callback = function() RefreshConfigDropdown() Notify("Configs", "Saved config list refreshed.") end }) AutoLoadToggle = SettingsTab:CreateToggle({ Name = "Auto-Load Selected Config", CurrentValue = false, Flag = "AutoLoadConfigToggle", Callback = function(value) AutoLoadEnabled = value if value then if SelectedConfigName == "" then AutoLoadEnabled = false Notify("Configs", "Select a saved config before enabling auto-load.") task.defer(function() if AutoLoadToggle and type(AutoLoadToggle.Set) == "function" then pcall(function() AutoLoadToggle:Set(false) end) end end) return end AutoLoadConfigName = SelectedConfigName else AutoLoadConfigName = "" end if SaveAutoLoadSetting() then Notify( "Configs", value and ("Auto-load enabled for: " .. AutoLoadConfigName) or "Auto-load disabled." ) else Notify("Configs", "Could not save auto-load setting; check executor file access.") end end }) task.defer(function() task.wait(1) if not EnsureConfigFolders() then return end local ok, saved = pcall(function() if typeof(isfile) == "function" and not isfile(AUTOLOAD_PATH) then return nil end return HttpService:JSONDecode(readfile(AUTOLOAD_PATH)) end) if ok and type(saved) == "table" and saved.Enabled == true and type(saved.ConfigName) == "string" then AutoLoadConfigName = saved.ConfigName SelectedConfigName = saved.ConfigName AutoLoadEnabled = true if AutoLoadToggle and type(AutoLoadToggle.Set) == "function" then pcall(function() AutoLoadToggle:Set(true) end) else AutoLoadEnabled = true end LoadConfig(AutoLoadConfigName, true) Notify("Configs", "Auto-loaded: " .. AutoLoadConfigName) end end) --================================================== -- INFO TAB --================================================== local InfoTab = Window:CreateTab("Info", 4483362458) InfoTab:CreateParagraph({ Title = "Pluto's Script Hub", Content = "Adjust the hub panel background transparency or copy the Discord invite." }) ConfigControls.HubOpacitySlider = InfoTab:CreateSlider({ Name = "Hub Opacity", Range = {0, 100}, Increment = 5, Suffix = "%", CurrentValue = 100, Flag = "HubOpacitySlider", Callback = function(value) ConfigValues.HubOpacitySlider = value HubOpacity = value local applied = ApplyHubOpacity() if not applied then task.spawn(function() for _ = 1, 8 do task.wait(0.25) if ApplyHubOpacity() then return end end Notify( "Hub Opacity", "This Rayfield layout could not be detected, so opacity may not be supported here." ) end) end end }) InfoTab:CreateButton({ Name = "Copy Discord Invite", Callback = function() local invite = "https://discord.gg/sr9Q3rn9Bf" local copied = false if typeof(setclipboard) == "function" then copied = pcall(setclipboard, invite) elseif typeof(toclipboard) == "function" then copied = pcall(toclipboard, invite) end if copied then Notify("Discord", "Invite link copied to your clipboard!") else Notify("Discord Invite", invite .. " (clipboard access unavailable)") end end }) task.spawn(function() for _ = 1, 10 do if ApplyHubOpacity() then break end task.wait(0.5) end end) task.spawn(function() while task.wait(0.75) do if HubOpacity < 100 then ApplyHubOpacity() end end end) Notify( "Pluto's Script Hub", "Lumber Empire tools loaded!" )