infinite saplings
Key Required

infinite saplings

99 Nights in the Forest 🔦SURVIVALGOONESYSURVIVALGOONESY 3K views 245 executesUpdated Dec 23, 2025
5.0/ 5(6 votes)
60100% Positive
Lua Script•473 lines (15809 chars)
local Client = require(game.Players.LocalPlayer.PlayerScripts.Client)
local player = game.Players.LocalPlayer

local config = {
    plantDelay = 1,
    plantAmount = 3,
    surroundBase = false,
    circleRadius = 45
}

local screenGui = Instance.new("ScreenGui")
screenGui.Name = "SaplingPlanterUI"
screenGui.ResetOnSpawn = false
screenGui.Parent = player.PlayerGui

local frame = Instance.new("Frame")
frame.Size = UDim2.new(0, 320, 0, 400)
frame.Position = UDim2.new(0.5, -160, 0.5, -200)
frame.BackgroundColor3 = Color3.fromRGB(40, 40, 40)
frame.BorderSizePixel = 2
frame.BorderColor3 = Color3.fromRGB(80, 80, 80)
frame.Parent = screenGui

local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 8)
corner.Parent = frame

local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, 0, 0, 40)
title.BackgroundTransparency = 1
title.Text = "infinite saplings ;)"
title.TextColor3 = Color3.fromRGB(255, 255, 255)
title.TextSize = 20
title.Font = Enum.Font.GothamBold
title.Parent = frame

local usageLabel = Instance.new("TextLabel")
usageLabel.Size = UDim2.new(1, -20, 0, 25)
usageLabel.Position = UDim2.new(0, 10, 0, 45)
usageLabel.BackgroundTransparency = 1
usageLabel.Text = "Plant saplings.  Discord - heyboysb"
usageLabel.TextColor3 = Color3.fromRGB(200, 200, 200)
usageLabel.TextSize = 13
usageLabel.Font = Enum.Font.Gotham
usageLabel.TextXAlignment = Enum.TextXAlignment.Left
usageLabel.Parent = frame

local delayLabel = Instance.new("TextLabel")
delayLabel.Size = UDim2.new(1, -20, 0, 25)
delayLabel.Position = UDim2.new(0, 10, 0, 85)
delayLabel.BackgroundTransparency = 1
delayLabel.Text = "Plant Delay: 1s"
delayLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
delayLabel.TextSize = 14
delayLabel.Font = Enum.Font.Gotham
delayLabel.TextXAlignment = Enum.TextXAlignment.Left
delayLabel.Parent = frame

local delaySlider = Instance.new("TextBox")
delaySlider.Size = UDim2.new(1, -20, 0, 35)
delaySlider.Position = UDim2.new(0, 10, 0, 110)
delaySlider.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
delaySlider.Text = "1"
delaySlider.TextColor3 = Color3.fromRGB(255, 255, 255)
delaySlider.TextSize = 14
delaySlider.Font = Enum.Font.Gotham
delaySlider.PlaceholderText = "0-2 seconds"
delaySlider.Parent = frame

local delayCorner = Instance.new("UICorner")
delayCorner.CornerRadius = UDim.new(0, 4)
delayCorner.Parent = delaySlider

local amountLabel = Instance.new("TextLabel")
amountLabel.Size = UDim2.new(1, -20, 0, 25)
amountLabel.Position = UDim2.new(0, 10, 0, 160)
amountLabel.BackgroundTransparency = 1
amountLabel.Text = "Plant Amount: 3"
amountLabel.TextColor3 = Color3.fromRGB(255, 255, 255)
amountLabel.TextSize = 14
amountLabel.Font = Enum.Font.Gotham
amountLabel.TextXAlignment = Enum.TextXAlignment.Left
amountLabel.Parent = frame

local amountInput = Instance.new("TextBox")
amountInput.Size = UDim2.new(1, -20, 0, 35)
amountInput.Position = UDim2.new(0, 10, 0, 185)
amountInput.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
amountInput.Text = "3"
amountInput.TextColor3 = Color3.fromRGB(255, 255, 255)
amountInput.TextSize = 14
amountInput.Font = Enum.Font.Gotham
amountInput.PlaceholderText = "1-1000"
amountInput.Parent = frame

local amountCorner = Instance.new("UICorner")
amountCorner.CornerRadius = UDim.new(0, 4)
amountCorner.Parent = amountInput

