From 3977d83adefabca77f6c20efc4c27ac4cbe0d3e2 Mon Sep 17 00:00:00 2001 From: ErrorNoInternet Date: Fri, 13 Jan 2023 14:55:33 +0800 Subject: [PATCH] More new commands --- src/bot.rs | 221 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/main.rs | 76 +++++++++++++----- 2 files changed, 278 insertions(+), 19 deletions(-) diff --git a/src/bot.rs b/src/bot.rs index 5fdad7b..48e926a 100644 --- a/src/bot.rs +++ b/src/bot.rs @@ -1,5 +1,5 @@ use crate::{logging::log_error, State}; -use azalea::{pathfinder::BlockPosGoal, prelude::*, BlockPos}; +use azalea::{pathfinder::BlockPosGoal, prelude::*, BlockPos, SprintDirection, WalkDirection}; use azalea_protocol::packets::game::{ self, serverbound_interact_packet::InteractionHand, ServerboundGamePacket, }; @@ -26,6 +26,12 @@ pub enum Command { Look, Sneak, Unsneak, + Interact, + Attack, + Walk, + Sprint, + DropItem, + DropStack, ToggleBotStatusMessages, ToggleAlertMessages, Unknown, @@ -64,6 +70,12 @@ pub async fn process_command( "look" => command = Command::Look, "sneak" => command = Command::Sneak, "unsneak" => command = Command::Unsneak, + "interact" => command = Command::Interact, + "attack" => command = Command::Attack, + "walk" => command = Command::Walk, + "sprint" => command = Command::Sprint, + "drop_item" => command = Command::DropItem, + "drop_stack" => command = Command::DropStack, "toggle_alert_messages" => command = Command::ToggleAlertMessages, "toggle_bot_status_messages" => command = Command::ToggleBotStatusMessages, _ => (), @@ -359,6 +371,213 @@ pub async fn process_command( ); return "I am no longer sneaking!".to_string(); } + Command::Interact => { + if segments.len() < 1 { + return "Please give me IDs to interact with!".to_string(); + } + + let mut found = false; + let mob_locations = state.mob_locations.lock().unwrap().to_owned(); + for (mob, _) in mob_locations { + if mob.id.to_string() == segments[0] + || mob.uuid == segments[0] + || mob.entity_type == segments[0] + { + found = true; + log_error( + client + .write_packet(ServerboundGamePacket::Interact( + game::serverbound_interact_packet::ServerboundInteractPacket { + action: + game::serverbound_interact_packet::ActionType::Interact { + hand: InteractionHand::MainHand, + }, + entity_id: mob.id, + using_secondary_action: false, + }, + )) + .await, + ); + } + } + let player_locations = state.player_locations.lock().unwrap().to_owned(); + for (player, _) in player_locations { + if player.entity_id.to_string() == segments[0] + || player.uuid == segments[0] + || player.username == segments[0] + { + found = true; + log_error( + client + .write_packet(ServerboundGamePacket::Interact( + game::serverbound_interact_packet::ServerboundInteractPacket { + action: + game::serverbound_interact_packet::ActionType::Interact { + hand: InteractionHand::MainHand, + }, + entity_id: player.entity_id, + using_secondary_action: false, + }, + )) + .await, + ); + } + } + if found { + return "Successfully interacted with entity!".to_string(); + } else { + return "Unable to find entity!".to_string(); + } + } + Command::Attack => { + if segments.len() < 1 { + return "Please give me IDs to attack!".to_string(); + } + + let mut found = false; + let mob_locations = state.mob_locations.lock().unwrap().to_owned(); + for (mob, _) in mob_locations { + if mob.id.to_string() == segments[0] + || mob.uuid == segments[0] + || mob.entity_type == segments[0] + { + found = true; + log_error( + client + .write_packet(ServerboundGamePacket::Interact( + game::serverbound_interact_packet::ServerboundInteractPacket { + action: game::serverbound_interact_packet::ActionType::Attack, + entity_id: mob.id, + using_secondary_action: false, + }, + )) + .await, + ); + } + } + let player_locations = state.player_locations.lock().unwrap().to_owned(); + for (player, _) in player_locations { + if player.entity_id.to_string() == segments[0] + || player.uuid == segments[0] + || player.username == segments[0] + { + found = true; + log_error( + client + .write_packet(ServerboundGamePacket::Interact( + game::serverbound_interact_packet::ServerboundInteractPacket { + action: game::serverbound_interact_packet::ActionType::Attack, + entity_id: player.entity_id, + using_secondary_action: false, + }, + )) + .await, + ); + } + } + if found { + return "Successfully attacked entity!".to_string(); + } else { + return "Unable to find entity!".to_string(); + } + } + Command::Walk => { + if segments.len() < 2 { + return "Please give me a direction (and duration) to walk in!".to_string(); + } + + let direction = match segments[0].to_lowercase().as_str() { + "forward" => WalkDirection::Forward, + "forward_left" => WalkDirection::ForwardLeft, + "forward_right" => WalkDirection::ForwardRight, + "backward" => WalkDirection::Backward, + "backward_left" => WalkDirection::BackwardLeft, + "backward_right" => WalkDirection::BackwardRight, + "left" => WalkDirection::Left, + "right" => WalkDirection::Right, + _ => WalkDirection::None, + }; + let duration = match segments[1].parse() { + Ok(duration) => duration, + Err(error) => return format!("Unable to parse duration: {}", error), + }; + + log_error( + client + .send_command_packet(&format!( + "msg {} I am now walking {} for {} ms!", + executor, + segments[0].to_lowercase(), + duration, + )) + .await, + ); + client.walk(direction); + tokio::time::sleep(std::time::Duration::from_millis(duration)).await; + client.walk(WalkDirection::None); + return "I have finished walking!".to_string(); + } + Command::Sprint => { + if segments.len() < 2 { + return "Please give me a direction (and duration) to sprint in!".to_string(); + } + + let direction = match segments[0].to_lowercase().as_str() { + "forward" => SprintDirection::Forward, + "forward_left" => SprintDirection::ForwardLeft, + "forward_right" => SprintDirection::ForwardRight, + _ => return "Please give me a valid direction to sprint in!".to_string(), + }; + let duration = match segments[1].parse() { + Ok(duration) => duration, + Err(error) => return format!("Unable to parse duration: {}", error), + }; + + log_error( + client + .send_command_packet(&format!( + "msg {} I am now sprinting {} for {} ms!", + executor, + segments[0].to_lowercase(), + duration, + )) + .await, + ); + client.sprint(direction); + tokio::time::sleep(std::time::Duration::from_millis(duration)).await; + client.walk(WalkDirection::None); + return "I have finished sprinting!".to_string(); + } + Command::DropItem => { + log_error( + client + .write_packet(ServerboundGamePacket::PlayerAction( + game::serverbound_player_action_packet::ServerboundPlayerActionPacket { + action: game::serverbound_player_action_packet::Action::DropItem, + pos: BlockPos { x: 0, y: 0, z: 0 }, + direction: Default::default(), + sequence: 0, + }, + )) + .await, + ); + return "I have successfully dropped 1 item!".to_string(); + } + Command::DropStack => { + log_error( + client + .write_packet(ServerboundGamePacket::PlayerAction( + game::serverbound_player_action_packet::ServerboundPlayerActionPacket { + action: game::serverbound_player_action_packet::Action::DropAllItems, + pos: BlockPos { x: 0, y: 0, z: 0 }, + direction: Default::default(), + sequence: 0, + }, + )) + .await, + ); + return "I have successfully dropped 1 stack!".to_string(); + } Command::ToggleAlertMessages => { if state.alert_players.lock().unwrap().contains(executor) { let mut players = state.alert_players.lock().unwrap().to_vec(); diff --git a/src/main.rs b/src/main.rs index 91744c2..e0d42c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -111,6 +111,7 @@ async fn main() { alert_second_counter: Arc::new(Mutex::new(0)), followed_player: Arc::new(Mutex::new(None)), player_locations: Arc::new(Mutex::new(HashMap::new())), + mob_locations: Arc::new(Mutex::new(HashMap::new())), player_timestamps: Arc::new(Mutex::new(HashMap::new())), alert_players: Arc::new(Mutex::new(bot_configuration.clone().alert_players)), alert_queue: Arc::new(Mutex::new(HashMap::new())), @@ -130,11 +131,18 @@ async fn main() { #[derive(Eq, Hash, PartialEq, PartialOrd, Debug, Clone)] pub struct Player { - uuid: u128, + uuid: String, entity_id: u32, username: String, } +#[derive(Eq, Hash, PartialEq, PartialOrd, Debug, Clone)] +pub struct Entity { + id: u32, + uuid: String, + entity_type: String, +} + #[derive(Default, Debug, Clone)] pub struct PositionTimeData { position: Vec, @@ -165,6 +173,7 @@ pub struct State { alert_second_counter: Arc>, followed_player: Arc>>, player_locations: Arc>>, + mob_locations: Arc>>, player_timestamps: Arc>>, alert_players: Arc>>, alert_queue: Arc>>>, @@ -311,29 +320,37 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R } Event::Packet(packet) => match packet.as_ref() { ClientboundGamePacket::MoveEntityPos(packet) => { - let entity: (u128, u32, azalea::Vec3) = - match (client.world.read()).entity(packet.entity_id) { - Some(entity) => (entity.uuid.as_u128(), entity.id, entity.pos().to_owned()), - None => return Ok(()), - }; + let world = client.world.read(); + let raw_entity = match world.entity(packet.entity_id) { + Some(raw_entity) => raw_entity, + None => return Ok(()), + }; + let entity = Entity { + id: raw_entity.id, + uuid: raw_entity.uuid.as_hyphenated().to_string(), + entity_type: format!("{:?}", raw_entity.metadata), + }; + let entity_position = raw_entity.pos(); + + let mut is_player = false; let players = client.players.read().to_owned(); for (uuid, player) in players.iter().map(|item| item.to_owned()) { - if uuid.as_u128() == entity.0 { - let position = entity.2; + if uuid.as_hyphenated().to_string() == entity.uuid { + is_player = true; let mut player_locations = state.player_locations.lock().unwrap().to_owned(); player_locations.insert( Player { - uuid: uuid.as_u128(), - entity_id: entity.1, + uuid: uuid.as_hyphenated().to_string(), + entity_id: entity.id, username: player.profile.name.to_owned(), }, PositionTimeData { position: vec![ - position.x as i32, - position.y as i32, - position.z as i32, + entity_position.x as i32, + entity_position.y as i32, + entity_position.z as i32, ], time: SystemTime::now() .duration_since(UNIX_EPOCH) @@ -347,12 +364,12 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R - state.bot_configuration.alert_radius) ..(state.bot_configuration.alert_location[0] + state.bot_configuration.alert_radius)) - .contains(&(position.x as i32)) + .contains(&(entity_position.x as i32)) && ((state.bot_configuration.alert_location[1] - state.bot_configuration.alert_radius) ..(state.bot_configuration.alert_location[1] + state.bot_configuration.alert_radius)) - .contains(&(position.z as i32)) + .contains(&(entity_position.z as i32)) { if !state .whitelist @@ -363,13 +380,36 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R let mut alert_queue = state.alert_queue.lock().unwrap().to_owned(); alert_queue.insert( player.profile.name.to_owned(), - vec![position.x as i32, position.y as i32, position.z as i32], + vec![ + entity_position.x as i32, + entity_position.y as i32, + entity_position.z as i32, + ], ); *state.alert_queue.lock().unwrap() = alert_queue; } } } } + + if !is_player { + let mut mob_locations = state.mob_locations.lock().unwrap().to_owned(); + mob_locations.insert( + entity, + PositionTimeData { + position: vec![ + entity_position.x as i32, + entity_position.y as i32, + entity_position.z as i32, + ], + time: SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(), + }, + ); + *state.mob_locations.lock().unwrap() = mob_locations; + } } ClientboundGamePacket::SetHealth(packet) => { *state.bot_status.lock().unwrap() = BotStatus { @@ -391,9 +431,9 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R "msg {} {}", player, format!( - "Health: {}/20, Food: {}/20, Saturation: {}/20", + "Health: {:.1}/20, Food: {}/20, Saturation: {:.1}/20", packet.health, packet.food, packet.saturation - ) + ), )) .await, );