init
This commit is contained in:
commit
c44f23ed2b
8 changed files with 4249 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
/target
|
||||||
4002
Cargo.lock
generated
Normal file
4002
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
20
Cargo.toml
Normal file
20
Cargo.toml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
[package]
|
||||||
|
name = "mc_bot"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.98"
|
||||||
|
azalea = { git = "https://github.com/azalea-rs/azalea", version = "0.12.0" }
|
||||||
|
azalea-viaversion = { git = "https://github.com/azalea-rs/azalea-viaversion", version = "0.1.0" }
|
||||||
|
once_cell = "1.21.3"
|
||||||
|
parking_lot = "0.12.3"
|
||||||
|
tokio = { version = "1.45.0", features = ["full", "io-std"] }
|
||||||
|
tracing = "0.1.41"
|
||||||
|
tracing-subscriber = "0.3.19"
|
||||||
|
win32console = "0.1.5"
|
||||||
|
|
||||||
|
[profile.dev]
|
||||||
|
opt-level = 1
|
||||||
|
[profile.dev.package."*"]
|
||||||
|
opt-level = 3
|
||||||
1
README.md
Normal file
1
README.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
# UwUMine Auto-Farm bot
|
||||||
95
src/main.rs
Normal file
95
src/main.rs
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
#![feature(never_type)]
|
||||||
|
|
||||||
|
pub mod utils;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate tracing;
|
||||||
|
|
||||||
|
use azalea::prelude::*;
|
||||||
|
use azalea_viaversion::ViaVersionPlugin;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use utils::commands;
|
||||||
|
use std::time::Instant;
|
||||||
|
use utils::tools::*;
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use win32console::console::WinConsole;
|
||||||
|
|
||||||
|
static OWNER_NAME: OnceCell<String> = OnceCell::new();
|
||||||
|
|
||||||
|
#[derive(Default, Clone, Component)]
|
||||||
|
pub struct State {
|
||||||
|
pub messages_received: Arc<Mutex<usize>>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
match WinConsole::set_title("UwUMine | Auto-Farm Bot") {
|
||||||
|
Ok(_) => println!("Заголовок терминала изменен на: {}", new_title),
|
||||||
|
Err(e) => eprintln!("Ошибка при изменении заголовка терминала: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
println!(":: Бот сделан AmokDev");
|
||||||
|
|
||||||
|
let bot_account = get_bot_account().await;
|
||||||
|
println!(":: Success logged as {}", bot_account.name_or_email);
|
||||||
|
|
||||||
|
let owner = get_owner_name().await;
|
||||||
|
if OWNER_NAME.set(owner.clone()).is_err() {
|
||||||
|
eprintln!(":: Ошибка: OWNER_NAME");
|
||||||
|
}
|
||||||
|
|
||||||
|
println!(":: Имя владельца установлено: {}", owner);
|
||||||
|
|
||||||
|
ClientBuilder::new()
|
||||||
|
.add_plugins(ViaVersionPlugin::start("1.18.2").await)
|
||||||
|
.set_handler(handle)
|
||||||
|
.start(bot_account.account, "mc.uwupad.me")
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle(bot: Client, event: Event, _state: State) -> anyhow::Result<()> {
|
||||||
|
match event {
|
||||||
|
Event::Chat(packet) => {
|
||||||
|
let message = packet.message().to_string();
|
||||||
|
println!("{}", message);
|
||||||
|
|
||||||
|
if message.contains("хочет к тебе!") {
|
||||||
|
bot.send_command_packet("tpaccept");
|
||||||
|
} else if message.contains("[UwU] Телепорт в") {
|
||||||
|
bot.send_command_packet("tpconfirm");
|
||||||
|
} else if message.contains("[UwU] Не хватает лапок!") {
|
||||||
|
bot.send_chat_packet(&format!("!{message}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut dm = None;
|
||||||
|
if message.starts_with('[') && message.contains("-> Я] ") {
|
||||||
|
dm = Some((
|
||||||
|
message.split(" ").next().unwrap()[1..].to_owned(),
|
||||||
|
message.split("-> Я] ").collect::<Vec<_>>()[1].to_owned(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some((sender, content)) = dm {
|
||||||
|
let (command, args) = if content.contains(' ') {
|
||||||
|
let mut all_args: Vec<_> = content.split(' ').map(|s| s.to_owned()).collect();
|
||||||
|
let command = all_args.remove(0);
|
||||||
|
(command, all_args)
|
||||||
|
} else {
|
||||||
|
(content, vec![])
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("Executing command {command:?} sent by {sender:?} with args {args:?}");
|
||||||
|
if commands::execute(bot.clone(), sender, command, args).await? {
|
||||||
|
Some(Instant::now());
|
||||||
|
} else {
|
||||||
|
warn!("pizdec");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
82
src/utils/commands.rs
Normal file
82
src/utils/commands.rs
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
use azalea::{
|
||||||
|
prelude::*,
|
||||||
|
GameProfileComponent,
|
||||||
|
entity::{metadata::Player, Position},
|
||||||
|
pathfinder::goals::BlockPosGoal,
|
||||||
|
ecs::query::With,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub async fn execute(
|
||||||
|
bot: Client,
|
||||||
|
sender: String,
|
||||||
|
mut command: String,
|
||||||
|
args: Vec<String>,
|
||||||
|
) -> anyhow::Result<bool> {
|
||||||
|
if command.starts_with('!') {
|
||||||
|
command.remove(0);
|
||||||
|
}
|
||||||
|
command = command.to_lowercase();
|
||||||
|
|
||||||
|
match command.as_str() {
|
||||||
|
"stop" => {
|
||||||
|
if true {
|
||||||
|
send_command(bot, &format!("msg {sender} Sorry, but you need to be specified as an admin to use this command!"));
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("Stopping... Bye!");
|
||||||
|
std::process::exit(0);
|
||||||
|
}
|
||||||
|
"walk" => {
|
||||||
|
let sender_entity = bot.entity_by::<With<Player>, (&GameProfileComponent,)>(
|
||||||
|
|(profile,): &(&GameProfileComponent,)| profile.name == sender,
|
||||||
|
);
|
||||||
|
if let Some(sender_entity) = sender_entity {
|
||||||
|
let position = bot.entity_component::<Position>(sender_entity);
|
||||||
|
let goal = BlockPosGoal(azalea::BlockPos {
|
||||||
|
x: position.x.floor() as i32,
|
||||||
|
y: position.y.floor() as i32,
|
||||||
|
z: position.z.floor() as i32,
|
||||||
|
});
|
||||||
|
// bot.goto_without_mining(goal).await;
|
||||||
|
bot.goto(goal).await;
|
||||||
|
send_command(
|
||||||
|
bot,
|
||||||
|
&format!("msg {sender} Walking to your block position..."),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
send_command(
|
||||||
|
bot,
|
||||||
|
&format!("msg {sender} I could not find you in my render distance!"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
"tp" => {
|
||||||
|
info!("Teleporting to: {sender}");
|
||||||
|
send_command(bot, &format!("tpa {sender}"));
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
"say" => {
|
||||||
|
if sender != "AmokDev" {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
let command_or_chat = args.join(" ");
|
||||||
|
if command_or_chat.starts_with("/") {
|
||||||
|
info!("Sending command: {command_or_chat}");
|
||||||
|
bot.send_command_packet(&format!("{}", &command_or_chat[1..]));
|
||||||
|
} else {
|
||||||
|
info!("Sending chat message: {command_or_chat}");
|
||||||
|
bot.send_chat_packet(&command_or_chat);
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => Ok(false), // Do nothing if unrecognized command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_command(bot: Client, command: &str) {
|
||||||
|
info!("Sending command: {command}");
|
||||||
|
bot.send_command_packet(command);
|
||||||
|
}
|
||||||
2
src/utils/mod.rs
Normal file
2
src/utils/mod.rs
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod tools;
|
||||||
|
pub mod commands;
|
||||||
46
src/utils/tools.rs
Normal file
46
src/utils/tools.rs
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
use std::io;
|
||||||
|
use std::io::Write;
|
||||||
|
use azalea::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct BotAccount {
|
||||||
|
pub name_or_email: String,
|
||||||
|
pub account: Account
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_nickname(data: &str) -> Option<&str> {
|
||||||
|
let start_index = data.find(']');
|
||||||
|
let end_index = data.find(':');
|
||||||
|
|
||||||
|
match (start_index, end_index) {
|
||||||
|
(Some(start), Some(end)) if start < end => {
|
||||||
|
Some(&data[start + 1..end].trim())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_bot_account() -> BotAccount {
|
||||||
|
print!("Введите ник или Microsoft почту: ");
|
||||||
|
io::stdout().flush().expect("Не удалось очистить буфер вывода");
|
||||||
|
|
||||||
|
let mut name_or_email = String::new();
|
||||||
|
io::stdin().read_line(&mut name_or_email).expect("Не удалось прочитать строку");
|
||||||
|
|
||||||
|
if name_or_email.contains('@') {
|
||||||
|
return BotAccount { name_or_email: name_or_email.clone(), account: Account::microsoft(name_or_email.as_str()).await.unwrap() }
|
||||||
|
} else {
|
||||||
|
return BotAccount { name_or_email: name_or_email.clone(), account: Account::offline(name_or_email.as_str()) }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get_owner_name() -> String {
|
||||||
|
print!("Введите СВОЙ ник в Minecraft (не ник бота): ");
|
||||||
|
io::stdout().flush().expect("Не удалось очистить буфер вывода");
|
||||||
|
|
||||||
|
let mut owner_name = String::new();
|
||||||
|
io::stdin().read_line(&mut owner_name).expect("Не удалось прочитать строку");
|
||||||
|
return owner_name;
|
||||||
|
}
|
||||||
Reference in a new issue