1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00
azalea/azalea/examples/testbot.rs

200 lines
6.9 KiB
Rust

//! a bot for testing new azalea features
#![feature(type_alias_impl_trait)]
use azalea::ecs::query::With;
use azalea::entity::metadata::Player;
use azalea::entity::Position;
use azalea::pathfinder::BlockPosGoal;
use azalea::{prelude::*, swarm::prelude::*, BlockPos, GameProfileComponent, WalkDirection};
use azalea::{Account, Client, Event};
use azalea_protocol::packets::game::serverbound_client_command_packet::ServerboundClientCommandPacket;
use azalea_protocol::packets::game::ClientboundGamePacket;
use std::time::Duration;
#[derive(Default, Clone, Component)]
struct State {}
#[derive(Default, Clone, Resource)]
struct SwarmState {}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
{
use parking_lot::deadlock;
use std::thread;
use std::time::Duration;
// Create a background thread which checks for deadlocks every 10s
thread::spawn(move || loop {
thread::sleep(Duration::from_secs(10));
let deadlocks = deadlock::check_deadlock();
if deadlocks.is_empty() {
continue;
}
println!("{} deadlocks detected", deadlocks.len());
for (i, threads) in deadlocks.iter().enumerate() {
println!("Deadlock #{i}");
for t in threads {
println!("Thread Id {:#?}", t.thread_id());
println!("{:#?}", t.backtrace());
}
}
});
}
let mut accounts = Vec::new();
let mut states = Vec::new();
for i in 0..5 {
accounts.push(Account::offline(&format!("bot{i}")));
states.push(State::default());
}
loop {
let e = SwarmBuilder::new()
.add_accounts(accounts.clone())
.set_handler(handle)
.set_swarm_handler(swarm_handle)
.join_delay(Duration::from_millis(1000))
.start("localhost")
.await;
// let e = azalea::ClientBuilder::new()
// .set_handler(handle)
// .start(Account::offline("bot"), "localhost")
// .await;
eprintln!("{e:?}");
}
}
async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result<()> {
match event {
Event::Init => {
println!("bot init");
// bot.set_client_information(ClientInformation {
// view_distance: 2,
// ..Default::default()
// })
// .await?;
}
Event::Login => {
bot.chat("Hello world");
}
Event::Chat(m) => {
println!("client chat message: {}", m.content());
if m.content() == bot.profile.name {
bot.chat("Bye");
tokio::time::sleep(Duration::from_millis(50)).await;
bot.disconnect();
}
let Some(sender) = m.username() else {
return Ok(())
};
// let mut ecs = bot.ecs.lock();
// let entity = bot
// .ecs
// .lock()
// .query::<&Player>()
// .iter(&mut ecs)
// .find(|e| e.name() == Some(sender));
// let entity = bot.entity_by::<With<Player>>(|name: &Name| name == sender);
let entity = bot.entity_by::<With<Player>, (&GameProfileComponent,)>(
|profile: &&GameProfileComponent| {
println!("entity {profile:?}");
profile.name == sender
},
);
println!("sender entity: {entity:?}");
if let Some(entity) = entity {
match m.content().as_str() {
"whereami" => {
let pos = bot.entity_component::<Position>(entity);
bot.chat(&format!("You're at {pos:?}",));
}
"whereareyou" => {
let pos = bot.component::<Position>();
bot.chat(&format!("I'm at {pos:?}",));
}
"goto" => {
let entity_pos = bot.entity_component::<Position>(entity);
let target_pos: BlockPos = entity_pos.into();
println!("going to {target_pos:?}");
bot.goto(BlockPosGoal::from(target_pos));
}
"look" => {
let entity_pos = bot.entity_component::<Position>(entity);
let target_pos: BlockPos = entity_pos.into();
println!("target_pos: {target_pos:?}");
bot.look_at(target_pos.center());
}
"jump" => {
bot.set_jumping(true);
}
"walk" => {
bot.walk(WalkDirection::Forward);
}
"stop" => {
bot.set_jumping(false);
bot.walk(WalkDirection::None);
}
"lag" => {
std::thread::sleep(Duration::from_millis(1000));
}
_ => {}
}
}
}
Event::Death(_) => {
bot.write_packet(ServerboundClientCommandPacket {
action: azalea_protocol::packets::game::serverbound_client_command_packet::Action::PerformRespawn,
}.get());
}
Event::Packet(packet) => match *packet {
ClientboundGamePacket::Login(_) => {
println!("login packet");
}
_ => {}
},
_ => {}
}
Ok(())
}
async fn swarm_handle(
mut swarm: Swarm,
event: SwarmEvent,
_state: SwarmState,
) -> anyhow::Result<()> {
match &event {
SwarmEvent::Disconnect(account) => {
println!("bot got kicked! {}", account.username);
tokio::time::sleep(Duration::from_secs(5)).await;
swarm
.add_with_exponential_backoff(account, State::default())
.await?;
}
SwarmEvent::Chat(m) => {
println!("swarm chat message: {}", m.message().to_ansi());
if m.message().to_string() == "<py5> world" {
for (name, world) in &swarm.world_container.read().worlds {
println!("world name: {name}");
if let Some(w) = world.upgrade() {
for chunk_pos in w.read().chunks.chunks.values() {
println!("chunk: {chunk_pos:?}");
}
} else {
println!("nvm world is gone");
}
}
}
if m.message().to_string() == "<py5> hi" {
for bot in swarm {
bot.chat("hello");
}
}
}
_ => {}
}
Ok(())
}