use azalea::{ account::yggdrasil::Backend, ecs::prelude::{With, Without}, entity::{Dead, LocalEntity, Position, metadata::AbstractMonster}, error::MissingComponentError, prelude::*, }; use clap::Parser; #[derive(Parser, Debug)] #[command(version, about, long_about = None)] struct Args { /// Player name #[arg(short, long)] username: String, /// Drasl backend to authenticate with (should have /auth, /session and optionally /player routes) #[arg(short, long)] backend: String, /// Minecraft server to connect to #[arg(short, long)] server: String, /// If not present, password will be queried at runtime as needed. Drasl Minecraft Token can be used instead of password. #[arg(short, long)] password: Option, /// Disable requesting signing certificates #[arg(short, long, default_value_t = false)] no_certs: bool, /// Enable attacking closest entity #[arg(short, long, default_value_t = false)] autoclick: bool, } #[derive(Default, Clone, Component)] struct State { autoclick: bool, } #[tokio::main] async fn main() -> AppExit { let args = Args::parse(); let backend = Backend::new_drasl(&args.backend, !args.no_certs); let account = match args.password { None => Account::yggdrasil(args.username.clone(), backend).await, Some(x) => { Account::yggdrasil_with_password(args.username.clone(), x.clone(), backend).await } }; let account = match account { Ok(x) => x, Err(e) => { eprintln!("Error logging in: {e}"); return AppExit::error(); } }; ClientBuilder::new() .set_handler(handle) .set_state(State { autoclick: args.autoclick, }) .start(account, args.server.as_str()) .await } fn autoclick(bot: Client) -> Result<(), MissingComponentError> { let bot_position = bot.eye_position()?; let nearest_entity = bot.nearest_entity_by::<&Position, ( With, Without, Without, )>(|position: &Position| { let distance = bot_position.distance_to(**position); distance < 4. })?; if let Some(nearest_entity) = nearest_entity { nearest_entity.attack(); } Ok(()) } async fn handle(bot: Client, event: Event, state: State) -> Result<(), ()> { match event { Event::Chat(m) => { println!("{}", m.message().to_ansi()); } Event::Tick => { if state.autoclick && !bot.has_attack_cooldown() { autoclick(bot).ok(); } } _ => {} } Ok(()) }