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<i32>,
@@ -165,6 +173,7 @@ pub struct State {
     alert_second_counter: Arc<Mutex<u8>>,
     followed_player: Arc<Mutex<Option<Player>>>,
     player_locations: Arc<Mutex<HashMap<Player, PositionTimeData>>>,
+    mob_locations: Arc<Mutex<HashMap<Entity, PositionTimeData>>>,
     player_timestamps: Arc<Mutex<HashMap<String, PlayerTimeData>>>,
     alert_players: Arc<Mutex<Vec<String>>>,
     alert_queue: Arc<Mutex<HashMap<String, Vec<i32>>>>,
@@ -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,
                     );