Scripts

Your own macros, in Lua 5.4

Beta

A script is a text file that tells Prism what to do, step by step: mine logs until night, go home, wait for the morning, put the logs in a chest. It runs inside the game, so it can use everything the client can, and it keeps going while you do something else.

Scripts are written in Lua, a small language made for this. You do not need to know it well: the example at the bottom is a complete script.

Getting started

Open the scripts folder
Click GUI, Scripts panel, Script Manager, Open scripts folder (PrismData\scripts next to the client)
Put a .lua file in it
Any text editor works. block_miner.lua and auto_crafter.lua are already there as examples
Reload scripts
In Script Manager: the new file gets its own entry in the Scripts panel
Switch it on, or bind it a key
Switched on in the menu, it starts when you close the menu. Its key starts and stops it while you play
Or use chat
#script list, #script run <name>, #script stop [name]; #mark <name> saves the block you look at; #craft <item> shows its recipes

How a script runs

  • It runs from top to bottom, and ends when it reaches the end. Most scripts are one while true do ... end loop.
  • wait() pauses only the script, never the game. A loop has to wait at least every 200 ms (a wait(1000) at its end is plenty), or Prism stops the script so the game does not freeze.
  • When it ends, any Baritone job it started stops too. Pressing a movement key stops Baritone, and with it a script that drives Baritone.
  • While a script runs, Minecraft keeps going when you switch to another window or minimize it, and you keep your mouse.
  • An error stops the script and shows the line it was on in your chat.

Settings in the header

Shown in the script's panel

The comment lines at the very top name the script and give it settings. Each setting appears in the script's panel in the click GUI (right click its entry), and the script reads it as settings.key, always the value the panel shows right now.

-- @name Block miner
-- @description Mines blocks; goes home at night
-- @text  block      "Blocks to mine"                     "oak_log"
-- @bool  store      "Put them in the chest"              true
-- @int   free_slots "Store when free slots are at most"  2 0 36
-- @number pause     "Seconds between checks"             1.0 0.1 10
-- @point  chest     "Storage chest"                      chest
  • @bool key "Label" true: a switch
  • @int key "Label" default min max: a whole-number slider
  • @number key "Label" default min max: a slider with decimals
  • @text key "Label" "default": a text box
  • @point key "Label" block: a place set with a button, like Schematica's supply chest. Look at the block and press Set Label; the last word is the block it has to be (chest, crafting_table). The script gets { x=, y=, z= }, or nil while it is not set.

Basics

Timing and output

print(...)
Writes to your chat (only you see it) and to the client log.
notify(text)
A client notification in the corner.
wait(ms)
Pauses this script; the game keeps going. sleep(ms) is the same.
wait_until(fn [, timeout_ms])
Pauses until fn() returns true (checked every frame). Returns false if the timeout ran out first.
millis()
A clock in milliseconds, for timing things yourself.
stop()
Ends this script.
settings.<key>
A setting from the script's header, as its panel shows it right now (see Settings below).

chat

Messages and commands

chat.send(text)
Sends a message or a command: chat.send("/home 2"). Text starting with # goes to Prism's own commands ("#mine oak_log").
chat.print(text)
Shows text in your chat only, with Minecraft's § colour codes.
chat.wait_for(text [, timeout_ms])
Pauses until a chat line containing text arrives (any case). Returns the line, or nil on the timeout: chat.wait_for("Teleported", 5000).
chat.last([n])
The last n chat lines (10 if you leave it out), oldest first, colour codes removed.

player

Position, view, health

player.pos()
x, y, z of your feet. Nothing (nil) outside a world.
player.block()
The block position you stand in, as whole numbers.
player.health(), player.food()
Your health and hunger.
player.in_world()
true while you are in a world (false on menus and loading screens).
player.dead()
true on the death screen.
player.target()
x, y, z of the block your crosshair is on.
player.rotation()
yaw, pitch of your view. Yaw 0 faces south (+Z), pitch 90 looks straight down.
player.look(yaw, pitch [, timeout_ms])
Turns your view there the way the mouse does. true once it gets there.
player.look_at(x, y, z [, timeout_ms])
Turns your view to a point. A block's centre is x + 0.5, y + 0.5, z + 0.5.
player.name()
Your name.