local surroundToggle = Instance.new("TextButton")
surroundToggle.Size = UDim2.new(1, -20, 0, 35)
surroundToggle.Position = UDim2.new(0, 10, 0, 235)
surroundToggle.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
surroundToggle.Text = "Surround Base: OFF"
surroundToggle.TextColor3 = Color3.fromRGB(255, 255, 255)
surroundToggle.TextSize = 14
surroundToggle.Font = Enum.Font.GothamBold
surroundToggle.Parent = frame

local surroundToggleCorner = Instance.new("UICorner")
surroundToggleCorner.CornerRadius = UDim.new(0, 4)
surroundToggleCorner.Parent = surroundToggle

local radiusLabel = Instance.new("TextLabel")
radiusLabel.Size = UDim2.new(1, -20, 0, 25)
radiusLabel.Position = UDim2.new(0, 10, 0, 280)
radiusLabel.BackgroundTransparency = 1
radiusLabel.Text = "Base Radius: 45"
radiusLabel.TextColor3 = Color3.fromRGB(200, 200, 200)
radiusLabel.TextSize = 14
radiusLabel.Font = Enum.Font.Gotham
radiusLabel.TextXAlignment = Enum.TextXAlignment.Left
radiusLabel.Visible = false
radiusLabel.Parent = frame

local radiusInput = Instance.new("TextBox")
radiusInput.Size = UDim2.new(1, -20, 0, 35)
radiusInput.Position = UDim2.new(0, 10, 0, 305)
radiusInput.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
radiusInput.Text = "45"
radiusInput.TextColor3 = Color3.fromRGB(255, 255, 255)
radiusInput.TextSize = 14
radiusInput.Font = Enum.Font.Gotham
radiusInput.PlaceholderText = "41-100 studs"
radiusInput.Visible = false
radiusInput.Parent = frame

local radiusCorner = Instance.new("UICorner")
radiusCorner.CornerRadius = UDim.new(0, 4)
radiusCorner.Parent = radiusInput

local previewButton = Instance.new("TextButton")
previewButton.Size = UDim2.new(0.48, 0, 0, 40)
previewButton.Position = UDim2.new(0, 10, 0, 350)
previewButton.BackgroundColor3 = Color3.fromRGB(0, 120, 200)
previewButton.Text = "Preview"
previewButton.TextColor3 = Color3.fromRGB(255, 255, 255)
previewButton.TextSize = 16
previewButton.Font = Enum.Font.GothamBold
previewButton.Parent = frame

local previewCorner = Instance.new("UICorner")
previewCorner.CornerRadius = UDim.new(0, 6)
previewCorner.Parent = previewButton

local plantButton = Instance.new("TextButton")
plantButton.Size = UDim2.new(0.48, 0, 0, 40)
plantButton.Position = UDim2.new(0.52, 0, 0, 350)
plantButton.BackgroundColor3 = Color3.fromRGB(0, 170, 0)
plantButton.Text = "Plant"
plantButton.TextColor3 = Color3.fromRGB(255, 255, 255)
plantButton.TextSize = 16
plantButton.Font = Enum.Font.GothamBold
plantButton.Parent = frame

local buttonCorner = Instance.new("UICorner")
buttonCorner.CornerRadius = UDim.new(0, 6)
buttonCorner.Parent = plantButton


local dragging = false
local dragInput, dragStart, startPos

local function update(input)
    local delta = input.Position - dragStart
    frame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
end

frame.InputBegan:Connect(function(input)
    if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
        dragging = true
        dragStart = input.Position
        startPos = frame.Position
        
        input.Changed:Connect(function()
            if input.UserInputState == Enum.UserInputState.End then
                dragging = false
            end
        end)
    end
end)

frame.InputChanged:Connect(function(input)
    if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
        dragInput = input
    end
end)

game:GetService("UserInputService").InputChanged:Connect(function(input)
    if input == dragInput and dragging then
        update(input)
    end
end)

surroundToggle.MouseButton1Click:Connect(function()
    config.surroundBase = not config.surroundBase
    if config.surroundBase then
        surroundToggle.Text = "Surround Base: ON"
        surroundToggle.BackgroundColor3 = Color3.fromRGB(0, 170, 0)
        radiusLabel.Visible = true
        radiusInput.Visible = true
    else
        surroundToggle.Text = "Surround Base: OFF"
        surroundToggle.BackgroundColor3 = Color3.fromRGB(60, 60, 60)
        radiusLabel.Visible = false
        radiusInput.Visible = false
    end
end)

radiusInput.FocusLost:Connect(function()
    local value = tonumber(radiusInput.Text)
    if value and value >= 41 and value <= 100 then
        config.circleRadius = value
        radiusLabel.Text = "Base Radius: " .. value
    else
        radiusInput.Text = tostring(config.circleRadius)
    end
end)

