Overview New

The two input layers of Bedrock, the order of one tick, threads, time budget, priority with the native aim and silent angles.

On a Source game a single usercmd carries the input of a tick from the client to the server. Bedrock keeps the same input in two places, and xiao.cmd gives you both with the same cmd object.

The two layers

  createmove (client) authinput (server)
Data MoveInputComponent, rotation, head rotation, camera of the local player the PlayerAuthInputPacket payload
When every client tick (20 per second), before the tick is simulated every PlayerAuthInputPacket the client sends (20 per second)
Angles real: the camera turns, the client simulates with them only in the packet: the view does not move
Movement the client moves with it and sends it, nothing to fix only the server moves you: the client keeps its own position
Buttons jump_down, sprint_down, sneak_down all 66 input buttons of the packet
Read only position position, tick

Which one to use

Goal Layer
move, jump, sneak or sprint for the player (auto sprint, bunny hop, follow a path) createmove
turn the view for real (aim lock that the player sees) createmove set_view_angles
aim for the server only, view untouched (silent aim) createmove lock_angles or authinput set_view_angles + rotate_movement
change a button the client never sets (start_gliding, missed_swing) authinput
observe exactly what the server receives authinput

One tick, step by step

client game thread, 20 ticks per second
1. ClientInputUpdateSystem      the game reads keyboard, mouse and gamepad into MoveInputComponent
2. xiao.cmd createmove           forced states of xiao.game.set_state, then your callbacks; changes are written to
                                MoveInputComponent, rotation and camera
3. movement simulation          SetMoveSystemClient, RotateAndSetVelocitySystem, JumpInputSystem ...
4. SendPlayerInputPacketSystem  builds PlayerAuthInputPacket from MoveInputComponent, rotation and position
5. send of the packet           native aim, then set_state buttons, then silent angles of lock_angles, then
                                xiao.cmd authinput, then xiao.packet.hook on PlayerAuthInput, then the wire
next tick: the MoveInputComponent values written at step 2 are restored before step 1

Step 2 runs in the client tick hook used by the pathfinder (after its own input, so a script sees and can override the pathfinder). The restore before the next step 1 means the game never sees your input as a key it pressed itself: a callback that stops writing gives the keyboard back at once.

Threads and time budget

Both callbacks run outside the render thread, inside the same VM as the rest of the script, with the rules of packet hooks (see Execution contexts):

Measured in lua_runtime_test and actors_test (Release, one callback):

Case Cost per tick
no cmd callback installed 0.004 us (one atomic read)
authinput callback that reads 0.9 us
authinput callback that changes angles (packet encoded again) 0.8 us
createmove callback that reads 0.5 us
createmove callback that changes the input 0.8 us
createmove game memory: read, then write and restore 1.6 us, then 2.2 us

A packet that nothing changed is never encoded again: the game sends its own bytes.

Forced states New

xiao.game.set_state uses these two layers without any callback: a forced sprinting, sneaking or jumping is written into the client input of every tick before the createmove callbacks, and the start_*, stop_* and held buttons of every state go into the packet before the authinput callbacks. A callback sees the forced state and keeps the last word for its tick. xiao.cmd.stats() counts it in state_client and state_server.

Priority with the native aim

The client aim features (kill aura, aim assist toward the server) rewrite the angles of the outgoing packet in the network layer. The order is fixed:

  1. native aim writes its angles and rotates the movement to match;
  2. New the buttons of xiao.game.set_state are applied (buttons only, angles untouched);
  3. the silent angles of a createmove lock_angles are applied;
  4. authinput callbacks run and see the result (cmd:native_aim() is true);
  5. xiao.packet.hook callbacks on PlayerAuthInput see the cmd result.

The script has the last word. When the angles that leave are not the ones the native aim wrote, the native aim is told its rotation was not delivered, so the aura waits for a packet that carries its own angles before it attacks. To leave the native aim alone, test cmd:native_aim() and do not touch the angles.

Silent angles

lock_angles() makes the angle changes of the cmd silent: the server receives them, the camera and the player view do not move.

  • In createmove, the camera and the rotation are left untouched and the angles are carried to the next PlayerAuthInputPacket (it is sent in the same tick, the angles expire after 100 ms). The movement in that packet was simulated with the real view, so it is rotated to the silent yaw: the server moves you along the same path.

  • In authinput, angles are always packet only; lock_angles() adds the same movement rotation at the end of the callbacks, so you do not need rotate_movement.

See angles and the silent aim example.

Lifecycle

  • A new callback takes effect at the next frame; removing the last one stops the layer at the next frame.

  • Clear VM and unload stop both layers: no callback runs after the VM is closed, pending silent angles are dropped and the client input is restored at the next tick.

  • When a layer is not installed in the current game build (xiao.cmd.available(event) is false), its callbacks never run and the other layer keeps working.