Skip to main content

yog_api/
control.rs

1//! Doing what a player does, for automation — tours, cut scenes, bots:
2//! moving (its own keys held), looking, attacking, using, mining, placing,
3//! picking a slot, clicking a container slot, chatting. No-ops on a
4//! dedicated server and without a player.
5//!
6//! ```ignore
7//! use yog_api::{client::player, control};
8//! if let Some(me) = player::state() {
9//!     control::look(me.yaw + 90.0, 0.0);
10//!     control::drive(control::Drive { forward: 1.0, ..Default::default() });
11//! }
12//! ```
13
14use serde::Serialize;
15use serde_json::{Value, json};
16use yog_ids::client_op as op;
17
18use crate::client::op::{ask, call};
19
20/// Movement keys held for the player, till [`release`].
21#[derive(Serialize, Debug, Clone, Copy, PartialEq, Default)]
22pub struct Drive {
23    /// -1 (back) to 1 (forward).
24    pub forward: f32,
25    /// -1 (right) to 1 (left), as the game's input has it.
26    pub strafe: f32,
27    pub jump: bool,
28    pub sneak: bool,
29    pub sprint: bool,
30    /// The use key held: a shield raised, a bow drawn, food eaten.
31    pub use_item: bool,
32}
33
34/// Holds `keys` for the player each tick, till [`release`].
35pub fn drive(keys: Drive) {
36    call(op::DRIVE, json!(keys));
37}
38
39/// Gives the movement keys back to the player.
40pub fn release() {
41    call(op::RELEASE, Value::Null);
42}
43
44/// Turns the player to `yaw`, `pitch` (degrees).
45pub fn look(yaw: f32, pitch: f32) {
46    call(op::LOOK, json!({ "yaw": yaw, "pitch": pitch }));
47}
48
49/// Attacks entity `uuid`, or (`None`) what the crosshair is on.
50pub fn attack(uuid: Option<&str>) {
51    call(op::ATTACK, json!({ "entity": uuid }));
52}
53
54/// Uses the held item, the main hand's or the off hand's.
55pub fn use_item(off_hand: bool) {
56    call(op::USE, json!({ "off_hand": off_hand }));
57}
58
59/// A block's side: the game's `Direction`.
60#[derive(Serialize, Debug, Clone, Copy, PartialEq, Eq)]
61#[serde(rename_all = "lowercase")]
62pub enum Face {
63    Down,
64    Up,
65    North,
66    South,
67    West,
68    East,
69}
70
71/// Keeps breaking the block at `pos` from `face` (call each tick); whether it's still there.
72pub fn mine(pos: [i32; 3], face: Face) -> bool {
73    ask(op::MINE, json!({ "x": pos[0], "y": pos[1], "z": pos[2], "face": face })).unwrap_or(false)
74}
75
76/// Stops breaking a block.
77pub fn stop_mining() {
78    call(op::MINE, json!({ "stop": true }));
79}
80
81/// Places the held block against the block at `pos`, on `face`; whether the game took it.
82pub fn place(pos: [i32; 3], face: Face) -> bool {
83    ask(op::PLACE, json!({ "x": pos[0], "y": pos[1], "z": pos[2], "face": face })).unwrap_or(false)
84}
85
86/// Selects hotbar slot `slot` (0–8).
87pub fn select_slot(slot: u8) {
88    call(op::SLOT, json!({ "slot": slot }));
89}
90
91/// Clicks `slot` of the open container (`button` and `mode` as the game's `ClickType`).
92pub fn click(slot: i32, button: i32, mode: &str) {
93    call(op::CLICK, json!({ "slot": slot, "button": button, "mode": mode }));
94}
95
96/// Sends `text` to the chat — a command when it starts with `/`.
97pub fn chat(text: &str) {
98    call(op::CHAT, json!({ "text": text }));
99}