Lewati ke konten utama

Examples

Script praktis end-to-end yang ngegabungin permukaan API yang udah didokumentasikan di tempat lain. Paste salah satu di Scripts page terus tekan Run.

Mayoritas contoh asumsiin bot udah connected. Kalau lo nge-drive bot yang baru di-spawn, bracket body-nya pake wait-loop client:status() == Status.IN_WORLD.


Inventory dump

List tiap slot dengan id / type / amount / name. Pas buat sanity check abis tutorial run atau pack purchase.

local client = getClient()
local inv = client:inventory()

local typeNames = {
[0] = "block", [1] = "background", [2] = "seed", [3] = "water",
[4] = "wearable", [5] = "weapon", [6] = "throwable", [7] = "consumable",
[8] = "shard", [9] = "blueprint", [10] = "familiar", [11] = "food",
[12] = "wiring",
}

print(string.format("=== %s — %d slots ===", client.username, inv.slots))
print(string.format("%-5s %-12s %-8s %s", "id", "type", "amount", "name"))
print(string.rep("-", 60))

for _, item in pairs(inv.items) do
print(string.format("%-5d %-12s %-8d %s",
item.id, typeNames[item.type] or "?", item.amount, item.name or "?"))
end

Place → break (sleep-based)

Pattern stable: place block, tunggu, hit N kali. Optimistic state bikin client:hit ngeliat block yang baru di-place di tick berikutnya, jadi smart_punch ngeluarin sequence mP+HB beneran instead of jatuh ke branch SKIP-air.

local client = getClient()
local TARGET = 3316 -- RockPillar (medium-tier; ganti ke block id apa aja)
local HITS = 4

for cycle = 1, 5 do
local inv = client:inventory()
local amount = inv:count(TARGET, InventoryItemType.block)
if amount == 0 then break end

local p = client:point()
local tile = Vector2i.new(p.x - 1, p.y) -- ke KIRI
print(string.format("[c%d] inv=%d place at (%d,%d)", cycle, amount, tile.x, tile.y))

client:place(tile, TARGET, InventoryItemType.block)
sleep(250)
for h = 1, HITS do
client:hit(tile)
sleep(250)
end
end

Timing reference (4 hits, sleep 250 ms antar hit):

MarkerWaktu
Hit 1 firesT = 0
Hit 4 firesT ≈ 0.75 s
Server kirim DBT ≈ 1.4 s

Tune sleep(...) per tier block:

Tier block (hits_required)Hits dibutuhinsleep rekomendasi
Soft (~600, mis. CaveWall, Lily)4sleep(120) ≈ 0.5 s/cycle
Medium (~1000, mis. Soil, Brick)4–6sleep(180) ≈ 1 s/cycle
Hard (~1500, mis. Obsidian)30+sleep(200) ≈ 6 s/cycle

Turun di bawah sleep(80) resiko anti-flood server kebawa.


Presend hook — atomic burst

Pas perlu place + hit packet ride TCP write yang sama (mis. duping micro-window place-then-instant-hit), pake callback presend. Scheduler drain outbound_tx abis callback jadi packet apa pun yang lo queue di dalam masuk batch saat ini.

local client = getClient()
local TARGET = 1 -- SoilBlock

client:on("presend", function(batch)
local amount = client:inventory():count(TARGET, InventoryItemType.block)
if amount == 0 then return end

local p = client:point()
local tile = Vector2i.new(p.x - 1, p.y)
for i = 1, math.min(amount, 5) do
client:place(tile, TARGET, InventoryItemType.block)
for j = 1, 4 do client:hit(tile) end
end
end)

presend fire tiap slot tick (~250 ms / 4× per detik). Apa pun yang berat di sini bakal di-multiply cepet. Server mungkin disconnect kalau flood agresif (contoh original dari komunitas datang dengan warning client disconnects). Pake counter atau status-gate di dalam callback kalau cuma mau jalan di tick tertentu.


Throttled presend (tiap Nth tick)

Hook yang sama, di-gate biar fire tiap 10 slot tick (~2.5 s):

local tickCount = 0
client:on("presend", function(batch)
tickCount = tickCount + 1
if tickCount % 10 ~= 0 then return end

local p = client:point()
client:send("BUp", { Bi = 33557167 }) -- punch animation
client:send("HB", { x = p.x - 1, y = p.y })
end)

Conditional injection — cuma pas gerak

Inspect batch yang mau di-flush, inject packet ekstra cuma di tick movement:

client:on("presend", function(batch)
local moving = false
for _, pkt in ipairs(batch) do
if pkt.ID == "mP" then moving = true; break end
end
if not moving then return end

local p = client:point()
client:send("HB", { x = p.x, y = p.y })
end)

Dengerin destroy confirmation

Server push DB (Destroy Block) pas block beneran break. Pake buat trigger step farming berikutnya instead of nebak pake sleep:

local client = getClient()
local destroys = {}

client:on("p:DB", function(doc)
destroys[#destroys + 1] = {
block = doc.DBBT,
x = doc.x, y = doc.y,
ts = os.time(),
}
print(string.format("destroyed block #%d at (%d,%d)", doc.DBBT, doc.x, doc.y))
end)

-- ... sisanya script

Listener p:<ID> fire buat tiap inbound packet dengan id itu; p (tanpa suffix) catch semua.


Tutorial gate

Skip akun mid-tutorial sebelum warp. Auto-driver idempotent — call di akun yang udah selesai langsung return.

local c = getClient()
local a = c.automation

while a:tutorialState() == nil do task.wait(0.2) end

if a:isInTutorial() then
local err = a:tutorial()
if err then return print("tutorial gagal: " .. err) end
end

c:warp("WORLD_PILIHAN")

Auto-collect + chat throttle

Combine setAutoCollect sama chat periodik:

local c = getClient()
c:setAutoCollect(true, 250) -- pickup drops di tile bot

local lines = {
"Selling rare hats DM me",
"Buy doubles 200 each",
"Need scaffolding pls",
}
local idx = 1
while true do
c:say(lines[idx])
idx = (idx % #lines) + 1
sleep(8000) -- 8 s antar chat — server rate-limit kalau lebih cepet
end

Tunggu di-world, terus action

Pattern startup gate — pas di top tiap script yang butuh bot udah masuk world (mis. script yang jalan abis Add Bot, pas bot masih mid-handshake).

local c = getClient()

while c:status() ~= Status.IN_WORLD do
if c:status() == Status.ERROR or c:status() == Status.BANNED then
return print("ga bisa lanjut: " .. tostring(c:lastError()))
end
sleep(200)
end

-- Aman buat drive bot.
print("ready: " .. c.username .. " di " .. tostring(c.world and c.world.name or "?"))

Lihat juga

  • Events — referensi client:on(event, ...) (lifecycle, packet, presend)
  • Game Client — surface method full (warp, place, hit, send, inventory, …)
  • Tutorial — auto-driver + state queries