Changelog
Changes to the Lua API, most recent first. Supported game: Minecraft Bedrock 1.26.6201.0.
2026-11-06
Movement states New
-
xiao.game.state(name)and newplayer()fieldssprinting,sneaking,swimming,gliding,crawling,flying,jumping: read from the local player each frame (actor flags of the game,flyingability, "is jumping" marker), absent ornilwhen unreadable. -
xiao.game.set_state(name, true | false | nil)forces a state until it is released withnil: applied every tick in the client input (sprinting,sneaking,jumping) and in everyPlayerAuthInputPacket(start_*once, held buttons,stop_*on release).xiao.game.requested(name)returns the request. -
xiao.cmdkeeps the last word:createmoveandauthinputcallbacks run after the forced states and see them.xiao.cmd.stats()addsstate_clientandstate_server. -
Clear VM, unload and a new script release every request; the server gets the
stop_*it still needs on the next packet.
2026-11-05
Fixes after the in-game test run
-
xiao.game.player():hunger,saturation,levelandexperienceare now known after an injection in the middle of a game (the attribute packet is matched to the local runtime id read in memory) and again after a dimension change. -
damagesignal: a hit without a health drop seen on the target has noamountand nohealth(it reportedamount = 0); a hit with a drop giveshealthandmax_health, the health left on the target (0on a kill). -
xiao.packet.send_fieldsraises the encoding error (missing field runtime_id) likeencode; it still returnsfalse, errorfor send failures (size, queue, connection). -
cmd:command_number()increatemoveis theClient Tickof the PlayerAuthInputPacket that leaves with this tick (it was a separate counter),nilbefore the first packet.xiao.cmd.stats()addscreatemove.matched,createmove.mismatched,createmove.lead_usandsilent_matched. -
C++ errors inside a
xiaofunction (for examplexiao.json.decodeon invalid text) give their message, with line and column for JSON, instead ofC++ exception.
xiao.timer New
-
xiao.timer:
after(seconds, fn),every(seconds, fn)andcancel(id), on the frame clock (sum ofdt), one frame of resolution, at most 4096 pending. -
spawn(fn, ...)runs a coroutine at once until its firstwait(seconds);waitreturns the time waited and a plaincoroutine.yield()waits one frame. -
Timers run at a new step of the order of a frame: after the game signals, before
on_frame. They count in the 100 ms budget, a failing callback or coroutine is removed with its error in the console, Clear VM drops them all. -
after,everyandcancelwork in packet and cmd hooks, their callback runs later on the render thread;spawnis refused there.
xiao.json, xiao.workspace and xiao.notify New
-
xiao.json:
encode(value, opts)withprettyandindent,decode(text)with line and column in errors,array()for[],null. Sequences1..nare arrays, other tables objects with sorted string keys, integers exact to 2^53, cycles and depth over 128 refused with the path of the value. -
xiao.workspace:
load(name)andsave(name, t), one JSON file per name inC:\xiaohook\lua\workspace, named after the script by default, 1 MiB at most, written atomically and again on Clear VM and unload. -
xiao.notify
(title, text, kind): toast of the client menu, kindsinfo,success,warning, 3 per second, ASCII, title 48 and text 128 characters. -
xiao.workspaceandxiao.notifyraise an error inside a packet hook or a cmd hook,xiao.jsonworks there.
xiao.cmd New
-
New category xiao.cmd, the Bedrock
usercmd/CreateMove: a callback gets a cmd object once per tick with the view angles, the movement and the input buttons of the local player. -
Two layers with the same object:
xiao.cmd.hook("createmove", ...)changes the input the client simulates, before the tick (client and server agree);xiao.cmd.hook("authinput", ...)changes thePlayerAuthInputPacketthe server receives.xiao.cmd.unhook,current(),available(event)andstats()complete the module. -
xiao.cmd.buttonsnames the 66 input buttons of the game schema (jump_down,sprint_down,start_sprinting...), by index:get_buttons,set_buttons,has_button,set_button,remove_button. -
get_view_angles,set_view_angles,get_head_yaw,set_head_yawandlock_angles(silent angles, movement turned for the server). Bedrock has no roll. -
get_move,set_move,get/set_forward_move,get/set_left_move,get/set_up_move,get/set_analog_moveandrotate_movement(yaw). -
Same time rules as packet hooks: 2 ms budget, 3 overruns remove a callback.
xiao.paintis inert andxiao.config,xiao.workspace,xiao.notifyandxiao.timer.spawnraise an error, see Execution contexts. A packet nothing changed is sent untouched; no callback costs nothing. -
The script wins over the native aim: changed angles cancel the aim delivery of that packet, and
cmd:native_aim()tells when the packet was aimed. -
Packet hooks: a hook that changes the angles of an aimed
PlayerAuthInputorMovePlayernow cancels the aim delivery too.
xiao.config New
-
xiao.config.get(key),set(key, value)andtype(key)read and change every client setting by a dotted key (misc.hit_sound.volume), with six types:bool,int,float,string,colorandmulti. -
A
setacts like a change in the menu: applied at once, shown in the menu, written by the autosave. Numbers are clamped and the stored value is returned, a refused choice raisesrejected the value. -
xiao.config.load(name),save(name),list()anddirectory()work on the configs of the Configs tab. -
config_names.txtin the config folder lists every key with its type and factory value,xiao.config.names()writes it again. -
Every
xiao.configfunction raisesxiao.config is not available inside a packet hook or a cmd hookthere.
Packets: decoding and field names New
-
Field names of every packet come from the game schemas, so
msg:fields()and the packet log use the same names. -
msg:fields()andxiao.packet.fields(packet, bytes)return a packet as a Lua table: numbers, booleans, enum names, vectors, lists and nested tables. Cut or invalid payloads return the fields read so far plus_error, and uninterpreted trailing bytes are in_rest. -
Layout bytes have names too:
has_<field>for presence bytes,<string>_lengthfor lengths, the plural of a list for its count. -
Integers past 2^53 become decimal strings, NBT is also given as bytes in
<name>_raw. -
12 enum values take the exact schema name: the
PlayerAuthInputinput_flagnames are now the xiao.cmd buttons (block_break_delay->block_breaking_delay_enabled,hotbar_touch_only->is_hotbar_only_touch...),input_modegamepad->game_pad, Animateswing_arm->swing. The encoder still accepts the old names, see Renamed fields.
Packets: encoding New
xiao.packet.send_fields(packet, fields)encodes a fields table and sends it.xiao.packet.encode(packet, fields)returns the payload without sending it.writer:fields(fields)replaces the payload of a writer.- Computable fields are optional:
has_<name>,<name>_lengthand list counts. encode(id, fields(id, bytes)) == bytesfor every complete decode.- Errors name the field:
missing field position.x,field mode: unknown value 'fly'.
Packets: interception New
-
xiao.packet.hook(packet, identity, callback)sees a packet in both directions and can returnnil(unchanged),false(cancel), a string (new payload) or a fields table (encoded for you). -
xiao.packet.unhook(packet, identity)removes a hook. -
Time constraint: 1 ms wait for the VM and a 2 ms budget per packet. A busy VM passes the packet unchanged and counts in
busy, an over budget hook counts inoverruns, and 3 overruns in a row remove the hook. At most 64 hooks. -
xiao.packet.hook_stats()returns the counters (calls,busy,overruns,errors,dropped,replaced,removed,avg_us,max_us,total_us,budget_us,wait_us).
Packets: sending New
- Sends are flushed in the order of the
sendcalls. xiao.packet.pending()andxiao.packet.capacity()(8 places) expose the queue.- A send waits for the next packet the game sends on the same connection and is dropped after 2 seconds without one.
Packet log New
-
Copy as Lua writes readable code: values first as named variables, enum tables, nested tables for lists and sub-structures, and
write_*calls that rebuild the original payload byte for byte. -
Copy as receiver copies a receiver that reads the packet field by field and prints the first fields.
-
Both are generated off the render thread, announced by a notification, and refuse payloads over 4 MiB.
Signals New
-
chat: incoming text, withsource,typeand ametatable (xuid,needs_translation,parameters). -
entity_addandentity_remove: entities entering and leaving, withid,unique_id,name,type,is_player, position anddistance. -
damage: hits by the local player and damage taken by the local player. -
world_change:old,newand areasonamongenter,leave,dimension,session. -
Fixed order inside a frame and limits per frame, see Running scripts.
xiao.game New
player(): position, rotation, velocity, health, hunger, saturation, level, experience, selected slot, dimension.world():in_world,session,dimension,dimension_name.hotbar(),inventory(),armor(),offhand(),held_item(),selected_slot().block(x, y, z)with failure reasonsunloaded,busy,no_world,budget,failed,unavailable.- Entities now have
type,is_playeranddistance, plushealthandmax_healthwhen known. local_player()is kept for older scripts.players()andentities()are filled whenever a script runs, even with the ESP turned off.
Editor New
- Copy, cut and paste no longer block the game: the clipboard is read off the render thread.
Fixes Fixed
-
os.date: an unknown directive (
%Q,%k, a lone%...) ended the game process inside the Windows C runtime. The format is now checked first and the erroros.date: invalid conversion specifier '%Q'can be caught withpcall; valid directives give the same text as before. -
debug.sethook could remove the 2 ms budget inside a packet or cmd hook, and a looping hook function escaped the 100 ms watchdog of a frame. It now raises
debug.sethook is not available inside a packet hook or a cmd hookin a hook and refuses to install a hook anywhere;debug.sethook()without a function does nothing. -
jit.attachand thejit.profilemodule are removed: their callbacks ran with the hooks turned off, outside every time limit. -
xiao.packet.send,send_rawandsend_fieldscalled from a packet hook read the send route of the network thread while the render thread updated it: the route is now locked, a send never mixes two routes.
Documentation
- The documentation has a new structure: Introduction, Engine, Minecraft Bedrock and Guides.
Initial release
Core
- Embedded LuaJIT 2.1 VM with a sandbox: no
io, noffi, no bytecode,requirelimited toC:\xiaohook\lua. - Lua tab with an editor, the console, Execute and Clear VM.
- Lifecycle:
on_frame(dt),on_unload(), thethinkandunloadsignals. - Time limits: 2000 ms for the main chunk, 100 ms per frame.
xiao.paint
- Paint listeners, points (screen and world), colors (
rgb,rgba,hex,hsv,hsl). - Shapes: line, circle, triangle, rectangle (rounded, gradient), rotated rectangle, quad, polygon.
- Text with baked fonts, images from files or raw RGBA.
xiao.packet
- Receive packets by id, name or
"*", read them with a packet object andread_*functions. - Build and send packets with
start/write_*/sendor writer objects, andsend_raw. decode,reader,id,name,dropped.- Block packet ids in both directions with
block,unblock,unblock_all,is_blocked.
xiao.game
players(),entities(),local_player(),world_to_screen()andtime().
xiao.signal and xiao.fs
- Named signals with
add,remove,get,calland their aliases. - File access inside
C:\xiaohook: read, write, append, list, create and delete, plus path helpers.