world

Time, blocks, players

world.time()
The time of day, 0 to 23999 (nil when the server does not say).
world.is_day(), world.is_night()
Night is 12542 to 23459, the time beds work. Time Changer does not fool these: they read the real time.
world.block(x, y, z)
The block's name ("stone", "oak_log"), or nil when that part of the world is not loaded.
world.find(pattern, radius [, max])
Blocks matching within radius (up to 48) of you, nearest first: { {x=, y=, z=}, ... }. pattern can be a list: {"*_ore", "chest"}. Big searches take a few ticks.
world.dimension()
"overworld", "nether" or "end".

players

Who is around

world.players([radius])
Players loaded near you, nearest first: { {name=, x=, y=, z=, distance=}, ... }.
world.online()
The names on the server's player list (what Tab shows).

inventory

What you carry

inventory.count(pattern)
How many items match: "oak_log", "*_log" (ends with), "oak_*" (starts with), "*" (anything).
inventory.free()
Empty slots.
inventory.items()
Every stack: { {slot=0, name="oak_log", count=12}, ... }. Slots 0 to 8 are the hotbar.
inventory.selected()
The hotbar slot in hand, and its item.
inventory.select(slot)
Picks hotbar slot 0 to 8.
inventory.find(pattern)
The first slot holding a match, and how many are there. nil when there is none.
inventory.equip(pattern)
Puts a matching item in your hand. Brings it up from the inventory when it is not in the hotbar. true if it worked.
inventory.move(from, to [, count])
Moves a stack, or count items of it, to an empty slot or one with the same item. true, or false and why.
inventory.drop(slot [, count])
Drops a stack, or count items of it. true, or false and why.

craft

Crafting by recipe

craft.make(item [, count [, x, y, z]])
Crafts count items from what you carry, the way the recipe book does. Without a position it uses the 2x2 grid in your inventory. With a crafting table's position it walks there and uses it, for 3x3 recipes. Returns the items made, and an error text.
craft.can(item [, table])
How many you could make right now, and whether it needs a crafting table.
craft.recipes(item)
The recipes that make it: { {item=, makes=, table=, ingredients={ {name=, count=, tag=}, ... }}, ... }. tag=true means any item of that kind ("minecraft:planks").

baritone

Walking and mining

baritone.mine(block, ...)
Mines the blocks named, like #mine.
baritone.goto(x, y, z)
Walks there, like #goto.
baritone.goto_near(x, y, z)
Walks to somewhere that block can be reached from.
baritone.stop()
Stops the job.
baritone.busy()
true while a job runs.
baritone.wait([timeout_ms])
Pauses until the job ends.
baritone.status()
The status line, as the menu shows it.
baritone.command(text)
Any Baritone command: "#dig", "#sbuild", "#select".

container

Chests

