diff options
| author | mat <27899617+mat-1@users.noreply.github.com> | 2025-02-22 21:45:26 -0600 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-02-22 21:45:26 -0600 |
| commit | e21e1b97bf9337e9f4747cd1b545b1b3a03e2ce7 (patch) | |
| tree | add6f8bfce40d0c07845d8aa4c9945a0b918444c /azalea-client/src/interact.rs | |
| parent | f8130c3c92946d2293634ba4e252d6bc93026c3c (diff) | |
| download | azalea-drasl-e21e1b97bf9337e9f4747cd1b545b1b3a03e2ce7.tar.xz | |
Refactor azalea-client (#205)
* start organizing packet_handling more by moving packet handlers into their own functions
* finish writing all the handler functions for packets
* use macro for generating match statement for packet handler functions
* fix set_entity_data
* update config state to also use handler functions
* organize az-client file structure by moving things into plugins directory
* fix merge issues
Diffstat (limited to 'azalea-client/src/interact.rs')
| -rw-r--r-- | azalea-client/src/interact.rs | 369 |
1 files changed, 0 insertions, 369 deletions
diff --git a/azalea-client/src/interact.rs b/azalea-client/src/interact.rs deleted file mode 100644 index fdeff197..00000000 --- a/azalea-client/src/interact.rs +++ /dev/null @@ -1,369 +0,0 @@ -use std::ops::AddAssign; - -use azalea_block::BlockState; -use azalea_core::{ - block_hit_result::BlockHitResult, - direction::Direction, - game_type::GameMode, - position::{BlockPos, Vec3}, -}; -use azalea_entity::{ - Attributes, EyeHeight, LocalEntity, LookDirection, Position, clamp_look_direction, view_vector, -}; -use azalea_inventory::{ItemStack, ItemStackData, components}; -use azalea_physics::clip::{BlockShapeType, ClipContext, FluidPickType}; -use azalea_protocol::packets::game::{ - s_interact::InteractionHand, - s_swing::ServerboundSwing, - s_use_item_on::{BlockHit, ServerboundUseItemOn}, -}; -use azalea_world::{Instance, InstanceContainer, InstanceName}; -use bevy_app::{App, Plugin, Update}; -use bevy_ecs::{ - component::Component, - entity::Entity, - event::{Event, EventReader, EventWriter}, - query::{Changed, With}, - schedule::IntoSystemConfigs, - system::{Commands, Query, Res}, -}; -use derive_more::{Deref, DerefMut}; -use tracing::warn; - -use crate::{ - Client, - attack::handle_attack_event, - inventory::{Inventory, InventorySet}, - local_player::{LocalGameMode, PermissionLevel, PlayerAbilities}, - movement::MoveEventsSet, - packet_handling::game::{SendPacketEvent, handle_send_packet_event}, - respawn::perform_respawn, -}; - -/// A plugin that allows clients to interact with blocks in the world. -pub struct InteractPlugin; -impl Plugin for InteractPlugin { - fn build(&self, app: &mut App) { - app.add_event::<BlockInteractEvent>() - .add_event::<SwingArmEvent>() - .add_systems( - Update, - ( - ( - update_hit_result_component.after(clamp_look_direction), - handle_block_interact_event, - handle_swing_arm_event, - ) - .before(handle_send_packet_event) - .after(InventorySet) - .after(perform_respawn) - .after(handle_attack_event) - .chain(), - update_modifiers_for_held_item - .after(InventorySet) - .after(MoveEventsSet), - ), - ); - } -} - -impl Client { - /// Right click a block. The behavior of this depends on the target block, - /// and it'll either place the block you're holding in your hand or use the - /// block you clicked (like toggling a lever). - /// - /// Note that this may trigger anticheats as it doesn't take into account - /// whether you're actually looking at the block. - pub fn block_interact(&mut self, position: BlockPos) { - self.ecs.lock().send_event(BlockInteractEvent { - entity: self.entity, - position, - }); - } -} - -/// Right click a block. The behavior of this depends on the target block, -/// and it'll either place the block you're holding in your hand or use the -/// block you clicked (like toggling a lever). -#[derive(Event)] -pub struct BlockInteractEvent { - /// The local player entity that's opening the container. - pub entity: Entity, - /// The coordinates of the container. - pub position: BlockPos, -} - -/// A component that contains the number of changes this client has made to -/// blocks. -#[derive(Component, Copy, Clone, Debug, Default, Deref)] -pub struct CurrentSequenceNumber(u32); - -impl AddAssign<u32> for CurrentSequenceNumber { - fn add_assign(&mut self, rhs: u32) { - self.0 += rhs; - } -} - -/// A component that contains the block that the player is currently looking at. -#[derive(Component, Clone, Debug, Deref, DerefMut)] -pub struct HitResultComponent(BlockHitResult); - -pub fn handle_block_interact_event( - mut events: EventReader<BlockInteractEvent>, - mut query: Query<(Entity, &mut CurrentSequenceNumber, &HitResultComponent)>, - mut send_packet_events: EventWriter<SendPacketEvent>, -) { - for event in events.read() { - let Ok((entity, mut sequence_number, hit_result)) = query.get_mut(event.entity) else { - warn!("Sent BlockInteractEvent for entity that doesn't have the required components"); - continue; - }; - - // TODO: check to make sure we're within the world border - - *sequence_number += 1; - - // minecraft also does the interaction client-side (so it looks like clicking a - // button is instant) but we don't really need that - - // the block_hit data will depend on whether we're looking at the block and - // whether we can reach it - - let block_hit = if hit_result.block_pos == event.position { - // we're looking at the block :) - BlockHit { - block_pos: hit_result.block_pos, - direction: hit_result.direction, - location: hit_result.location, - inside: hit_result.inside, - world_border: hit_result.world_border, - } - } else { - // we're not looking at the block, so make up some numbers - BlockHit { - block_pos: event.position, - direction: Direction::Up, - location: event.position.center(), - inside: false, - world_border: false, - } - }; - - send_packet_events.send(SendPacketEvent::new( - entity, - ServerboundUseItemOn { - hand: InteractionHand::MainHand, - block_hit, - sequence: sequence_number.0, - }, - )); - } -} - -#[allow(clippy::type_complexity)] -pub fn update_hit_result_component( - mut commands: Commands, - mut query: Query<( - Entity, - Option<&mut HitResultComponent>, - &LocalGameMode, - &Position, - &EyeHeight, - &LookDirection, - &InstanceName, - )>, - instance_container: Res<InstanceContainer>, -) { - for (entity, hit_result_ref, game_mode, position, eye_height, look_direction, world_name) in - &mut query - { - let pick_range = if game_mode.current == GameMode::Creative { - 6. - } else { - 4.5 - }; - let eye_position = Vec3 { - x: position.x, - y: position.y + **eye_height as f64, - z: position.z, - }; - - let Some(instance_lock) = instance_container.get(world_name) else { - continue; - }; - let instance = instance_lock.read(); - - let hit_result = pick(look_direction, &eye_position, &instance.chunks, pick_range); - if let Some(mut hit_result_ref) = hit_result_ref { - **hit_result_ref = hit_result; - } else { - commands - .entity(entity) - .insert(HitResultComponent(hit_result)); - } - } -} - -/// Get the block that a player would be looking at if their eyes were at the -/// given direction and position. -/// -/// If you need to get the block the player is looking at right now, use -/// [`HitResultComponent`]. -pub fn pick( - look_direction: &LookDirection, - eye_position: &Vec3, - chunks: &azalea_world::ChunkStorage, - pick_range: f64, -) -> BlockHitResult { - let view_vector = view_vector(look_direction); - let end_position = eye_position + &(view_vector * pick_range); - azalea_physics::clip::clip( - chunks, - ClipContext { - from: *eye_position, - to: end_position, - block_shape_type: BlockShapeType::Outline, - fluid_pick_type: FluidPickType::None, - }, - ) -} - -/// Whether we can't interact with the block, based on your gamemode. If -/// this is false, then we can interact with the block. -/// -/// Passing the inventory, block position, and instance is necessary for the -/// adventure mode check. -pub fn check_is_interaction_restricted( - instance: &Instance, - block_pos: &BlockPos, - game_mode: &GameMode, - inventory: &Inventory, -) -> bool { - match game_mode { - GameMode::Adventure => { - // vanilla checks for abilities.mayBuild here but servers have no - // way of modifying that - - let held_item = inventory.held_item(); - match &held_item { - ItemStack::Present(item) => { - let block = instance.chunks.get_block_state(block_pos); - let Some(block) = block else { - // block isn't loaded so just say that it is restricted - return true; - }; - check_block_can_be_broken_by_item_in_adventure_mode(item, &block) - } - _ => true, - } - } - GameMode::Spectator => true, - _ => false, - } -} - -/// Check if the item has the `CanDestroy` tag for the block. -pub fn check_block_can_be_broken_by_item_in_adventure_mode( - item: &ItemStackData, - _block: &BlockState, -) -> bool { - // minecraft caches the last checked block but that's kind of an unnecessary - // optimization and makes the code too complicated - - if !item.components.has::<components::CanBreak>() { - // no CanDestroy tag - return false; - }; - - false - - // for block_predicate in can_destroy { - // // TODO - // // defined in BlockPredicateArgument.java - // } - - // true -} - -pub fn can_use_game_master_blocks( - abilities: &PlayerAbilities, - permission_level: &PermissionLevel, -) -> bool { - abilities.instant_break && **permission_level >= 2 -} - -/// Swing your arm. This is purely a visual effect and won't interact with -/// anything in the world. -#[derive(Event)] -pub struct SwingArmEvent { - pub entity: Entity, -} -pub fn handle_swing_arm_event( - mut events: EventReader<SwingArmEvent>, - mut send_packet_events: EventWriter<SendPacketEvent>, -) { - for event in events.read() { - send_packet_events.send(SendPacketEvent::new( - event.entity, - ServerboundSwing { - hand: InteractionHand::MainHand, - }, - )); - } -} - -#[allow(clippy::type_complexity)] -fn update_modifiers_for_held_item( - mut query: Query<(&mut Attributes, &Inventory), (With<LocalEntity>, Changed<Inventory>)>, -) { - for (mut attributes, inventory) in &mut query { - let held_item = inventory.held_item(); - - use azalea_registry::Item; - let added_attack_speed = match held_item.kind() { - Item::WoodenSword => -2.4, - Item::WoodenShovel => -3.0, - Item::WoodenPickaxe => -2.8, - Item::WoodenAxe => -3.2, - Item::WoodenHoe => -3.0, - - Item::StoneSword => -2.4, - Item::StoneShovel => -3.0, - Item::StonePickaxe => -2.8, - Item::StoneAxe => -3.2, - Item::StoneHoe => -2.0, - - Item::GoldenSword => -2.4, - Item::GoldenShovel => -3.0, - Item::GoldenPickaxe => -2.8, - Item::GoldenAxe => -3.0, - Item::GoldenHoe => -3.0, - - Item::IronSword => -2.4, - Item::IronShovel => -3.0, - Item::IronPickaxe => -2.8, - Item::IronAxe => -3.1, - Item::IronHoe => -1.0, - - Item::DiamondSword => -2.4, - Item::DiamondShovel => -3.0, - Item::DiamondPickaxe => -2.8, - Item::DiamondAxe => -3.0, - Item::DiamondHoe => 0.0, - - Item::NetheriteSword => -2.4, - Item::NetheriteShovel => -3.0, - Item::NetheritePickaxe => -2.8, - Item::NetheriteAxe => -3.0, - Item::NetheriteHoe => 0.0, - - Item::Trident => -2.9, - _ => 0., - }; - attributes - .attack_speed - .insert(azalea_entity::attributes::base_attack_speed_modifier( - added_attack_speed, - )); - } -} |
