use std::io::{self, Error, ErrorKind};
use std::pin::Pin;
use azalea_core::direction::Direction;
use azalea_core::position::{BlockPos, Vec3};
use azalea_entity::LookDirection;
use azalea_protocol::common::movements::MoveFlags;
use azalea_protocol::packets::game::s_player_action::Action;
use azalea_protocol::packets::game::{ServerboundGamePacket, ServerboundMovePlayerPos, ServerboundMovePlayerRot, ServerboundPlayerAction, ServerboundSwing, ServerboundUseItem};
use crate::bot::Bot;
use crate::bot::terminal::BotCommand;
use crate::bot::transmitter::BotPackage;
pub type CommandProcessorFn<P> = for<'a> fn(&'a mut Bot<P>, BotCommand) -> Pin<Box<dyn std::future::Future<Output = io::Result<bool>> + Send + 'a>>;
pub fn default_command_processor<P: BotPackage>(bot: &mut Bot<P>, command: BotCommand) -> std::pin::Pin<Box<dyn std::future::Future<Output = io::Result<bool>> + Send + '_>> {
Box::pin(process_command(bot, command))
}
async fn process_command<P: BotPackage>(bot: &mut Bot<P>, command: BotCommand) -> io::Result<bool> {
let Some(conn) = &mut bot.connection else {
return Err(Error::new(ErrorKind::NotConnected, "Connection could not be obtained"));
};
match command {
BotCommand::Chat(message) => {
bot.chat(message).await?;
}
BotCommand::SetDirection { yaw, pitch } => {
conn
.write(ServerboundGamePacket::MovePlayerRot(ServerboundMovePlayerRot {
look_direction: LookDirection::new(yaw, pitch),
flags: MoveFlags {
on_ground: bot.physics.on_ground,
horizontal_collision: false,
},
}))
.await?;
}
BotCommand::SetPosition { x, y, z } => {
conn
.write(ServerboundGamePacket::MovePlayerPos(ServerboundMovePlayerPos {
pos: Vec3::new(x, y, z),
flags: MoveFlags {
on_ground: bot.physics.on_ground,
horizontal_collision: false,
},
}))
.await?;
}
BotCommand::SwingArm(hand) => {
conn.write(ServerboundGamePacket::Swing(ServerboundSwing { hand })).await?;
}
BotCommand::StartUseItem(hand) => {
let rotation = bot.components.rotation;
conn
.write(ServerboundGamePacket::UseItem(ServerboundUseItem {
hand: hand,
seq: 0,
y_rot: rotation.yaw,
x_rot: rotation.pitch,
}))
.await?;
}
BotCommand::ReleaseUseItem => {
conn
.write(ServerboundGamePacket::PlayerAction(ServerboundPlayerAction {
action: Action::ReleaseUseItem,
pos: BlockPos::new(0, 0, 0),
direction: Direction::Down,
seq: 0,
}))
.await?;
}
BotCommand::SendPacket(packet) => {
conn.write(packet).await?;
}
BotCommand::Disconnect => {
bot.disconnect().await?;
return Ok(false);
}
BotCommand::Reconnect {
server_host,
server_port,
interval,
} => {
bot.reconnect(&server_host, server_port, interval).await?;
}
}
Ok(true)
}