container.deposit(x, y, z, pattern, ...)
Walks to the chest, opens it, puts every stack that matches in, closes it. Returns how many items went in, and an error text if something failed ("the chest is full").
container.withdraw(x, y, z, pattern [, count])
The other way round: takes matching stacks out into free slots, up to count items. Returns how many came out, and an error text.
container.click(item, ...)
Presses the first matching item in the open menu, as a click there does (a server's confirm panes: "lime_stained_glass_pane"). true once sent, or false and why.

points

Places you saved

points.get(name)
x, y, z of a point saved with #mark <name> (look at a block and type it in chat). nil if there is none.
points.set(name, x, y, z)
Saves a point from the script.

store

Values kept between runs

store.get(key [, default])
A value this script saved earlier, or default.
store.set(key, value)
Saves true/false, a number or text for next time. nil removes it.

module, input

Modules, keys, clicks

module.enable(name), module.disable(name)
Switches a module, by its name in the menu ("Kill Aura", "Fly").
module.toggle(name), module.enabled(name)
Flips it, or tells whether it is on.
module.get(name, setting), module.set(name, setting, value)
Reads or changes a setting, by the name its panel shows: module.set("Kill Aura", "Range", 3.5). An option is set by its name.
module.list()
Every module's name.
input.click("left" | "right")
A mouse click in the game.
input.key("e" | "1" | "escape" | ...)
A key tap: a letter or digit, escape, enter, space, shift, ctrl, tab.
input.down(key), input.up(key)
Holds a key until you let go: input.down("w") walks forward. Keys still held when the script ends are let go.

Examples

Block miner (comes with Prism)

Mines any blocks with Baritone (oak logs by default, several at once if you list them), comes back to store them when the inventory is nearly full (set the chest near where your come-back command takes you), and goes to your night home at night. After the number you set (64 by default) it comes back (/home 1), stores everything and can die there (/kill, pressing the green confirm pane) to start the next trip with full food and health. The moment you take damage it stops and sends your save command, waits there, then goes back to mining. Set the chest with the Set Storage chest button in its settings.

-- @name Block miner
-- @description Mines any blocks with Baritone and stores them in a chest. Comes back after a number mined, and can kill you there to reset food and health. Day: your mining home; night: your night home. Gets hurt: teleports you to your save home.
-- @text   block       "Blocks to mine (several: spaces between)"   "oak_log"
-- @text   items       "Items to store (empty: the blocks)"          ""
-- @text   day_home    "Command to go mining"                        "/home 3"
-- @int    trip        "Come back after mining this many (0: never)" 64 0 2304
-- @text   back_home   "Command to come back"                        "/home 1"
-- @bool   suicide     "Die after coming back (resets food, health)" true
-- @text   suicide_cmd "Command to die"                              "/kill"
-- @text   confirm     "Press in the menu that asks (empty: none)"   "lime_stained_glass_pane green_stained_glass_pane"
-- @bool   night_stop  "Stop at night"                               true
-- @text   night_home  "Command when it is night"                    "/home 2"
-- @int    tp_wait     "Seconds to wait after a teleport"            4 1 20
-- @bool   store       "Put what you mine in the chest"              true
-- @point  chest       "Storage chest"                               chest
-- @int    free_slots  "Come back to store when free slots are at most" 2 0 36
-- @bool   save        "Save me when I get hurt"                     true
-- @text   save_home   "Save command"                                "/home 1"
-- @int    save_rest   "Seconds to stay there after a save"          30 5 600
-- @bool   save_stop   "Stop the script after a save"                false

-- Set the chest with the button in this script's settings (look at it, press "Set Storage chest"). Bind a key to the
-- script in the Scripts panel: the key starts it and stops it (stopping it stops the mining too).
-- A trip: it mines until it has gathered the number set (counted from your inventory) or your inventory is nearly full,
-- then sends the come-back command, puts everything in the chest (set it near where that command takes you), and with "Die after coming back" sends
-- the die command, presses the green pane in the menu that asks to confirm it (Donut SMP), respawns and goes mining
-- again with full food and health. Dying drops what you carry unless the
-- server keeps inventories: the chest is filled first, but tools and armour go with you.
-- The save: any damage (a mob, a fall, drowning, lava) stops the mining and sends the save command at once; it stays
-- there for the rest time, then goes back to mining (or stops, if you chose that).

local function words(text)
  local out = {}
  for word in string.gmatch(text or "", "[^%s,]+") do out[#out + 1] = word end
  return out
end

local blocks = words(settings.block)
if #blocks == 0 then
  print("Name a block to mine in this script's settings")
  return
end
local items = words(settings.items)
if #items == 0 then items = blocks end

local mode = nil   -- "day" or "night": what was last done (nil: go again)
local last_health = player.health() or 20

-- What you carry of the items, all patterns together.
local function carried()
  local total = 0
  for _, pattern in ipairs(items) do total = total + (inventory.count(pattern) or 0) end
  return total
end

-- This trip: what you carried when it began, and what went into the chest since.
local trip_base = carried()
local trip_stored = 0
local function new_trip()
  trip_base = carried()
  trip_stored = 0
end
local function trip_mined()
  return math.max(0, carried() - trip_base) + trip_stored
end

-- True when you lost health since the last check (and keeps the newest value).
local function hurt()
  local health = player.health()
  if not health then return false end
  local was = last_health
  last_health = health
  return health < was - 0.01
end

local function send(command)
  if command and command ~= "" then chat.send(command) end
end

local function save()
  baritone.stop()
  print("Hurt (" .. string.format("%.1f", last_health) .. " health): saving you with " .. settings.save_home)
  notify("Block miner: hurt, " .. settings.save_home)
  send(settings.save_home)
  if settings.save_stop then
    wait(settings.tp_wait * 1000)
    print("Saved: stopping")
    stop()
  end
  -- Damage while it waits there (still burning, the teleport's delay) does not send the command again.
  wait(settings.save_rest * 1000)
  last_health = player.health() or last_health
  mode = nil   -- Back to mining from the start
end

-- Waits ms, saving you the moment you get hurt; true if it did.
local function pause(ms)
  local finish = millis() + ms
  repeat
    if hurt() and settings.save then
      save()
      return true
    end
    wait(100)
  until millis() >= finish
  return false
end

local function teleport(command)
  baritone.stop()
  send(command)
  pause(settings.tp_wait * 1000)   -- the teleport and the chunks
end

-- The chest must be near where the come-back command takes you: a walk across the world to it never ends.
local kChestReach = 64

local function store()
  local chest = settings.chest
  if not chest then
    print("No storage chest set: look at it and press \"Set Storage chest\" in this script's settings")
    return false
  end
  local x, y, z = player.pos()
  if x then
    local far = math.sqrt((chest.x + 0.5 - x) ^ 2 + (chest.y + 0.5 - y) ^ 2 + (chest.z + 0.5 - z) ^ 2)
    if far > kChestReach then
      print(string.format("The storage chest (%d %d %d) is %d blocks from here (%d %d %d): set it near where %s takes you " ..
                          "(look at it there and press \"Set Storage chest\")", chest.x, chest.y, chest.z, math.floor(far),
                          math.floor(x), math.floor(y), math.floor(z), settings.back_home))
      notify("Block miner: the chest is " .. math.floor(far) .. " blocks away")
      return false
    end
  end
  baritone.stop()
  local mined_before = trip_mined()
  print("Putting " .. table.concat(items, ", ") .. " in the chest")
  local moved, err = container.deposit(chest.x, chest.y, chest.z, table.unpack(items))
  if err then print("Chest: " .. err) end
  print("Stored " .. (moved or 0))
  -- The trip's count stays: what it was before is kept, and what is left in the bag counts from here.
  trip_stored = mined_before
  trip_base = carried()
  last_health = player.health() or last_health
  return true
end

local function dead()
  local health = player.health()
  return player.dead and player.dead() or (health ~= nil and health <= 0)
end

-- Sends the die command, presses the confirm item in the menu the server opens for it (again every 1.5 s while that
-- menu stays), and waits through the death and the respawn; false if you did not die.
local function die()
  print("Dying with " .. settings.suicide_cmd .. " to reset food and health")
  send(settings.suicide_cmd)
  local confirm = words(settings.confirm)
  local finish = millis() + 10000
  local pressed = -1e9
  while not dead() and millis() < finish do
    if #confirm > 0 and millis() - pressed >= 1500 and container.click(table.unpack(confirm)) then
      pressed = millis()
      print("Pressed confirm")
    end
    wait(250)
  end
  if not dead() then
    print("Did not die (the server may not allow " .. settings.suicide_cmd .. ", or nothing to confirm in its menu): going on")
    return false
  end
  print("Dead: respawning")
  local since = millis()
  while dead() do
    if player.respawn then player.respawn() end
    wait(1000)
    if millis() - since > 60000 then
      print("Still dead after a minute: press Respawn")
      since = millis()
    end
  end
  wait_until(player.in_world, 30000)
  wait(settings.tp_wait * 1000)   -- the spawn's chunks
  last_health = player.health() or 20
  return true
end

-- The trip is over: back, everything in the chest, and (if chosen) a fresh life.
local function come_back(why)
  print(why .. ": coming back with " .. settings.back_home)
  notify("Block miner: " .. why .. ", coming back")
  teleport(settings.back_home)
  if mode == nil then return end   -- Got hurt on the way: the save handled it
  -- Nowhere to put it (no chest, or the chest is not here): it stops rather than die with it or keep coming back.
  if settings.store and not store() then
    print("Stopping: what you mined is still with you")
    stop()
  end
  if settings.suicide then die() end
  new_trip()
  mode = nil   -- Mining again from the start
end

local time = world.time()
if time then
  print("World time " .. time .. (world.is_night() and " (night)" or " (day)"))
else
  print("The world time cannot be read here: it counts as day")
end

local chest_missing_told = false
while true do
  local night = settings.night_stop and world.is_night()
  if night and mode ~= "night" then
    mode = "night"
    local t = world.time() or 12542
    local minutes = math.max(1, math.floor((23460 - t) / 1200 + 0.5))
    print("Night: waiting at " .. settings.night_home .. " until day (about " .. minutes .. " min). Switch off 'Stop at night' to mine at night.")
    notify("Block miner: night, waiting about " .. minutes .. " min")
    teleport(settings.night_home)
  elseif not night and mode ~= "day" then
    mode = "day"
    print("Going to " .. settings.day_home .. " to mine " .. table.concat(blocks, ", ") ..
          (settings.trip > 0 and (" (coming back after " .. settings.trip .. ")") or ""))
    teleport(settings.day_home)
  end
  if mode == "day" then
    if settings.trip > 0 and trip_mined() >= settings.trip then
      come_back("Mined " .. trip_mined())
    elseif settings.store and inventory.free() <= settings.free_slots and settings.chest then
      -- Stored where the chest is: after the come-back command, never by walking there from the mine.
      come_back("Inventory full")
    elseif settings.store and inventory.free() <= settings.free_slots and not chest_missing_told then
      chest_missing_told = true
      print("Inventory full and no storage chest set: look at it and press \"Set Storage chest\" in this script's settings")
    elseif not baritone.busy() then
      baritone.mine(table.unpack(blocks))
    end
  end
  pause(1000)
end

Sticks from logs

Both recipes fit the 2x2 grid, so no crafting table is needed. Prism also comes with auto_crafter.lua: it crafts any item until you have enough, fetches the ingredients from a chest and stores what it makes.

-- Turns logs into planks, then planks into sticks, until there are 64 sticks.
while inventory.count("stick") < 64 do
  if inventory.count("*_planks") < 2 then
    local made, err = craft.make("oak_planks", 4)
    if made == 0 then print("No planks: " .. (err or "?")) stop() end
  end
  local made, err = craft.make("stick", 64 - inventory.count("stick"))
  if made == 0 and err then print(err) stop() end
  wait(500)
end
print("64 sticks")

Twenty diamonds

-- Mines diamonds until you have 20, then goes home.
baritone.mine("diamond_ore", "deepslate_diamond_ore")
wait_until(function() return inventory.count("diamond") >= 20 end)
baritone.stop()
chat.send("/home")
print("20 diamonds: going home")

Also there: Lua's string, table, math and utf8 libraries, os.time, os.clock and os.date, and coroutines. Files, other programs and loading code are switched off.