delaySlider.FocusLost:Connect(function()
    local value = tonumber(delaySlider.Text)
    if value and value >= 0 and value <= 2 then
        config.plantDelay = value
        delayLabel.Text = "Plant Delay: " .. value .. "s"
    else
        delaySlider.Text = tostring(config.plantDelay)
    end
end)

amountInput.FocusLost:Connect(function()
    local value = tonumber(amountInput.Text)
    if value and value >= 1 and value <= 1000 then
        config.plantAmount = math.floor(value)
        amountLabel.Text = "Plant Amount: " .. config.plantAmount
        amountInput.Text = tostring(config.plantAmount)
    else
        amountInput.Text = tostring(config.plantAmount)
    end
end)

local function findNearestSapling()
    local character = player.Character
    if not character or not character.PrimaryPart then
        return nil
    end
    
    local playerPosition = character.PrimaryPart.Position
    local nearestSapling = nil
    local shortestDistance = math.huge
    
    for _, item in ipairs(workspace.Items:GetChildren()) do
        if item.Name == "Sapling" and item.PrimaryPart then
            local distance = (item.PrimaryPart.Position - playerPosition).Magnitude
            if distance < shortestDistance then
                shortestDistance = distance
                nearestSapling = item
            end
        end
    end
    
    return nearestSapling
end

local function FindGrassBlock(position)
    local raycastParams = RaycastParams.new()
    raycastParams.FilterDescendantsInstances = {workspace.Map.Ground, workspace.Map:FindFirstChild("Snow")}
    raycastParams.FilterType = Enum.RaycastFilterType.Include
    raycastParams.IgnoreWater = true
    
    local raycastResult = workspace:Raycast(position, Vector3.new(0, -55, 0), raycastParams)
    if raycastResult then
        return raycastResult.Position
    end
    return nil
end

local function getCirclePositions(centerPosition, radius, count)
    local positions = {}
    local angleStep = (2 * math.pi) / count
    
    for i = 0, count - 1 do
        local angle = i * angleStep
        local x = centerPosition.X + radius * math.cos(angle)
        local z = centerPosition.Z + radius * math.sin(angle)
        local position = Vector3.new(x, centerPosition.Y + 10, z)
        
        local groundPos = FindGrassBlock(position)
        if groundPos then
            table.insert(positions, groundPos)
        end
    end
    
    return positions
end

local function getCampfirePosition()
    if workspace.Map.Campground.MainFire.PrimaryPart then
        return workspace.Map.Campground.MainFire.PrimaryPart.Position
    end
    return nil
end

local previewParts = {}

local function clearPreview()
    for _, part in ipairs(previewParts) do
        if part and part.Parent then
            part:Destroy()
        end
    end
    previewParts = {}
end

local function showPreview()
    clearPreview()
    
    local campfirePos = getCampfirePosition()
    if not campfirePos then
        return
    end
    
    if config.surroundBase then
        local circlePositions = getCirclePositions(campfirePos, config.circleRadius, config.plantAmount)
        
        for i, position in ipairs(circlePositions) do
            local previewPart = Instance.new("Part")
            previewPart.Size = Vector3.new(2, 0.5, 2)
            previewPart.Position = position + Vector3.new(0, 0.5, 0)
            previewPart.Anchored = true
            previewPart.CanCollide = false
            previewPart.Transparency = 0.5
            previewPart.Material = Enum.Material.Neon
            previewPart.Color = Color3.fromRGB(0, 255, 0)
            previewPart.Parent = workspace
            table.insert(previewParts, previewPart)
        end
    else
        local targetItem = findNearestSapling()
        if not targetItem or not targetItem.PrimaryPart then
            return
        end
        
        local groundPosition = FindGrassBlock(targetItem.PrimaryPart.Position)
        if not groundPosition then
            return
        end
        
        local centerPreview = Instance.new("Part")
        centerPreview.Size = Vector3.new(2, 0.5, 2)
        centerPreview.Position = groundPosition + Vector3.new(0, 0.5, 0)
        centerPreview.Anchored = true
        centerPreview.CanCollide = false
        centerPreview.Transparency = 0.5
        centerPreview.Material = Enum.Material.Neon
        
        local distance = (campfirePos - groundPosition).Magnitude
        centerPreview.Color = distance < 40 and Color3.fromRGB(255, 0, 0) or Color3.fromRGB(0, 255, 0)
        centerPreview.Parent = workspace
        table.insert(previewParts, centerPreview)
        
        for i = 1, math.min(config.plantAmount - 1, 5) do
            local previewPart = Instance.new("Part")
            previewPart.Size = Vector3.new(2, 0.5, 2)
            previewPart.Position = groundPosition + Vector3.new(0, 0.5 + (i * 0.3), 0)
            previewPart.Anchored = true
            previewPart.CanCollide = false
            previewPart.Transparency = 0.5 + (i * 0.08)
            previewPart.Material = Enum.Material.Neon
            previewPart.Color = distance < 40 and Color3.fromRGB(255, 0, 0) or Color3.fromRGB(0, 255, 0)
            previewPart.Parent = workspace
            table.insert(previewParts, previewPart)
        end
    end
    
    task.delay(10, clearPreview)
