diff options
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | azalea-client/src/plugins/interact.rs | 1 | ||||
| -rw-r--r-- | azalea-client/src/plugins/mining.rs | 160 | ||||
| -rw-r--r-- | azalea-client/src/plugins/packet/game/events.rs | 3 | ||||
| -rw-r--r-- | azalea/src/bot.rs | 5 | ||||
| -rw-r--r-- | azalea/src/pathfinder/moves/mod.rs | 1 |
6 files changed, 91 insertions, 80 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 6cddfee6..151621df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,3 +36,4 @@ write down most non-trivial breaking changes. - Update the `InstanceName` component correctly when we receive a respawn or second login packet. - Block shapes and some properties were using data from `1.20.3-pre4` due to using an old data generator (Pixlyzer), which has now been replaced with the data generator from [Pumpkin](https://github.com/Pumpkin-MC/Extractor). - No more chunk errors when the client joins another world with the same name but different height. +- Mining now cancels correctly and doesn't flag Grim. diff --git a/azalea-client/src/plugins/interact.rs b/azalea-client/src/plugins/interact.rs index 9ca216fb..81c69121 100644 --- a/azalea-client/src/plugins/interact.rs +++ b/azalea-client/src/plugins/interact.rs @@ -98,6 +98,7 @@ impl AddAssign<u32> for CurrentSequenceNumber { } /// A component that contains the block that the player is currently looking at. +#[doc(alias("looking at", "looking at block", "crosshair"))] #[derive(Component, Clone, Debug, Deref, DerefMut)] pub struct HitResultComponent(BlockHitResult); diff --git a/azalea-client/src/plugins/mining.rs b/azalea-client/src/plugins/mining.rs index f4caec41..f2fb3361 100644 --- a/azalea-client/src/plugins/mining.rs +++ b/azalea-client/src/plugins/mining.rs @@ -2,7 +2,7 @@ use azalea_block::{Block, BlockState, fluid_state::FluidState}; use azalea_core::{direction::Direction, game_type::GameMode, position::BlockPos, tick::GameTick}; use azalea_entity::{FluidOnEyes, Physics, mining::get_mine_progress}; use azalea_inventory::ItemStack; -use azalea_physics::PhysicsSet; +use azalea_physics::{PhysicsSet, collision::BlockWithShape}; use azalea_protocol::packets::game::s_player_action::{self, ServerboundPlayerAction}; use azalea_world::{InstanceContainer, InstanceName}; use bevy_app::{App, Plugin, Update}; @@ -10,7 +10,7 @@ use bevy_ecs::prelude::*; use derive_more::{Deref, DerefMut}; use crate::{ - Client, + Client, InstanceHolder, interact::{ CurrentSequenceNumber, HitResultComponent, SwingArmEvent, can_use_game_master_blocks, check_is_interaction_restricted, @@ -26,14 +26,18 @@ pub struct MiningPlugin; impl Plugin for MiningPlugin { fn build(&self, app: &mut App) { app.add_event::<StartMiningBlockEvent>() - .add_event::<StartMiningBlockWithDirectionEvent>() .add_event::<FinishMiningBlockEvent>() .add_event::<StopMiningBlockEvent>() .add_event::<MineBlockProgressEvent>() .add_event::<AttackBlockEvent>() .add_systems( GameTick, - (continue_mining_block, handle_auto_mine) + ( + update_mining_component, + continue_mining_block, + handle_auto_mine, + handle_mining_queued, + ) .chain() .before(PhysicsSet), ) @@ -41,7 +45,6 @@ impl Plugin for MiningPlugin { Update, ( handle_start_mining_block_event, - handle_start_mining_block_with_direction_event, handle_finish_mining_block_event, handle_stop_mining_block_event, ) @@ -65,7 +68,9 @@ pub struct MiningSet; impl Client { pub fn start_mining(&self, position: BlockPos) { - self.ecs.lock().send_event(StartMiningBlockEvent { + let mut ecs = self.ecs.lock(); + + ecs.send_event(StartMiningBlockEvent { entity: self.entity, position, }); @@ -155,8 +160,8 @@ pub struct StartMiningBlockEvent { pub position: BlockPos, } fn handle_start_mining_block_event( + mut commands: Commands, mut events: EventReader<StartMiningBlockEvent>, - mut start_mining_events: EventWriter<StartMiningBlockWithDirectionEvent>, mut query: Query<&HitResultComponent>, ) { for event in events.read() { @@ -168,29 +173,29 @@ fn handle_start_mining_block_event( // we're not looking at the block, arbitrary direction Direction::Down }; - start_mining_events.write(StartMiningBlockWithDirectionEvent { - entity: event.entity, + commands.entity(event.entity).insert(MiningQueued { position: event.position, direction, }); } } -#[derive(Event)] -pub struct StartMiningBlockWithDirectionEvent { - pub entity: Entity, +/// Present on entities when they're going to start mining a block next tick. +#[derive(Component)] +pub struct MiningQueued { pub position: BlockPos, pub direction: Direction, } #[allow(clippy::too_many_arguments, clippy::type_complexity)] -fn handle_start_mining_block_with_direction_event( - mut events: EventReader<StartMiningBlockWithDirectionEvent>, - mut finish_mining_events: EventWriter<FinishMiningBlockEvent>, +fn handle_mining_queued( mut commands: Commands, + mut finish_mining_events: EventWriter<FinishMiningBlockEvent>, mut attack_block_events: EventWriter<AttackBlockEvent>, mut mine_block_progress_events: EventWriter<MineBlockProgressEvent>, - mut query: Query<( - &InstanceName, + query: Query<( + Entity, + &MiningQueued, + &InstanceHolder, &LocalGameMode, &Inventory, &FluidOnEyes, @@ -203,29 +208,30 @@ fn handle_start_mining_block_with_direction_event( &mut MineItem, &mut MineBlockPos, )>, - instances: Res<InstanceContainer>, ) { - for event in events.read() { - let ( - instance_name, - game_mode, - inventory, - fluid_on_eyes, - physics, - mining, - mut sequence_number, - mut mine_delay, - mut mine_progress, - mut mine_ticks, - mut current_mining_item, - mut current_mining_pos, - ) = query.get_mut(event.entity).unwrap(); + for ( + entity, + mining_queued, + instance_holder, + game_mode, + inventory, + fluid_on_eyes, + physics, + mining, + mut sequence_number, + mut mine_delay, + mut mine_progress, + mut mine_ticks, + mut current_mining_item, + mut current_mining_pos, + ) in query + { + commands.entity(entity).remove::<MiningQueued>(); - let instance_lock = instances.get(instance_name).unwrap(); - let instance = instance_lock.read(); + let instance = instance_holder.instance.read(); if check_is_interaction_restricted( &instance, - &event.position, + &mining_queued.position, &game_mode.current, inventory, ) { @@ -237,13 +243,13 @@ fn handle_start_mining_block_with_direction_event( if game_mode.current == GameMode::Creative { *sequence_number += 1; finish_mining_events.write(FinishMiningBlockEvent { - entity: event.entity, - position: event.position, + entity, + position: mining_queued.position, }); **mine_delay = 5; } else if mining.is_none() || !is_same_mining_target( - event.position, + mining_queued.position, inventory, ¤t_mining_pos, ¤t_mining_item, @@ -252,40 +258,29 @@ fn handle_start_mining_block_with_direction_event( if mining.is_some() { // send a packet to stop mining since we just changed target commands.trigger(SendPacketEvent::new( - event.entity, + entity, ServerboundPlayerAction { action: s_player_action::Action::AbortDestroyBlock, pos: current_mining_pos .expect("IsMining is true so MineBlockPos must be present"), - direction: event.direction, + direction: mining_queued.direction, sequence: 0, }, )); } let target_block_state = instance - .get_block_state(&event.position) + .get_block_state(&mining_queued.position) .unwrap_or_default(); - *sequence_number += 1; - let target_registry_block = azalea_registry::Block::from(target_block_state); // we can't break blocks if they don't have a bounding box - - // TODO: So right now azalea doesn't differenciate between different types of - // bounding boxes. See ClipContext::block_shape for more info. Ideally this - // should just call ClipContext::block_shape and check if it's empty. - let block_is_solid = !target_block_state.is_air() - // this is a hack to make sure we can't break water or lava - && !matches!( - target_registry_block, - azalea_registry::Block::Water | azalea_registry::Block::Lava - ); + let block_is_solid = !target_block_state.outline_shape().is_empty(); if block_is_solid && **mine_progress == 0. { // interact with the block (like note block left click) here attack_block_events.write(AttackBlockEvent { - entity: event.entity, - position: event.position, + entity, + position: mining_queued.position, }); } @@ -304,34 +299,37 @@ fn handle_start_mining_block_with_direction_event( { // block was broken instantly finish_mining_events.write(FinishMiningBlockEvent { - entity: event.entity, - position: event.position, + entity, + position: mining_queued.position, }); } else { - commands.entity(event.entity).insert(Mining { - pos: event.position, - dir: event.direction, + commands.entity(entity).insert(Mining { + pos: mining_queued.position, + dir: mining_queued.direction, }); - **current_mining_pos = Some(event.position); + **current_mining_pos = Some(mining_queued.position); **current_mining_item = held_item; **mine_progress = 0.; **mine_ticks = 0.; mine_block_progress_events.write(MineBlockProgressEvent { - entity: event.entity, - position: event.position, + entity, + position: mining_queued.position, destroy_stage: mine_progress.destroy_stage(), }); } + *sequence_number += 1; commands.trigger(SendPacketEvent::new( - event.entity, + entity, ServerboundPlayerAction { action: s_player_action::Action::StartDestroyBlock, - pos: event.position, - direction: event.direction, + pos: mining_queued.position, + direction: mining_queued.direction, sequence: **sequence_number, }, )); + commands.trigger(SwingArmEvent { entity }); + commands.trigger(SwingArmEvent { entity }); } } } @@ -530,8 +528,6 @@ pub fn continue_mining_block( mut commands: Commands, mut mine_block_progress_events: EventWriter<MineBlockProgressEvent>, mut finish_mining_events: EventWriter<FinishMiningBlockEvent>, - mut start_mining_events: EventWriter<StartMiningBlockWithDirectionEvent>, - mut swing_arm_events: EventWriter<SwingArmEvent>, instances: Res<InstanceContainer>, ) { for ( @@ -572,17 +568,20 @@ pub fn continue_mining_block( sequence: **sequence_number, }, )); - swing_arm_events.write(SwingArmEvent { entity }); + commands.trigger(SwingArmEvent { entity }); } else if is_same_mining_target( mining.pos, inventory, current_mining_pos, current_mining_item, ) { + println!("continue mining block at {:?}", mining.pos); let instance_lock = instances.get(instance_name).unwrap(); let instance = instance_lock.read(); let target_block_state = instance.get_block_state(&mining.pos).unwrap_or_default(); + println!("target_block_state: {:?}", target_block_state); + if target_block_state.is_air() { commands.entity(entity).remove::<Mining>(); continue; @@ -604,6 +603,7 @@ pub fn continue_mining_block( if **mine_progress >= 1. { commands.entity(entity).remove::<Mining>(); *sequence_number += 1; + println!("finished mining block at {:?}", mining.pos); finish_mining_events.write(FinishMiningBlockEvent { entity, position: mining.pos, @@ -627,15 +627,27 @@ pub fn continue_mining_block( position: mining.pos, destroy_stage: mine_progress.destroy_stage(), }); - swing_arm_events.write(SwingArmEvent { entity }); + commands.trigger(SwingArmEvent { entity }); } else { - start_mining_events.write(StartMiningBlockWithDirectionEvent { - entity, + println!("switching mining target to {:?}", mining.pos); + commands.entity(entity).insert(MiningQueued { position: mining.pos, direction: mining.dir, }); } + } +} - swing_arm_events.write(SwingArmEvent { entity }); +fn update_mining_component( + mut commands: Commands, + mut query: Query<(Entity, &mut Mining, &HitResultComponent)>, +) { + for (entity, mut mining, hit_result_component) in &mut query.iter_mut() { + if hit_result_component.miss { + commands.entity(entity).remove::<Mining>(); + } else { + mining.pos = hit_result_component.block_pos; + mining.dir = hit_result_component.direction; + } } } diff --git a/azalea-client/src/plugins/packet/game/events.rs b/azalea-client/src/plugins/packet/game/events.rs index 68bfb4b3..707d2cd9 100644 --- a/azalea-client/src/plugins/packet/game/events.rs +++ b/azalea-client/src/plugins/packet/game/events.rs @@ -9,7 +9,7 @@ use azalea_protocol::packets::{ use azalea_world::Instance; use bevy_ecs::prelude::*; use parking_lot::RwLock; -use tracing::error; +use tracing::{error, trace}; use uuid::Uuid; use crate::{PlayerInfo, client::InGameState, connection::RawConnection}; @@ -60,6 +60,7 @@ pub fn handle_outgoing_packets_observer( mut query: Query<(&mut RawConnection, Option<&InGameState>)>, ) { let event = trigger.event(); + trace!("Sending game packet: {:?}", event.packet); if let Ok((mut raw_connection, in_game_state)) = query.get_mut(event.sent_by) { if in_game_state.is_none() { diff --git a/azalea/src/bot.rs b/azalea/src/bot.rs index bca0174b..63a3adcb 100644 --- a/azalea/src/bot.rs +++ b/azalea/src/bot.rs @@ -1,6 +1,5 @@ use std::f64::consts::PI; -use azalea_client::interact::SwingArmEvent; use azalea_client::mining::Mining; use azalea_client::tick_broadcast::{TickBroadcast, UpdateBroadcast}; use azalea_core::position::{BlockPos, Vec3}; @@ -172,10 +171,6 @@ impl BotClientExt for azalea_client::Client { async fn mine(&self, position: BlockPos) { self.start_mining(position); - // vanilla sends an extra swing arm packet when we start mining - self.ecs.lock().send_event(SwingArmEvent { - entity: self.entity, - }); let mut receiver = self.get_tick_broadcaster(); while receiver.recv().await.is_ok() { diff --git a/azalea/src/pathfinder/moves/mod.rs b/azalea/src/pathfinder/moves/mod.rs index 248f0a5c..24dc8ac1 100644 --- a/azalea/src/pathfinder/moves/mod.rs +++ b/azalea/src/pathfinder/moves/mod.rs @@ -166,6 +166,7 @@ impl ExecuteCtx<'_, '_, '_, '_, '_, '_, '_> { if self.should_mine(block) { if at_start_position { + self.look_at(block.center()); self.mine(block); } else { self.look_at(self.start.center()); |
