Scripting and trolling
ZimanDLC runs Lua 5.2 scripts inside the client. Write them in the Scripts tab of the menu, press Run, and they react to the game every tick. This page covers the whole API and the CS-style movement modules (Movement tab, plus AntiAim in Combat).
Your first script
- Open the client menu (Right Shift) and pick Scripts in the sidebar.
- Press + to make a script. It's saved as
config/zimandlc/scripts/script1.lua in your game folder.
- Click into the editor, write something, press Run.
function on_load()
print("hi " .. player.name())
end
function on_render()
render.text("I'm alive", 20, 20)
end
A script is a plain Lua file that defines some of the callback functions. The client calls them when things happen. Everything you print shows up in the console under the editor, and so do errors.
Scripts that were running when you quit start again next time. On first launch you get hello.lua: a speed readout on the HUD, plus the K key toggles AntiAim.
The editor
Click a script in the list to open it. The green dot means it's running.
| Key | What it does |
Ctrl+S | Save. A running script restarts with the new code. |
Ctrl+Enter | Save and run. |
Ctrl+V | Paste at the cursor. Tabs become two spaces. |
Ctrl+C | Copy the whole script. The editor has no selection. |
Ctrl+D | Duplicate the current line. |
Tab | Indent by two spaces. Enter keeps the indent, and adds a level after then, do, function(…) and {. |
Home / End | Jump to the start of the code or the end of the line. Page Up and Page Down scroll a screen. |
Esc | Leave the editor. Press it again to close the menu. |
Cmd works instead of Ctrl on macOS. If you'd rather use a real editor, edit the file in config/zimandlc/scripts and press Reload. Delete asks you to press it twice, and then the file is gone.
Callbacks
Define any of these as global functions. Leave out the ones you don't need.
| Function | When it runs |
on_load() | Once, right after the script starts. |
on_tick() | Every game tick, 20 times a second, while you're in a world. |
on_render() | Every frame. Only here can you draw with render. It doesn't run while the client menu is open. |
on_key(key) | When a key is pressed in game, not in menus. key is a GLFW key code; compare it with keys. |
on_chat(text) | For every chat message you receive. Return true to hide it. |
on_unload() | When the script is stopped or restarted. |
One error stops the script. If a callback throws, the error goes to the console with its line number and the script stops. Fix it and press Run again.
player
You. Every function is called with a dot: player.x(). Calling these outside a world raises not in a world, so guard with client.in_game() in on_load.
| Function | Returns | Notes |
x() y() z() | number | Position in blocks. |
pos() | x, y, z | All three at once. |
yaw() pitch() | number | Where the camera looks, in degrees. Pitch 90 is straight down. |
set_yaw(deg) set_pitch(deg) | | Turn the camera. Pitch is clamped to ±90. |
look(yaw, pitch) | | Server-only look for this tick. Others see it, your camera doesn't move. Call it from on_tick every tick you want it. Ignored while an aura is aiming. |
vel() | x, y, z | Velocity in blocks per tick. |
set_vel(x, y, z) | | Set the velocity. |
speed() | number | Horizontal speed in blocks per second. |
jump() | | Jump, if you're on the ground. |
health() max_health() food() | number | Health is in half-hearts, so 20 is full. |
on_ground() sneaking() sprinting() in_water() | boolean | |
set_sprint(on) | | |
fall_distance() | number | Blocks fallen since you last stood on something. |
name() | string | |
held() | string | Item id in the main hand, like minecraft:diamond_sword. |
slot() set_slot(n) | 1–9 | Hotbar slot. |
world
| Function | Returns | Notes |
block(x, y, z) | string | Block id at a position, like minecraft:air. |
players() | table | Every other player you can see: a list of {name, x, y, z, health, distance}. |
time() | 0–23999 | Time of day in ticks. 6000 is noon. |
client
| Function | Returns | Notes |
chat(text) | | Show a message in your chat only. |
say(text) | | Send a chat message. Text starting with / runs as a command. |
in_game() | boolean | Whether you're in a world. |
menu_open() | boolean | Whether any screen is open: chat, inventory, pause menu. |
server() | string or nil | Server address, or nil in singleplayer. |
screen() | w, h | Window size in pixels, the same units render uses. |
fps() | number | |
ms() | number | Milliseconds since 1970. Use it for timers. |
key_down(key) | boolean | Whether a key is held right now. |
modules
Control any client module by the name shown in the menu, like "AttackAura" or "AntiAim". Setting names are also as shown, and the case doesn't matter.
| Function | Returns | Notes |
list() | table | All module names. |
is_on(name) | boolean | |
set(name, on) | | Turn a module on or off. |
toggle(name) | boolean | Flip it and get the new state. |
settings(name) | table | The module's setting names. |
get(name, setting) | value | A boolean, number or string. |
set_value(name, setting, value) | | Checkboxes take a boolean and sliders a number, clamped to their range. Mode lists take one of their mode names. |
modules.set_value("AntiAim", "Yaw", "Jitter")
modules.set_value("AntiAim", "Jitter Range", 120)
render
Draw on the HUD from on_render. Coordinates are window pixels from the top-left. Colors are numbers made with render.rgba. All rectangles are drawn first and all text on top of them.
| Function | Returns | Notes |
rgba(r, g, b, a) | color | Each value is 0–255. Alpha defaults to 255. |
rect(x, y, w, h, color, radius) | | A filled rectangle. Radius rounds the corners and defaults to 0. |
text(str, x, y, color, size) | | Text with its top-left at x, y. Size defaults to 14, and color to white. |
text_width(str, size) | number | Use it to center or right-align text. |
text_height(size) | number | |
theme
The client's current theme colors, ready to pass to render. Every color function takes an optional alpha from 0 to 255 (default 255), so HUDs can match whatever theme the user picked.
| Function | Returns |
accent(a) background(a) surface(a) | color: main accent, base background, raised surface |
text(a) text_secondary(a) muted(a) on_accent(a) | color: text shades that stay readable on the theme; on_accent is for text drawn over the accent |
name() | string: theme name, like "Dark Mint" |
is_light() | boolean |
function on_render()
local w, h = client.screen()
render.rect(w / 2 - 40, h / 2 + 20, 80, 20, theme.background(200), 6)
render.text(string.format("%.1f", player.speed()), w / 2 - 14, h / 2 + 23, theme.accent())
end
keys
Key codes to compare with on_key and client.key_down: keys.A to keys.Z, keys.N0 to keys.N9, keys.F1 to keys.F12, plus SPACE, ENTER, TAB, BACKSPACE, ESCAPE, LEFT_SHIFT, LEFT_CONTROL, LEFT_ALT, UP, DOWN, LEFT and RIGHT. Any other key works by its GLFW code.
Limits
- Each callback gets 50 ms. A loop that runs longer is stopped with
took longer than 50 ms (endless loop?) so the game doesn't freeze.
- Scripts can't touch files or Java:
io, os, require, dofile, debug and luajava aren't there. string, table, math, bit32 and coroutine are.
- Every script has its own globals. Two scripts can't see each other's variables.
- Everything runs on the game thread, so slow scripts cost frames.
Only run scripts you've read. A script can't reach your files, but it can send chat messages and commands as you, and turn modules on and off.
Lua Unsafe
By default scripts cannot touch files or other scripts. The Lua Unsafe module (Misc tab, off by default) lifts that while it is on: scripts started in that state get require, dofile, loadfile, io and os. require("name") loads name.lua from the scripts folder, so scripts can share helper files. debug and luajava stay unavailable, and the 50 ms limit still applies.
Unsafe scripts can read and write any file you can and run programs, so only enable it for scripts you have read. Turning the module off stops every script that was started in unsafe mode. Clawd never starts a script that uses these functions on its own.
Examples
Coordinates in the corner
function on_render()
local x, y, z = player.pos()
local line = string.format("%d %d %d", math.floor(x), math.floor(y), math.floor(z))
local w, h = client.screen()
render.text(line, w - render.text_width(line) - 16, h - 30)
end
Hide chat spam
local banned = { "discord.gg", "cheap coins" }
function on_chat(text)
for _, word in ipairs(banned) do
if text:lower():find(word, 1, true) then return true end
end
end
Your own anti-aim
-- a slow helicopter that nods up and down
local t = 0
function on_tick()
t = t + 1
player.look(t * 12, math.sin(t / 4) * 90)
end
Low health warning
local warned = false
function on_tick()
local low = player.health() < 8
if low and not warned then client.chat("low health, back off") end
warned = low
end
function on_render()
if warned then
local w, h = client.screen()
render.rect(0, 0, w, h, render.rgba(255, 0, 0, 40))
end
end
CS movement modules
Source engine movement and CS anti-aim, rebuilt for Minecraft for the fun of it. Each one is a normal module: bind it, favorite it, script it.
AntiAim
Other players see you look somewhere silly while your own camera stays put. It pauses while an aura is aiming and, by default, while you click.
- Yaw
- Backwards, Spin, Jitter (flips left and right every tick), Sideways, Random, or Off.
- Spin Speed
- Degrees per tick for Spin.
- Jitter Range
- How far Jitter and Random swing.
- Pitch
- Down, Up, Zero, Jitter (straight up, straight down), Random, or Off.
- Pause On Click
- Look normal while attacking or using an item, so hits and block placing still go where you aim.
Pixelsurf
Fall against a wall and you stop falling. You glide along it and keep your speed, like surfing a pixel-wide ledge in CS.
- Fall Speed
- How fast you still sink while surfing. 0 holds you level.
- Boost
- Speed multiplier per tick while surfing.
- Max Speed
- Top speed Boost can reach, in blocks per tick.
- Only While Sneaking
- Surf only while you hold sneak.
- Sound
- A pling when a surf starts.
Edgebug
Land a long fall on the very edge of a block and the landing doesn't happen: no fall damage, and you slide off with your speed. Edge means the middle of your feet is over air while a corner would touch the block.
- Min Fall
- Fall height in blocks before an edgebug can trigger.
- Any Landing
- Trigger on every landing, not just edges.
- Sound
- A bell on each edgebug.
- Chat Message
- Count your edgebugs in chat.
Bhop
Land and jump on the same tick and you keep the speed you built in the air instead of losing it to ground friction.
- Gain
- Speed multiplier per hop.
- Max Speed
- Top speed Gain can reach, in blocks per tick.
- Only When Moving
- Skip the carry when you hold no movement key.
AutoStrafe
Air strafing like Source. Turn while holding a side key and you gain speed in the air.
- Air Cap
- How much speed one tick of strafing can add along your wish direction.
- Max Speed
- Top speed, in blocks per tick.
- Auto (Follow Mouse)
- Strafe toward wherever your mouse turns, no A or D needed.
StairSurf
Fall onto a stair or slab and you glide over it, keeping and boosting your speed.
- Boost
- Speed multiplier per tick while surfing.
- Max Speed
- Top speed Boost can reach, in blocks per tick.
- Slabs
- Surf slabs as well as stairs.
LongJump
Your jump launches you far along your view direction instead of straight up.
- Speed
- Horizontal launch speed.
- Height
- Vertical launch speed.
- Only While Sprinting
- Trigger only when you sprint.
JumpBug
Sneak as you land a long fall and the landing becomes a jump, with no fall damage.
- Height
- Jump speed after the bug.
- Min Fall
- Fall height in blocks before it can trigger.
- Sound
- A chime on each jumpbug.
TextureBug
Hold jump against a wall and you climb it, like squeezing up a bad texture seam.
- Climb Speed
- Upward speed while climbing.
- Reset Fall Distance
- Take no fall damage after climbing.
Anticheats notice this. Pixelsurf, Edgebug, Bhop, AutoStrafe, StairSurf, LongJump, JumpBug and TextureBug change your movement in ways vanilla can't, and AntiAim sends rotations no human makes. Expect kicks on servers with an anticheat.