end

local capturedArgs = nil
local capturedRemote = nil

local originalInvokeServer = Client.Events.RequestPlantItem.InvokeServer
Client.Events.RequestPlantItem.InvokeServer = function(self, ...)
    local args = {...}
    capturedArgs = args
    capturedRemote = self
    return originalInvokeServer(self, ...)
end

local function plantSapling()
    clearPreview()
    
    local targetItem = findNearestSapling()
    
    if not targetItem or not targetItem.PrimaryPart then
        return
    end
    
    local campfirePos = getCampfirePosition()
    if not campfirePos then
        return
    end
    
    if config.surroundBase then
        local circlePositions = getCirclePositions(campfirePos, config.circleRadius, config.plantAmount)
        
        if #circlePositions == 0 then
            return
        end
        
        targetItem.Parent = game.ReplicatedStorage.TempStorage
        local originalParent = targetItem.Parent
        
        local result = Client.Events.RequestPlantItem:InvokeServer(targetItem, circlePositions[1])
        
        if not result or not result.Success then
            targetItem.Parent = originalParent
            return
        end
        
        task.spawn(function()
            if capturedArgs and capturedRemote then
                for i = 2, #circlePositions do
                    task.wait(config.plantDelay)
                    capturedArgs[2] = circlePositions[i]
                    capturedRemote:InvokeServer(unpack(capturedArgs))
                end
            end
        end)
    else
        local groundPosition = FindGrassBlock(targetItem.PrimaryPart.Position)
        
        if not groundPosition then
            return
        end
        
        local distance = (campfirePos - groundPosition).Magnitude
        if distance < 40 then
            return
        end
        
        targetItem.Parent = game.ReplicatedStorage.TempStorage
        local originalParent = targetItem.Parent
        
        local result = Client.Events.RequestPlantItem:InvokeServer(targetItem, groundPosition)
        
        if not result or not result.Success then
            targetItem.Parent = originalParent
            return
        end
        
        task.spawn(function()
            if capturedArgs and capturedRemote then
                for i = 1, config.plantAmount - 1 do
                    task.wait(config.plantDelay)
                    capturedRemote:InvokeServer(unpack(capturedArgs))
                end
            end
        end)
    end
end

previewButton.MouseButton1Click:Connect(showPreview)
plantButton.MouseButton1Click:Connect(plantSapling)

Features & Information

infinite saplings from just one, lots of scripts hide this behind a paywall when its so easy to make. update ---- added a surround base feature, surrounds the base with trees.

Community Comments (13)

WuzRERBornWuzRERBornDec 23, 2025

bro your a legend for making this opensource holy

jzfssaqjzfssaqDec 23, 2025

so am thinking its patched

Replying to @jzfssaq
SURVIVALGOONESYSURVIVALGOONESYDec 24, 2025

@sebix2011wlodarz ill check if its patched now

Replying to @jzfssaq
SURVIVALGOONESYSURVIVALGOONESYDec 24, 2025

@sebix2011wlodarz its not patched

jzfssaqjzfssaqDec 24, 2025

how do i use it

Replying to @jzfssaq
SURVIVALGOONESYSURVIVALGOONESYDec 24, 2025

add me on discord, heyboysb

jzfssaqjzfssaqDec 25, 2025

added

jzfssaqjzfssaqDec 25, 2025

my discord is mexnzxc.

HCZyuHCZyuDec 28, 2025

I executed the script, but he didn't have a UI

Tuboos92Tuboos92Jan 22, 2026

does it work

99ProX99ProXFeb 16, 2026

Works 8/10 but not mobile friendly

noobernooberFeb 17, 2026(edited)

nevermind

jeruhmi523jeruhmi523Feb 28, 2026

W BRO YOU ARE A TRUE LEGEND

More Scripts for 99 Nights in the Forest 🔦