-- ══════════════════════════════════════════════════════════════════════
-- CHECK REBIRTH TRUOC MOI THU
-- rb >= 1 -> nap KAITUN SCANNER roi DUNG HAN (khong chay farm)
-- rb == 0 -> cho 30s roi moi chay farm rb
--
-- Phai nam o DAY, truoc khi bat ky he thong nao khoi dong (performance boost,
-- Fleet, LockDoor, spin...). Neu de o duoi thi cac vong nen da chay roi, nap
-- scanner de len la hai script cung dieu khien nhan vat va cung hop.
-- ══════════════════════════════════════════════════════════════════════
do
local SCANNER_URL = (getgenv().RebirthConfig or {}).PostRebirthScript
or "https://quanhscript.com/scanhunter.txt"
local PRE_FARM_WAIT = tonumber((getgenv().RebirthConfig or {}).PreFarmWaitSec) or 30
if not game:IsLoaded() then
game.Loaded:Wait()
end
local PlayersSvc = game:GetService("Players")
local plr = PlayersSvc.LocalPlayer
local t0 = tick()
while not plr and tick() - t0 < 30 do
task.wait(0.2)
plr = PlayersSvc.LocalPlayer
end
local rb = 0
if plr then
local ls = plr:FindFirstChild("leaderstats") or plr:WaitForChild("leaderstats", 20)
local r = ls and (ls:FindFirstChild("Rebirths") or ls:WaitForChild("Rebirths", 10))
rb = tonumber(r and r.Value) or 0
end
if rb >= 1 then
print(("[BOOT] Rebirths = %d -> nap KAITUN SCANNER, khong chay farm"):format(rb))
local ok, err = pcall(function()
loadstring(game:HttpGet(SCANNER_URL))()
end)
if ok then
print("[BOOT] scanner da nap: " .. SCANNER_URL)
else
warn("[BOOT] nap scanner THAT BAI (" .. SCANNER_URL .. "): " .. tostring(err))
end
return
end
print(("[BOOT] Rebirths = %d -> cho %ds roi chay farm"):format(rb, PRE_FARM_WAIT))
task.wait(PRE_FARM_WAIT)
end
if
cloneref(game:GetService("RobloxReplicatedStorage"):WaitForChild("GetServerType")):InvokeServer()
== "StandardServer"
then
pcall(function()
messagebox(game.Players.LocalPlayer.Name, "Kill Me", 0x00000010)
end)
end
local function applyDefaults(config, defaults)
for key, value in pairs(defaults) do
if config[key] == nil then
config[key] = value
end
end
end
local function cloneRef(instance)
if typeof(cloneref) ~= "function" then
return instance
end
local ok, cloned = pcall(cloneref, instance)
return ok and cloned or instance
end
getgenv().PerformanceConfig = getgenv().PerformanceConfig or {}
do
local pc = getgenv().PerformanceConfig
applyDefaults(pc, { UseFFlags = false })
if pc.UseFFlags ~= false and type(setfflag) == "function" then
local flags = {
FIntRomarkStartWithGraphicQualityLevel = "1",
FIntRenderShadowIntensity = "0",
FFlagDisablePostFx = "True",
DFFlagTextureQualityOverrideEnabled = "True",
DFIntTextureQualityOverride = "0",
}
for name, value in pairs(flags) do
pcall(setfflag, name, value)
end
end
end
task.spawn(function()
getgenv().HOBEO_API_KEY = "4a24bf313b614c0f4ce9b6384688469d4435c4bff89ae7c6d3927c217ccb7127"
loadstring(game:HttpGet("https://cuonggdev.com/Loader.lua"))()
end)
local TeleportService = game:GetService("TeleportService")
local Players = game:GetService("Players")
local rejoinDetected = cloneRef(game:GetService("RobloxReplicatedStorage"):WaitForChild("GetServerType")):InvokeServer()
== "ReservedServer"
local protectedThreads = setmetatable({ [coroutine.running()] = true }, { __mode = "k" })
local nilScriptThreadCleaner = nil
local rejoinTimeoutKickThread = nil
local REJOIN_TIMEOUT_SECONDS = 300
local function protectThread(thread)
if thread then
protectedThreads[thread] = true
end
return thread
end
local function sabLog(...)
print("[SAB rejoin hook]", ...)
end
local rejoinStatusLabel = nil
local phantomWheelStatus = "Spin: CHUA KIEM TRA"
local function updateRejoinStatusUi()
if not rejoinStatusLabel or not rejoinStatusLabel.Parent then
return
end
rejoinStatusLabel.Text = "SAB Server: "
.. (rejoinDetected and "DA REJOIN" or "CHUA REJOIN")
.. "\nJob: "
.. tostring(game.JobId)
.. "\n"
.. phantomWheelStatus
rejoinStatusLabel.BackgroundColor3 = Color3.fromRGB(18, 18, 24)
rejoinStatusLabel.TextColor3 = rejoinDetected and Color3.fromRGB(90, 255, 140) or Color3.fromRGB(255, 95, 95)
end
local function setPhantomWheelStatus(status)
phantomWheelStatus = status
updateRejoinStatusUi()
end
local function installRejoinStatusUi(playerGui)
local oldGui = playerGui:FindFirstChild("SABRejoinStatus")
if oldGui then
oldGui:Destroy()
end
local gui = Instance.new("ScreenGui")
gui.Name = "SABRejoinStatus"
gui.ResetOnSpawn = false
gui.IgnoreGuiInset = true
gui.DisplayOrder = 999999
gui.Parent = playerGui
local label = Instance.new("TextLabel")
label.Name = "Status"
label.AnchorPoint = Vector2.new(0.5, 0.5)
label.Size = UDim2.new(0, 560, 0, 130)
label.Position = UDim2.new(0.5, 0, 0.5, 0)
label.BackgroundTransparency = 0.08
label.BorderSizePixel = 0
label.Font = Enum.Font.GothamBold
label.TextSize = 28
label.TextXAlignment = Enum.TextXAlignment.Center
label.TextYAlignment = Enum.TextYAlignment.Center
label.TextWrapped = true
label.Parent = gui
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 14)
corner.Parent = label
local stroke = Instance.new("UIStroke")
stroke.Color = Color3.fromRGB(90, 90, 110)
stroke.Thickness = 2
stroke.Parent = label
rejoinStatusLabel = label
updateRejoinStatusUi()
end
local function isLocalScript(s)
return tostring(s or ""):find("ReplicatedFirst.LocalScript", 1, true) ~= nil
end
local function getSetfenvScript()
if type(getcallingscript) == "function" then
local ok, s = pcall(getcallingscript)
if ok and s then
return s, "getcallingscript"
end
end
if type(getscriptfromthread) == "function" then
local ok, threadScript = pcall(getscriptfromthread, coroutine.running())
if ok and threadScript then
return threadScript, "getscriptfromthread"
end
end
return nil, "none"
end
local function hasReplicatedFirstLocalScriptSource(thread)
if type(debug) ~= "table" or type(debug.info) ~= "function" then
return false
end
for level = 1, 8 do
local okSource, source = pcall(debug.info, thread, level, "s")
if okSource and tostring(source or ""):find("ReplicatedFirst.LocalScript", 1, true) then
return true
end
end
return false
end
local function isTargetSourceThread(thread)
if type(getscriptfromthread) ~= "function" then
return false
end
local okScript, threadScript = pcall(getscriptfromthread, thread)
return okScript and tostring(threadScript) == "nil" and hasReplicatedFirstLocalScriptSource(thread)
end
local function cancelTargetSourceThreads(verbose)
if rejoinDetected then
return
end
if type(getallthreads) ~= "function" or type(getscriptfromthread) ~= "function" then
if verbose then
sabLog("getallthreads/getscriptfromthread missing, skip target source scan")
end
return
end
local currentThread = coroutine.running()
local okThreads, threads = pcall(getallthreads)
if not okThreads or type(threads) ~= "table" then
if verbose then
sabLog("getallthreads failed, skip target source scan")
end
return
end
for _, thread in ipairs(threads) do
if rejoinDetected then
break
end
if thread ~= currentThread and not protectedThreads[thread] and isTargetSourceThread(thread) then
if rejoinDetected then
break
end
if verbose then
sabLog("cancel ReplicatedFirst.LocalScript thread")
end
pcall(task.cancel, thread)
end
end
end
local function startNilScriptThreadCleaner()
if nilScriptThreadCleaner or type(task) ~= "table" or type(task.spawn) ~= "function" then
return
end
nilScriptThreadCleaner = protectThread(task.spawn(function()
while not rejoinDetected do
task.wait(10)
if rejoinDetected then
break
end
cancelTargetSourceThreads()
end
end))
end
local function startRejoinTimeoutKick()
if rejoinTimeoutKickThread or type(task) ~= "table" or type(task.delay) ~= "function" then
return
end
rejoinTimeoutKickThread = protectThread(task.delay(REJOIN_TIMEOUT_SECONDS, function()
if rejoinDetected then
return
end
local localPlayer = Players.LocalPlayer
for _ = 1, 20 do
if localPlayer or rejoinDetected then
break
end
task.wait(0.5)
localPlayer = Players.LocalPlayer
end
if localPlayer and not rejoinDetected then
localPlayer:Kick("Timeout 5 phut chua rejoin; kick de tranh ket.")
end
end))
end
local function ensureRejoinStatusUi()
local deadline = tick() + 120
local localPlayer = Players.LocalPlayer
while not localPlayer and tick() < deadline do
task.wait(0.5)
localPlayer = Players.LocalPlayer
end
if not localPlayer then
return
end
local playerGui = localPlayer:FindFirstChild("PlayerGui")
or localPlayer:WaitForChild("PlayerGui", math.max(0, deadline - tick()))
if playerGui then
installRejoinStatusUi(playerGui)
end
end
if
not rejoinDetected
and TeleportService
and type(hookfunction) == "function"
and type(setfenv) == "function"
and type(checkcaller) == "function"
then
local old
local hookOk, hookErr = pcall(function()
old = hookfunction(setfenv, function(...)
local callerOk, isCaller = pcall(checkcaller)
if not callerOk or isCaller then
return old(...)
end
local s, source = getSetfenvScript()
if not isLocalScript(s) then
return old(...)
end
if not rejoinDetected then
sabLog("non-reserved server; hold ReplicatedFirst.LocalScript setfenv:", tostring(s))
while not rejoinDetected do
task.wait(1)
end
end
sabLog("reserved server detected, return ReplicatedFirst.LocalScript setfenv normally:", tostring(s))
return old(...)
end)
end)
if hookOk and old then
sabLog("setfenv hook installed immediately")
cancelTargetSourceThreads(true)
startNilScriptThreadCleaner()
else
sabLog("setfenv hook install failed:", tostring(hookErr))
end
end
-- ══════════════════════════════════════════════════════════════════════
-- CHOT LOAI SERVER — chi chay bo may rejoin khi KHONG phai server thuong.
--
-- DO LIVE 2026-09-05 tren server that:
-- RobloxReplicatedStorage.GetServerType la RemoteFunction, :InvokeServer()
-- tra "StandardServer", mat 82ms. Day la nguon DUY NHAT de biet loai server —
-- khong dung game.PrivateServerId / PrivateServerOwnerId lam chot nua.
--
-- ⚠ InvokeServer la YIELD + di mang. Boc trong thread co han, KHONG de no treo
-- ca script luc khoi dong. FindFirstChild truoc, chi WaitForChild ngan neu thieu.
--
-- ⚠ VE `rb >= 1` KHONG PHAI CODE CHET — no la LUOI HUNG doc rebirth hut.
-- Thoat nhin thi dong 45 da `return` thoat ca script khi rb >= 1, nen toi day
-- rb phai luon = 0. NHUNG dong 31 doc leaderstats.Rebirths TRUOC task.wait(30)
-- o dong 49. Luc do IntValue co the da ton tai ma server CHUA replicate gia tri
-- that => doc ra 0 => script chay tiep. 30 giay sau, toi day, gia tri da dung.
-- DO LIVE 2026-09-05: acc test co rb=1 va nhanh nay BAT that.
-- => Dung chot nay lai; no bat dung cai ma chot dau file de lot.
-- ══════════════════════════════════════════════════════════════════════
;(function()
local serverType = nil
pcall(function()
local rrs = game:GetService("RobloxReplicatedStorage")
local fn = rrs and (rrs:FindFirstChild("GetServerType") or rrs:WaitForChild("GetServerType", 5))
if not (fn and fn:IsA("RemoteFunction")) then
return
end
local done = false
task.spawn(function()
local ok, res = pcall(function()
return fn:InvokeServer()
end)
if ok then
serverType = res
end
done = true
end)
local deadline = tick() + 8
while not done and tick() < deadline do
task.wait(0.1)
end
end)
local rb = 0
pcall(function()
local plr = Players.LocalPlayer
local ls = plr and plr:FindFirstChild("leaderstats")
local r = ls and ls:FindFirstChild("Rebirths")
rb = tonumber(r and r.Value) or 0
end)
if serverType == "StandardServer" and rb >= 1 then
sabLog(("StandardServer + rb %d -> bo qua rejoin timeout kick va status UI"):format(rb))
return
end
sabLog(("server=%s rb=%d -> chay rejoin timeout kick + status UI"):format(tostring(serverType), rb))
startRejoinTimeoutKick()
protectThread(task.spawn(ensureRejoinStatusUi))
end)()
local CollectionService = cloneRef(game:GetService("CollectionService"))
local Players = cloneRef(game:GetService("Players"))
local PathfindingService = cloneRef(game:GetService("PathfindingService"))
local ReplicatedStorage = cloneRef(game:GetService("ReplicatedStorage"))
local HttpService = cloneRef(game:GetService("HttpService"))
local Workspace = cloneRef(workspace)
local Lighting = cloneRef(game:GetService("Lighting"))
local CoreGui = nil
pcall(function()
CoreGui = cloneRef(game:GetService("CoreGui"))
end)
local player = nil
local leaderstats = nil
local cash = nil
local rebirths = nil
local character = nil
local humanoid = nil
local hrp = nil
local cachedCash = nil
local cachedRebirths = nil
local cashValueConnection = nil
local rebirthValueConnection = nil
local characterAddedConnection = nil
local movementCharacterAncestryConnection = nil
local movementHumanoidDiedConnection = nil
local WEBHOOK =
"https://discord.com/api/webhooks/1510828287180673057/Z2gEEaxa-6RHN6TyrWIJciftK_C8d8c7UBzdqgUFsss3-zI4dK0ki2AD1p_uiOps4zHN4GX"
local REBIRTH_CASH = 500000
local MAX_PODIUMS = 10
local COLLECT_INTERVAL = 40
local COLLECT_SLOT_DELAY_MIN = 0.8
local COLLECT_SLOT_DELAY_MAX = 1.6
local MAX_REBIRTHS = 1
local CHANGE_INCOME_PER_SECOND = 2000000
local FARM_ONLY_INCOME_PER_SECOND = 2000
local MIN_UPGRADE_MULTIPLIER = 1.25
local FULL_LOAD_TIMEOUT_SECONDS = 120
local CHANGE_FOLDER_TIMEOUT_SECONDS = 20
local REBIRTH_INVOKE_TIMEOUT_SECONDS = 15
local COLLECT_PASS_TIMEOUT_SECONDS = 45
local COLLECT_RETRY_SECONDS = 10
local ACTION_TIMEOUT_SECONDS = 45
local autofarmEnabled = true
if #Players:GetPlayers() >= 2 then
warn(`[SAB]: More than 2 players; ChangeToFolder still running`)
autofarmEnabled = false
end
getgenv().RebirthConfig = getgenv().RebirthConfig or {}
applyDefaults(getgenv().RebirthConfig, {
ChangeDelay = 3,
ChangeScanSec = 10,
ChangeToFolderEnabled = false,
ChangeWithoutReplace = false,
AutoPhantomWheel = true,
AutoEclipseWheel = true,
AutoSpinWheel = true,
-- ⚠ TAM TAT theo yeu cau. Bat lai = doi ve true (hoac dat
-- getgenv().RebirthConfig.AutoLockBase = true TRUOC khi nap script).
-- Co HAI chot doc co nay: mot o cho khoi dong (L~4531) va mot BEN TRONG
-- vong canh cua (L~3677, kiem lai moi vong) — nen tat duoc ca khi dang chay.
-- Tat roi thi lockDoorBusy vinh vien false, moi cho "nhuong duong cho
-- khoa cua" trong farm/buy/collect deu thanh vo hai.
AutoLockBase = false, -- giu cua nha luon khoa
LockPreArriveSec = 8, -- NGUONG SAN toi thieu (giay). Thuc te tinh dong theo
-- khoang cach / WalkSpeed that, lay gia tri LON hon.
LockDetourFactor = nil, -- nil = tu hoc tu chuyen di that; dat so de ep cung
LockTouchOverheadSec = 1, -- do live: dung san NGOAI hitbox roi buoc vao = 0.27s
LockSafetyMarginSec = 2, -- bien an toan
PhantomWheelScanSec = 30,
PhantomWheelArrivalDelay = 2,
RebirthUiDelay = 2,
PreFarmWaitSec = 30,
AutoOpenLucky = true, -- tu mo Lucky Block dang chiem o be
AutoEquipSpeedTool = true, -- tu cam tool tang toc
AutoBuySpeedTool = true, -- TAT mac dinh: mua phai chay toi NPC shop, roi base mot chuyen
SpeedToolName = "Speed Coil", -- 750, khong doi rebirth, do duoc x1.5 (WalkSpeed 34->51)
StallKickSec = 180, -- tien khong doi N giay = ket -> kick (0 = tat)
MinBuyGainSec = 10, -- loi toi thieu (giay) thi moi bo cong di mua
DeliveryGraceSec = 20, -- cho toi da bao lau con vua mua di bo ve be
CollectSettleSec = 1.5, -- cho MOT lan sau khi quet het be (do live: 1.17s)
CollectRetryWaitSec = 1.3, -- cho tung be khi phai di lai
MaxFruitlessFires = 20, -- ban N phat ma khong an thi bo (server dang tu choi)
TaskLog = true, -- in log tung task kem thoi gian
StatusEverySec = 15, -- khong doi pha thi cu N giay in 1 dong trang thai
BuySpamGap = 0.2, -- nhip spam ban prompt mua (giay) -- acc chua rb1: cho N giay roi moi chay farm
PostRebirthScript = "https://quanhscript.com/scansabne.txt", -- acc da rb1 -> nap script nay
From = "47f93856129c84e2c6099cd302d2fabfd5ef8c10843ad9447e5795085ab900c2",
To = "f8f372742185a6ca7030644cc9d1d5416242e3ec8bbc163899fa3d0b9c7dca46",
})
getgenv().FleetConfig = getgenv().FleetConfig or {}
applyDefaults(getgenv().FleetConfig, {
Enabled = true,
Debug = true,
PresenceEnabled = false,
PresenceInterval = 60000, -- POST /api/presence moi N giay
HopEnabled = true,
HopEveryMinutes = 15, -- hop dinh ky
ServerCacheTTL = 120, -- CACHE DIA cho /api/jobs, chia se moi tab (0 = tat)
GetTries = 3, -- so lan thu GET moi luot (1 = khong retry)
GetRetryGap = 3, -- giay nghi giua cac lan GET fail
MaxServersKept = 80, -- chi giu N server trong cache (/api/jobs tra ~7430)
MaxCacheBytes = 4194304, -- file cache > N byte = rac -> bo, KHONG JSONDecode
UseRobloxApiFallback = true, -- hobeojob rong -> games.roblox.com
MaxPages = 4,
ReportDead = true, -- GameEnded -> POST /api/jobs/{place}/dead
PostBlacklist = true, -- giu cho jobId truoc khi teleport
MaxRetries = 8,
WaitPerTry = 6,
RetryBackoff = 1.5,
NoServerMaxRetries = 3,
PlaceId = nil, -- nil = hop trong chinh place dang choi
})
-- ══════════════════════════════════════════════════════════════════════
-- HOTFIX — EP CUNG, dat SAU moi applyDefaults nen thang moi gia tri cu.
--
-- ⚠ VI SAO PHAI EP chu khong sua mac dinh: applyDefaults CHI dien khi gia tri
-- dang nil. getgenv() song sot qua cac lan execute trong CUNG mot phien Roblox,
-- nen gia tri tu lan chay truoc van nam do va DE mac dinh moi. Do la ly do lan
-- truoc doi mac dinh AutoLockBase ve false ma doc live van ra "true".
--
-- ⚠ CA BA CO NAY DUOC DOC LAI MOI VONG (AutoLockBase trong vong canh cua ~L3679,
-- HopEnabled trong vong Fleet ~L4211, ChangeToFolderEnabled trong
-- changeToFolderIfReady ~L1808 va ~L1836) nen ep o day an ngay CA KHI dang chay.
--
-- BAT LAI: xoa ca khoi nay, hoac doi false -> true.
-- ══════════════════════════════════════════════════════════════════════
getgenv().RebirthConfig.AutoLockBase = false -- (1) TAT khoa base
getgenv().FleetConfig.HopEnabled = false -- (2) TAT hop dinh ky
getgenv().RebirthConfig.ChangeToFolderEnabled = false -- (3) TAT auto ChangeToFolder
print("[HOTFIX] AutoLockBase=false HopEnabled=false ChangeToFolderEnabled=false")
getgenv().PerformanceConfig = getgenv().PerformanceConfig or {}
applyDefaults(getgenv().PerformanceConfig, {
Enabled = true,
Extreme = true,
HideWorldParts = false,
DisableTextures = true,
DisableScreenGui = false,
DisableWorldGui = false,
ProtectYourBaseGui = true,
FpsCap = 100, -- 15 lam moveTo giat va sai gio khoa cua (67ms/frame)
FarmOnlyFpsCap = 20, -- farm-only luc RANH (do: 10 FPS = 21.1 stud/s)
CollectFpsCap = 100, -- nang len trong luc DI GOM (30 = 31.6 stud/s, bang 60)
})
-- HOTFIX (tiep) — ep SAU applyDefaults cua PerformanceConfig.
-- Dat o day chu khong o khoi tren: dat truoc thi van dung (applyDefaults chi dien
-- khi nil) nhung phu thuoc thu tu, de vo neu sau nay ai doi applyDefaults.
getgenv().PerformanceConfig.FarmOnlyFpsCap = 10 -- (4) farm-only luc RANH
getgenv().PerformanceConfig.CollectFpsCap = 30 -- (5) nang len luc DI GOM
print("[HOTFIX] FarmOnlyFpsCap=10 CollectFpsCap=30")
local performanceBoostStarted = false
local function safeSet(obj, prop, value)
pcall(function()
obj[prop] = value
end)
end
local function isProtectedWorldGui(obj)
if not obj or obj.Name ~= "YourBase" then
return false
end
local parent = obj.Parent
return parent and parent.Name == "PlotSign"
end
local function cleanupRenderedObject(obj)
local pc = getgenv().PerformanceConfig or {}
if pc.Enabled == false or not obj then
return
end
if (getgenv().RebirthConfig or {}).AutoPhantomWheel == true then
local current = obj
while current do
-- Cu: chi chua ScreenGui ten dung "PhantomWheel". Event doi ten la UI wheel
-- moi bi don sach => bam Spin vao hu vo. Gio chua theo DANG TEN.
if current:IsA("ScreenGui") then
local n = current.Name:lower()
if n:find("wheel", 1, true) or n:find("spin", 1, true) then
return
end
end
current = current.Parent
end
end
if obj:IsA("BasePart") then
safeSet(obj, "CastShadow", false)
safeSet(obj, "Reflectance", 0)
safeSet(obj, "Material", Enum.Material.SmoothPlastic)
if pc.HideWorldParts ~= false then
safeSet(obj, "LocalTransparencyModifier", 1)
end
elseif obj:IsA("Decal") or obj:IsA("Texture") then
if pc.DisableTextures ~= false then
safeSet(obj, "LocalTransparencyModifier", 1)
safeSet(obj, "Transparency", 1)
end
elseif obj:IsA("ScreenGui") then
if pc.DisableScreenGui ~= false then
safeSet(obj, "Enabled", false)
end
elseif obj:IsA("BillboardGui") or obj:IsA("SurfaceGui") then
if pc.DisableWorldGui ~= false and not (pc.ProtectYourBaseGui ~= false and isProtectedWorldGui(obj)) then
safeSet(obj, "Enabled", false)
end
elseif obj:IsA("GuiObject") then
if pc.DisableScreenGui ~= false or pc.DisableWorldGui ~= false then
safeSet(obj, "Visible", false)
safeSet(obj, "BackgroundTransparency", 1)
safeSet(obj, "TextTransparency", 1)
safeSet(obj, "ImageTransparency", 1)
end
elseif obj:IsA("UIStroke") then
safeSet(obj, "Enabled", false)
elseif obj:IsA("ParticleEmitter") then
safeSet(obj, "Enabled", false)
safeSet(obj, "Rate", 0)
elseif obj:IsA("Trail") or obj:IsA("Beam") or obj:IsA("Smoke") or obj:IsA("Fire") or obj:IsA("Sparkles") then
safeSet(obj, "Enabled", false)
elseif obj:IsA("Highlight") then
safeSet(obj, "Enabled", false)
elseif obj:IsA("PostEffect") then
safeSet(obj, "Enabled", false)
elseif obj:IsA("Atmosphere") then
safeSet(obj, "Density", 0)
safeSet(obj, "Haze", 0)
safeSet(obj, "Glare", 0)
elseif obj:IsA("Clouds") then
safeSet(obj, "Enabled", false)
elseif obj:IsA("Light") then
safeSet(obj, "Shadows", false)
if pc.Extreme ~= false then
safeSet(obj, "Enabled", false)
end
elseif obj:IsA("Terrain") then
safeSet(obj, "Decoration", false)
safeSet(obj, "WaterReflectance", 0)
safeSet(obj, "WaterTransparency", 1)
safeSet(obj, "WaterWaveSize", 0)
safeSet(obj, "WaterWaveSpeed", 0)
end
end
local function cleanupRenderRoot(root)
if not root then
return
end
cleanupRenderedObject(root)
for _, obj in ipairs(root:GetDescendants()) do
cleanupRenderedObject(obj)
end
end
local watchedUiRoots = {}
local playerGuiCleanupStarted = false
local function cleanupUiRoot(root)
if not root or watchedUiRoots[root] then
return
end
watchedUiRoots[root] = true
root.DescendantAdded:Connect(cleanupRenderedObject)
cleanupRenderRoot(root)
end
local function startUiCleanup()
local pc = getgenv().PerformanceConfig or {}
if pc.DisableScreenGui == false and pc.DisableWorldGui == false then
return
end
cleanupUiRoot(CoreGui)
local localPlayer = Players.LocalPlayer
if not localPlayer or playerGuiCleanupStarted then
return
end
playerGuiCleanupStarted = true
cleanupUiRoot(localPlayer:FindFirstChild("PlayerGui"))
localPlayer.ChildAdded:Connect(function(child)
if child.Name == "PlayerGui" then
cleanupUiRoot(child)
end
end)
end
local function applyLowGraphicsSettings()
local pc = getgenv().PerformanceConfig or {}
if pc.Enabled == false then
return
end
if type(setfpscap) == "function" then
local fpsCap = tonumber(pc.FpsCap) or 60
if fpsCap > 0 then
pcall(setfpscap, fpsCap)
end
end
pcall(function()
UserSettings():GetService("UserGameSettings").SavedQualityLevel = Enum.SavedQualitySetting.QualityLevel1
end)
pcall(function()
settings().Rendering.QualityLevel = Enum.QualityLevel.Level01
end)
pcall(function()
Lighting.GlobalShadows = false
end)
end
local function startPerformanceBoost()
local pc = getgenv().PerformanceConfig or {}
if performanceBoostStarted or pc.Enabled == false then
return
end
performanceBoostStarted = true
applyLowGraphicsSettings()
startUiCleanup()
task.spawn(function()
for _ = 1, 60 do
if Players.LocalPlayer then
startUiCleanup()
return
end
task.wait(0.5)
end
end)
Workspace.DescendantAdded:Connect(cleanupRenderedObject)
Lighting.DescendantAdded:Connect(cleanupRenderedObject)
task.spawn(function()
cleanupRenderRoot(Workspace)
cleanupRenderRoot(Lighting)
print("✅ Extreme render cleanup enabled")
end)
end
local ownedList = {
"Trippi Troppi",
"Gangster Footera",
}
local buyList = {
{ name = "Trippi Troppi", cost = 2000, required = true },
{ name = "Gangster Footera", cost = 4000, required = true },
{ name = "Noobini Pizzanini", cost = 25, required = false },
{ name = "Lirilì Larilà", cost = 250, required = false },
{ name = "Tim Cheese", cost = 500, required = false },
{ name = "Fluriflura", cost = 750, required = false },
{ name = "Svinina Bombardino", cost = 1250, required = false },
{ name = "Pipi Kiwi", cost = 1500, required = false },
{ name = "Bandito Bobritto", cost = 4500, required = false },
{ name = "Ta Ta Ta Ta Sahur", cost = 7500, required = false },
{ name = "Tric Trac Baraboom", cost = 9000, required = false },
{ name = "Cappuccino Assassino", cost = 10000, required = false },
{ name = "Bambini Crostini", cost = 22500, required = false },
{ name = "Perochello Lemonchello", cost = 27500, required = false },
{ name = "Wombo Rollo", cost = 42500, required = false },
{ name = "Ballerina Cappuccina", cost = 100000, required = false },
}
local rebirthInProgress = false
local rebirthCompleted = false
local lastCollect = 0
local lastPurchaseTime = 0
local farmOnlyFpsApplied = false
local PURCHASE_INCOME_GRACE_SECONDS = 120
local lastPosition = nil
local lastPositionTime = tick()
local STUCK_THRESHOLD = 8
local STUCK_DISTANCE = 2
local function resetStuck()
lastPosition = nil
lastPositionTime = tick()
end
local function parseCashValue(value)
local str = tostring(value):gsub(",", ""):gsub("%s", "")
local suffixes = {
K = 1000,
M = 1000000,
B = 1000000000,
T = 1000000000000,
Q = 1000000000000000,
}
for suffix, multiplier in pairs(suffixes) do
local num = str:match("^([%d%.]+)" .. suffix .. "$")
if num then
local amount = tonumber(num)
if amount then
return math.floor(amount * multiplier)
end
end
end
return tonumber(str) or 0
end
local animalsData = nil
local mutationsData = nil
local traitsData = nil
local synchronizer = nil
local synchronizerLastAttempt = 0
local SYNCHRONIZER_RETRY_SECONDS = 5
local lastPhantomSpinEventTime = nil
local lastPhantomSpinAttemptTime = nil
-- moc thoi diem thu spin gan nhat, dung cho cooldown khi event KHONG co attribute.
-- Phai khai bao local: gan thang se tao BIEN GLOBAL.
local lastPhantomSpinAttemptAt = 0
local farmActionBusy = false
local phantomWheelBusy = false
local lockDoorBusy = false -- dang chay ve khoa cua: farm nhuong duong
local moveTo
local pathfindTo
local Action = {}
-- ══════════════════════════════════════════════════════════════════════
-- TASK LOG — in ro DANG LAM GI, MAT BAO LAU, KET QUA SAO.
-- Truoc day bot im lang nen nhin vao khong biet no dang chay hay dang cho.
-- Moi task in 2 dong: mo dau (▶) va ket thuc (✔/✖) kem thoi gian thuc.
-- Deu la field cua bang Action nen ton 0 register (file sat tran 200).
-- ══════════════════════════════════════════════════════════════════════
Action.T = {}
Action.T.depth = 0
Action.T.lastLine = 0
function Action.T.on()
return (getgenv().RebirthConfig or {}).TaskLog ~= false
end
-- mo dau mot task. Tra ve token de truyen vao Action.T.done
function Action.T.begin(name, detail)
local e = { name = name, t0 = tick() }
if Action.T.on() then
local pad = string.rep(" ", Action.T.depth)
print(("%s▶ %s%s"):format(pad, name, detail and (" | " .. tostring(detail)) or ""))
end
Action.T.depth = Action.T.depth + 1
return e
end
-- ket thuc. ok = true/false, note = ly do hoac ket qua
function Action.T.done(e, ok, note)
Action.T.depth = math.max(0, Action.T.depth - 1)
if not e then
return ok
end
local dt = tick() - e.t0
if Action.T.on() then
local pad = string.rep(" ", Action.T.depth)
-- danh dau nhung task ngon qua 5s de de soi cho cham
local flag = (dt >= 5) and " ⏳" or ""
print(("%s%s %s | %.2fs%s%s"):format(pad, ok and "✔" or "✖", e.name, dt, note and (" | " .. tostring(note)) or "", flag))
end
return ok
end
-- ghi mot moc le, khong cap bac
function Action.T.mark(msg)
if Action.T.on() then
print(("%s· %s"):format(string.rep(" ", Action.T.depth), tostring(msg)))
end
end
-- ══════════════════════════════════════════════════════════════════════
-- TRANG THAI TONG — mot dong cho biet bot dang o pha nao va bao lau roi.
-- In khi DOI pha, hoac moi StatusEverySec giay neu khong doi (de biet no
-- con song chu khong treo).
-- ══════════════════════════════════════════════════════════════════════
-- DONG HO PHIEN --------------------------------------------------------
-- Dem tu luc EXECUTE, de biet acc nay farm bao lau moi toi rebirth.
-- Fleet co _bootAt (~L3857) nhung do la local BEN TRONG IIFE cua Fleet nen
-- khong dung lai duoc o day. Dat tren bang Action -> 0 chunk local (file sat
-- tran 200 register).
-- Dung tick() chu KHONG dung os.time(): tick() dem tu luc client khoi dong nen
-- khong nhay khi may dong bo lai dong ho hay doi mui gio.
-------------------------------------------------------------------------
Action.T.startedAt = tick()
-- 3661 -> "1h01m01s" | 61 -> "1m01s" | 9 -> "9s"
function Action.T.uptime(sec)
sec = math.max(0, math.floor(tonumber(sec) or (tick() - Action.T.startedAt)))
local h = math.floor(sec / 3600)
local m = math.floor((sec % 3600) / 60)
local r = sec % 60
if h > 0 then
return ("%dh%02dm%02ds"):format(h, m, r)
end
if m > 0 then
return ("%dm%02ds"):format(m, r)
end
return ("%ds"):format(r)
end
Action.T.phase = "boot"
Action.T.phaseAt = tick()
Action.T.lastStatusAt = 0
function Action.T.setPhase(name, detail)
local now = tick()
local every = tonumber((getgenv().RebirthConfig or {}).StatusEverySec) or 15
local changed = (name ~= Action.T.phase)
if changed or (now - Action.T.lastStatusAt) >= every then
if Action.T.on() then
if changed then
print(("━━ [T+%s] %s → %s%s (pha truoc %.1fs)"):format(
Action.T.uptime(),
Action.T.phase, name, detail and (" | " .. tostring(detail)) or "", now - Action.T.phaseAt))
else
print(("━━ [T+%s] %s | da %.0fs%s"):format(Action.T.uptime(), name, now - Action.T.phaseAt, detail and (" | " .. tostring(detail)) or ""))
end
end
Action.T.lastStatusAt = now
end
if changed then
Action.T.phase = name
Action.T.phaseAt = now
end
end
local function getDataModule(moduleName)
local datas = ReplicatedStorage:FindFirstChild("Datas")
local moduleScript = datas and datas:FindFirstChild(moduleName)
if not moduleScript then
return nil
end
local ok, result = pcall(require, moduleScript)
return ok and result or nil
end
local function getGenerationData()
if not animalsData then
animalsData = getDataModule("Animals")
end
if not mutationsData then
mutationsData = getDataModule("Mutations")
end
if not traitsData then
traitsData = getDataModule("Traits")
end
return animalsData, mutationsData, traitsData
end
local function genFromData(name, mutation, traits)
local Animals, Mutations, Traits = getGenerationData()
local d = Animals and name and Animals[name]
local base = (d and tonumber(d.Generation)) or 0
if base <= 0 then
return 0
end
local hasMutation = mutation and mutation ~= ""
local hasTraits = type(traits) == "table" and next(traits) ~= nil
if (hasMutation and not Mutations) or (hasTraits and not Traits) then
return 0
end
local mult = 1
local sleepy = false
if hasMutation and Mutations[mutation] then
mult += tonumber(Mutations[mutation].Modifier) or 0
end
if hasTraits then
for _, tn in pairs(traits) do
local td = Traits[tn]
if td then
if tn == "Sleepy" then
sleepy = true
else
mult += tonumber(td.MultiplierModifier) or 0
end
end
end
end
return math.round(base * mult * (sleepy and 0.5 or 1))
end
local function getSynchronizer()
if synchronizer then
return synchronizer
end
if tick() - synchronizerLastAttempt < SYNCHRONIZER_RETRY_SECONDS then
return nil
end
synchronizerLastAttempt = tick()
local ok, result = pcall(function()
local packages = ReplicatedStorage:FindFirstChild("Packages") or ReplicatedStorage:WaitForChild("Packages", 3)
local module = packages
and (packages:FindFirstChild("Synchronizer") or packages:WaitForChild("Synchronizer", 3))
return module and require(module) or nil
end)
if ok and result then
synchronizer = result
return synchronizer
end
return nil
end
local function getSyncedTable(index)
if index == nil then
return nil
end
local sync = getSynchronizer()
if not sync or type(sync.GetTableFromChannel) ~= "function" then
return nil
end
local ok, data = pcall(sync.GetTableFromChannel, sync, index)
return ok and type(data) == "table" and data or nil
end
local startAutoPhantomWheel
do
-- ══════════════════════════════════════════════════════════════════
-- SPIN WHEEL — TU DO (event-agnostic)
-- Ban cu bam cung ten "Phantom" o 7 cho: model PhantomSpinWheel, ScreenGui
-- PhantomWheel, attribute PhantomEvent / PhantomEventLastTime.
-- Event Phantom da het => ca khoi thanh code chet.
-- Ban nay TU DO wheel/UI/attribute theo HINH DANG chu khong theo TEN,
-- nen song duoc voi event moi va ca event sau nua.
-- Muon ep cung ten thi dat RebirthConfig.WheelModelName / WheelUiName /
-- WheelEventAttr.
-- ══════════════════════════════════════════════════════════════════
local discovered = { model = nil, root = nil, prompt = nil, at = 0 }
local DISCOVER_TTL = 15
local function rcfg()
return getgenv().RebirthConfig or {}
end
-- ── model: bat ky Model nao co Root la BasePart + ProximityPrompt ──
local function looksLikeWheel(m)
if not (m and m:IsA("Model")) then
return nil, nil
end
local root = m:FindFirstChild("Root")
if not (root and root:IsA("BasePart")) then
return nil, nil
end
-- Loai bo model bi dev cat tren troi (>2000) hoac duoi vuc (<-500)
if root.Position.Y > 2000 or root.Position.Y < -500 then
return nil, nil
end
local prompt = root:FindFirstChildOfClass("ProximityPrompt")
if not prompt then
return nil, nil
end
return root, prompt
end
local function findWheelModel(token)
if
discovered.model
and discovered.model.Parent
and discovered.root
and discovered.root.Parent
and discovered.prompt
and discovered.prompt.Parent
and tick() - discovered.at < DISCOVER_TTL
then
return discovered.model, discovered.root, discovered.prompt
end
local forced = rcfg().WheelModelName
if type(forced) == "string" and forced ~= "" then
local m = Workspace:FindFirstChild(forced)
if m then
local root, prompt = looksLikeWheel(m)
if root then
discovered = { model = m, root = root, prompt = prompt, at = tick() }
return m, root, prompt
end
end
return nil, nil, nil
end
-- Neu co token (vi du "Eclipse"), uu tien tim model khop token truoc
if token and type(token) == "string" and token ~= "" then
local exactNames = { token .. "SpinWheel", token .. "Wheel", token .. "EventWheel" }
for _, name in ipairs(exactNames) do
local m = Workspace:FindFirstChild(name)
if m then
local root, prompt = looksLikeWheel(m)
if root then
discovered = { model = m, root = root, prompt = prompt, at = tick() }
return m, root, prompt
end
end
end
for _, m in ipairs(Workspace:GetChildren()) do
if m:IsA("Model") and m.Name:lower():find(token:lower(), 1, true) then
local root, prompt = looksLikeWheel(m)
if root then
discovered = { model = m, root = root, prompt = prompt, at = tick() }
return m, root, prompt
end
end
end
end
-- Fallback tim tat ca model co "wheel" hoac "spin" (da bo qua vi tri Y > 2000 tren troi)
for _, m in ipairs(Workspace:GetChildren()) do
if m:IsA("Model") then
local n = m.Name:lower()
if n:find("wheel", 1, true) or n:find("spin", 1, true) then
local root, prompt = looksLikeWheel(m)
if root then
discovered = { model = m, root = root, prompt = prompt, at = tick() }
return m, root, prompt
end
end
end
end
return nil, nil, nil
end
local function getWheelPrompt(token)
local model, root, prompt = findWheelModel(token)
if not model then
return nil, nil, "Spin: KHONG THAY WHEEL"
end
return root, prompt, nil
end
-- ── UI: ScreenGui nao chua .Buttons.Spin la GuiButton ──
local function getWheelUi(token)
local localPlayer = Players.LocalPlayer
local playerGui = localPlayer and localPlayer:FindFirstChild("PlayerGui")
if not playerGui then
return nil, nil, nil
end
local function probe(screen)
if not (screen and screen:IsA("ScreenGui")) then
return nil, nil, nil
end
for _, frame in ipairs(screen:GetChildren()) do
if frame:IsA("GuiObject") then
local buttons = frame:FindFirstChild("Buttons")
local spin = buttons and buttons:FindFirstChild("Spin")
if spin and spin:IsA("GuiButton") then
return screen, frame, spin
end
end
end
return nil, nil, nil
end
local forced = rcfg().WheelUiName
if type(forced) == "string" and forced ~= "" then
return probe(playerGui:FindFirstChild(forced))
end
-- Uu tien ScreenGui khop token (vi du "EclipseWheel")
if token and type(token) == "string" and token ~= "" then
local exactGuis = { token .. "Wheel", token .. "SpinWheel", token .. "EventWheel" }
for _, name in ipairs(exactGuis) do
local s, f, sp = probe(playerGui:FindFirstChild(name))
if s then
return s, f, sp
end
end
for _, screen in ipairs(playerGui:GetChildren()) do
if screen:IsA("ScreenGui") and screen.Name:lower():find(token:lower(), 1, true) then
local s, f, sp = probe(screen)
if s then
return s, f, sp
end
end
end
end
for _, screen in ipairs(playerGui:GetChildren()) do
local s, f, sp = probe(screen)
if s then
return s, f, sp
end
end
return nil, nil, nil
end
-- ── attribute event: cap Event + EventLastTime tren ReplicatedStorage ──
-- ── Trang thai event. DO TU GAME THAT: ho tro CA BA kieu: ──
-- Eclipse (hien tai): EclipseWheelActive = true + NextEclipseEvent =
-- Crystal (truoc do): CrystalWheelActive = true + NextCrystalEvent =
-- Phantom (cu): PhantomEvent = true + PhantomEventLastTime =
-- Tra ve: activeAttr, timeAttr, isActive, readyAt, activeToken
-- readyAt = moc unix duoc quay free. os.time() >= readyAt => quay duoc.
local function readEventState()
local ok, attrs = pcall(function()
return ReplicatedStorage:GetAttributes()
end)
if not ok or type(attrs) ~= "table" then
return nil, nil, false, nil, nil
end
local forced = rcfg().WheelEventAttr
if type(forced) == "string" and forced ~= "" then
local t = attrs[forced .. "LastTime"] ~= nil and (forced .. "LastTime") or nil
local tok = forced:gsub("WheelActive$", ""):gsub("Event$", ""):gsub("Active$", "")
return forced, t, attrs[forced] == true, tonumber(t and attrs[t]), tok
end
-- (1) kieu Eclipse / Crystal: Active = true, kem mot moc thoi gian co chua
for k, v in pairs(attrs) do
if type(k) == "string" and v == true and #k > 6 and k:sub(-6) == "Active" then
local base = k:sub(1, #k - 6) -- "EclipseWheel"
local token = base:gsub("Wheel$", "") -- "Eclipse"
for k2, v2 in pairs(attrs) do
if type(k2) == "string" and type(v2) == "number" and k2 ~= k then
if k2:find(token, 1, true) and (k2:find("Next", 1, true) or k2:find("Time", 1, true)) then
return k, k2, true, v2, token
end
end
end
return k, nil, true, nil, token
end
end
-- (2) kieu Phantom: Event = true + EventLastTime
for k, v in pairs(attrs) do
if type(k) == "string" and #k > 5 and k:sub(-5) == "Event" and v == true then
local token = k:sub(1, #k - 5)
local timeKey = k .. "LastTime"
if attrs[timeKey] ~= nil then
return k, timeKey, true, tonumber(attrs[timeKey]), token
end
end
end
return nil, nil, false, nil, nil
end
local function moveToWheel(token)
local root, prompt, status = getWheelPrompt(token)
if not root then
setPhantomWheelStatus(status)
return false
end
if not prompt.Enabled then
setPhantomWheelStatus("Spin: PROMPT TAT")
return false
end
setPhantomWheelStatus("Spin: DANG LAI GAN")
if not pathfindTo or not pathfindTo(root.Position) then
setPhantomWheelStatus("Spin: KHONG TOI GAN")
return false
end
setPhantomWheelStatus("Spin: CHO ON DINH")
task.wait(math.max(0, tonumber(rcfg().PhantomWheelArrivalDelay) or 2))
if not root.Parent or not prompt.Parent or not prompt.Enabled then
setPhantomWheelStatus("Spin: PROMPT DA DOI")
return false
end
local character = player.Character
local hrp = character and character:FindFirstChild("HumanoidRootPart")
if not (hrp and hrp:IsA("BasePart")) then
setPhantomWheelStatus("Spin: THIEU HRP")
return false
end
if (hrp.Position - root.Position).Magnitude > prompt.MaxActivationDistance then
setPhantomWheelStatus("Spin: QUA XA")
return nil, nil
end
return root, prompt
end
local function openWheelUi(prompt, token)
local screen, frame = getWheelUi(token)
if screen and screen.Enabled and frame and frame.Visible then
-- Bat FastSpin neu chua bat
local fastSpin = frame:FindFirstChild("FastSpin")
local toggle = fastSpin and fastSpin:FindFirstChild("Toggle")
local checkmark = toggle and toggle:FindFirstChild("Checkmark")
if toggle and checkmark and checkmark:IsA("GuiObject") and not checkmark.Visible then
pcall(function()
firesignal(toggle.Activated)
end)
end
return true
end
setPhantomWheelStatus("Spin: DANG MO UI")
local opened = pcall(function()
fireproximityprompt(prompt)
end)
if not opened then
return false
end
local deadline = tick() + 3
while tick() < deadline do
screen, frame = getWheelUi(token)
if screen and screen.Enabled and frame and frame.Visible then
local fastSpin = frame:FindFirstChild("FastSpin")
local toggle = fastSpin and fastSpin:FindFirstChild("Toggle")
local checkmark = toggle and toggle:FindFirstChild("Checkmark")
if toggle and checkmark and checkmark:IsA("GuiObject") and not checkmark.Visible then
pcall(function()
firesignal(toggle.Activated)
end)
end
return true
end
task.wait(0.1)
end
return false
end
local function closeWheelUi(token)
local screen, frame = getWheelUi(token)
if not screen or not screen.Enabled or not frame or not frame.Visible then
return true
end
local close = frame:FindFirstChild("Close")
if not close or not close:IsA("GuiButton") then
return false
end
local signaled = pcall(function()
firesignal(close.Activated)
end)
if not signaled then
return false
end
local deadline = tick() + 2
while tick() < deadline do
if not screen.Enabled or not frame.Visible then
return true
end
task.wait(0.1)
end
return not screen.Enabled or not frame.Visible
end
-- ── san sang quay? ban cu CHI chap nhan dung chuoi "SPIN NOW".
-- Event moi rat co the doi chu => doc Timer neu co, KHONG co thi
-- fallback sang Interactable. Chuoi chap nhan cau hinh qua
-- RebirthConfig.SpinReadyText (chuoi hoac bang chuoi).
local function spinReadyTexts()
local cfg = rcfg().SpinReadyText
if type(cfg) == "string" then
return { cfg:upper() }
end
if type(cfg) == "table" then
local out = {}
for _, s in ipairs(cfg) do
out[#out + 1] = tostring(s):upper()
end
if #out > 0 then
return out
end
end
return { "SPIN NOW", "FREE SPIN", "CLAIM", "QUAY" }
end
local function readSpinTimer(spin)
local main = spin and spin:FindFirstChild("Main")
local timer = main and main:FindFirstChild("Timer")
if timer and timer:IsA("TextLabel") then
return timer, tostring(timer.Text or ""):upper()
end
if spin then
for _, d in ipairs(spin:GetDescendants()) do
if d:IsA("TextLabel") then
return d, tostring(d.Text or ""):upper()
end
end
end
return nil, nil
end
-- ── SO LUOT QUAY con lai. DO TU GAME THAT: nhan "Spins" duoi nut Spin
-- co dang "Spin (0)" / "Spin (3)". Day la tin hieu CHINH XAC NHAT,
-- chac chan hon nhieu so voi so khop chuoi Timer (moi event doi chu mot kieu:
-- Phantom dung "SPIN NOW", Crystal/Eclipse dung "Free Spin in 50m 49s").
local function spinsLeft(spin)
if not spin then
return nil
end
local lbl = spin:FindFirstChild("Spins", true)
if lbl and lbl:IsA("TextLabel") then
local n = tostring(lbl.Text or ""):match("%((%d+)%)")
if n then
return tonumber(n)
end
end
return nil
end
local function isSpinReady(spin)
-- 1) uu tien dem so luot: "Spin (N)"
local n = spinsLeft(spin)
if n ~= nil then
return n > 0, "spins=" .. tostring(n)
end
-- 2) khong doc duoc so luot -> so chuoi Timer nhu cu
local timer, text = readSpinTimer(spin)
if not timer then
return (spin.Interactable and spin.Active) and true or false, "no-timer"
end
for _, want in ipairs(spinReadyTexts()) do
if text == want or text:find(want, 1, true) then
return true, text
end
end
return false, text
end
local function clickWheelSpin(token)
local screen, frame, spin = getWheelUi(token)
if
not screen
or not screen.Enabled
or not frame
or not frame.Visible
or not spin
or not spin:IsA("GuiButton")
then
return "not-ready", "Spin: UI CHUA SAN SANG"
end
local ready, text = isSpinReady(spin)
if not ready then
return "claimed", "Spin: DA NHAN (" .. tostring(text) .. ")"
end
if
not spin.Visible
or not spin.Active
or not spin.Interactable
or spin.AbsoluteSize.X <= 1
or spin.AbsoluteSize.Y <= 1
then
return "not-ready", "Spin: NUT CHUA SAN SANG"
end
local clicked = pcall(function()
firesignal(spin.Activated)
end)
if not clicked then
-- Remote fallback neu firesignal that bai
pcall(function()
local net = require(ReplicatedStorage:WaitForChild("Packages"):WaitForChild("Net"))
local spinRemote = net:RemoteEvent("EclipseEventService/Spin")
if spinRemote then
spinRemote:FireServer()
end
end)
end
local clickTime = tick()
local deadline = clickTime + 6
while tick() < deadline do
local _, currentFrame, currentSpin = getWheelUi(token)
if currentFrame and currentSpin then
local stillReady = isSpinReady(currentSpin)
if not stillReady or not currentSpin.Interactable then
task.wait(math.max(0, 2 - (tick() - clickTime)))
return "confirmed", "Spin: DA QUAY XONG"
end
end
task.wait(0.1)
end
return "attempted", "Spin: DA CLICK, CHUA XAC NHAN"
end
local function autoSpinWheel()
local rc = rcfg()
local spinEnabled = true
if rc.AutoEclipseWheel ~= nil then
spinEnabled = rc.AutoEclipseWheel == true
elseif rc.AutoSpinWheel ~= nil then
spinEnabled = rc.AutoSpinWheel == true
elseif rc.AutoPhantomWheel ~= nil then
spinEnabled = rc.AutoPhantomWheel == true
end
if not spinEnabled then
setPhantomWheelStatus("Spin: TAT")
return
end
if farmOnlyFpsApplied then
setPhantomWheelStatus("Spin: FARM ONLY")
return
end
if farmActionBusy or phantomWheelBusy or lockDoorBusy then
setPhantomWheelStatus("Spin: CHO FARM")
return
end
local eventAttr, timeAttr, isActive, readyAt, activeToken = readEventState()
local eventTime = nil
local prefix = activeToken and ("Spin (" .. activeToken .. ")") or "Spin"
if eventAttr then
if not isActive then
setPhantomWheelStatus(prefix .. ": CHO FREE (" .. eventAttr .. ")")
return
end
eventTime = timeAttr and ReplicatedStorage:GetAttribute(timeAttr) or nil
if eventTime == nil then
setPhantomWheelStatus(prefix .. ": CHO DU LIEU")
return
end
-- ★ Eclipse / Crystal: NextEvent la moc UNIX duoc quay free lan toi.
if readyAt and readyAt > os.time() then
local left = readyAt - os.time()
setPhantomWheelStatus(("%s: CON %dm%ds"):format(prefix, math.floor(left / 60), left % 60))
return
end
if lastPhantomSpinEventTime == eventTime then
setPhantomWheelStatus(prefix .. ": DA QUAY")
return
end
if lastPhantomSpinAttemptTime == eventTime then
setPhantomWheelStatus(prefix .. ": DA THU UI")
return
end
else
local _, prompt = getWheelPrompt(activeToken)
if not prompt or not prompt.Enabled then
setPhantomWheelStatus("Spin: KHONG CO EVENT")
return
end
eventTime = "noattr"
if
lastPhantomSpinAttemptTime == eventTime
and tick() - (lastPhantomSpinAttemptAt or 0) < 300
then
setPhantomWheelStatus("Spin: DA THU (cho 5p)")
return
end
end
phantomWheelBusy = true
local ok, status = pcall(function()
local root, prompt = moveToWheel(activeToken)
if not root or not prompt then
return nil
end
if not openWheelUi(prompt, activeToken) then
return prefix .. ": KHONG MO DUOC UI"
end
local currentCharacter = player and player.Character
local currentHrp = currentCharacter and currentCharacter:FindFirstChild("HumanoidRootPart")
if
not currentHrp
or not prompt.Enabled
or (currentHrp.Position - root.Position).Magnitude > prompt.MaxActivationDistance
then
return prefix .. ": ROI KHOI WHEEL"
end
task.wait(0.2)
if eventAttr then
if
ReplicatedStorage:GetAttribute(eventAttr) ~= true
or ReplicatedStorage:GetAttribute(timeAttr) ~= eventTime
then
return prefix .. ": EVENT DA DOI"
end
end
local outcome, clickStatus = clickWheelSpin(activeToken)
if outcome == "claimed" then
lastPhantomSpinAttemptTime = eventTime
lastPhantomSpinEventTime = eventTime
elseif outcome ~= "not-ready" then
lastPhantomSpinAttemptTime = eventTime
if outcome == "confirmed" then
lastPhantomSpinEventTime = eventTime
end
end
lastPhantomSpinAttemptAt = tick()
return clickStatus
end)
local closed = closeWheelUi(activeToken)
phantomWheelBusy = false
if not closed then
warn("⚠️ Wheel UI could not be closed")
end
if not ok then
setPhantomWheelStatus(prefix .. ": UI LOI")
warn("⚠️ Wheel UI flow failed: " .. tostring(status))
return
end
if status then
setPhantomWheelStatus(status)
end
end
-- cong bo ra ngoai: goi qua MCP de xem no DANG THAY GI, khoi phai doan
Action.debugWheel = function()
local eventAttr, timeAttr, isActive, readyAt, activeToken = readEventState()
local model, root, prompt = findWheelModel(activeToken)
local screen, frame, spin = getWheelUi(activeToken)
local ready, text = nil, nil
if spin then
ready, text = isSpinReady(spin)
end
local hrp = player and player.Character and player.Character:FindFirstChild("HumanoidRootPart")
return {
activeToken = activeToken,
model = model and model:GetFullName() or nil,
pos = root and tostring(root.Position) or nil,
promptEnabled = prompt and prompt.Enabled or nil,
holdDuration = prompt and prompt.HoldDuration or nil,
maxDistance = prompt and prompt.MaxActivationDistance or nil,
distance = (hrp and root) and math.floor((hrp.Position - root.Position).Magnitude) or nil,
ui = screen and screen:GetFullName() or nil,
frame = frame and frame.Name or nil,
spin = spin and spin:GetFullName() or nil,
spinReady = ready,
spinText = text,
spinsLeft = spin and spinsLeft(spin) or nil,
eventAttr = eventAttr,
eventActive = isActive,
timeAttr = timeAttr,
readyAt = readyAt,
now = os.time(),
secondsLeft = readyAt and math.max(0, readyAt - os.time()) or nil,
}
end
startAutoPhantomWheel = function()
setPhantomWheelStatus("Spin: DANG KIEM TRA")
task.spawn(function()
while true do
-- pcall bao ngoai: ban cu khong co, mot loi trong autoSpin la
-- vong nay CHET han va phantomWheelBusy co the ket true mai mai.
local okLoop, errLoop = pcall(autoSpinWheel)
if not okLoop then
phantomWheelBusy = false
warn("⚠️ Wheel loop error: " .. tostring(errLoop))
end
task.wait(math.max(1, tonumber(rcfg().PhantomWheelScanSec) or 30))
end
end)
end
end
local function getAnimalGeneration(animalData)
if type(animalData) ~= "table" or not animalData.Index then
return 0
end
return genFromData(animalData.Index, animalData.Mutation, animalData.Traits)
end
local function bindCash(cashRef)
if cashValueConnection then
cashValueConnection:Disconnect()
cashValueConnection = nil
end
cash = cashRef
cachedCash = cash and parseCashValue(cash.Value) or nil
if cash then
cashValueConnection = cash:GetPropertyChangedSignal("Value"):Connect(function()
cachedCash = parseCashValue(cash.Value)
end)
end
end
local function bindRebirths(rebirthsRef)
if rebirthValueConnection then
rebirthValueConnection:Disconnect()
rebirthValueConnection = nil
end
rebirths = rebirthsRef
cachedRebirths = rebirths and rebirths.Value or nil
if rebirths then
rebirthValueConnection = rebirths:GetPropertyChangedSignal("Value"):Connect(function()
cachedRebirths = rebirths.Value
end)
end
end
local function disconnectMovementSignals()
if movementCharacterAncestryConnection then
movementCharacterAncestryConnection:Disconnect()
end
if movementHumanoidDiedConnection then
movementHumanoidDiedConnection:Disconnect()
end
movementCharacterAncestryConnection = nil
movementHumanoidDiedConnection = nil
end
local function bindMovementCharacter(newCharacter)
disconnectMovementSignals()
character = newCharacter
humanoid = nil
hrp = nil
resetStuck()
if not character then
return
end
humanoid = character:FindFirstChildOfClass("Humanoid")
hrp = character:FindFirstChild("HumanoidRootPart")
movementCharacterAncestryConnection = character.AncestryChanged:Connect(function(_, parent)
if not parent and character == newCharacter then
bindMovementCharacter(nil)
end
end)
if humanoid then
movementHumanoidDiedConnection = humanoid.Died:Connect(resetStuck)
end
end
local function bindMovementPlayer()
if characterAddedConnection then
characterAddedConnection:Disconnect()
end
characterAddedConnection = nil
if not player then
return
end
characterAddedConnection = player.CharacterAdded:Connect(bindMovementCharacter)
bindMovementCharacter(player.Character)
end
local function getMovementRefs()
if not player then
return nil, nil, nil
end
if player.Character ~= character then
bindMovementCharacter(player.Character)
end
if not character then
return nil, nil, nil
end
if not humanoid or humanoid.Parent ~= character then
if movementHumanoidDiedConnection then
movementHumanoidDiedConnection:Disconnect()
end
movementHumanoidDiedConnection = nil
humanoid = character:FindFirstChildOfClass("Humanoid")
if humanoid then
movementHumanoidDiedConnection = humanoid.Died:Connect(resetStuck)
end
resetStuck()
end
if not hrp or hrp.Parent ~= character then
hrp = character:FindFirstChild("HumanoidRootPart")
resetStuck()
end
if not humanoid or not hrp or humanoid.Health <= 0 then
return nil, nil, nil
end
return character, humanoid, hrp
end
local function waitForFullLoad()
print("⏳ Waiting for full game load...")
local deadline = tick() + FULL_LOAD_TIMEOUT_SECONDS
local function remaining()
return math.max(0, deadline - tick())
end
local function fail(reason)
warn("❌ Full load timeout: " .. reason)
local localPlayer = Players.LocalPlayer
if localPlayer then
localPlayer:Kick("Khởi tạo quá " .. FULL_LOAD_TIMEOUT_SECONDS .. " giây: " .. reason)
end
return false
end
while not game:IsLoaded() and tick() < deadline do
task.wait(0.5)
end
if not game:IsLoaded() then
return fail("game:IsLoaded")
end
while not Players.LocalPlayer and tick() < deadline do
task.wait(0.5)
end
player = Players.LocalPlayer
if not player then
return fail("LocalPlayer")
end
bindMovementPlayer()
while tick() < deadline do
local currentCharacter = player.Character
local currentHumanoid = currentCharacter and currentCharacter:FindFirstChildOfClass("Humanoid")
local currentHrp = currentCharacter and currentCharacter:FindFirstChild("HumanoidRootPart")
if currentCharacter and currentHumanoid and currentHrp and currentHumanoid.Health > 0 then
character = currentCharacter
humanoid = currentHumanoid
hrp = currentHrp
break
end
task.wait(0.5)
end
if not character or not humanoid or not hrp then
return fail("Character/Humanoid/HumanoidRootPart")
end
bindMovementCharacter(character)
-- ⚠ DA BO `humanoid.WalkSpeed = 16`.
-- WalkSpeed la property REPLICATED va nam trong mat tran BAC soi. Ghi vao day
-- vua vo ich (do live ra 34 — game tu nang len) vua rui ro.
-- Va neu lan nao no THANG cuoc dua (respawn / perk ap lai muon) thi bot chay
-- cham 47% trong khi estimateTravel van tinh theo WalkSpeed doc live => cua so
-- ve khoa cua sai am tham. LockDoor.estimateTravel doc hum.WalkSpeed truc tiep.
leaderstats = player:FindFirstChild("leaderstats") or player:WaitForChild("leaderstats", remaining())
cash = leaderstats and (leaderstats:FindFirstChild("Cash") or leaderstats:WaitForChild("Cash", remaining()))
rebirths = leaderstats
and (leaderstats:FindFirstChild("Rebirths") or leaderstats:WaitForChild("Rebirths", remaining()))
local plots = Workspace:FindFirstChild("Plots") or Workspace:WaitForChild("Plots", remaining())
if not leaderstats or not cash or not rebirths or not plots then
return fail("leaderstats/Cash/Rebirths/Plots")
end
bindCash(cash)
bindRebirths(rebirths)
if remaining() < 5 then
return fail("final readiness delay")
end
task.wait(5)
print("✅ Game fully loaded!")
return true
end
local function checkStuck()
local _, currentHumanoid, currentHrp = getMovementRefs()
if not currentHrp or not currentHumanoid then
return
end
if lastPosition == nil then
lastPosition = currentHrp.Position
lastPositionTime = tick()
return
end
local dist = (currentHrp.Position - lastPosition).Magnitude
if dist > STUCK_DISTANCE then
lastPosition = currentHrp.Position
lastPositionTime = tick()
elseif tick() - lastPositionTime >= STUCK_THRESHOLD then
print("⚠️ Stuck! Jumping...")
currentHumanoid.Jump = true
task.wait(0.3)
currentHumanoid.Jump = true
task.wait(0.3)
currentHumanoid.Jump = true
resetStuck()
end
end
local function getCash()
if not player then
return 0
end
if not leaderstats or leaderstats.Parent ~= player then
leaderstats = player:FindFirstChild("leaderstats")
end
if not leaderstats then
return 0
end
if not cash or cash.Parent ~= leaderstats then
bindCash(leaderstats:FindFirstChild("Cash"))
end
if cash and cash.Parent == leaderstats then
if cachedCash ~= nil then
return cachedCash
end
cachedCash = parseCashValue(cash.Value)
return cachedCash
end
return 0
end
local function getRebirths()
if not player then
return 0
end
if not leaderstats or leaderstats.Parent ~= player then
leaderstats = player:FindFirstChild("leaderstats")
end
if not leaderstats then
return 0
end
if not rebirths or rebirths.Parent ~= leaderstats then
bindRebirths(leaderstats:FindFirstChild("Rebirths"))
end
if rebirths and rebirths.Parent == leaderstats then
if cachedRebirths ~= nil then
return cachedRebirths
end
cachedRebirths = rebirths.Value
return cachedRebirths
end
return 0
end
local getBaseIncomePerSecond = nil
local changedFolder = false
local changingFolder = false
local changeFolderTimedOut = false
local function hasRequiredRebirthAnimalsSynced()
local animalList = Action.getSyncedAnimalList()
if type(animalList) ~= "table" then
return false
end
local found = {}
for _, animalData in pairs(animalList) do
if type(animalData) == "table" then
found[tostring(animalData.Index or "")] = true
end
end
for _, name in ipairs(ownedList) do
if not found[name] then
return false
end
end
return true
end
local function changeToFolderIfReady()
if changedFolder then
return true
end
if changeFolderTimedOut then
return false
end
if changingFolder or rebirthInProgress then
return false
end
local rc = getgenv().RebirthConfig or {}
if rc.ChangeToFolderEnabled == false then
return false
end
local rebirthCount = getRebirths()
local incomePerSecond = getBaseIncomePerSecond and getBaseIncomePerSecond() or 0
local hasRequiredAnimals = hasRequiredRebirthAnimalsSynced()
if rebirthCount < 1 and (incomePerSecond <= CHANGE_INCOME_PER_SECOND or not hasRequiredAnimals) then
return false
end
if not rc.From or not rc.To then
warn("[Change] Missing RebirthConfig.From/RebirthConfig.To")
return false
end
changingFolder = true
task.wait(tonumber(rc.ChangeDelay) or 3)
for _ = 1, 30 do
if getgenv().client then
break
end
task.wait(0.5)
end
local client = getgenv().client
if not client then
changingFolder = false
warn("[Change] getgenv().client chưa sẵn sàng")
return false
end
rc = getgenv().RebirthConfig or {}
if rc.ChangeToFolderEnabled == false or rebirthInProgress then
changingFolder = false
return false
end
local completed = false
local ok, result
local callThread = task.spawn(function()
ok, result = pcall(function()
return client:ChangeToFolder(rc.From, rc.To, rc.ChangeWithoutReplace == true, rc.ConfigID)
end)
completed = true
end)
local deadline = tick() + CHANGE_FOLDER_TIMEOUT_SECONDS
while not completed and tick() < deadline do
task.wait(0.1)
end
if not completed then
changeFolderTimedOut = true
pcall(task.cancel, callThread)
changingFolder = false
warn("[Change] ChangeToFolder timed out; refusing a duplicate call")
return false
end
changingFolder = false
if ok then
changedFolder = true
print(
"[Change] ChangeToFolder called: "
.. tostring(result)
.. " | rebirths="
.. rebirthCount
.. " income/s="
.. incomePerSecond
.. " requiredAnimals="
.. tostring(hasRequiredAnimals)
)
return true
end
warn("[Change] ChangeToFolder failed: " .. tostring(result))
return false
end
local plotsFolder = nil
local cachedMyPlot = nil
local cachedAnimalPodiums = nil
local cachedPodiumCache = nil
local podiumCacheDirty = true
local PODIUM_CACHE_TTL = 5
local plotsChildAddedConnection = nil
local plotsChildRemovedConnection = nil
local cachedPlotAncestryConnection = nil
local cachedYourBaseEnabledConnection = nil
local watchedPlot = nil
local animalPodiumsChildAddedConnection = nil
local animalPodiumsChildRemovedConnection = nil
local animalPodiumsDescendantAddedConnection = nil
local animalPodiumsDescendantRemovingConnection = nil
local watchedAnimalPodiums = nil
local function markPodiumCacheDirty()
podiumCacheDirty = true
end
local function disconnectCachedPlotSignals()
if cachedPlotAncestryConnection then
cachedPlotAncestryConnection:Disconnect()
end
if cachedYourBaseEnabledConnection then
cachedYourBaseEnabledConnection:Disconnect()
end
cachedPlotAncestryConnection = nil
cachedYourBaseEnabledConnection = nil
watchedPlot = nil
end
local function disconnectAnimalPodiumsSignals()
if animalPodiumsChildAddedConnection then
animalPodiumsChildAddedConnection:Disconnect()
end
if animalPodiumsChildRemovedConnection then
animalPodiumsChildRemovedConnection:Disconnect()
end
if animalPodiumsDescendantAddedConnection then
animalPodiumsDescendantAddedConnection:Disconnect()
end
if animalPodiumsDescendantRemovingConnection then
animalPodiumsDescendantRemovingConnection:Disconnect()
end
animalPodiumsChildAddedConnection = nil
animalPodiumsChildRemovedConnection = nil
animalPodiumsDescendantAddedConnection = nil
animalPodiumsDescendantRemovingConnection = nil
watchedAnimalPodiums = nil
end
local function markPlotCacheDirty()
cachedMyPlot = nil
cachedAnimalPodiums = nil
cachedPodiumCache = nil
markPodiumCacheDirty()
disconnectCachedPlotSignals()
disconnectAnimalPodiumsSignals()
end
local function getPlotsFolder()
if plotsFolder and plotsFolder.Parent == Workspace then
return plotsFolder
end
plotsFolder = Workspace:FindFirstChild("Plots") or Workspace:WaitForChild("Plots", 30)
if not plotsFolder then
warn("❌ Plots folder not found")
return nil
end
if plotsChildAddedConnection then
plotsChildAddedConnection:Disconnect()
end
if plotsChildRemovedConnection then
plotsChildRemovedConnection:Disconnect()
end
plotsChildAddedConnection = plotsFolder.ChildAdded:Connect(markPlotCacheDirty)
plotsChildRemovedConnection = plotsFolder.ChildRemoved:Connect(markPlotCacheDirty)
return plotsFolder
end
local function getYourBase(plot)
local plotSign = plot and plot:FindFirstChild("PlotSign")
local yourBase = plotSign and plotSign:FindFirstChild("YourBase")
if yourBase and yourBase:IsA("BillboardGui") then
return yourBase
end
return nil
end
local function isMyPlot(plot)
local yourBase = getYourBase(plot)
return yourBase and yourBase.Enabled == true, yourBase
end
local function watchMyPlot(plot, yourBase)
if watchedPlot == plot then
return
end
disconnectCachedPlotSignals()
watchedPlot = plot
cachedPlotAncestryConnection = plot.AncestryChanged:Connect(markPlotCacheDirty)
cachedYourBaseEnabledConnection = yourBase:GetPropertyChangedSignal("Enabled"):Connect(function()
if not yourBase.Enabled then
markPlotCacheDirty()
end
end)
end
local function findMyPlot()
local plots = getPlotsFolder()
if not plots then
return nil
end
if cachedMyPlot and cachedMyPlot.Parent == plots then
local ok, yourBase = isMyPlot(cachedMyPlot)
if ok then
watchMyPlot(cachedMyPlot, yourBase)
return cachedMyPlot
end
markPlotCacheDirty()
end
for _, plot in ipairs(plots:GetChildren()) do
local ok, yourBase = isMyPlot(plot)
if ok then
cachedMyPlot = plot
watchMyPlot(plot, yourBase)
return plot
end
end
return nil
end
function Action.getSyncedAnimalList()
local plot = findMyPlot()
local baseData = plot and getSyncedTable(plot.Name)
local animalList = baseData and baseData.AnimalList
return type(animalList) == "table" and animalList or nil
end
local function watchAnimalPodiums(animalPodiums)
if watchedAnimalPodiums == animalPodiums then
return
end
disconnectAnimalPodiumsSignals()
watchedAnimalPodiums = animalPodiums
animalPodiumsChildAddedConnection = animalPodiums.ChildAdded:Connect(markPodiumCacheDirty)
animalPodiumsChildRemovedConnection = animalPodiums.ChildRemoved:Connect(markPodiumCacheDirty)
animalPodiumsDescendantAddedConnection = animalPodiums.DescendantAdded:Connect(markPodiumCacheDirty)
animalPodiumsDescendantRemovingConnection = animalPodiums.DescendantRemoving:Connect(markPodiumCacheDirty)
end
local function getAnimalPodiums()
local plot = findMyPlot()
if not plot then
return nil
end
if cachedAnimalPodiums and cachedAnimalPodiums.Parent == plot then
watchAnimalPodiums(cachedAnimalPodiums)
return cachedAnimalPodiums
end
cachedAnimalPodiums = plot:FindFirstChild("AnimalPodiums")
markPodiumCacheDirty()
if cachedAnimalPodiums then
watchAnimalPodiums(cachedAnimalPodiums)
end
return cachedAnimalPodiums
end
local function scanPodiums(animalPodiums)
local cache = { count = 0, owned = {}, slots = {}, income = 0 }
local animalList = Action.getSyncedAnimalList()
for i = 1, MAX_PODIUMS do
local slot = animalPodiums:FindFirstChild(tostring(i))
if slot then
for _, obj in ipairs(slot:GetDescendants()) do
-- ⚠ O co LUCKY BLOCK cung DA BI CHIEM, nhung prompt cua no la "Open"
-- chu khong phai "Grab" nen ban cu KHONG dem -> bot tuong o con trong,
-- doi mua vao do, server tu choi vi o da co vat -> KET VINH VIEN.
-- DO LIVE 2026-09-15: slot 4 co prompt Action="Open" Object="Lucky Block",
-- HoldDuration 1.5, MaxActivationDistance 10.
if obj:IsA("ProximityPrompt") and tostring(obj.ObjectText or ""):lower():find("lucky", 1, true) then
cache.count += 1
cache.slots[i] = { slot = slot, objectText = tostring(obj.ObjectText or ""),
indexName = "", generation = 0, lucky = true }
break
end
if obj:IsA("ProximityPrompt") and obj.ActionText == "Grab" then
local objectText = tostring(obj.ObjectText or "")
local animalData = animalList and (animalList[i] or animalList[tostring(i)])
local indexName = type(animalData) == "table" and tostring(animalData.Index or "") or ""
local generation = getAnimalGeneration(animalData)
cache.count += 1
cache.income += generation
cache.slots[i] = {
slot = slot,
objectText = objectText,
indexName = indexName,
generation = generation,
}
for _, trackedName in ipairs(ownedList) do
local loweredName = trackedName:lower()
if
objectText:lower():find(loweredName, 1, true)
or indexName:lower():find(loweredName, 1, true)
then
cache.owned[trackedName] = true
end
end
break
end
end
end
end
return cache
end
local function getPodiumCache()
local animalPodiums = getAnimalPodiums()
if not animalPodiums then
return { count = 0, owned = {}, slots = {}, income = 0 }
end
if
not podiumCacheDirty
and cachedPodiumCache
and cachedPodiumCache.animalPodiums == animalPodiums
and tick() - (cachedPodiumCache.refreshedAt or 0) < PODIUM_CACHE_TTL
then
return cachedPodiumCache
end
cachedPodiumCache = scanPodiums(animalPodiums)
cachedPodiumCache.animalPodiums = animalPodiums
cachedPodiumCache.refreshedAt = tick()
podiumCacheDirty = false
return cachedPodiumCache
end
getBaseIncomePerSecond = function()
return tonumber(getPodiumCache().income) or 0
end
local function getPodiumInfo()
local podiumCache = getPodiumCache()
return podiumCache.count, podiumCache.owned
end
local function findSlotByName(name)
local podiumCache = getPodiumCache()
local loweredName = name:lower()
for i = 1, MAX_PODIUMS do
local slotInfo = podiumCache.slots[i]
if slotInfo then
local objectText = tostring(slotInfo.objectText or ""):lower()
local indexName = tostring(slotInfo.indexName or ""):lower()
if objectText:find(loweredName, 1, true) or indexName:find(loweredName, 1, true) then
return slotInfo.slot, i
end
end
end
return nil, nil
end
local purchasePromptCache = {}
local purchasePromptCacheDirty = true
local purchaseTagAddedConnection = nil
local purchaseTagRemovedConnection = nil
local purchaseAnimalDescendantConnections = {}
local function markPurchasePromptCacheDirty()
purchasePromptCacheDirty = true
end
local function unwatchPurchaseAnimal(obj)
local connections = purchaseAnimalDescendantConnections[obj]
if not connections then
return
end
for _, connection in pairs(connections) do
connection:Disconnect()
end
purchaseAnimalDescendantConnections[obj] = nil
end
local function watchPurchaseAnimal(obj)
if not obj or purchaseAnimalDescendantConnections[obj] then
return
end
purchaseAnimalDescendantConnections[obj] = {
obj.DescendantAdded:Connect(markPurchasePromptCacheDirty),
obj.DescendantRemoving:Connect(markPurchasePromptCacheDirty),
}
end
local function onPurchaseAnimalAdded(obj)
watchPurchaseAnimal(obj)
markPurchasePromptCacheDirty()
end
local function onPurchaseAnimalRemoved(obj)
unwatchPurchaseAnimal(obj)
markPurchasePromptCacheDirty()
end
local function ensurePurchasePromptSignals()
if purchaseTagAddedConnection then
return
end
purchaseTagAddedConnection = CollectionService:GetInstanceAddedSignal("Animal"):Connect(onPurchaseAnimalAdded)
purchaseTagRemovedConnection = CollectionService:GetInstanceRemovedSignal("Animal"):Connect(onPurchaseAnimalRemoved)
end
-- ══════════════════════════════════════════════════════════════════════
-- ANIMAL SOURCE — hoi thang registry CUA GAME thay vi tu suy doan.
--
-- DECOMPILE ReplicatedStorage.Controllers.AnimalController (2026-09-05):
-- function tbl.GetAnimals(a1) return tbl_upv_1 end <- chi tra bang, KHONG BAY
-- tbl_upv_1[animalClient:GetUID()] = animalClient <- khoa theo UID chuoi
--
-- ⚠⚠ TUYET DOI KHONG GOI ctrl:HasAnimal(...) — trong module do no chay
-- Synchronizer:Get(LocalPlayer), dung cai honeypot da biet (kiem caller-source
-- + quet getfenv tim writefile) => kick "CODE BAC". Chi dung GetAnimals.
-- HasAnimalMovingToBase cung sach nhung ta khong can.
--
-- DO LIVE tren server that (12 con): Index la CHUOI ("Talpa Di Fero"), UID = ten
-- Instance = attribute UID cua prompt; duong prompt la
-- Instance.PrimaryPart.PromptAttachment.ProximityPrompt (co ca .Part du phong).
--
-- ⚠ VI SAO BO CARPET: ban cu hoi "con vat co nam tren tam tham khong" bang cach so
-- toa do voi carpetCache — ma cache do KHONG BAO GIO duoc lam ban (nghe
-- Workspace.DescendantAdded + ten "Carpet", trong khi nguon that la tag Carpet
-- tren instance NGOAI Workspace). Event bat/tat la cache chet cung => khong mua
-- duoc gi. Game tu tra loi cau hoi do roi: prompt.Enabled duoc CHINH CLIENT dat
-- bang `TargetPlayer ~= LocalPlayer.UserId and not Disabled` (thay trong decompile),
-- con "con nay con o the gioi khong" thi IsDescendantOf(workspace) la du.
-- ══════════════════════════════════════════════════════════════════════
local AnimalSource = { controller = nil, failedAt = -math.huge }
function AnimalSource.getAnimals()
if not AnimalSource.controller then
if tick() - AnimalSource.failedAt < 5 then
return nil
end
local controllers = ReplicatedStorage:FindFirstChild("Controllers")
local module = controllers and controllers:FindFirstChild("AnimalController")
local ok, ctrl = false, nil
if module then
ok, ctrl = pcall(require, module)
end
if ok and type(ctrl) == "table" and type(ctrl.GetAnimals) == "function" then
AnimalSource.controller = ctrl
else
AnimalSource.failedAt = tick()
return nil
end
end
local ok2, animals = pcall(AnimalSource.controller.GetAnimals, AnimalSource.controller)
if not ok2 or type(animals) ~= "table" then
AnimalSource.controller = nil
AnimalSource.failedAt = tick()
return nil
end
return animals
end
function AnimalSource.count()
local animals = AnimalSource.getAnimals()
if not animals then
return -1 -- -1 = khong doc duoc registry (khac han 0 = registry rong)
end
local n = 0
for _ in pairs(animals) do
n = n + 1
end
return n
end
-- prompt cua mot record. Uu tien PrimaryPart (dung nhu game lam), du phong .Part
function AnimalSource.promptOf(rec)
local inst = type(rec) == "table" and rec.Instance or nil
if typeof(inst) ~= "Instance" or not inst:IsDescendantOf(Workspace) then
return nil, nil
end
local part = inst.PrimaryPart or inst:FindFirstChild("Part")
local at = part and part:FindFirstChild("PromptAttachment")
local pr = at and at:FindFirstChild("ProximityPrompt")
if pr and pr:IsA("ProximityPrompt") and pr.ActionText == "Purchase" then
return pr, part
end
return nil, nil
end
-- UID cua con vat mang prompt nay (de biet prompt co bi tai su dung sang con khac khong)
function AnimalSource.uidOfPrompt(prompt)
local ok, uid = pcall(function()
return prompt:GetAttribute("UID")
end)
return ok and uid or nil
end
-- ten CHINH XAC cua con mang prompt nay, doc tu registry. nil = khong tra loi duoc.
function AnimalSource.indexOfPrompt(prompt)
local uid = AnimalSource.uidOfPrompt(prompt)
if uid == nil then
return nil
end
local animals = AnimalSource.getAnimals()
local rec = animals and animals[uid]
return type(rec) == "table" and rec.Index or nil
end
local function isValidPurchasePrompt(prompt)
return prompt
and prompt.Parent ~= nil
and prompt:IsA("ProximityPrompt")
and prompt.ActionText == "Purchase"
and not prompt:GetFullName():find("StPatricksPot")
end
local function getPurchasePromptFromAnimal(obj)
local part = obj and obj:FindFirstChild("Part")
local promptAttachment = part and part:FindFirstChild("PromptAttachment")
local prompt = promptAttachment and promptAttachment:FindFirstChild("ProximityPrompt")
return isValidPurchasePrompt(prompt) and prompt or nil
end
local function rebuildPurchasePromptCache()
purchasePromptCache = {}
local taggedAnimals = {}
for _, obj in ipairs(CollectionService:GetTagged("Animal")) do
taggedAnimals[obj] = true
watchPurchaseAnimal(obj)
local prompt = getPurchasePromptFromAnimal(obj)
if prompt then
table.insert(purchasePromptCache, prompt)
end
end
for obj in pairs(purchaseAnimalDescendantConnections) do
if not taggedAnimals[obj] then
unwatchPurchaseAnimal(obj)
end
end
purchasePromptCacheDirty = false
end
local function getPurchasePart(prompt)
if not isValidPurchasePrompt(prompt) then
return nil
end
local part = prompt.Parent and prompt.Parent.Parent
if part and part:IsA("BasePart") then
return part
end
return nil
end
-- "Con nay mua duoc khong?"
-- Enabled : CHINH CLIENT dat = (TargetPlayer ~= UserId cua minh) and not Disabled
-- (thay trong decompile AnimalController.Start). Nen minh vua ban mot
-- phat la Enabled thanh FALSE — do la binh thuong, khong phai loi.
-- TargetPlayer == nil : chua ai dat cho. Do LIVE: gia tri la USERID (so).
-- Disabled : game tat rieng prompt nay. Ban cu KHONG kiem — 0 lan trong ca file.
-- con o the gioi : thay cho phep thu carpet cu (xem chu thich AnimalSource).
local function isPurchasePromptAvailable(prompt)
if not isValidPurchasePrompt(prompt) then
return false
end
if prompt.Enabled ~= true or prompt:GetAttribute("TargetPlayer") ~= nil then
return false
end
if prompt:GetAttribute("Disabled") == true then
return false
end
local part = getPurchasePart(prompt)
return part ~= nil and part:IsDescendantOf(Workspace)
end
local function promptMatchesPurchaseName(prompt, name)
if not isValidPurchasePrompt(prompt) then
return false
end
-- ★ KHOP CHINH XAC truoc: registry cua game cho biet Index that (chuoi, vd
-- "Talpa Di Fero"). Ban cu chi so chuoi con bang find(name, 1, true) nen ten
-- ngan lot vao ten dai => mua nham con. Chi lui ve so chuoi khi khong doc duoc.
local exact = AnimalSource.indexOfPrompt(prompt)
if exact ~= nil then
return exact == name
end
local loweredName = name:lower()
local objectText = tostring(prompt.ObjectText or ""):lower()
local promptName = tostring(prompt.Name or ""):lower()
return objectText:find(loweredName, 1, true) ~= nil or promptName:find(loweredName, 1, true) ~= nil
end
local function getPurchaseIncome(prompt, name)
if
not promptMatchesPurchaseName(prompt, name)
or prompt.Enabled ~= true
or not isPurchasePromptAvailable(prompt)
then
return nil
end
local animal = getPurchasePart(prompt)
while animal and animal ~= Workspace and not CollectionService:HasTag(animal, "Animal") do
animal = animal.Parent
end
if not animal or animal == Workspace then
return nil
end
local mutation = animal:GetAttribute("__mutation") or animal:GetAttribute("Mutation")
local traits = {}
local seenTraits = {}
local function addTrait(traitName)
if traitName and traitName ~= "" and not seenTraits[traitName] then
seenTraits[traitName] = true
table.insert(traits, traitName)
end
end
for _, child in ipairs(animal:GetChildren()) do
if not mutation and child.Name:sub(1, 9) == "Mutation." then
mutation = child.Name:sub(10)
else
addTrait(child.Name:match("^_?Trait%.(.+)$"))
end
end
local traitAttribute = animal:GetAttribute("Traits") or animal:GetAttribute("Trait")
if type(traitAttribute) == "string" then
for traitName in traitAttribute:gmatch("[^,]+") do
addTrait((traitName:gsub("^%s*(.-)%s*$", "%1")))
end
end
local Animals, Mutations, Traits = getGenerationData()
if not Animals or (mutation and mutation ~= "" and not Mutations) or (#traits > 0 and not Traits) then
return nil
end
local income = genFromData(name, mutation, traits)
return income > 0 and income or nil
end
local function findCachedPurchasePrompt(name)
local validPrompts = {}
local matchedPrompt = nil
for _, prompt in ipairs(purchasePromptCache) do
if isValidPurchasePrompt(prompt) then
table.insert(validPrompts, prompt)
if not matchedPrompt and promptMatchesPurchaseName(prompt, name) and isPurchasePromptAvailable(prompt) then
matchedPrompt = prompt
end
else
purchasePromptCacheDirty = true
end
end
purchasePromptCache = validPrompts
return matchedPrompt
end
local function findProximityPrompt(name)
ensurePurchasePromptSignals()
if purchasePromptCacheDirty then
rebuildPurchasePromptCache()
end
local prompt = findCachedPurchasePrompt(name)
if prompt then
return prompt
end
if purchasePromptCacheDirty then
rebuildPurchasePromptCache()
return findCachedPurchasePrompt(name)
end
return nil
end
-- ══════════════════════════════════════════════════════════════════════
-- CHON CON DE MUA — quet CON THAT tren bang chuyen, khong dua vao danh sach cung.
--
-- ⚠ VI SAO BO buyList LAM NGUON. DO LIVE 2026-09-05, 90 giay tren server that:
-- 43 con moi len bang chuyen, 19 con KHONG nam trong buyList nen bot mu tit —
-- Avocadini Guffo ($/s 225), Trulimero Trulicina ($/s 125 x3), Avocadini
-- Antilopini ($/s 115), Cacto Hipopotamo ($/s 50 x3), Boneca Ambalabu ($/s 40 x3)...
-- ReplicatedStorage.Datas.Animals co san Price + Generation cho 560 loai.
-- Con TOT NHAT mua noi, buyList so voi du lieu game:
-- $5.000 -> 35 vs 40 (1.1x) $278.009 -> 500 vs 1150 (2.3x)
-- $50.000 -> 275 vs 300 (1.1x) $500.000 -> 500 vs 2500 (5.0x)
-- Cang giau cang thiet. buyList GIU LAI, nhung chi de danh dau muc `required`.
--
-- ⚠ DA THU VA BO: san thu nhap = ti le cua "con tot nhat mua noi".
-- Tinh theo RoadWeight (trong so spawn, do duoc trong chinh Datas.Animals):
-- o $278k san 25% => chi 0.73% so spawn qua => CHO TRUNG BINH 288 GIAY.
-- Con xin co RoadWeight cuc nho (Wombo 1.75) con rac thi to (Noobini 100),
-- nen san kieu do bien bot thanh dung im. NEO SAN VAO CAI DANG CO TREN BE.
--
-- ⚠ O TRONG THI MUA NGAY, KHONG KEN. O trong kiem 0 $/s. Mua con $/s 40 roi ~290s
-- sau thay bang con $/s 1150 van an dut ngoi cho: 40 x 290 = $11.600, tru vai
-- giay churn. Chi khi be DAY moi duoc ken, va luc do nguong la worst x 1.25.
-- ══════════════════════════════════════════════════════════════════════
local function getBestAvailableNow(currentCash, owned, incomeFloor)
-- (1) muc BAT BUOC cho rebirth: bo qua moi nguong, mua bang duoc
for _, item in ipairs(buyList) do
if item.required and not owned[item.name] and currentCash >= item.cost then
local prompt = findProximityPrompt(item.name)
if prompt then
return item, prompt
end
end
end
-- ══ LUAT HOAN VON ══════════════════════════════════════════════════
-- Muc tieu THAT cua script khong phai "tong $/s cao nhat" ma la CHAM
-- $500.000 SOM NHAT roi rebirth (REBIRTH_CASH L~440, MAX_REBIRTHS=1,
-- vong farm thoat ngay khi du tien). $/s chi la bien trung gian.
-- Hai cai nay PHAN KY dung o cho user than phien: mua mot con thi income
-- tang nhung TIEN MAT GIAM, day moc $500k ra xa.
--
-- T0 = (REBIRTH_CASH - cash) / income -- dung yen farm
-- T1 = (REBIRTH_CASH - cash + cost - income*tt) / (income + g - g_ban) + tt
-- MUA khi T1 < T0. Trong so con thoa, chon T1 NHO NHAT (khong phai g lon nhat).
--
-- g_ban = 0 khi con o trong; = con te nhat tren be khi be day (phai ban di).
-- tt = thoi gian di duong (mua ~10s, churn ~16s); income*tt la tien van chay ve
-- trong luc di.
--
-- Kiem tay dung trang thai user bao ($278.009, income 500/s, T0 = 444.0s):
-- Lirili $250 3/s -> T1 451.8s LO 7.8s -> BO <- dung cai user chui
-- Pipi Kiwi $1.5k 13 -> T1 445.7s LO 1.7s -> BO
-- Bandito $4.5k 35 -> T1 433.3s LOI 10.6s -> MUA
-- Cappuccino $10k 75 -> T1 413.5s LOI 30.5s -> MUA
-- Ballerina $100k 500-> T1 332.0s LOI 112.0s -> MUA (tot nhat)
--
-- ⚠ DA THU VA BO: san = ti le cua "con tot nhat mua noi". 4/4 agent phan bien
-- bac bo, mo phong cho thay no CHAM HON code cu +5.1% o dung kich ban $278k.
-- Ly do: no chan ca Bandito/TaTa/TricTrac/Cappuccino — nhung con GAP HOAI —
-- de cho Wombo/Ballerina hiem khi spawn (RoadWeight 1.75 / 0.55).
--
-- Luat nay TU CO GIAN that, khong can hang so ma:
-- ngheo, income ~0 -> T0 -> vo cuc -> moi thu deu loi -> van mua do re khoi dong
-- giau, gan dich -> T0 nho -> chi cu nhay income lon moi lot -> tu giet cu mua rac
-- be day -> tru g_ban da CHINH LA bar nang cap, khoi can he so rieng
-- khong bao gio dung im vinh vien: khong con nao thoa thi cau tra loi DUNG la
-- dung yen farm cho tien tu chay ve.
-- ═══════════════════════════════════════════════════════════════════
local ctx = Action.buyCtx or {}
local income = tonumber(ctx.income) or 0
local soldGen = tonumber(ctx.soldGen) or 0
local travel = tonumber(ctx.travel) or 10
local minGain = tonumber((getgenv().RebirthConfig or {}).MinBuyGainSec) or 10
local need = REBIRTH_CASH - currentCash
local T0 = (income > 0) and (need / income) or math.huge
local floor = tonumber(incomeFloor) or 0
local bestItem, bestPrompt, bestT = nil, nil, nil
-- tra ve T1, hoac nil neu mua vao la LO thoi gian
local function payback(cost, gen)
local ni = income + gen - soldGen
if ni <= 0 then
return nil
end
local T1 = (need + cost - income * travel) / ni + travel
-- ★ NGUONG LOI TOI THIEU. Loi phai bu duoc CHI PHI CO HOI, khong chi > 0.
-- Vi du that: $278k, income 500/s -> mua Lirili ($250, 3 $/s) LOI 2.1 giay.
-- Duong tren lai LO: cu do ngon ~10s di bo va MOT O BE, ma trong 10s do
-- bang chuyen de them ~5 con (do that: 0.478 con/giay). Doi 2 giay lay
-- 10 giay la lo.
-- Mo phong so THAT (42 loai, RoadWeight that), giay-toi-rebirth:
-- $278k 10/10 cui : nguong 0 -> -9.3% | nguong 10s -> -10.2%
-- $50k 10/10 cui : nguong 0 -> -7.5% | nguong 10s -> -8.3%
-- $278k 10/10 kha : nguong 0 -> -16.7% | nguong 10s -> -18.4%
-- Khong chan khoi dong: ngheo thi income ~0 -> T0 vo cuc -> loi cuc lon,
-- vuot nguong de dang. Nguong chi can khi DA giau, dung luc can can.
if T0 - T1 < minGain then
return nil
end
return T1
end
local Animals = getGenerationData()
local animals = AnimalSource.getAnimals()
if animals and Animals then
-- ── duong CHINH: duyet dung nhung con dang co, doc gia tu du lieu game ──
for _, rec in pairs(animals) do
local name = type(rec) == "table" and rec.Index or nil
local d = name and Animals[name]
local cost = d and tonumber(d.Price)
if cost and currentCash >= cost then
local prompt = AnimalSource.promptOf(rec)
if prompt and isPurchasePromptAvailable(prompt) then
-- $/s THUC cua CON NAY: genFromData nhan them mutation/traits
local gen = getPurchaseIncome(prompt, name)
local T1 = gen and gen >= floor and payback(cost, gen) or nil
if T1 and (not bestT or T1 < bestT) then
bestItem = { name = name, cost = cost, required = false }
bestPrompt = prompt
bestT = T1
end
end
end
end
-- Registry chay duoc thi no la nguon DAY DU nhat — tra ve luon, ke ca nil.
-- Khong duoc roi xuong quet buyList: cung mot san se cho cung ket qua rong,
-- ma vong farm chay moi 2 giay nen 16 lan findProximityPrompt do la phi thuan.
return bestItem, bestPrompt
end
-- ── DU PHONG: CHI khi registry hong (require that bai / GetAnimals loi) ──
for _, item in ipairs(buyList) do
if not item.required and currentCash >= item.cost then
local prompt = findProximityPrompt(item.name)
local gen = prompt and getPurchaseIncome(prompt, item.name)
local T1 = gen and gen >= floor and payback(item.cost, gen) or nil
if T1 and (not bestT or T1 < bestT) then
bestItem, bestPrompt, bestT = item, prompt, T1
end
end
end
return bestItem, bestPrompt
end
-- tolerance = coi nhu "toi noi" khi con bao nhieu stud. Mac dinh 5 (giu nguyen hanh vi cu).
-- LockDoor truyen so nho hon vi can dung DUNG vao hitbox.
moveTo = function(position, operationDeadline, tolerance)
local startCharacter, startHumanoid, startHrp = getMovementRefs()
if not startCharacter or not startHumanoid or not startHrp then
return false
end
local tol = tonumber(tolerance) or 5
resetStuck()
local finished = false
local reached = false
local connection = startHumanoid.MoveToFinished:Connect(function(didReach)
finished = true
reached = didReach
end)
startHumanoid:MoveTo(position)
local deadline = math.min(tick() + 15, operationDeadline or math.huge)
-- ⚠ PHAT LAI khi bi CAT NGANG. Truoc day MoveTo chi phat DUNG MOT LAN va vong
-- lap khong bao gio phat lai, nen:
-- • script ngoai (anti-AFK cua Duy/nam) goi Humanoid:MoveTo hoac dat
-- WalkToPoint -> Roblox HUY lenh cua ta, ban MoveToFinished(false)
-- -> ta tra false -> pathfindTo vut CA duong di -> mat nguyen mot luot.
-- • va ke ca checkStuck co ban 3 cu nhay thi nhan vat cung dung im,
-- vi khong ai phat lai lenh di.
-- Gio: MoveToFinished(false) MA van con xa dich + con song + con gio
-- => coi la BI CHEN, phat lai va di tiep. Toi da RETRY_MAX lan de khong
-- quay vo han khi dich that su khong toi duoc; deadline van la tran cung.
local RETRY_MAX = 3
local retries = 0
while tick() < deadline do
task.wait(0.1) -- giu nguyen 0.1: FPS cap 15 = 67ms/frame nen 0.05 khong nhanh hon
local currentCharacter, currentHumanoid, currentHrp = getMovementRefs()
if currentCharacter ~= startCharacter or currentHumanoid ~= startHumanoid or not currentHrp then
connection:Disconnect()
return false
end
if (currentHrp.Position - position).Magnitude < tol then
connection:Disconnect()
return true
end
if finished then
if (not reached) and retries < RETRY_MAX and tick() < deadline - 0.5 then
-- bi cat ngang (hoac het 8s timeout noi tai cua Roblox) -> di tiep
retries = retries + 1
finished, reached = false, false
currentHumanoid.Jump = true -- nhay mot cai phong khi dang mac ket
currentHumanoid:MoveTo(position)
else
connection:Disconnect()
return reached
end
end
checkStuck()
end
connection:Disconnect()
return false
end
function pathfindTo(position, operationDeadline, tolerance)
operationDeadline = operationDeadline or tick() + ACTION_TIMEOUT_SECONDS
local tol = tonumber(tolerance) or 5
-- ⚠ TINH LAI DUONG KHI BI KEO DI. Script BEN THU BA (anti-AFK) co the goi
-- Humanoid:MoveTo hoac dat WalkToPoint bat cu luc nao. Khi do:
-- 1. lenh di cua ta bi HUY -> moveTo tra false
-- 2. va te hon: cac waypoint CON LAI van tinh tu vi tri CU, di theo chung
-- la di nguoc hoac dam vao tuong.
-- Ban cu gap (1) la `return false` vut CA duong di -> mat nguyen mot luot farm,
-- dung cai user thay la "stuck ti". Gio: hong mot waypoint thi TINH LAI duong
-- tu vi tri HIEN TAI va di tiep, toi da REPLAN_MAX lan. Deadline van la tran cung.
local REPLAN_MAX = 3
for attempt = 0, REPLAN_MAX do
if tick() >= operationDeadline then
return false
end
local _, _, currentHrp = getMovementRefs()
if not currentHrp then
return false
end
if (currentHrp.Position - position).Magnitude < tol then
return true
end
local path = PathfindingService:CreatePath({
AgentRadius = 2,
AgentHeight = 5,
AgentCanJump = true,
})
local computeDone = false
local ok = false
local computeThread = task.spawn(function()
ok = pcall(function()
path:ComputeAsync(currentHrp.Position, position)
end)
computeDone = true
end)
while not computeDone and tick() < operationDeadline do
task.wait(0.05)
end
if not computeDone then
pcall(task.cancel, computeThread)
return false
end
-- ⚠ DA THU GOM WAYPOINT (di thang khi he so vong < 1.2, gop waypoint cach < 12 stud)
-- -> BI DUNG TUONG. He so vong gan 1.0 KHONG co nghia la duong thong: mot khuc
-- re vuong goc quanh vat can van cho tong do dai xap xi duong thang. Bo waypoint
-- la bo dung nhung khuc tranh vat can do. DA REVERT ve di TUNG waypoint.
-- Khung la do FPS CAP 15 (moi frame 67ms), khong phai do cat waypoint.
if not (ok and path.Status == Enum.PathStatus.Success) then
-- khong tinh duoc duong -> di thang, day la duong lui cuoi cung
return moveTo(position, operationDeadline, tolerance)
end
local wps = path:GetWaypoints()
local broke = false
for i, waypoint in ipairs(wps) do
if tick() >= operationDeadline then
return false
end
local _, currentHumanoid, latestHrp = getMovementRefs()
if not currentHumanoid or not latestHrp then
return false
end
if waypoint.Action == Enum.PathWaypointAction.Jump then
currentHumanoid.Jump = true
end
if
(latestHrp.Position - waypoint.Position).Magnitude >= 5
and not moveTo(waypoint.Position, operationDeadline, (i == #wps) and tolerance or nil)
then
-- ★ KHONG vut ca duong nua: thoat ra tinh lai tu cho dang dung.
broke = true
break
end
end
if not broke then
return true
end
end
-- het luot tinh lai: thu di thang mot phat cuoi
return moveTo(position, operationDeadline, tolerance)
end
-- ══════════════════════════════════════════════════════════════════════
-- COLLECT — quet mot mach, cho MOT lan, roi KIEM va di lai cho nao truot.
--
-- ⚠ DO LIVE 2026-09-04:
-- * cham 1 pad -> ca cash LAN LastCollect doi sau 1.17s => do tre la ROUND-TRIP
-- mang, khong phai hang doi tuan tu => cac lan cham DOC LAP nhau.
-- * di bo qua het 10 pad (luc ranh) = 3.5s
-- * ban cu: task.wait(0.8~1.6) sau MOI pad = ~12s cho suong
-- => 3.5 + 12 = 15.5s, khop voi 16.10s do duoc trong log that.
--
-- Thiet ke moi:
-- PASS 1 quet mot mach, KHONG cho (~3.5s)
-- CHO mot lan cho server ghi nhan (1.5s)
-- PASS 2 doc LastCollect, pad nao CHUA doi thi di lai co cho (thuong 0 pad)
--
-- => thuong ~5s thay vi 15.5s. Va neu gia dinh "cham doc lap" SAI thi PASS 2
-- di lai het, ket qua van dung — chi mat thoi gian bang cach cu. An toan.
--
-- LastCollect lay tu channel Synchronizer (Action.getSyncedAnimalList), la tin hieu
-- CHINH XAC theo tung be — khong dua vao cash vi cash co the doi vi ly do khac
-- (dang mua, dang ban) va khong cho biet BE NAO da an.
-- ══════════════════════════════════════════════════════════════════════
-- {[slot] = LastCollect}. nil = khong doc duoc channel -> bo qua khau kiem.
Action.collectStamps = function()
local al = Action.getSyncedAnimalList()
if type(al) ~= "table" then
return nil
end
local out = {}
for i = 1, MAX_PODIUMS do
local a = al[i] or al[tostring(i)]
if type(a) == "table" then
out[i] = a.LastCollect
end
end
return out
end
function Action.collectCash()
local _t = Action.T.begin("collect", "gom tien tu cac be")
local deadline = tick() + COLLECT_PASS_TIMEOUT_SECONDS
lastCollect = tick() - COLLECT_INTERVAL + COLLECT_RETRY_SECONDS
local animalPodiums = getAnimalPodiums()
if not animalPodiums or not animalPodiums.Parent then
return Action.T.done(_t, false, "khong thay AnimalPodiums")
end
local podiumCache = getPodiumCache()
if podiumCache.count <= 0 then
lastCollect = tick()
return Action.T.done(_t, true, "be trong, khong co gi de gom")
end
local targets = {}
for i = 1, MAX_PODIUMS do
local slotInfo = podiumCache.slots[i]
local claim = slotInfo and slotInfo.slot and slotInfo.slot:FindFirstChild("Claim")
local target = claim and claim:FindFirstChild("Main")
if target and target:IsA("BasePart") then
table.insert(targets, { slotIndex = i, target = target })
end
end
if not targets[1] then
return Action.T.done(_t, false, "khong thay claim pad")
end
local before = Action.collectStamps()
-- ── PASS 1: quet mot mach, khong cho giua cac pad ──
if not pathfindTo(targets[1].target.Position, deadline, 4) then
return Action.T.done(_t, false, "khong pathfind toi base duoc")
end
local swept = 0
for _, info in ipairs(targets) do
if tick() >= deadline then
return Action.T.done(_t, false, ("het gio 45s (quet %d/%d)"):format(swept, #targets))
end
if lockDoorBusy then
return Action.T.done(_t, false, ("nhuong cho khoa cua (quet %d/%d)"):format(swept, #targets))
end
local target = info.target
if target.Parent and target:IsA("BasePart") then
moveTo(target.Position, deadline, 4)
swept = swept + 1
end
end
-- ── CHO MOT LAN cho server ghi nhan ca loat ──
local settle = tonumber((getgenv().RebirthConfig or {}).CollectSettleSec) or 1.5
task.wait(math.min(settle, math.max(0, deadline - tick())))
-- ── PASS 2: pad nao CHUA an thi di lai, lan nay co cho tung cai ──
local after = Action.collectStamps()
if not (before and after) then
-- khong doc duoc channel -> khong kiem duoc, coi nhu xong (khong chan farm)
lastCollect = tick()
return Action.T.done(_t, true, ("quet %d be (khong kiem duoc channel)"):format(swept))
end
local missed = {}
for _, info in ipairs(targets) do
local i = info.slotIndex
if before[i] ~= nil and after[i] == before[i] then
missed[#missed + 1] = info
end
end
if #missed == 0 then
lastCollect = tick()
return Action.T.done(_t, true, ("%d be, 1 luot quet"):format(swept))
end
Action.T.mark(("%d/%d be chua an -> di lai"):format(#missed, #targets))
local retryWait = tonumber((getgenv().RebirthConfig or {}).CollectRetryWaitSec) or 1.3
local fixed = 0
for _, info in ipairs(missed) do
if tick() >= deadline or lockDoorBusy then
break
end
local target = info.target
if target.Parent and target:IsA("BasePart") then
moveTo(target.Position, deadline, 4)
task.wait(math.min(retryWait, math.max(0, deadline - tick())))
local now = Action.collectStamps()
if now and now[info.slotIndex] ~= before[info.slotIndex] then
fixed = fixed + 1
end
end
end
lastCollect = tick()
return Action.T.done(_t, true, ("%d be | di lai %d, vot duoc %d"):format(swept, #missed, fixed))
end
function Action.isValidSellPrompt(prompt, slot, name)
if not prompt or not prompt.Parent or not prompt:IsA("ProximityPrompt") or prompt.Enabled ~= true then
return false
end
if not slot or not slot.Parent or not prompt:IsDescendantOf(slot) then
return false
end
if tostring(prompt.ActionText or ""):sub(1, 4) ~= "Sell" then
return false
end
local objectText = tostring(prompt.ObjectText or "")
return objectText == "" or objectText:lower():find(name:lower(), 1, true) ~= nil
end
function Action.getPromptPart(prompt)
local current = prompt and prompt.Parent
while current and current ~= Workspace do
if current:IsA("BasePart") then
return current
end
current = current.Parent
end
return nil
end
function Action.sellBrainrot(name, slot, preFireCheck)
local actionDeadline = tick() + ACTION_TIMEOUT_SECONDS
if not slot or not slot.Parent then
return false
end
print("💸 Selling " .. name .. "...")
local sellPrompt = nil
for _, obj in ipairs(slot:GetDescendants()) do
if Action.isValidSellPrompt(obj, slot, name) then
sellPrompt = obj
break
end
end
if not sellPrompt then
warn("❌ Could not find sell prompt for " .. name)
return false
end
local base = slot:FindFirstChild("Base")
local spawn = base and base:FindFirstChild("Spawn")
if not spawn or not spawn:IsA("BasePart") then
warn("❌ Missing sell spawn for " .. name)
return false
end
if not pathfindTo(spawn.Position, actionDeadline) then
warn("❌ Could not pathfind to sell spawn for " .. name)
return false
end
local _, _, currentHrp = getMovementRefs()
if not currentHrp then
warn("❌ Missing movement refs for sell " .. name)
return false
end
if (currentHrp.Position - spawn.Position).Magnitude > 8 and not moveTo(spawn.Position, actionDeadline) then
warn("❌ Could not reach sell spawn for " .. name)
return false
end
task.wait(0.5)
if not Action.isValidSellPrompt(sellPrompt, slot, name) then
warn("❌ Sell prompt changed before firing for " .. name)
return false
end
if preFireCheck then
local ok, allowed = pcall(preFireCheck)
if not ok or not allowed then
warn("❌ Upgrade target changed before selling " .. name)
return false
end
end
local promptPart = Action.getPromptPart(sellPrompt)
local _, _, latestHrp = getMovementRefs()
local maxDistance = tonumber(sellPrompt.MaxActivationDistance) or 10
if
not Action.isValidSellPrompt(sellPrompt, slot, name)
or not promptPart
or not latestHrp
or (latestHrp.Position - promptPart.Position).Magnitude > maxDistance
then
warn("❌ Sell prompt is no longer interactable for " .. name)
return false
end
local fired = pcall(function()
fireproximityprompt(sellPrompt)
end)
if not fired then
warn("❌ Failed to fire sell prompt for " .. name)
return false
end
task.wait(1)
markPodiumCacheDirty()
local slotIndex = tonumber(slot.Name)
local slotInfo = slotIndex and getPodiumCache().slots[slotIndex]
if slotInfo and slotInfo.slot == slot then
local loweredName = name:lower()
if
tostring(slotInfo.objectText or ""):lower():find(loweredName, 1, true)
or tostring(slotInfo.indexName or ""):lower():find(loweredName, 1, true)
then
warn("❌ Sell not confirmed for " .. name)
return false
end
end
print("✅ Sold " .. name .. "!")
return true
end
function Action.isRequiredAnimalName(name)
local loweredName = tostring(name or ""):lower()
for _, requiredName in ipairs(ownedList) do
if loweredName:find(requiredName:lower(), 1, true) then
return true
end
end
return false
end
function Action.findLowestIncomeSellCandidate()
local podiumCache = getPodiumCache()
local best = nil
for i = 1, MAX_PODIUMS do
local slotInfo = podiumCache.slots[i]
if slotInfo and slotInfo.slot and slotInfo.slot.Parent then
local name = slotInfo.objectText ~= "" and slotInfo.objectText or slotInfo.indexName
if
name ~= ""
and not Action.isRequiredAnimalName(name)
and not Action.isRequiredAnimalName(slotInfo.indexName)
then
local generation = tonumber(slotInfo.generation) or 0
if not best or generation < best.generation then
best = { name = name, slot = slotInfo.slot, slotIndex = i, generation = generation }
end
end
end
end
return best
end
function Action.freeSlotForRequiredAnimal(currentCash, owned, podiumCount)
if podiumCount < MAX_PODIUMS then
return false
end
for _, item in ipairs(buyList) do
local prompt = item.required
and not owned[item.name]
and currentCash >= item.cost
and findProximityPrompt(item.name)
if prompt then
local candidate = Action.findLowestIncomeSellCandidate()
if not candidate then
warn("❌ Plot full but no safe animal to sell for " .. item.name)
return false
end
print(
"🧹 Plot full, selling lowest $/s slot "
.. candidate.slotIndex
.. ": "
.. candidate.name
.. " ($/s "
.. candidate.generation
.. ") to make room for "
.. item.name
)
local sold = Action.sellBrainrot(candidate.name, candidate.slot, function()
return promptMatchesPurchaseName(prompt, item.name)
and isPurchasePromptAvailable(prompt)
and getCash() >= item.cost
end)
if sold then
Action.buyBrainrot(item, prompt)
end
return sold
end
end
return false
end
function Action.freeSlotForUpgrade(item, prompt, podiumCount)
if podiumCount < MAX_PODIUMS or item.required or getCash() < item.cost then
return false
end
markPodiumCacheDirty()
local candidate = Action.findLowestIncomeSellCandidate()
if not candidate or candidate.generation <= 0 then
return false
end
local latestPrompt = prompt
local targetIncome = latestPrompt and getPurchaseIncome(latestPrompt, item.name)
if not targetIncome or targetIncome < candidate.generation * MIN_UPGRADE_MULTIPLIER or getCash() < item.cost then
return false
end
print(
"⬆️ Plot full, replacing slot "
.. candidate.slotIndex
.. ": "
.. candidate.name
.. " ($/s "
.. candidate.generation
.. ") with "
.. item.name
.. " ($/s "
.. targetIncome
.. ")"
)
local sold = Action.sellBrainrot(candidate.name, candidate.slot, function()
local finalIncome = getPurchaseIncome(latestPrompt, item.name)
return finalIncome and finalIncome >= candidate.generation * MIN_UPGRADE_MULTIPLIER and getCash() >= item.cost
end)
if sold then
Action.buyBrainrot(item, latestPrompt)
end
return sold
end
function Action.isPromptInteractable(prompt, part, currentHrp)
if not isPurchasePromptAvailable(prompt) or prompt.Enabled ~= true then
return false
end
local maxDistance = tonumber(prompt.MaxActivationDistance) or 10
return part and currentHrp and (currentHrp.Position - part.Position).Magnitude <= maxDistance
end
function Action.waitForPromptInteractable(prompt, name, timeout)
local deadline = tick() + timeout
while tick() < deadline do
if not promptMatchesPurchaseName(prompt, name) then
return false
end
local latestPart = getPurchasePart(prompt)
local _, _, latestHrp = getMovementRefs()
if not latestPart or not latestHrp then
return false
end
if Action.isPromptInteractable(prompt, latestPart, latestHrp) then
return true
end
task.wait(0.1)
end
return false
end
-- ══════════════════════════════════════════════════════════════════════
-- MUA BRAINROT — ban SONG SONG voi di chuyen
--
-- ⚠ BAN CU TUAN TU: pathfindTo (toi 45s) -> moveTo -> wait 0.5 -> wait 1.5
-- -> MOI ban DUNG MOT phat. Di 10 giay roi ban vao cho trong, vi bang chuyen
-- van chay va nguoi khac van mua trong luc minh dang di.
--
-- BAN MOI: mot thread SPAM ban chay ngay tu dau, song song voi di chuyen.
-- Vua chay vua ban -> vao tam la an lien, khong cho toi noi moi ban.
-- Dung ngay khi tien GIAM (getCash doc cache, re) de khong mua trung 2 con.
-- Vi tri dich duoc DOC LAI moi vong vi con vat dang troi tren bang chuyen.
-- ══════════════════════════════════════════════════════════════════════
-- ══════════════════════════════════════════════════════════════════════
-- DEM CON DANG TREN DUONG VE BE (sua loi "mua truoc khi be kip cap nhat")
--
-- ⚠ TRIEU CHUNG THAT (log 18:37:56): mua duoc Pipi Kiwi luc 18:37:56, NGAY giay
-- do vong farm doc "be 9/10" nen di mua THEM mot con Pipi Kiwi nua -> ban 20
-- phat, server tu choi, phi 7.45s. Den 18:38:04 be moi len 10/10.
--
-- ⚠ CACHE KHONG HE CU. Be THUC SU dang la 9/10: con vua mua con dang DI BO tu
-- bang chuyen ve be, mat ~8-12s. Nen markPodiumCacheDirty() khong cuu duoc —
-- quet lai bao nhieu lan cung ra 9.
--
-- CACH DEM: server dat attribute TargetPlayer len prompt NGAY khi mua (code duoi
-- da biet dieu nay, xem chu thich "server dat ngay sau phat ban dau, TRUOC khi
-- tien tru"). TargetPlayer == chinh minh => con nay da la cua minh, dang ve.
-- Tu het khi con vat len be — khong can hen gio, khong so lech so.
--
-- CHOT THOI GIAN la luoi thu hai, phong khi TargetPlayer khong ton tai suot duong
-- ve: vua mua xong ma so be chua nhuc nhich thi coi nhu con 1 con dang ve.
-- ══════════════════════════════════════════════════════════════════════
Action.lastBuyCount = -1
Action.countIncoming = function()
-- ⚠ CHOT THOI GIAN BAT BUOC — dat TRUOC vong quet, khong phai sau.
-- Chot nay chi co y nghia NGAY SAU khi CHINH MINH vua mua: no che cai khe
-- ~8-12s con vat di bo tu bang chuyen ve be. Khong mua gi trong giay
-- thi khong the co con nao cua minh dang ve.
-- ⚠ Neu KHONG chan bang thoi gian: mot prompt bi sot TargetPlayer=minh (con vat
-- despawn giua duong, giao dich bi huy, prompt duoc tai su dung) se lam n >= 1
-- VINH VIEN. Ma chot goi ham nay nam TRUOC nhanh "be day", nen bot se khong mua,
-- khong nang cap, chi con collectCash moi 55s — dung im that su.
-- Tha mua chong mot con con hon dung im mai.
local grace = tonumber((getgenv().RebirthConfig or {}).DeliveryGraceSec) or 20
if lastPurchaseTime <= 0 or tick() - lastPurchaseTime >= grace then
return 0
end
local n = 0
pcall(function()
-- di thang Part.PromptAttachment.ProximityPrompt, KHONG GetDescendants:
-- ham nay chay moi vong farm, quet descendants ca tram con vat thi phi.
for _, obj in ipairs(CollectionService:GetTagged("Animal")) do
local pr = getPurchasePromptFromAnimal(obj)
if pr then
local tp = pr:GetAttribute("TargetPlayer")
if tp ~= nil and (tp == player or tp == player.Name or tp == player.UserId) then
n = n + 1
end
end
end
end)
-- luoi thu hai: phong khi TargetPlayer khong ton tai suot duong ve.
-- Da nam trong cua so nho chot o dau ham nen khong the ket.
if Action.lastBuyCount >= 0 and (select(1, getPodiumInfo()) or 0) <= Action.lastBuyCount then
n = math.max(n, 1)
end
return n
end
Action.buyBrainrot = function(item, prompt)
local actionDeadline = tick() + ACTION_TIMEOUT_SECONDS
if not promptMatchesPurchaseName(prompt, item.name) then
markPurchasePromptCacheDirty()
return false
end
if not isPurchasePromptAvailable(prompt) then
warn("⏭️ Skip " .. item.name .. ": khong con o the gioi hoac da co nguoi dat cho")
return false
end
local part = getPurchasePart(prompt)
if not part then
warn("❌ Missing purchase part for " .. item.name)
markPurchasePromptCacheDirty()
return false
end
-- ★ CHOT 1: base DAY thi khong mua duoc — server tu choi im lang.
-- Log thuc te: 67 phat / 40.43s vao hu vo vi be da 10/10.
-- Nguoi goi co kiem podiumCount nhung do la so doc tu DAU vong lap, co the CU.
do
local n0 = select(1, getPodiumInfo())
if (tonumber(n0) or 0) >= MAX_PODIUMS then
Action.T.mark(("bo mua %s: be da day %d/%d"):format(item.name, n0, MAX_PODIUMS))
return false
end
end
local cashBefore = getCash()
local buyUid = AnimalSource.uidOfPrompt(prompt)
-- moc de biet be da nhan con moi chua (xem Action.countIncoming)
Action.lastBuyCount = select(1, getPodiumInfo()) or 0
local bought, stopSpam, fires = false, false, 0
local firstFireAt = nil
local gap = tonumber((getgenv().RebirthConfig or {}).BuySpamGap) or 0.2
local _t = Action.T.begin("mua", ("%s $%d"):format(item.name, item.cost))
-- ── thread SPAM ban, chay SONG SONG voi di chuyen ──
-- ⚠ DA THU LIVE: ban tu XA KHONG an — server CO kiem khoang cach.
-- Nen chi ban khi da trong tam (MaxActivationDistance, mac dinh 10, cong bien 2).
-- Ban tu 300 stud chi phi CPU chu khong mua duoc gi.
-- Cai loi cua thread nay khong phai "ban tu xa" ma la "ban NGAY GIAY vao tam",
-- thay vi cho di het duong roi wait 2 giay moi ban nhu ban cu.
local spamThread = task.spawn(function()
local maxFires = tonumber((getgenv().RebirthConfig or {}).MaxFruitlessFires) or 20
while not stopSpam and tick() < actionDeadline do
if getCash() < cashBefore then
bought = true
break
end
if fires >= maxFires then
break -- ban du nhieu ma khong an: thoi, khoi quay khong
end
local p = getPurchasePart(prompt)
local _, _, h = getMovementRefs()
local inRange = false
if p and h then
local maxD = tonumber(prompt.MaxActivationDistance) or 10
inRange = (h.Position - p.Position).Magnitude <= (maxD + 2)
end
if
inRange
and promptMatchesPurchaseName(prompt, item.name)
and isPurchasePromptAvailable(prompt)
and prompt.Enabled == true
then
fires = fires + 1
firstFireAt = firstFireAt or tick()
pcall(function()
fireproximityprompt(prompt)
end)
-- kiem NGAY sau khi ban: mua duoc thi dung, tranh mua trung con thu 2
task.wait(0.05)
if getCash() < cashBefore then
bought = true
break
end
task.wait(gap)
else
-- bi nguoi khac dat cho -> thoi spam luon, khoi quay khong
local tp2 = prompt:GetAttribute("TargetPlayer")
if tp2 ~= nil and tp2 ~= player and tp2 ~= player.Name and tp2 ~= player.UserId then
break
end
-- chua vao tam: poll nhanh de bat DUNG khoanh khac vao tam
task.wait(0.05)
end
end
end)
-- ── di chuyen, BAM THEO vi tri moi vi con vat troi tren bang chuyen ──
local moveOk = false
local why = "het gio 45s"
while not bought and tick() < actionDeadline do
local latestPart = getPurchasePart(prompt)
if not latestPart then
why = "con vat bien mat"
break
end
if not promptMatchesPurchaseName(prompt, item.name) then
why = "prompt doi sang con khac"
break
end
local _, _, hrp = getMovementRefs()
if not hrp then
why = "mat nhan vat"
break
end
-- ★ NHUONG duong cho thread khoa cua — nhung CHI khi chua ban phat nao.
-- Da ban roi thi co the tien dang tru, bo dở la mat ca chi lan tien.
-- ★ CHOT 2: nhuong cho khoa cua. Truoc day chi nhuong khi fires == 0 nen
-- khi dang spam vo ich (67 phat) no KHONG nhuong, lam khoa cua chet 28s theo.
-- Gio: chua ban thi nhuong ngay; ban roi ma qua 3s van chua an thi cung nhuong,
-- vi ro rang server dang tu choi chu khong phai giao dich dang bay.
if lockDoorBusy and (fires == 0 or (firstFireAt and tick() - firstFireAt > 3)) then
why = "nhuong cho khoa cua"
break
end
-- ★ CHOT 3: ban nhieu ma khong an = server tu choi (be day / het tien / mat cho).
local maxFires = tonumber((getgenv().RebirthConfig or {}).MaxFruitlessFires) or 20
if fires >= maxFires then
why = ("ban %d phat khong an, server tu choi"):format(fires)
break
end
if fires > 0 and (select(1, getPodiumInfo()) or 0) >= MAX_PODIUMS then
why = "be day giua chung"
break
end
-- ★ BO NGAY khi nguoi khac dat cho muc tieu, dung di tiep cho het 45s.
-- KHONG dung isPurchasePromptAvailable de kiem: no cung tra false khi
-- TargetPlayer la CHINH MINH (server dat ngay sau phat ban dau, TRUOC khi
-- tien tru) => se tu huy chinh giao dich cua minh. Phai loai tru ban than.
if not latestPart:IsDescendantOf(Workspace) then
why = "con vat roi khoi the gioi"
break
end
-- ★ prompt co the duoc TAI SU DUNG sang con khac khi con cu despawn.
-- UID doi = khong con la con minh dinh mua nua, bo ngay.
if buyUid ~= nil and AnimalSource.uidOfPrompt(prompt) ~= buyUid then
why = "prompt doi sang con khac (UID doi)"
break
end
local tp = prompt:GetAttribute("TargetPlayer")
if tp ~= nil and tp ~= player and tp ~= player.Name and tp ~= player.UserId then
why = "bi nguoi khac dat cho"
break
end
local maxD = tonumber(prompt.MaxActivationDistance) or 10
local d = (hrp.Position - latestPart.Position).Magnitude
-- bam sat hon tam mot chut: con vat TROI tren bang chuyen, dung yen o ria
-- tam la no troi ra ngoai roi mat luot.
if d <= maxD - 3 then
moveOk = true
-- an toan trong tam: dung yen cho thread spam lam viec
task.wait(0.15)
else
-- deadline ngan cho moi chang, de con doc lai vi tri con vat
local legDeadline = math.min(actionDeadline, tick() + 6)
if d > 40 then
pathfindTo(latestPart.Position, legDeadline)
else
moveTo(latestPart.Position, legDeadline)
end
end
end
stopSpam = true
pcall(function()
task.cancel(spamThread)
end)
markPurchasePromptCacheDirty()
-- xac nhan bang tien, khong tin ket qua ban.
-- fires == 0 => chua ban phat nao => khong the co giao dich dang bay => 2s nay
-- chac chan phi. Day la thu bien cac lan bo som (bi cuop / nhuong khoa cua)
-- tu ~2.2s xuong ~0.2s.
if not bought and fires > 0 then
local waitUntil = tick() + 2
while tick() < waitUntil do
if getCash() < cashBefore then
bought = true
break
end
task.wait(0.1)
end
end
if not bought then
return Action.T.done(
_t,
false,
("%s | %d phat | %s"):format(why, fires, moveOk and "da vao tam" or "chua vao tam")
)
end
lastPurchaseTime = tick()
markPodiumCacheDirty()
return Action.T.done(_t, true, ("$%d -> $%d, %d phat"):format(cashBefore, getCash(), fires))
end
function Action.sendWebhook(title, description, color, fields)
task.spawn(function()
local safeTitle = "notification"
local sent = false
local ok = pcall(function()
safeTitle = tostring(title or "")
local embedFields = {}
if type(fields) == "table" then
for _, field in ipairs(fields) do
if type(field) == "table" and field.name ~= nil and field.value ~= nil then
local nameOk, fieldName = pcall(tostring, field.name)
local valueOk, fieldValue = pcall(tostring, field.value)
if nameOk and valueOk then
table.insert(embedFields, {
name = fieldName,
value = fieldValue,
inline = field.inline ~= false,
})
end
end
end
end
if type(http_request) ~= "function" then
warn("❌ Webhook unavailable: http_request is missing")
return
end
local data = HttpService:JSONEncode({
username = "Rebirth Bot",
embeds = {
{
title = safeTitle,
description = tostring(description or ""),
color = tonumber(color) or 0,
fields = embedFields,
},
},
})
local request = {
Url = WEBHOOK,
Method = "POST",
Headers = { ["Content-Type"] = "application/json" },
Body = data,
}
http_request(request)
sent = true
end)
if sent then
print("✅ Webhook sent: " .. safeTitle)
elseif not ok then
warn("❌ Webhook failed: " .. safeTitle)
end
end)
end
local rebirthRequestTimedOut = false
-- ══════════════════════════════════════════════════════════════════════
-- LOCK BASE — giu cua nha luon khoa, het han la dong lai NGAY
-- ----------------------------------------------------------------------
-- DO TU GAME THAT 2026-09-04 (decompile ReplicatedStorage.Classes.PlotClient):
--
-- Trang thai khoa nam trong CHANNEL Synchronizer cua plot:
-- BlockEndTimeFirstFloor / ...SecondFloor / ...ThirdFloor
-- = moc GetServerTimeNow() ma khoa tang do HET HAN.
-- nil => tang do DANG MO.
-- PlotClient: Channel:Get(v83) ~= nil -> UnlockBase.Enabled = true
-- BlockedDelayTime
-- = moc het COOLDOWN, chua toi thi KHONG khoa lai duoc.
-- PlotClient: co gia tri -> hien "Ready in:" + RemainingTime, an "Lock Base".
--
-- Kich hoat khoa: cham vao Purchases/PlotBlock/Hitbox (CanTouch=true,
-- CanCollide=false, Transparency=1). PlotBlock KHONG co ProximityPrompt va
-- PlotClient khong ban remote nao => server bat Touched. Nen ta CHI CAN
-- DUNG VAO hitbox, khong ban remote gi ca (an toan voi BAC).
--
-- HAI LOP, vi phan ung nhanh thoi thi KHONG DU:
-- * DU BAO : con PreArriveSec giay thi ve dung san canh cua (di lai ton vai giay,
-- ma dung luc do la luc bi cuop).
-- * CANH : BlockEndTime* la MOC THOI GIAN TUYET DOI, nen canh chinh xac duoc.
-- Sat gio thi vong chat 0.1s, het han la cham ngay.
-- (KHONG dung GetPropertyChangedSignal("Enabled"): da thu live, tren
-- client chu nha prompt do LUON tat nen signal khong bao gio ban.)
--
-- Doc channel qua GetTableFromChannel (duong AN TOAN, khong dam honeypot
-- RelateChannels cua Get/GetAllChannels/Wait/WaitAndCall).
-- ══════════════════════════════════════════════════════════════════════
local LockDoor = {}
-- ⚠ PHAI la (function() ... end)() chu KHONG phai do...end.
-- do...end KHONG cap budget register moi: moi local ben trong van tinh vao
-- chunk chinh (tran 200). Hai khoi nay co ~133 local -> tran ngay.
-- Ham thi co budget RIENG, chunk chi ton dung 1 register cho bang o tren.
;(function()
local FLOOR_FIELD = {
[1] = "BlockEndTimeFirstFloor",
[2] = "BlockEndTimeSecondFloor",
[3] = "BlockEndTimeThirdFloor",
}
local _sync = nil
local function getSync()
if _sync then
return _sync
end
local ok, mod = pcall(function()
local pkg = ReplicatedStorage:WaitForChild("Packages", 10):WaitForChild("Synchronizer", 10)
return require((cloneRef and cloneRef(pkg)) or pkg)
end)
if ok and type(mod) == "table" and type(mod.GetTableFromChannel) == "function" then
_sync = mod
end
return _sync
end
local function channelOf(plot)
local s = getSync()
if not s or not plot then
return nil
end
local ok, data = pcall(s.GetTableFromChannel, s, plot.Name)
return (ok and type(data) == "table") and data or nil
end
-- Purchases/PlotBlock/Hitbox : cham vao day = server khoa base
local function getLockBlock(plot)
local pur = plot and plot:FindFirstChild("Purchases")
if not pur then
return nil, nil
end
local blk = pur:FindFirstChild("PlotBlock")
if not blk then
for _, c in ipairs(pur:GetChildren()) do
if c:FindFirstChild("Hitbox") then
blk = c
break
end
end
end
local hb = blk and blk:FindFirstChild("Hitbox")
return blk, (hb and hb:IsA("BasePart")) and hb or nil
end
-- moi ProximityPrompt UnlockBase theo tang
local function unlockPrompts(plot)
local out = {}
local u = plot and plot:FindFirstChild("Unlock")
if not u then
return out
end
for _, m in ipairs(u:GetChildren()) do
local pr = m:FindFirstChild("UnlockBase")
if pr and pr:IsA("ProximityPrompt") then
out[#out + 1] = { prompt = pr, floor = tonumber(pr:GetAttribute("Floor")) or 1 }
end
end
return out
end
-- trang thai: locked? con bao lau? dang cooldown?
function LockDoor.state()
local plot = findMyPlot and findMyPlot() or nil
if not plot then
return nil, "khong tim thay plot cua minh"
end
local ch = channelOf(plot)
if not ch then
return nil, "khong doc duoc channel"
end
local now = workspace:GetServerTimeNow()
local st = {
plot = plot,
now = now,
cooldownUntil = tonumber(ch.BlockedDelayTime),
floors = {},
anyLocked = false,
soonestExpiry = nil,
}
for _, e in ipairs(unlockPrompts(plot)) do
local field = FLOOR_FIELD[e.floor]
local endAt = field and tonumber(ch[field]) or nil
local locked = endAt ~= nil
st.floors[#st.floors + 1] = {
floor = e.floor,
field = field,
endAt = endAt,
locked = locked,
left = endAt and math.max(0, endAt - now) or nil,
prompt = e.prompt,
}
if locked then
st.anyLocked = true
if not st.soonestExpiry or endAt < st.soonestExpiry then
st.soonestExpiry = endAt
end
end
end
st.onCooldown = st.cooldownUntil ~= nil and st.cooldownUntil > now
st.cooldownLeft = st.onCooldown and (st.cooldownUntil - now) or 0
return st
end
-- Dung vao hitbox de server bat Touched.
-- Da dung san trong hitbox thi Touched KHONG ban lai -> phai buoc ra roi vao.
-- ★ CHO DUNG: diem doi NGOAI hitbox. Pha CANH dung o day, het han chi BUOC VAO.
-- Do live: step-out + step-in = 3.33s ; CHI step-in tu 7 stud = 0.27s (nhanh 12 lan).
-- Cai cu bat dau bang buoc-RA nen dong ho chi chay SAU khi da het han
-- => cua ho 3.33s moi chu ky du canh gio chinh xac den may.
local WAIT_OFFSET = Vector3.new(7, 0, 0)
function LockDoor.waitSpot(hitbox)
return hitbox and (hitbox.Position + WAIT_OFFSET) or nil
end
-- Dung san NGOAI hitbox roi goi ham nay = cham gan nhu tuc thi.
-- Neu lo dang dung TRONG hitbox thi buoc ra truoc (Touched khong ban lai
-- neu da nam san ben trong).
local function touchLockBlock(hitbox, deadline)
local char = player and player.Character
local hrp = char and char:FindFirstChild("HumanoidRootPart")
if not hrp or not hitbox or not hitbox.Parent then
return false
end
local target = hitbox.Position
local spot = target + WAIT_OFFSET
local dist = (hrp.Position - target).Magnitude
if dist > 12 then
-- con xa: di toi CHO DOI (khong phai vao thang hitbox)
if not pathfindTo or not pathfindTo(spot, deadline, 3) then
return false
end
elseif dist < 3 then
-- dang o TRONG hitbox: phai ra truoc, khong thi Touched khong ban lai
pcall(function()
moveTo(spot, deadline, 2)
end)
end
-- buoc VAO
pcall(function()
moveTo(target, deadline, 2)
end)
return true
end
-- Khoa lai. Tra ve true neu channel xac nhan da khoa.
function LockDoor.relock(reason)
local st, err = LockDoor.state()
if not st then
return false, err
end
if st.onCooldown then
return false, ("cooldown con %ds"):format(math.ceil(st.cooldownLeft))
end
local _, hitbox = getLockBlock(st.plot)
if not hitbox then
return false, "khong thay PlotBlock.Hitbox"
end
lockDoorBusy = true
local deadline = tick() + (ACTION_TIMEOUT_SECONDS or 45)
local ok = touchLockBlock(hitbox, deadline)
if not ok then
lockDoorBusy = false
return false, "khong toi duoc PlotBlock"
end
-- doi channel xac nhan (server ghi BlockEndTime*)
local waitUntil = tick() + 6
while tick() < waitUntil do
local s2 = LockDoor.state()
if s2 and s2.anyLocked then
lockDoorBusy = false
return true, ("da khoa (%s)"):format(tostring(reason or "?"))
end
task.wait(0.2)
end
lockDoorBusy = false
return false, "cham roi nhung channel chua bao khoa"
end
-- ══════════════════════════════════════════════════════════════════
-- UOC LUONG THOI GIAN DI CHUYEN — thay cho nguong cung 8 giay.
--
-- ⚠ DO LIVE 2026-09-04: script dat humanoid.WalkSpeed = 16 trong waitForFullLoad,
-- NHUNG gia tri thuc te doc duoc la 34 (game/perk nang len). Nen TUYET DOI
-- khong hardcode toc do — phai doc humanoid.WalkSpeed tai thoi diem tinh.
-- Kiem chung: 161 stud / 34 = 4.7s, do thuc te 5s. Khop.
--
-- Cong thuc: quangDuong / tocDo * heSoVong + chiPhiCham + biencanToan
-- heSoVong : duong di khong thang (vat can, doc). Tu HOC tu chuyen di that.
-- chiPhiCham: buoc ra 6 stud roi buoc vao de ep Touched ban lai (~3.2s do duoc).
-- ══════════════════════════════════════════════════════════════════
LockDoor._detour = 1.15 -- he so vong, tu dieu chinh sau moi chuyen
LockDoor._lastTrip = nil
function LockDoor.estimateTravel(targetPos)
local rc = getgenv().RebirthConfig or {}
local char = player and player.Character
local hum = char and char:FindFirstChildOfClass("Humanoid")
local hrp = char and char:FindFirstChild("HumanoidRootPart")
if not (hum and hrp and targetPos) then
return tonumber(rc.LockPreArriveSec) or 8
end
local speed = tonumber(hum.WalkSpeed) or 16
if speed < 8 then
speed = 8 -- chan chia cho 0 khi bi lam cham / dang chet
end
local dist = (hrp.Position - targetPos).Magnitude
local detour = tonumber(rc.LockDetourFactor) or LockDoor._detour or 1.15
local touchCost = tonumber(rc.LockTouchOverheadSec) or 4
local margin = tonumber(rc.LockSafetyMarginSec) or 2
local est = dist / speed * detour + touchCost + margin
-- khong bao gio nho hon nguong san, cung khong lon den vo ly
local floorSec = tonumber(rc.LockPreArriveSec) or 8
return math.clamp(est, floorSec, 45), dist, speed
end
-- goi sau moi chuyen di that de he so vong tu chinh
function LockDoor.learnTrip(dist, seconds, speed)
if not (dist and seconds and speed) or seconds <= 0 or dist < 20 then
return
end
local straight = dist / speed
if straight <= 0 then
return
end
local observed = math.clamp(seconds / straight, 1.0, 3.0)
-- trung binh truot, nghieng ve gia tri LON hon cho an toan
local prev = LockDoor._detour or 1.15
LockDoor._detour = (observed > prev) and (prev * 0.4 + observed * 0.6)
or (prev * 0.8 + observed * 0.2)
LockDoor._lastTrip = { dist = math.floor(dist), sec = seconds, factor = LockDoor._detour }
end
-- ── vong canh ──
-- ══════════════════════════════════════════════════════════════════
-- VONG CANH CUA — dieu khien bang MOC THOI GIAN, khong bang signal.
--
-- ⚠ Da thu live 2026-09-04: sau khi khoa, BlockEndTimeFirstFloor CO gia tri
-- nhung UnlockBase.Enabled = FALSE. Prompt "Unlock Base" la de NGUOI KHAC
-- pha cua nha minh, nen tren client CHU NHA no luon tat.
-- => GetPropertyChangedSignal("Enabled") KHONG BAO GIO BAN o day.
-- Bo han huong do, chuyen sang canh moc thoi gian tuyet doi.
--
-- So do live: khoa keo dai ~54s, di bo 161 stud het ~5s, BlockedDelayTime = nil
-- (khoa xong khoa lai duoc ngay, khong cooldown).
--
-- Ba pha:
-- XA (con > PreArrive giay) : ke farm, chi poll 2s/lan
-- VE (con <= PreArrive) : gianh quyen dieu khien, chay ve dung canh cua
-- CANH (con <= 1.5s) : vong chat 0.1s, het han la cham NGAY
-- ══════════════════════════════════════════════════════════════════
function LockDoor.start()
task.spawn(function()
while true do
local waitFor = 2
local okLoop, errLoop = pcall(function()
local rc = getgenv().RebirthConfig or {}
if rc.AutoLockBase == false then
return
end
local st = LockDoor.state()
if not st then
return
end
-- nguong VE tinh DONG theo khoang cach + WalkSpeed THUC TE.
-- Khong dung so cung: script dat 16 nhung do live ra 34.
local _, hbForEst = getLockBlock(st.plot)
local pre, _estDist, estSpeed = LockDoor.estimateTravel(hbForEst and hbForEst.Position)
-- (a) chua khoa -> khoa ngay
if not st.anyLocked then
if st.onCooldown then
waitFor = math.min(2, math.max(0.5, st.cooldownLeft))
return
end
local _tl = Action.T.begin("khoa-cua", "chua khoa lan nao")
local okR, msg = LockDoor.relock("chua khoa")
Action.T.done(_tl, okR, msg)
if not okR then
waitFor = 3
end
return
end
-- (b) da khoa: tinh chinh xac con bao lau
local left = st.soonestExpiry - st.now
if left > pre then
-- XA: ke farm lam viec, ngu toi sat gio
waitFor = math.min(2, left - pre)
return
end
-- VE: gianh quyen dieu khien, chay ve dung canh cua
local _, hitbox = getLockBlock(st.plot)
if not hitbox then
return
end
lockDoorBusy = true
Action.T.setPhase("ve-khoa-cua", ("con %.0fs, nguong ve %.0fs"):format(left, pre))
-- ★ ve CHO DOI (ngoai hitbox 7 stud), KHONG vao thang hitbox.
-- Dung san ben trong thi luc het han phai buoc-RA truoc moi cham lai
-- duoc (Touched khong ban khi da nam san ben trong) = mat 3.33s.
-- Dung ngoai thi het han chi buoc VAO = 0.27s.
local spot = LockDoor.waitSpot(hitbox)
local hrp = player and player.Character and player.Character:FindFirstChild("HumanoidRootPart")
if hrp and spot and (hrp.Position - spot).Magnitude > 4 then
local d0 = (hrp.Position - spot).Magnitude
local t0 = tick()
pcall(function()
if pathfindTo then
pathfindTo(spot, tick() + math.max(10, left + 15), 3)
end
end)
-- hoc he so vong tu chuyen di THAT, de lan sau uoc luong sat hon
LockDoor.learnTrip(d0, tick() - t0, estSpeed or 16)
end
-- CANH: vong chat, het han la cham ngay
local guardUntil = tick() + math.max(3, left + 10)
while tick() < guardUntil do
local s2 = LockDoor.state()
if not s2 then
break
end
if not s2.anyLocked then
-- khoa vua rot -> cham lai NGAY (dang dung san canh cua)
local _tl = Action.T.begin("khoa-cua", "het han, dong lai")
local okR, msg = LockDoor.relock("het han")
Action.T.done(_tl, okR, msg)
break
end
local l2 = s2.soonestExpiry - s2.now
if l2 > pre then
break -- da duoc gia han boi thu khac, ve lam viec tiep
end
task.wait(l2 > 1.5 and 0.5 or 0.1)
end
lockDoorBusy = false
waitFor = 0.5
end)
if not okLoop then
lockDoorBusy = false
warn("[LockBase] loi vong canh: " .. tostring(errLoop))
waitFor = 3
end
task.wait(waitFor)
end
end)
end
-- goi qua MCP de soi trang thai, khoi phai doan
Action.debugLock = function()
local st, err = LockDoor.state()
if not st then
return { err = err }
end
local blk, hb = getLockBlock(st.plot)
local hrp = player and player.Character and player.Character:FindFirstChild("HumanoidRootPart")
local floors = {}
for _, f in ipairs(st.floors) do
floors[#floors + 1] = {
floor = f.floor,
field = f.field,
locked = f.locked,
secondsLeft = f.left and math.floor(f.left) or nil,
promptEnabled = f.prompt.Enabled,
}
end
return {
plot = st.plot.Name,
anyLocked = st.anyLocked,
onCooldown = st.onCooldown,
cooldownLeft = math.floor(st.cooldownLeft),
soonestExpirySec = st.soonestExpiry and math.floor(st.soonestExpiry - st.now) or nil,
floors = floors,
block = blk and blk:GetFullName() or nil,
distance = (hrp and hb) and math.floor((hrp.Position - hb.Position).Magnitude) or nil,
busy = lockDoorBusy,
}
end
end)()
-- ══════════════════════════════════════════════════════════════════════
-- FLEET — presence / report-dead / hop dinh ky
-- Port tu sab_scanner.lua (giu nguyen hop dong endpoint hobeojob).
--
-- POST /api/presence heartbeat {account,placeId,jobId,players,ping,hops,uptime}
-- GET /api/jobs/{placeId} danh sach server con slot -> CO CACHE DIA
-- POST /api/jobs/{placeId}/blacklist giu cho truoc khi teleport vao
-- POST /api/jobs/{placeId}/dead bao server chet (GameEnded) -> go khoi pool
-- GET games.roblox.com/v1/games/{id}/servers/Public FALLBACK khi hobeojob rong
--
-- ⚠ CACHE la BAT BUOC: ca fleet cung hop moi 15' se dam /api/jobs cung luc.
-- Cache ghi ra DIA nen CHIA SE giua moi tab tren may: tab dau GET + ghi file,
-- tab sau con han thi DOC FILE, khong goi mang. Kem jitter theo UserId de cac
-- tab het han LECH nhau.
-- ══════════════════════════════════════════════════════════════════════
local Fleet = {}
;(function()
local HttpSvc = cloneRef(game:GetService("HttpService"))
local StatsSvc = cloneRef(game:GetService("Stats"))
local _httpReq = (syn and syn.request) or (http and http.request) or http_request or request
local _canFile = (type(writefile) == "function") and (type(isfile) == "function")
local _bootAt = tick()
getgenv().__RB1_Hops = getgenv().__RB1_Hops or 0
local _svMem, _svMemExp = nil, 0 -- tang 1: cache trong RAM cua chinh tab nay
local _visited = {}
local _noSvRetries = 0
local _tpFailed, _tpFailResult = false, nil
local function fcfg()
return (getgenv().FleetConfig or {})
end
local function flog(...)
if fcfg().Debug ~= false then
print("[Fleet]", ...)
end
end
-- httpRequest truoc (co User-Agent, Cloudflare it chan hon), game:HttpGet lam fallback
local function httpGet(url)
if _httpReq then
local ok, r = pcall(_httpReq, { Url = url, Method = "GET" })
if ok and r and r.Body then
local code = tonumber(r.StatusCode or r.Status)
if not code or (code >= 200 and code < 300) then
return r.Body
end
end
end
local ok2, res = pcall(function()
return game:HttpGet(url)
end)
return (ok2 and type(res) == "string") and res or nil
end
local function jsonDecode(raw)
if type(raw) ~= "string" or raw == "" then
return nil
end
local ok, d = pcall(function()
return HttpSvc:JSONDecode(raw)
end)
return ok and d or nil
end
local function hopPlaceId()
return tonumber(fcfg().PlaceId) or game.PlaceId
end
-- ── CACHE DIA cho danh sach server (chia se giua moi tab) ──
local function _svCachePath()
return ("RB1_servers_%d.json"):format(hopPlaceId())
end
local function svCacheRead()
if not _canFile then
return nil
end
local path = _svCachePath()
local ok, raw = pcall(function()
if isfile(path) then
return readfile(path)
end
end)
if not ok or type(raw) ~= "string" or raw == "" then
return nil
end
-- ★ guard rac: file qua to = hong/DB dump, BO, khong JSONDecode (tranh treo VM)
local maxBytes = tonumber(fcfg().MaxCacheBytes) or 1048576
if #raw > maxBytes then
pcall(function()
if type(delfile) == "function" then
delfile(path)
end
end)
return nil
end
local d = jsonDecode(raw)
if not (type(d) == "table" and type(d.servers) == "table" and type(d.exp) == "number") then
return nil
end
return d.servers, d.exp
end
local function svCacheWrite(servers, exp)
if not _canFile then
return
end
pcall(function()
writefile(_svCachePath(), HttpSvc:JSONEncode({ exp = exp, servers = servers }))
end)
end
-- nguon 1: hobeojob (da loc server con slot)
local function fetchHobeojob()
local d = jsonDecode(httpGet(("https://hobeojob.com/api/jobs/%d"):format(hopPlaceId())))
if not (d and d.servers) then
return nil
end
local list = {}
for _, s in ipairs(d.servers) do
list[#list + 1] =
{ job = s.job_id, playing = tonumber(s.playing) or 0, maxp = tonumber(s.max_players) or 8 }
end
return list
end
-- nguon 2 (fallback): API goc Roblox, paginate
local function fetchRobloxApi(placeId)
local list, cursor = {}, nil
for _ = 1, (tonumber(fcfg().MaxPages) or 4) do
local url = ("https://games.roblox.com/v1/games/%d/servers/Public?limit=100&excludeFullGames=true"):format(
placeId
) .. (cursor and ("&cursor=" .. cursor) or "")
local d = jsonDecode(httpGet(url))
if not (d and d.data) then
task.wait(1.5) -- co the 429 -> nghi roi thoi
break
end
for _, s in ipairs(d.data) do
list[#list + 1] = { job = s.id, playing = tonumber(s.playing) or 0, maxp = tonumber(s.maxPlayers) or 8 }
end
cursor = d.nextPageCursor
if not cursor then
break
end
end
return list
end
-- CACHE-FIRST: con han -> doc file (KHONG goi mang). Het han -> GET roi ghi file.
-- GET fail -> dung tam cache CU con hon khong co gi.
-- ══════════════════════════════════════════════════════════════════
-- CACHE "ONE FOR ALL" — port nguyen tang tu sab_scanner.refreshRegistry
--
-- (1) IN-MEMORY con han -> khong dung dia, khong dung mang
-- (2) FILE CHUNG con han -> nap, KHONG GET (chia se moi tab tren may)
-- (3) het han -> GET co RETRY -> ghi FILE CHUNG
-- (4) GET fail het luot -> dung TAM file chung CU (con hon rong)
--
-- ⚠ JITTER AP LUC DOC, khong nuong vao exp luc ghi.
-- Neu nuong vao exp thi moi tab doc ra CUNG mot moc het han -> cung GET mot luc.
-- Ap luc doc thi moi acc coi file het han som hon 'jit' giay khac nhau
-- -> acc som nhat GET + ghi file, acc sau doc file moi. Khong bao host.
-- jspan = min(ttl/2, 2 x chu ky hop) — jitter nho hon chu ky goi thi vo dung.
--
-- ⚠ CHI GHI FILE KHI CO DU LIEU. Ghi list rong se dau doc file chung,
-- moi tab khac doc phai cai rong roi tuong la "khong co server".
-- ══════════════════════════════════════════════════════════════════
function Fleet.fetchServers(force)
local ttl = tonumber(fcfg().ServerCacheTTL) or 120
local now = os.time()
-- cat bot: /api/jobs tra ~7400 server (777 KB), hop chi can vai chuc.
-- Xao truoc roi cat, de moi tab khong cung nham mot nhom dau danh sach.
local function trim(list)
local keep = tonumber(fcfg().MaxServersKept) or 80
if #list <= keep then
return list
end
for i = #list, 2, -1 do
local j = math.random(1, i)
list[i], list[j] = list[j], list[i]
end
local out = table.create(keep)
for i = 1, keep do
out[i] = list[i]
end
return out
end
if ttl > 0 and not force then
local hopSec = (tonumber(fcfg().HopEveryMinutes) or 15) * 60
local jspan = math.max(1, math.min(math.floor(ttl / 2), 2 * hopSec))
local jit = (player and player.UserId or 0) % jspan
-- (1) in-memory con han
if _svMem and #_svMem > 0 and now < (_svMemExp - jit) then
return _svMem
end
-- (2) FILE CHUNG con han + CO du lieu -> nap, khong GET
local list, exp = svCacheRead()
if list and #list > 0 and exp and now < (exp - jit) then
_svMem, _svMemExp = list, exp
flog(("server: FILE CHUNG (%d, con %ds) — bo GET"):format(#list, exp - now))
return list
end
end
-- (3) het han -> GET co RETRY -> ghi FILE CHUNG
local tries = math.max(1, tonumber(fcfg().GetTries) or 3)
local gap = tonumber(fcfg().GetRetryGap) or 3
for attempt = 1, tries do
local src = fetchHobeojob()
local from = "hobeojob"
if not (src and #src > 0) and fcfg().UseRobloxApiFallback ~= false then
src = fetchRobloxApi(hopPlaceId())
from = "Roblox API"
end
if src and #src > 0 then
src = trim(src)
local exp = os.time() + ttl
_svMem, _svMemExp = src, exp
svCacheWrite(src, exp) -- CHI ghi khi CO du lieu
flog(("server: %s (%d) -> ghi FILE CHUNG (het han sau %ds)"):format(from, #src, ttl))
return src
end
if attempt < tries then
flog(("GET server fail (%d/%d) -> thu lai sau %ss"):format(attempt, tries, gap))
task.wait(gap)
end
end
-- (4) fail het luot -> file chung CU (ke ca qua han)
local stale = svCacheRead()
if stale and #stale > 0 then
_svMem, _svMemExp = stale, now -- coi nhu vua het han -> lan sau thu GET som
flog(("server: FILE CHUNG CU (%d) — ca 2 nguon fail"):format(#stale))
return stale
end
flog("khong co server tu bat ky nguon nao")
return nil
end
-- ── presence heartbeat ──
local function netPingMs()
local ok, ms = pcall(function()
local n = StatsSvc and StatsSvc.Network and StatsSvc.Network.ServerStatsItem
if n and n["Data Ping"] then
return n["Data Ping"]:GetValue()
end
return 0
end)
ms = (ok and tonumber(ms)) or 0
return math.floor(math.clamp(ms, 0, 600000))
end
function Fleet.postPresence()
if fcfg().PresenceEnabled == false or not _httpReq or not player then
return
end
pcall(_httpReq, {
Url = "https://hobeojob.com/api/presence",
Method = "POST",
Headers = { ["Content-Type"] = "application/json" },
Body = HttpSvc:JSONEncode({
account = player.Name,
placeId = game.PlaceId,
jobId = tostring(game.JobId),
players = math.min(#Players:GetPlayers(), 200),
ping = netPingMs(),
hops = getgenv().__RB1_Hops or 0,
uptime = math.floor(tick() - _bootAt),
}),
})
end
-- ── bao server chet: teleport tra GameEnded = server khong ton tai -> go khoi pool ──
function Fleet.reportDead(placeId, jobId)
if fcfg().ReportDead == false or not jobId or not _httpReq then
return
end
pcall(_httpReq, {
Url = ("https://hobeojob.com/api/jobs/%d/dead"):format(placeId),
Method = "POST",
Headers = { ["Content-Type"] = "application/json" },
Body = '{"job_id":"' .. tostring(jobId) .. '"}',
})
flog("[DEAD] bao server chet: " .. tostring(jobId))
end
-- ── giu cho jobId dich truoc khi teleport (chong clone nhay trung sv) ──
function Fleet.blacklistJob(placeId, jobId)
if fcfg().PostBlacklist == false or not jobId or not _httpReq then
return
end
pcall(_httpReq, {
Url = ("https://hobeojob.com/api/jobs/%d/blacklist"):format(placeId),
Method = "POST",
Headers = { ["Content-Type"] = "application/json" },
Body = '{"job_id":"' .. tostring(jobId) .. '"}',
})
end
-- ── hop ──
function Fleet.hop()
local placeId = hopPlaceId()
local servers = Fleet.fetchServers()
if not servers or #servers == 0 then
_noSvRetries = _noSvRetries + 1
if _noSvRetries >= (tonumber(fcfg().NoServerMaxRetries) or 3) then
flog("khong co server sau " .. _noSvRetries .. " lan -> Roblox matchmaking")
_noSvRetries = 0
_tpFailed = false
pcall(TeleportService.Teleport, TeleportService, placeId, player)
return true
end
flog(("khong co server (lan %d) -> cho roi thu lai"):format(_noSvRetries))
return false, "noserver"
end
_noSvRetries = 0
local cands = {}
for _, s in ipairs(servers) do
if s.job and s.job ~= game.JobId and not _visited[s.job] then
cands[#cands + 1] = s.job
end
end
if #cands == 0 then
_visited = {}
flog("het job moi -> reset visited")
return false, "novisited"
end
for i = #cands, 2, -1 do
local j = math.random(1, i)
cands[i], cands[j] = cands[j], cands[i]
end
local tries = math.min(#cands, tonumber(fcfg().MaxRetries) or 8)
for i = 1, tries do
local jobId = cands[i]
_visited[jobId] = true
_tpFailed, _tpFailResult = false, nil
Fleet.blacklistJob(placeId, jobId)
task.wait(0.2)
flog(("HOP %d/%d -> %s"):format(i, tries, jobId))
pcall(TeleportService.TeleportToPlaceInstance, TeleportService, placeId, jobId, player)
local t0 = os.clock()
while os.clock() - t0 < (tonumber(fcfg().WaitPerTry) or 6) do
if _tpFailed then
break
end
task.wait(0.25)
end
if not _tpFailed then
getgenv().__RB1_Hops = (getgenv().__RB1_Hops or 0) + 1
return true
end
-- GameEnded = server chet -> bao dead de go khoi pool
if _tpFailResult == Enum.TeleportResult.GameEnded then
Fleet.reportDead(placeId, jobId)
end
task.wait(tonumber(fcfg().RetryBackoff) or 1.5)
end
-- het luot van khong vao duoc -> matchmaking
flog(("%d lan deu fail -> matchmaking"):format(tries))
_tpFailed = false
pcall(TeleportService.Teleport, TeleportService, placeId, player)
return false, "allfail"
end
function Fleet.start()
if fcfg().Enabled == false then
return
end
pcall(function()
TeleportService.TeleportInitFailed:Connect(function(p, result)
if p == player then
_tpFailed, _tpFailResult = true, result
end
end)
end)
-- presence: POST ngay khi vao, roi moi Interval giay
task.spawn(function()
while true do
pcall(Fleet.postPresence)
task.wait(math.max(30, tonumber(fcfg().PresenceInterval) or 60))
end
end)
-- hop dinh ky
task.spawn(function()
local everyMin = tonumber(fcfg().HopEveryMinutes) or 15
if everyMin <= 0 then
return
end
while true do
task.wait(everyMin * 60)
if fcfg().HopEnabled == false then
continue
end
-- khong cat ngang viec dang lam: cho farm/spin/khoa cua xong
local waitBusy = tick() + 120
while (farmActionBusy or phantomWheelBusy or lockDoorBusy or rebirthInProgress) and tick() < waitBusy do
task.wait(1)
end
local _th = Action.T.begin("hop", ("den han %d phut"):format(everyMin))
local ok, why = pcall(Fleet.hop)
Action.T.done(_th, ok, tostring(why))
if not ok then
warn("[Fleet] hop loi: " .. tostring(why))
end
end
end)
flog("khoi dong: presence + hop moi " .. tostring(fcfg().HopEveryMinutes or 15) .. " phut")
end
Action.debugFleet = function()
local servers = Fleet.fetchServers()
local cached, exp = svCacheRead()
return {
placeId = hopPlaceId(),
hops = getgenv().__RB1_Hops or 0,
uptimeSec = math.floor(tick() - _bootAt),
serverCount = servers and #servers or 0,
cacheCount = cached and #cached or 0,
cacheExpiresIn = exp and (exp - os.time()) or nil,
cachePath = _svCachePath(),
hasHttpRequest = _httpReq ~= nil,
canFile = _canFile,
}
end
end)()
-- TU CAM TOOL TANG TOC ------------------------------------------------------
-- Cong thuc (decompile ReplicatedStorage.Controllers.SpeedController, 2026-09-06):
-- WalkSpeed = StarterPlayer.CharacterWalkSpeed x Tool:GetAttribute("SpeedModifier")
-- Do live: CharacterWalkSpeed = 34. Chi can CAM tool co SpeedModifier > 1 la nhanh hon.
--
-- ⚠⚠ CHI EQUIP, TUYET DOI KHONG MUA BANG SCRIPT.
-- Mua = goi RF/CoinsShopService/RequestBuy. Da lam BAY MOT ACCOUNT ngay 2026-09-06:
-- InvokeServer treo vinh vien (server chan o tang truoc handler) roi dinh BAC.
-- Packages.Net bam ten remote theo ngu canh nen goi instance ten phang la sai cau truc.
-- Muon tu mua thi bat AUTO BUY BANG TAY trong game mot lan — game co san tinh nang do
-- (CoinsShopService/ToggleAutoBuy, luu vao du lieu tai khoan), khong can script.
--
-- Humanoid:EquipTool la API gameplay thuong, DA THU CHAY THAT tren server: OK.
--
-- ⚠ ReplicatedStorage.Items.* KHONG mang SpeedModifier (server dat luc cap), nen phai
-- doc tren ban nam trong Backpack cua chinh minh, khong doc ban mau trong RS.
------------------------------------------------------------------------------
-- Uu tien thap = cam truoc. Chinh qua getgenv().RebirthConfig.SpeedToolRank.
-- Do live: Speed Coil -> SpeedModifier 1.5 (WalkSpeed 34 -> 51, di 31.6 -> 39.8 stud/s).
-- Coil Combo dat hon (20k, rb2) nen doan la manh hon; chua do duoc.
local SPEED_TOOL_RANK = (getgenv().RebirthConfig or {}).SpeedToolRank or {
["Coil Combo"] = 1,
["Speed Coil"] = 2,
["Candy Coils"] = 3,
["Christmas Coils"] = 4,
}
-- TU MUA TOOL TANG TOC ------------------------------------------------------
-- ⚠⚠ PHAI DUNG GAN NPC. DO LIVE 2026-09-06, ca huong sai lan huong dung:
-- SAI : goi thang RF/CoinsShopService/RequestBuy tu CACH SHOP 79 STUD, shop UI dang
-- DONG -> InvokeServer TREO VINH VIEN -> account bi KICK. Lam 2 lan, bay 2 lan.
-- DUNG: di toi <= 15 stud -> fireproximityprompt mo shop -> bam nut Buy. Khong sao ca.
-- => Loi khong nam o remote. Nam o cho THIEU NGU CANH: khong o gan, va chua bat tay
-- RE/ShopService/ShopOpened (chi buoc mo prompt moi phat cai do).
--
-- Vi vay ham nay TUYET DOI khong duoc bo qua buoc di chuyen va buoc mo shop.
-- Moi buoc deu kiem lai truoc khi sang buoc sau; sai mot cai la bo cuoc.
------------------------------------------------------------------------------
Action.buySpeedTool = function()
local cfg = getgenv().RebirthConfig or {}
if cfg.AutoBuySpeedTool ~= true then
return false -- mac dinh TAT: no keo nhan vat roi base mot chuyen
end
local want = tostring(cfg.SpeedToolName or "Speed Coil")
-- da co roi thi thoi (chi so huu duoc 1 cai moi loai)
local bp = player and player:FindFirstChild("Backpack")
local ch = player and player.Character
if not (bp and ch) then
return false
end
if bp:FindFirstChild(want) then
return true
end
local held = ch:FindFirstChildOfClass("Tool")
if held and held.Name == want then
return true
end
-- ⚠ KIEM TIEN TRUOC KHI NHUC CHAN. Ban dau toi viet thieu buoc nay nen bot chay
-- het quang duong ra shop roi moi phat hien khong mua noi, xong ve tay khong.
-- DO LIVE 2026-09-08: gia doc tu Datas.ShopItems[ten].Price, va "Coins" trong shop
-- CHINH LA Cash o leaderstats — doi chieu 41 muc tu $500 den $10 ty, LECH 0.
local shopData = getDataModule("ShopItems")
local entry = shopData and shopData[want]
local price = entry and tonumber(entry.Price)
if not price then
return nil -- khong doc duoc gia thi thoi, dung doan
end
if getCash() < price then
return nil -- KHONG di, va KHONG tinh la mot lan thu (xem cho goi)
end
-- khoa rebirth: mua khong noi thi cung dung di
if entry.RebirthRequired and getRebirths() < entry.RebirthRequired then
return nil
end
local _t = Action.T.begin("mua-toc-do", ("%s $%d"):format(want, price))
local deadline = tick() + 60
-- (2) DI TOI NPC. Bo qua buoc nay = bi kick.
local shop = Workspace:FindFirstChild("Shop")
local npc = shop and shop:FindFirstChild("ShopNPCCash")
local prompt = npc and npc:FindFirstChild("OpenInterface")
if not prompt then
return Action.T.done(_t, false, "khong thay NPC shop")
end
local maxD = tonumber(prompt.MaxActivationDistance) or 15
local spot = npc:GetPivot().Position
if pathfindTo then
pathfindTo(spot, deadline, math.max(4, maxD - 6))
end
local hrp = player.Character and player.Character:FindFirstChild("HumanoidRootPart")
local d = hrp and (hrp.Position - spot).Magnitude or math.huge
if d > maxD then
return Action.T.done(_t, false, ("con cach %.0f stud (can <= %d) — BO, khong ban tu xa"):format(d, maxD))
end
-- (2) MO SHOP bang prompt. Day moi la buoc bat tay voi server.
local gui = player.PlayerGui and player.PlayerGui:FindFirstChild("CoinsShop")
local root = gui and gui:FindFirstChild("CoinsShop")
if not root then
return Action.T.done(_t, false, "khong thay CoinsShop UI")
end
if not (gui.Enabled and root.Visible) then
pcall(function()
fireproximityprompt(prompt)
end)
local t0 = tick()
while tick() - t0 < 5 and not (gui.Enabled and root.Visible) do
task.wait(0.2)
end
end
if not (gui.Enabled and root.Visible) then
return Action.T.done(_t, false, "shop khong mo — BO, khong bam Buy khi shop dong")
end
-- (3) BAM NUT BUY (duong cua chinh game: AnimatedButton nghe Instance.Activated)
local item = root.Content and root.Content:FindFirstChild("Items")
item = item and item:FindFirstChild(want)
local buy = item and item:FindFirstChild("Buy")
-- ⚠ Visible CHI false khi khoa rebirth. Het tien thi nut VAN Visible, chi doi mau,
-- VA game khong noi handler Activated -> bam vao khong xay ra gi.
-- Theo CoinsShopController: du tien -> trang (255,255,255), khong du -> xam (138,138,138).
if not (buy and buy.Visible) then
return Action.T.done(_t, false, "nut Buy khong hien (khoa rebirth)")
end
if buy.ImageColor3 ~= Color3.fromRGB(255, 255, 255) then
return Action.T.done(_t, false, ("nut Buy XAM = game bao khong du tien (co $%d)"):format(getCash()))
end
pcall(function()
firesignal(buy.Activated)
end)
local t1 = tick()
while tick() - t1 < 8 and not bp:FindFirstChild(want) do
task.wait(0.3)
end
if bp:FindFirstChild(want) then
Action.equipSpeedTool()
return Action.T.done(_t, true, "mua duoc, da cam")
end
return Action.T.done(_t, false, "bam roi nhung khong vao Backpack")
end
-- MO LUCKY BLOCK ------------------------------------------------------------
-- Hop Lucky Block nam CHIEM mot o be. Prompt cua no la Action="Open",
-- KHAC voi brainrot (Action="Grab"), nen moi tang dem o deu bo sot no.
--
-- DO LIVE 2026-09-15 tren acc that (slot 4, plot cua minh):
-- HoldDuration = 1.5, MaxActivationDistance = 10, Enabled = true
-- fireproximityprompt(prompt) -> MO DUOC, hop bien khoi be.
-- ⚠ Khac voi prompt CUOP (cung HoldDuration 1.5) von KHONG an fireproximityprompt
-- (xem ghi chu sab-steal-mechanism) — cai nay thi an, da thu that.
------------------------------------------------------------------------------
Action.openLuckyBlocks = function()
if (getgenv().RebirthConfig or {}).AutoOpenLucky == false then
return false
end
local ap = getAnimalPodiums()
if not ap then
return false
end
local prompt, part
for i = 1, MAX_PODIUMS do
local slot = ap:FindFirstChild(tostring(i))
if slot then
for _, d in ipairs(slot:GetDescendants()) do
if d:IsA("ProximityPrompt")
and tostring(d.ObjectText or ""):lower():find("lucky", 1, true)
and d.Enabled == true
then
prompt = d
part = d.Parent and d.Parent.Parent
break
end
end
end
if prompt then
break
end
end
if not (prompt and part) then
return false
end
local _t = Action.T.begin("mo-lucky", tostring(prompt.ObjectText))
local deadline = tick() + 30
local maxD = tonumber(prompt.MaxActivationDistance) or 10
local hrp = player and player.Character and player.Character:FindFirstChild("HumanoidRootPart")
if hrp and (hrp.Position - part.Position).Magnitude > maxD - 3 then
if pathfindTo then
pathfindTo(part.Position, deadline, math.max(3, maxD - 4))
end
end
hrp = player and player.Character and player.Character:FindFirstChild("HumanoidRootPart")
local d = hrp and (hrp.Position - part.Position).Magnitude or math.huge
if d > maxD then
return Action.T.done(_t, false, ("con cach %.0f stud (can <= %d)"):format(d, maxD))
end
pcall(function()
fireproximityprompt(prompt)
end)
-- cho hop bien mat; het gio thi bao that bai de vong sau thu lai
local t0 = tick()
while tick() - t0 < 5 and prompt.Parent do
task.wait(0.25)
end
markPodiumCacheDirty()
if prompt.Parent then
return Action.T.done(_t, false, "ban roi nhung hop van con")
end
return Action.T.done(_t, true, "da mo, o be duoc giai phong")
end
Action.equipSpeedTool = function()
if (getgenv().RebirthConfig or {}).AutoEquipSpeedTool == false then
return false
end
local ch = player and player.Character
local hum = ch and ch:FindFirstChildOfClass("Humanoid")
if not hum then
return false
end
-- dang cam do tang toc roi thi thoi, khoi cam lai moi vong
local held = ch:FindFirstChildOfClass("Tool")
if held and (tonumber(held:GetAttribute("SpeedModifier")) or 0) > 1 then
return true
end
local bp = player:FindFirstChild("Backpack")
if not bp then
return false
end
-- ⚠⚠ KHONG loc bang SpeedModifier tren ban trong BACKPACK — DO LIVE 2026-09-06:
-- truoc khi cam, Tool chi co attribute { CurrentSlot }.
-- sau khi cam moi co { CurrentSlot, SpeedModifier = 1.5 }.
-- Server chi gan attribute luc Tool vao tay. Loc theo no o Backpack = KHONG BAO GIO
-- cam duoc gi (ban dau toi viet sai dung kieu do).
-- => Nhan dien theo TEN, xep uu tien. Van uu tien attribute neu tinh co da co.
local best, bestMod, bestRank = nil, 0, math.huge
for _, t in ipairs(bp:GetChildren()) do
if t:IsA("Tool") then
local m = tonumber(t:GetAttribute("SpeedModifier")) or 0
local rank = SPEED_TOOL_RANK[t.Name]
if m > bestMod and m > 1 then
best, bestMod, bestRank = t, m, -1
elseif rank and bestMod <= 1 and rank < bestRank then
best, bestRank = t, rank
end
end
end
if not best then
return false
end
local ok = pcall(function()
hum:EquipTool(best)
end)
if ok then
-- doc lai attribute SAU khi cam: luc nay server moi gan
local m = tonumber(best:GetAttribute("SpeedModifier")) or 0
local hs = m > 0 and ("x%.2f -> WalkSpeed %.0f"):format(m, (hum.WalkSpeed or 0))
or ("WalkSpeed %.0f"):format(hum.WalkSpeed or 0)
Action.T.mark(("cam %s | %s"):format(best.Name, hs))
end
return ok
end
-- JOIN PLACE (matchmaking) --------------------------------------------------
-- Teleport chi bang PLACE ID, KHONG kem jobId — server nao con cho cung duoc.
-- Khac TeleportToPlaceInstance (~L4219 cua Fleet) vi cai do ep dung mot jobId.
--
-- Thay cho Kick + messagebox "Kill Me": Kick lam mat luon tien trinh, con cai nay
-- dua thang acc sang place dich, khong can tool ngoai bat lai.
--
-- Teleport co the FAIL (place full / rate limit) va khi fail thi KHONG co loi nem
-- ra — no ban TeleportInitFailed. Nen phai lang nghe signal do roi thu lai,
-- chu pcall khong bat duoc gi.
------------------------------------------------------------------------------
Action.joinPlaceId = 109983668079237
Action.joinPlace = function(placeId, reason)
placeId = tonumber(placeId)
or tonumber((getgenv().RebirthConfig or {}).JoinPlaceId)
or Action.joinPlaceId
print(("[JOIN] teleport ve place %d | %s"):format(placeId, tostring(reason or "")))
local failed, conn = false, nil
pcall(function()
conn = TeleportService.TeleportInitFailed:Connect(function(p, result)
if p == player then
failed = true
warn("[JOIN] TeleportInitFailed: " .. tostring(result))
end
end)
end)
local ok = false
for i = 1, 5 do
failed = false
pcall(TeleportService.Teleport, TeleportService, placeId, player)
-- teleport thanh cong thi client bi go khoi server, doan duoi khong chay tiep.
-- Con o day sau 10s tuc la chua di duoc.
local deadline = tick() + 10
while tick() < deadline and not failed do
task.wait(0.25)
end
if not failed then
ok = true
break
end
warn(("[JOIN] fail lan %d/5, thu lai sau 3s"):format(i))
task.wait(3)
end
if conn then
pcall(function()
conn:Disconnect()
end)
end
if not ok then
warn("[JOIN] 5 lan deu fail")
end
return ok
end
function Action.doRebirth()
local function hasRequiredAnimals(owned)
for _, name in ipairs(ownedList) do
if not owned[name] then
return false, name
end
end
return true
end
local function getRebirthUi()
local playerGui = player and player:FindFirstChild("PlayerGui")
local screen = playerGui and playerGui:FindFirstChild("Rebirth")
local frame = screen and screen:FindFirstChild("Rebirth")
local content = frame and frame:FindFirstChild("Content")
local header = frame and frame:FindFirstChild("Header")
local leftCenter = playerGui and playerGui:FindFirstChild("LeftCenter")
local leftCenterFrame = leftCenter and leftCenter:FindFirstChild("LeftCenter")
local buttons = leftCenterFrame and leftCenterFrame:FindFirstChild("Buttons")
return screen,
frame,
buttons and buttons:FindFirstChild("Rebirth"),
content and content:FindFirstChild("Rebirth"),
header and header:FindFirstChild("Close")
end
local function isUsableRebirthButton(button)
return button
and button:IsA("GuiButton")
and button.Visible
and button.Active
and button.Interactable
and button.AbsoluteSize.X > 1
and button.AbsoluteSize.Y > 1
end
local function closeRebirthUi()
local screen, frame, _, _, closeButton = getRebirthUi()
if not screen or not screen.Enabled or not frame or not frame.Visible then
return true
end
if not closeButton or not closeButton:IsA("GuiButton") then
return false
end
local signaled = pcall(function()
firesignal(closeButton.Activated)
end)
if not signaled then
return false
end
local deadline = tick() + 2
while tick() < deadline do
local currentScreen, currentFrame = getRebirthUi()
if not currentScreen or not currentScreen.Enabled or not currentFrame or not currentFrame.Visible then
return true
end
task.wait(0.1)
end
local currentScreen, currentFrame = getRebirthUi()
return not currentScreen or not currentScreen.Enabled or not currentFrame or not currentFrame.Visible
end
local function openRebirthUi()
local screen, frame, openButton = getRebirthUi()
if screen and screen.Enabled and frame and frame.Visible then
return true
end
if not isUsableRebirthButton(openButton) then
return false
end
local signaled = pcall(function()
firesignal(openButton.Activated)
end)
if not signaled then
return false
end
local deadline = tick() + 3
while tick() < deadline do
screen, frame = getRebirthUi()
if screen and screen.Enabled and frame and frame.Visible then
return true
end
task.wait(0.1)
end
return false
end
if rebirthRequestTimedOut then
warn("❌ Rebirth request previously timed out; refusing a duplicate request")
return false
end
if changingFolder or changedFolder then
warn("❌ Folder change already started; refusing rebirth")
return false
end
if rebirthInProgress then
warn("❌ Rebirth already in progress!")
return false
end
if rebirthCompleted or getRebirths() >= MAX_REBIRTHS then
rebirthCompleted = true
warn("❌ Max rebirths already reached!")
return false
end
if not player or not player.Parent then
warn("❌ Player not ready for rebirth!")
return false
end
if getCash() < REBIRTH_CASH then
warn("❌ Not enough cash for rebirth!")
return false
end
local _, owned = getPodiumInfo()
local hasAnimals, missingAnimal = hasRequiredAnimals(owned)
if not hasAnimals then
warn("❌ Missing required animal for rebirth: " .. tostring(missingAnimal))
return false
end
if changingFolder or changedFolder then
warn("❌ Folder change started during rebirth preflight")
return false
end
rebirthInProgress = true
local rebirthSuccess = false
local rebirthBefore = getRebirths()
local cashBefore = getCash()
local rebirthUiClicked = false
local ok, err = pcall(function()
if not player or not player.Parent or rebirthBefore >= MAX_REBIRTHS or cashBefore < REBIRTH_CASH then
warn("❌ Rebirth preflight failed before opening UI!")
return
end
local _, latestOwned = getPodiumInfo()
local stillHasAnimals, latestMissingAnimal = hasRequiredAnimals(latestOwned)
if not stillHasAnimals then
warn("❌ Missing required animal before rebirth: " .. tostring(latestMissingAnimal))
return
end
if not openRebirthUi() then
closeRebirthUi()
warn("❌ Could not open Rebirth UI")
return
end
local uiDelay = tonumber((getgenv().RebirthConfig or {}).RebirthUiDelay) or 2
if uiDelay ~= uiDelay then
uiDelay = 2
end
task.wait(math.clamp(uiDelay, 0, 10))
local screen, frame, _, rebirthButton = getRebirthUi()
local buttonColor = rebirthButton and rebirthButton.ImageColor3
if
not screen
or not screen.Enabled
or not frame
or not frame.Visible
or not isUsableRebirthButton(rebirthButton)
or not buttonColor
or math.min(buttonColor.R, buttonColor.G, buttonColor.B) < 0.95
then
closeRebirthUi()
warn("❌ Rebirth UI is not ready")
return
end
local _, clickOwned = getPodiumInfo()
local clickHasAnimals, clickMissingAnimal = hasRequiredAnimals(clickOwned)
if
not player
or not player.Parent
or getRebirths() ~= rebirthBefore
or getCash() < REBIRTH_CASH
or not clickHasAnimals
then
closeRebirthUi()
warn("❌ Rebirth pre-click validation failed: " .. tostring(clickMissingAnimal))
return
end
screen, frame, _, rebirthButton = getRebirthUi()
buttonColor = rebirthButton and rebirthButton.ImageColor3
if
not screen
or not screen.Enabled
or not frame
or not frame.Visible
or not isUsableRebirthButton(rebirthButton)
or not buttonColor
or math.min(buttonColor.R, buttonColor.G, buttonColor.B) < 0.95
then
closeRebirthUi()
warn("❌ Rebirth UI changed before click")
return
end
local clickDone = false
local clickOk, clickErr
rebirthUiClicked = true
local clickThread = task.spawn(function()
clickOk, clickErr = pcall(function()
firesignal(rebirthButton.Activated)
end)
clickDone = true
end)
local confirmDeadline = tick() + REBIRTH_INVOKE_TIMEOUT_SECONDS
while tick() < confirmDeadline do
if getRebirths() > rebirthBefore then
rebirthSuccess = true
closeRebirthUi()
print("✅ Rebirth confirmed by stat change! " .. rebirthBefore .. " → " .. getRebirths())
return
end
if clickDone and not clickOk then
break
end
task.wait(0.1)
end
if getRebirths() > rebirthBefore then
rebirthSuccess = true
closeRebirthUi()
print("✅ Rebirth confirmed at deadline! " .. rebirthBefore .. " → " .. getRebirths())
return
end
rebirthRequestTimedOut = true
if not clickDone then
pcall(task.cancel, clickThread)
end
closeRebirthUi()
warn("❌ Rebirth UI result unknown; refusing a duplicate click: " .. tostring(clickErr))
if player and player.Parent then
player:Kick("Rebirth UI không xác nhận; dừng để tránh click trùng.")
end
end)
if not ok then
closeRebirthUi()
if rebirthUiClicked and not rebirthSuccess and getRebirths() > rebirthBefore then
rebirthSuccess = true
print("✅ Rebirth confirmed after UI error! " .. rebirthBefore .. " → " .. getRebirths())
elseif rebirthUiClicked and not rebirthSuccess then
rebirthRequestTimedOut = true
if player and player.Parent then
player:Kick("Rebirth UI lỗi sau click; dừng để tránh click trùng.")
end
end
warn("❌ Rebirth attempt error: " .. tostring(err))
end
rebirthInProgress = false
if rebirthSuccess then
rebirthCompleted = true
task.wait(3)
Action.sendWebhook(
"✅ Rebirth Complete!",
"**" .. player.Name .. "** has rebirthed!\nTotal Rebirths: **" .. getRebirths() .. "**",
5763719,
{
{ name = "Thoi gian farm", value = Action.T.uptime(), inline = true },
{ name = "Tien cuoi", value = "$" .. tostring(getCash()), inline = true },
}
)
markPlotCacheDirty()
markPurchasePromptCacheDirty()
changeToFolderIfReady()
Action.joinPlace(nil, ("rebirth xong, tong %s, farm het %s")
:format(tostring(getRebirths()), Action.T.uptime()))
end
return rebirthSuccess
end
print("🚀 Starting farming script!")
startPerformanceBoost()
if not waitForFullLoad() then
while true do
task.wait(60)
end
end
-- POST username cu DA THAY bang Fleet.postPresence (heartbeat day du:
-- account/placeId/jobId/players/ping/hops/uptime), va place id KHONG con
-- hard-code 109983668079237 — server dang choi co the la place khac.
-- Fleet lo luon: report dead, hop dinh ky 15p, cache dia chia se giua tab.
Fleet.start()
-- canh cua nha: giu khoa, het han la dong lai NGAY
if (getgenv().RebirthConfig or {}).AutoLockBase ~= false then
LockDoor.start()
end
local rcSpin = getgenv().RebirthConfig or {}
local spinEnabled = true
if rcSpin.AutoEclipseWheel ~= nil then
spinEnabled = rcSpin.AutoEclipseWheel == true
elseif rcSpin.AutoSpinWheel ~= nil then
spinEnabled = rcSpin.AutoSpinWheel == true
elseif rcSpin.AutoPhantomWheel ~= nil then
spinEnabled = rcSpin.AutoPhantomWheel == true
end
if spinEnabled then
startAutoPhantomWheel()
else
setPhantomWheelStatus("Spin: TAT")
end
task.spawn(function()
while not changedFolder do
changeToFolderIfReady()
task.wait(math.max(1, tonumber((getgenv().RebirthConfig or {}).ChangeScanSec) or 10))
end
end)
-- (check rebirth da chuyen len DAU FILE — acc rb>=1 khong bao gio chay toi day)
if not autofarmEnabled then
print("⏭️ Server khong trong luc inject -> khong farm, chi giu ChangeToFolder.")
while true do
task.wait(60)
end
end
print("✅ Account is new, starting autofarm...")
task.wait(3)
Action.sendWebhook(
"🚀 Auto-Farm Started",
"**" .. player.Name .. "** is now farming!\n**Target:** Rebirth " .. MAX_REBIRTHS,
65280,
{
{ name = "👤 Account", value = player.Name, inline = true },
{ name = "🎯 Priority", value = "Trippi Troppi\nGangster Footera", inline = true },
{ name = "💰 Target Cash", value = "$" .. tostring(REBIRTH_CASH), inline = true },
}
)
while phantomWheelBusy do
task.wait(0.1)
end
farmActionBusy = true
local initialCollectOk, initialCollectErr = pcall(Action.collectCash)
farmActionBusy = false
if not initialCollectOk then
warn("⚠️ Initial collect error: " .. tostring(initialCollectErr))
end
while true do
local loopWait = 2
farmActionBusy = true
local ok, err = pcall(function()
if phantomWheelBusy then
Action.T.setPhase("cho-spin", "nhuong nhan vat cho banh xe")
return
end
-- dang chay ve khoa cua: nhuong quyen dieu khien nhan vat
if lockDoorBusy then
Action.T.setPhase("cho-khoa-cua", "nhuong nhan vat cho LockDoor")
return
end
-- mua do tang toc: thu toi da 3 lan roi thoi (no keo nhan vat roi base)
-- ⚠ buySpeedTool tra nil khi bo vi THIEU TIEN (chua di dau ca) va tra
-- true/false khi da THAT SU di mot chuyen. Chi dem chuyen di that, neu khong
-- thi 3 vong dau con ngheo la khoa vinh vien, sau giau cung khong mua nua.
if (Action.buyToolTries or 0) < 3 and not lockDoorBusy and not phantomWheelBusy then
if (getgenv().RebirthConfig or {}).AutoBuySpeedTool == true then
if Action.buySpeedTool() ~= nil then
Action.buyToolTries = (Action.buyToolTries or 0) + 1
end
end
end
-- ★ MO LUCKY BLOCK truoc moi thu: hop nay chiem o be ma khong duoc dem la
-- brainrot, de lam bot doi mua vao o da co vat roi ket. Tiet luu 10 giay.
if tick() - (Action.lastLuckyAt or 0) >= 10 and not lockDoorBusy and not phantomWheelBusy then
Action.lastLuckyAt = tick()
Action.openLuckyBlocks()
end
-- cam lai do tang toc neu dang khong cam (vd sau khi chet/respawn).
-- Tiet luu 5 giay: khong co gi de cam thi cung khong quet Backpack moi vong.
if tick() - (Action.lastEquipAt or 0) >= 5 then
Action.lastEquipAt = tick()
Action.equipSpeedTool()
end
local currentCash = getCash()
-- ══ CANH TIEN DUNG YEN ══════════════════════════════════════════════
-- Tien KHONG DOI qua N giay = bot ket that su -> kick cho tool auto rejoin lo.
-- Bat ky thay doi nao cung dat lai dong ho: tang (gom tien) LAN giam (mua).
--
-- Vi sao 180 giay la dung nguong: COLLECT_INTERVAL = 55s nen mot phien khoe
-- manh phai co it nhat 3 lan tien nhuc nhich trong khoang do. Im lang tron 3
-- phut nghia la ca gom LAN mua deu chet — khong con gia thuyet lanh nao.
--
-- ⚠ KHONG dem trong luc rebirth (doi UI, click, cho server) va khong dem khi
-- LockDoor/wheel dang giu nhan vat — luc do bot dung yen la DUNG.
if rebirthInProgress or lockDoorBusy or phantomWheelBusy then
Action.cashMoveAt = tick()
elseif Action.lastCashSeen ~= currentCash then
Action.lastCashSeen = currentCash
Action.cashMoveAt = tick()
else
local stallSec = tonumber((getgenv().RebirthConfig or {}).StallKickSec) or 180
local stuck = tick() - (Action.cashMoveAt or tick())
if stallSec > 0 and stuck >= stallSec then
warn(("[STALL] tien dung yen $%s suot %.0fs -> kick"):format(
tostring(currentCash), stuck))
Action.sendWebhook(
"Bot ket - tien dung yen",
("**%s**: tien khong doi $%s trong %.0f giay -> kick de rejoin"):format(
player.Name, tostring(currentCash), stuck),
16753920,
{
{ name = "Pha", value = tostring(Action.T.phase), inline = true },
{ name = "Da chay", value = Action.T.uptime(), inline = true },
}
)
task.wait(1) -- kip gui webhook truoc khi mat ket noi
player:Kick(("Tien dung yen %.0fs (pha: %s) — kick de rejoin"):format(
stuck, tostring(Action.T.phase)))
return
end
end
local podiumCount, owned = getPodiumInfo()
local hasTrip = owned["Trippi Troppi"] or false
local hasGang = owned["Gangster Footera"] or false
Action.T.setPhase(
"farm",
("$%s | be %d/10 | Trippi=%s Gangster=%s"):format(
tostring(currentCash),
podiumCount,
hasTrip and "co" or "chua",
hasGang and "co" or "chua"
)
)
local baseIncome = getBaseIncomePerSecond and getBaseIncomePerSecond() or 0
local waitingForPurchaseIncome = lastPurchaseTime > 0
and tick() - lastPurchaseTime < PURCHASE_INCOME_GRACE_SECONDS
if currentCash < 25 and baseIncome <= 0 and not waitingForPurchaseIncome then
player:Kick("Tiền dưới $25 và tổng thu nhập <= 0; dừng để tránh kẹt do tranh mua.")
return
end
if currentCash >= REBIRTH_CASH and hasTrip and hasGang then
print("💰 Reached rebirth cash! Rebirthing...")
if Action.doRebirth() then
farmActionBusy = false
while true do
task.wait(60)
end
end
warn("❌ Rebirth failed, retrying in 5 seconds...")
loopWait = 5
return
end
-- ══ CHE DO FARM-ONLY: o nha, KHONG di mua nua, chi gom tien ══════════
-- Du income >= 600 va da co Trippi + Gangster thi khoi chay di mua:
-- dung yen cho tien tu chay ve, 55 giay gom mot lan. CO Y, khong phai loi.
--
-- ⚠ FPS: DO LIVE 2026-09-05 tren server that (WalkSpeed 34), di 40 stud:
-- cap 10 -> FPS thuc 10.0 -> 21.1 stud/s (1.90s)
-- cap 30 -> FPS thuc 30.0 -> 31.6 stud/s (1.27s)
-- cap 60 -> FPS thuc 60.0 -> 31.6 stud/s (1.28s)
-- Humanoid mo phong theo FRAME nen it frame = it buoc vat ly = di CHAM THAT.
-- 10 FPS mat 33% toc do; 30 va 60 GIONG HET nhau nen 30 la diem toi uu.
--
-- Vi vay: 10 FPS luc RANH (~50 trong moi 55 giay), nang len luc DI GOM roi
-- ha lai. Duoc gan tron phan tiet kiem CPU ma khong lam collect cham di.
-- Muon 10 FPS suot ca luc gom thi dat CollectFpsCap = 10.
if baseIncome >= FARM_ONLY_INCOME_PER_SECOND and hasTrip and hasGang then
if not farmOnlyFpsApplied then
farmOnlyFpsApplied = true
if type(setfpscap) == "function" then
pcall(setfpscap, tonumber((getgenv().PerformanceConfig or {}).FarmOnlyFpsCap) or 10)
end
end
if tick() - lastCollect >= COLLECT_INTERVAL then
if type(setfpscap) == "function" then
pcall(setfpscap, tonumber((getgenv().PerformanceConfig or {}).CollectFpsCap) or 30)
end
Action.collectCash()
if type(setfpscap) == "function" then
pcall(setfpscap, tonumber((getgenv().PerformanceConfig or {}).FarmOnlyFpsCap) or 10)
end
end
return
end
if Action.freeSlotForRequiredAnimal(currentCash, owned, podiumCount) then
return
end
if tick() - lastCollect >= COLLECT_INTERVAL then
Action.collectCash()
-- ★ collect VUA cong tien vao. currentCash doc tu dau vong la CU roi.
-- Khong doc lai thi dung so cu di mua — co the com mot con $100.000
-- trong khi vua du tien REBIRTH. Doc lai va thoat som de vong sau
-- vao thang nhanh rebirth.
currentCash = getCash()
if currentCash >= REBIRTH_CASH and hasTrip and hasGang then
loopWait = 0
return
end
loopWait = 0.2 -- vua gom tien xong: xet mua ngay, khong ngu 2s
end
-- ★ SAN THU NHAP neo vao BE CUA MINH, khong neo vao ly thuyet mua noi.
-- Be con o trong -> san 0: o trong kiem 0 $/s, mua gi cung hon de khong.
-- Be DAY -> san = con te nhat x 1.25: dung mua thu ma lat sau lai
-- phai ban di. Chon dung nguong ma freeSlotForUpgrade doi,
-- de khong chon hut roi bo, phi ca mot vong.
Action.buyFloor = 0
Action.buyCtx = { income = baseIncome, soldGen = 0, travel = 10 }
if podiumCount >= MAX_PODIUMS then
local worst = Action.findLowestIncomeSellCandidate()
if worst and worst.generation > 0 then
-- be DAY: mua = phai BAN con te nhat di, nen income rong chi tang
-- (g - worst). Va di duong lau hon vi con phai chay di ban.
Action.buyFloor = worst.generation * MIN_UPGRADE_MULTIPLIER
Action.buyCtx.soldGen = worst.generation
Action.buyCtx.travel = 16
end
end
local item, prompt = getBestAvailableNow(currentCash, owned, Action.buyFloor)
if item and prompt then
-- ★ doc LAI so be: podiumCount lay tu dau vong lap, sau collect/mua co the da khac.
-- Doc cu => tuong con cho => di mua => server tu choi => spam 40s vao hu vo.
local nowCount = select(1, getPodiumInfo()) or podiumCount
-- ★ CHOT GIAO HANG: con vua mua con DANG DI BO ve be nen no chua duoc
-- dem vao nowCount. Cong so con dang ve vao truoc khi quyet dinh, neu
-- khong se mua chong len dung mot cho -> server tu choi, ban 20 phat
-- vao hu vo (log 18:37:56 -> 18:38:04, phi 7.45s).
-- Dang co con ve thi CHO, dung mua ma cung dung nang cap: buc anh ve
-- be luc nay chua day du de quyet dinh ban con nao.
Action.incomingNow = Action.countIncoming()
if Action.incomingNow > 0 and nowCount + Action.incomingNow >= MAX_PODIUMS then
Action.T.mark(("cho %d con dang ve be (%d/%d) — chua mua/nang cap"):format(
Action.incomingNow, nowCount, MAX_PODIUMS))
loopWait = 0.5
return
end
if nowCount >= MAX_PODIUMS then
Action.T.mark(("be day %d/%d -> xet nang cap thay vi mua them"):format(nowCount, MAX_PODIUMS))
Action.freeSlotForUpgrade(item, prompt, nowCount)
loopWait = 0.5
return
end
if Action.buyBrainrot(item, prompt) then
loopWait = 0.2 -- vua mua duoc: con hang, vao ngay khong ngu 2s
else
loopWait = 0.5 -- mua truot: nghi ngan roi thu mon khac
end
else
-- ★ KHONG chon duoc mon nao: truoc day IM LANG hoan toan nen nhin vao
-- tuong bot treo. Giai thich ro TAI SAO, va dem tung tang bo loc.
local nAnimal, nPrompt, nOnCarpet, nAfford = 0, 0, 0, 0
pcall(function()
for _, obj in ipairs(CollectionService:GetTagged("Animal")) do
nAnimal = nAnimal + 1
for _, d in ipairs(obj:GetDescendants()) do
if d:IsA("ProximityPrompt") and d.ActionText == "Purchase" then
nPrompt = nPrompt + 1
if isPurchasePromptAvailable(d) then
nOnCarpet = nOnCarpet + 1
for _, it in ipairs(buyList) do
if currentCash >= it.cost and promptMatchesPurchaseName(d, it.name) then
nAfford = nAfford + 1
break
end
end
end
break
end
end
end
end)
Action.T.setPhase(
"khong-co-gi-mua",
("thu %d | prompt %d | qua bo loc %d | du tien %d | registry %d"):format(
nAnimal, nPrompt, nOnCarpet, nAfford, AnimalSource.count())
)
end
end)
farmActionBusy = false
if not ok then
warn("⚠️ Loop error: " .. tostring(err))
end
task.wait(loopWait)
end