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):
| Marker | Waktu |
|---|---|
| Hit 1 fires | T = 0 |
| Hit 4 fires | T ≈ 0.75 s |
Server kirim DB | T ≈ 1.4 s |
Tune sleep(...) per tier block:
Tier block (hits_required) | Hits dibutuhin | sleep rekomendasi |
|---|---|---|
Soft (~600, mis. CaveWall, Lily) | 4 | sleep(120) ≈ 0.5 s/cycle |
Medium (~1000, mis. Soil, Brick) | 4–6 | sleep(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)
presendfire 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 warningclient 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