Major updates

This commit is contained in:
ErrorNoInternet 2023-01-12 17:33:48 +08:00
parent 5c3dcf79d1
commit eb81844ee5
Signed by untrusted user who does not match committer: ErrorNoInternet
GPG Key ID: 2486BFB7B1E6A4A3
2 changed files with 221 additions and 100 deletions

View File

@ -11,6 +11,9 @@ use strum_macros::EnumIter;
pub enum Command { pub enum Command {
Help, Help,
BotStatus, BotStatus,
Whitelist,
WhitelistAdd,
WhitelistRemove,
LastLocation, LastLocation,
LastOnline, LastOnline,
FollowPlayer, FollowPlayer,
@ -21,6 +24,8 @@ pub enum Command {
Slot, Slot,
UseItem, UseItem,
Look, Look,
Sneak,
Unsneak,
ToggleBotStatusMessages, ToggleBotStatusMessages,
ToggleAlertMessages, ToggleAlertMessages,
Unknown, Unknown,
@ -44,6 +49,9 @@ pub async fn process_command(
match segments[0].to_lowercase().as_str() { match segments[0].to_lowercase().as_str() {
"help" => command = Command::Help, "help" => command = Command::Help,
"bot_status" => command = Command::BotStatus, "bot_status" => command = Command::BotStatus,
"whitelist" => command = Command::Whitelist,
"whitelist_add" => command = Command::WhitelistAdd,
"whitelist_remove" => command = Command::WhitelistRemove,
"last_location" => command = Command::LastLocation, "last_location" => command = Command::LastLocation,
"last_online" => command = Command::LastOnline, "last_online" => command = Command::LastOnline,
"follow_player" => command = Command::FollowPlayer, "follow_player" => command = Command::FollowPlayer,
@ -54,6 +62,8 @@ pub async fn process_command(
"slot" => command = Command::Slot, "slot" => command = Command::Slot,
"use_item" => command = Command::UseItem, "use_item" => command = Command::UseItem,
"look" => command = Command::Look, "look" => command = Command::Look,
"sneak" => command = Command::Sneak,
"unsneak" => command = Command::Unsneak,
"toggle_alert_messages" => command = Command::ToggleAlertMessages, "toggle_alert_messages" => command = Command::ToggleAlertMessages,
"toggle_bot_status_messages" => command = Command::ToggleBotStatusMessages, "toggle_bot_status_messages" => command = Command::ToggleBotStatusMessages,
_ => (), _ => (),
@ -70,10 +80,60 @@ pub async fn process_command(
return "Commands: ".to_owned() + &commands.join(", "); return "Commands: ".to_owned() + &commands.join(", ");
} }
Command::BotStatus => { Command::BotStatus => {
let bot_status = state.bot_status.lock().unwrap().to_owned();
let metadata = client.metadata(); let metadata = client.metadata();
return format!( return format!(
"Health: {}/20, Score: {}, Air Supply: {}", "Health: {:.1}/20, Food: {}/20, Saturation: {:.1}/20, Score: {}, Air Supply: {}",
metadata.health, metadata.score, metadata.air_supply bot_status.health,
bot_status.food,
bot_status.saturation,
metadata.score,
metadata.air_supply
);
}
Command::Whitelist => {
let whitelist = state.whitelist.lock().unwrap().join(", ");
if whitelist.is_empty() {
return "There are no whitelisted players...".to_string();
} else {
return format!("Whitelisted players: {}", whitelist);
}
}
Command::WhitelistAdd => {
if segments.len() < 1 {
return "Please tell me the name of the player!".to_string();
}
let mut whitelist = state.whitelist.lock().unwrap().to_vec();
if whitelist.contains(&segments[0]) {
return format!("{} is already whitelisted!", segments[0]);
}
whitelist.push(segments[0].to_owned());
*state.whitelist.lock().unwrap() = whitelist;
return format!(
"{} has been successfully added to the whitelist!",
segments[0]
);
}
Command::WhitelistRemove => {
if segments.len() < 1 {
return "Please tell me the name of the player!".to_string();
}
let mut whitelist = state.whitelist.lock().unwrap().to_vec();
if !whitelist.contains(&segments[0]) {
return format!("{} is not whitelisted!", segments[0]);
}
whitelist.remove(
whitelist
.iter()
.position(|item| *item == segments[0])
.unwrap(),
);
*state.whitelist.lock().unwrap() = whitelist;
return format!(
"{} has been successfully removed from the whitelist!",
segments[0]
); );
} }
Command::LastLocation => { Command::LastLocation => {
@ -160,7 +220,7 @@ pub async fn process_command(
} }
Command::StopFollowPlayer => { Command::StopFollowPlayer => {
*state.followed_player.lock().unwrap() = None; *state.followed_player.lock().unwrap() = None;
let current_position = client.entity().pos().clone(); let current_position = client.entity().pos().to_owned();
client.goto(BlockPosGoal { client.goto(BlockPosGoal {
pos: BlockPos { pos: BlockPos {
x: current_position.x.round() as i32, x: current_position.x.round() as i32,
@ -203,7 +263,7 @@ pub async fn process_command(
) )
} }
Command::StopGoto => { Command::StopGoto => {
let current_position = client.entity().pos().clone(); let current_position = client.entity().pos().to_owned();
client.goto(BlockPosGoal { client.goto(BlockPosGoal {
pos: BlockPos { pos: BlockPos {
x: current_position.x.round() as i32, x: current_position.x.round() as i32,
@ -226,30 +286,32 @@ pub async fn process_command(
return "Please give me a slot to set!".to_string(); return "Please give me a slot to set!".to_string();
} }
client log_error(
.write_packet(ServerboundGamePacket::SetCarriedItem( client
game::serverbound_set_carried_item_packet::ServerboundSetCarriedItemPacket { .write_packet(ServerboundGamePacket::SetCarriedItem(
slot: match segments[0].parse() { game::serverbound_set_carried_item_packet::ServerboundSetCarriedItemPacket {
Ok(number) => number, slot: match segments[0].parse() {
Err(error) => return format!("Unable to parse slot: {}", error), Ok(number) => number,
Err(error) => return format!("Unable to parse slot: {}", error),
},
}, },
}, ))
)) .await
.await );
.unwrap(); "I have successfully switched slots!".to_string()
"Successfully sent a `SetCarriedItem` packet to the server".to_string()
} }
Command::UseItem => { Command::UseItem => {
client log_error(
.write_packet(ServerboundGamePacket::UseItem( client
game::serverbound_use_item_packet::ServerboundUseItemPacket { .write_packet(ServerboundGamePacket::UseItem(
hand: InteractionHand::MainHand, game::serverbound_use_item_packet::ServerboundUseItemPacket {
sequence: 0, hand: InteractionHand::MainHand,
}, sequence: 0,
)) },
.await ))
.unwrap(); .await,
"Successfully sent a `UseItem` packet to the server".to_string() );
"I have successfully used the item!".to_string()
} }
Command::Look => { Command::Look => {
if segments.len() < 2 { if segments.len() < 2 {
@ -266,6 +328,37 @@ pub async fn process_command(
client.set_rotation(rotation[0], rotation[1]); client.set_rotation(rotation[0], rotation[1]);
format!("I am now looking at {} {}!", rotation[0], rotation[1]) format!("I am now looking at {} {}!", rotation[0], rotation[1])
} }
Command::Sneak => {
let entity_id = client.entity_id.read().to_owned();
log_error(
client
.write_packet(ServerboundGamePacket::PlayerCommand(
game::serverbound_player_command_packet::ServerboundPlayerCommandPacket {
id: entity_id,
action: game::serverbound_player_command_packet::Action::PressShiftKey,
data: 0,
},
))
.await,
);
return "I am now sneaking!".to_string();
}
Command::Unsneak => {
let entity_id = client.entity_id.read().to_owned();
log_error(
client
.write_packet(ServerboundGamePacket::PlayerCommand(
game::serverbound_player_command_packet::ServerboundPlayerCommandPacket {
id: entity_id,
action:
game::serverbound_player_command_packet::Action::ReleaseShiftKey,
data: 0,
},
))
.await,
);
return "I am no longer sneaking!".to_string();
}
Command::ToggleAlertMessages => { Command::ToggleAlertMessages => {
if state.alert_players.lock().unwrap().contains(executor) { if state.alert_players.lock().unwrap().contains(executor) {
let mut players = state.alert_players.lock().unwrap().to_vec(); let mut players = state.alert_players.lock().unwrap().to_vec();

View File

@ -86,13 +86,13 @@ async fn main() {
.collect(); .collect();
if segments.len() == 1 { if segments.len() == 1 {
ServerAddress { ServerAddress {
host: segments[0].clone(), host: segments[0].to_owned(),
port: 25565, port: 25565,
} }
} else if segments.len() == 2 { } else if segments.len() == 2 {
ServerAddress { ServerAddress {
host: segments[0].clone(), host: segments[0].to_owned(),
port: segments[1].clone().parse().unwrap_or(25565), port: segments[1].to_owned().parse().unwrap_or(25565),
} }
} else { } else {
log_message( log_message(
@ -104,13 +104,16 @@ async fn main() {
}, },
state: State { state: State {
bot_configuration: bot_configuration.clone(), bot_configuration: bot_configuration.clone(),
whitelist: Arc::new(Mutex::new(bot_configuration.clone().whitelist)),
logged_in: Arc::new(Mutex::new(false)), logged_in: Arc::new(Mutex::new(false)),
bot_status: Arc::new(Mutex::new(BotStatus::default())),
tick_counter: Arc::new(Mutex::new(0)), tick_counter: Arc::new(Mutex::new(0)),
alert_second_counter: Arc::new(Mutex::new(0)), alert_second_counter: Arc::new(Mutex::new(0)),
followed_player: Arc::new(Mutex::new(None)), followed_player: Arc::new(Mutex::new(None)),
player_locations: Arc::new(Mutex::new(HashMap::new())), player_locations: Arc::new(Mutex::new(HashMap::new())),
player_timestamps: 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_players: Arc::new(Mutex::new(bot_configuration.clone().alert_players)),
alert_queue: Arc::new(Mutex::new(HashMap::new())),
bot_status_players: Arc::new(Mutex::new(Vec::new())), bot_status_players: Arc::new(Mutex::new(Vec::new())),
}, },
plugins: plugins![], plugins: plugins![],
@ -145,16 +148,26 @@ pub struct PlayerTimeData {
leave_time: u64, leave_time: u64,
} }
#[derive(Default, Debug, Clone)]
pub struct BotStatus {
health: f32,
food: u32,
saturation: f32,
}
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct State { pub struct State {
bot_configuration: BotConfiguration, bot_configuration: BotConfiguration,
whitelist: Arc<Mutex<Vec<String>>>,
logged_in: Arc<Mutex<bool>>, logged_in: Arc<Mutex<bool>>,
bot_status: Arc<Mutex<BotStatus>>,
tick_counter: Arc<Mutex<u8>>, tick_counter: Arc<Mutex<u8>>,
alert_second_counter: Arc<Mutex<u8>>, alert_second_counter: Arc<Mutex<u8>>,
followed_player: Arc<Mutex<Option<Player>>>, followed_player: Arc<Mutex<Option<Player>>>,
player_locations: Arc<Mutex<HashMap<Player, PositionTimeData>>>, player_locations: Arc<Mutex<HashMap<Player, PositionTimeData>>>,
player_timestamps: Arc<Mutex<HashMap<String, PlayerTimeData>>>, player_timestamps: Arc<Mutex<HashMap<String, PlayerTimeData>>>,
alert_players: Arc<Mutex<Vec<String>>>, alert_players: Arc<Mutex<Vec<String>>>,
alert_queue: Arc<Mutex<HashMap<String, Vec<i32>>>>,
bot_status_players: Arc<Mutex<Vec<String>>>, bot_status_players: Arc<Mutex<Vec<String>>>,
} }
@ -189,7 +202,7 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R
.await? .await?
} }
Event::AddPlayer(player) => { Event::AddPlayer(player) => {
let mut player_timestamps = state.player_timestamps.lock().unwrap().clone(); let mut player_timestamps = state.player_timestamps.lock().unwrap().to_owned();
let mut current_player = player_timestamps let mut current_player = player_timestamps
.get(&player.profile.name) .get(&player.profile.name)
.unwrap_or(&PlayerTimeData { .unwrap_or(&PlayerTimeData {
@ -206,7 +219,7 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R
*state.player_timestamps.lock().unwrap() = player_timestamps; *state.player_timestamps.lock().unwrap() = player_timestamps;
} }
Event::RemovePlayer(player) => { Event::RemovePlayer(player) => {
let mut player_timestamps = state.player_timestamps.lock().unwrap().clone(); let mut player_timestamps = state.player_timestamps.lock().unwrap().to_owned();
let mut current_player = player_timestamps let mut current_player = player_timestamps
.get(&player.profile.name) .get(&player.profile.name)
.unwrap_or(&PlayerTimeData { .unwrap_or(&PlayerTimeData {
@ -238,7 +251,7 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R
let followed_player = state.followed_player.lock().unwrap().to_owned(); let followed_player = state.followed_player.lock().unwrap().to_owned();
if followed_player.is_some() { if followed_player.is_some() {
let player_locations = state.player_locations.lock().unwrap().clone(); let player_locations = state.player_locations.lock().unwrap().to_owned();
match player_locations.get(&followed_player.unwrap()) { match player_locations.get(&followed_player.unwrap()) {
Some(position_time_data) => client.goto(BlockPosGoal { Some(position_time_data) => client.goto(BlockPosGoal {
pos: BlockPos { pos: BlockPos {
@ -255,82 +268,66 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R
if *state.alert_second_counter.lock().unwrap() >= 5 { if *state.alert_second_counter.lock().unwrap() >= 5 {
*state.alert_second_counter.lock().unwrap() = 0; *state.alert_second_counter.lock().unwrap() = 0;
let player_locations = state.player_locations.lock().unwrap().clone(); let alert_queue = state.alert_queue.lock().unwrap().to_owned();
for (player, position_time_data) in player_locations { for (intruder, position) in alert_queue {
if ((state.bot_configuration.alert_location[0] let alert_players = state.alert_players.lock().unwrap().to_vec();
- state.bot_configuration.alert_radius) for alert_player in alert_players {
..(state.bot_configuration.alert_location[0] log_error(
+ state.bot_configuration.alert_radius)) client
.contains(&position_time_data.position[0]) .send_command_packet(&format!(
|| ((state.bot_configuration.alert_location[1] "msg {} {}",
- state.bot_configuration.alert_radius) alert_player,
..(state.bot_configuration.alert_location[1] format!(
+ state.bot_configuration.alert_radius)) "{} is near our base at {} {} {}!",
.contains(&position_time_data.position[2]) intruder, position[0], position[1], position[2],
{ )
if !state.bot_configuration.whitelist.contains(&player.username) { ))
let alert_players = state.alert_players.lock().unwrap().clone(); .await,
for alert_player in alert_players { );
log_error( }
client let mut alert_command = state.bot_configuration.alert_command.to_vec();
.send_command_packet(&format!( for argument in alert_command.iter_mut() {
"msg {} {}", *argument = argument.replace("{player_name}", &intruder);
alert_player, *argument = argument.replace("{x}", &(position[0]).to_string());
format!( *argument = argument.replace("{y}", &(position[1]).to_string());
"{} is near our base at {} {} {}!", *argument = argument.replace("{z}", &(position[2]).to_string());
player.username, }
position_time_data.position[0], if alert_command.len() >= 1 {
position_time_data.position[1], log_message(Bot, &"Executing alert shell command...".to_string());
position_time_data.position[2], let command_name = alert_command[0].clone();
) alert_command.remove(0);
)) log_error(
.await, std::process::Command::new(command_name)
); .args(alert_command)
} .stdin(std::process::Stdio::null())
let mut alert_command = state.bot_configuration.alert_command.to_vec(); .stdout(std::process::Stdio::null())
for argument in alert_command.iter_mut() { .stderr(std::process::Stdio::null())
*argument = argument.replace("{player_name}", &player.username); .spawn(),
*argument = argument );
.replace("{x}", &position_time_data.position[0].to_string());
*argument = argument
.replace("{y}", &position_time_data.position[1].to_string());
*argument = argument
.replace("{z}", &position_time_data.position[2].to_string());
}
if alert_command.len() >= 1 {
log_message(Bot, &"Executing alert shell command...".to_string());
let command_name = alert_command[0].clone();
alert_command.remove(0);
log_error(
std::process::Command::new(command_name)
.args(alert_command)
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn(),
);
}
}
} }
} }
*state.alert_queue.lock().unwrap() = HashMap::new();
} }
} }
Event::Packet(packet) => match packet.as_ref() { Event::Packet(packet) => match packet.as_ref() {
ClientboundGamePacket::MoveEntityPos(packet) => { ClientboundGamePacket::MoveEntityPos(packet) => {
let world = client.world.read(); let entity: (u128, u32, azalea::Vec3) =
let entity = match world.entity(packet.entity_id) { match (client.world.read()).entity(packet.entity_id) {
Some(entity) => entity, Some(entity) => (entity.uuid.as_u128(), entity.id, entity.pos().to_owned()),
None => return Ok(()), None => return Ok(()),
}; };
for (uuid, player) in client.players.read().iter() { let players = client.players.read().to_owned();
if uuid.as_u128() == entity.uuid.as_u128() { for (uuid, player) in players.iter().map(|item| item.to_owned()) {
let position = entity.pos(); if uuid.as_u128() == entity.0 {
let mut player_locations = state.player_locations.lock().unwrap().clone(); let position = entity.2;
let mut player_locations =
state.player_locations.lock().unwrap().to_owned();
player_locations.insert( player_locations.insert(
Player { Player {
uuid: uuid.as_u128(), uuid: uuid.as_u128(),
entity_id: entity.id, entity_id: entity.1,
username: player.profile.name.clone(), username: player.profile.name.to_owned(),
}, },
PositionTimeData { PositionTimeData {
position: vec![ position: vec![
@ -345,10 +342,41 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R
}, },
); );
*state.player_locations.lock().unwrap() = player_locations; *state.player_locations.lock().unwrap() = player_locations;
if ((state.bot_configuration.alert_location[0]
- state.bot_configuration.alert_radius)
..(state.bot_configuration.alert_location[0]
+ state.bot_configuration.alert_radius))
.contains(&(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))
{
if !state
.whitelist
.lock()
.unwrap()
.contains(&player.profile.name)
{
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],
);
*state.alert_queue.lock().unwrap() = alert_queue;
}
}
} }
} }
} }
ClientboundGamePacket::SetHealth(packet) => { ClientboundGamePacket::SetHealth(packet) => {
*state.bot_status.lock().unwrap() = BotStatus {
health: packet.health,
food: packet.food,
saturation: packet.saturation,
};
let bot_status_players: Vec<String> = state let bot_status_players: Vec<String> = state
.bot_status_players .bot_status_players
.lock() .lock()
@ -404,7 +432,7 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R
return Ok(()); return Ok(());
} }
for bot_owner in state.bot_configuration.bot_owners.clone() { for bot_owner in state.bot_configuration.bot_owners.to_owned() {
if message if message
.message() .message()
.to_string() .to_string()
@ -435,7 +463,7 @@ async fn handle(mut client: Client, event: Event, mut state: State) -> anyhow::R
); );
} }
let mut player_timestamps = state.player_timestamps.lock().unwrap().clone(); let mut player_timestamps = state.player_timestamps.lock().unwrap().to_owned();
let mut current_player = player_timestamps let mut current_player = player_timestamps
.get(&message.username().unwrap_or("Someone".to_string())) .get(&message.username().unwrap_or("Someone".to_string()))
.unwrap_or(&PlayerTimeData { .unwrap_or(&PlayerTimeData {