mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
move some container stuff from az-client to azalea
This commit is contained in:
parent
12c1558c17
commit
0018442597
7 changed files with 141 additions and 105 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -477,6 +477,7 @@ dependencies = [
|
|||
"azalea-block",
|
||||
"azalea-buf",
|
||||
"azalea-chat",
|
||||
"azalea-client",
|
||||
"azalea-core",
|
||||
"azalea-inventory",
|
||||
"azalea-nbt",
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
use azalea_chat::FormattedText;
|
||||
use azalea_core::BlockPos;
|
||||
use azalea_inventory::{ItemSlot, Menu};
|
||||
use azalea_protocol::packets::game::serverbound_container_close_packet::ServerboundContainerClosePacket;
|
||||
use azalea_registry::MenuKind;
|
||||
|
@ -12,10 +10,10 @@ use bevy_ecs::{
|
|||
event::EventReader,
|
||||
prelude::EventWriter,
|
||||
schedule::{IntoSystemConfig, IntoSystemConfigs},
|
||||
system::{Commands, Query},
|
||||
system::{Query},
|
||||
};
|
||||
|
||||
use crate::{client::TickBroadcast, local_player::handle_send_packet_event, Client, LocalPlayer};
|
||||
use crate::{local_player::handle_send_packet_event, Client, LocalPlayer};
|
||||
|
||||
pub struct InventoryPlugin;
|
||||
impl Plugin for InventoryPlugin {
|
||||
|
@ -34,58 +32,7 @@ impl Plugin for InventoryPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
pub struct WaitingForInventoryOpen;
|
||||
|
||||
impl Client {
|
||||
/// Open a container in the world, like a chest.
|
||||
///
|
||||
/// ```
|
||||
/// # async fn example(mut bot: azalea_client::Client) {
|
||||
/// let target_pos = bot
|
||||
/// .world()
|
||||
/// .read()
|
||||
/// .find_block(bot.position(), &azalea_registry::Block::Chest.into());
|
||||
/// let Some(target_pos) = target_pos else {
|
||||
/// bot.chat("no chest found");
|
||||
/// return;
|
||||
/// };
|
||||
/// let container = bot.open_container(target_pos).await;
|
||||
/// # }
|
||||
/// ```
|
||||
pub async fn open_container(&mut self, pos: BlockPos) -> Option<ContainerHandle> {
|
||||
self.ecs
|
||||
.lock()
|
||||
.entity_mut(self.entity)
|
||||
.insert(WaitingForInventoryOpen);
|
||||
self.block_interact(pos);
|
||||
|
||||
let mut receiver = {
|
||||
let ecs = self.ecs.lock();
|
||||
let tick_broadcast = ecs.resource::<TickBroadcast>();
|
||||
tick_broadcast.subscribe()
|
||||
};
|
||||
while receiver.recv().await.is_ok() {
|
||||
let ecs = self.ecs.lock();
|
||||
if ecs.get::<WaitingForInventoryOpen>(self.entity).is_none() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let ecs = self.ecs.lock();
|
||||
let inventory = ecs
|
||||
.get::<InventoryComponent>(self.entity)
|
||||
.expect("no inventory");
|
||||
if inventory.id == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(ContainerHandle {
|
||||
id: inventory.id,
|
||||
client: self.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the menu that is currently open. If no menu is open, this will
|
||||
/// have the player's inventory.
|
||||
pub fn menu(&self) -> Menu {
|
||||
|
@ -95,49 +42,6 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
/// A handle to the open container. The container will be closed once this is
|
||||
/// dropped.
|
||||
pub struct ContainerHandle {
|
||||
pub id: i8,
|
||||
client: Client,
|
||||
}
|
||||
impl Drop for ContainerHandle {
|
||||
fn drop(&mut self) {
|
||||
self.client.ecs.lock().send_event(CloseContainerEvent {
|
||||
entity: self.client.entity,
|
||||
id: self.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
impl Debug for ContainerHandle {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ContainerHandle")
|
||||
.field("id", &self.id)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
impl ContainerHandle {
|
||||
/// Returns the menu of the container. If the container is closed, this
|
||||
/// will return `None`.
|
||||
pub fn menu(&self) -> Option<Menu> {
|
||||
let ecs = self.client.ecs.lock();
|
||||
let inventory = ecs
|
||||
.get::<InventoryComponent>(self.client.entity)
|
||||
.expect("no inventory");
|
||||
if inventory.id == self.id {
|
||||
Some(inventory.container_menu.clone().unwrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the item slots in the container. If the container is closed,
|
||||
/// this will return `None`.
|
||||
pub fn contents(&self) -> Option<Vec<ItemSlot>> {
|
||||
self.menu().map(|menu| menu.contents())
|
||||
}
|
||||
}
|
||||
|
||||
/// A component present on all local players that have an inventory.
|
||||
#[derive(Component)]
|
||||
pub struct InventoryComponent {
|
||||
|
@ -207,15 +111,10 @@ pub struct MenuOpenedEvent {
|
|||
pub title: FormattedText,
|
||||
}
|
||||
fn handle_menu_opened_event(
|
||||
mut commands: Commands,
|
||||
mut events: EventReader<MenuOpenedEvent>,
|
||||
mut query: Query<&mut InventoryComponent>,
|
||||
) {
|
||||
for event in events.iter() {
|
||||
commands
|
||||
.entity(event.entity)
|
||||
.remove::<WaitingForInventoryOpen>();
|
||||
|
||||
let mut inventory = query.get_mut(event.entity).unwrap();
|
||||
inventory.id = event.window_id as i8;
|
||||
inventory.container_menu = Some(Menu::from_kind(event.menu_type));
|
||||
|
|
|
@ -31,3 +31,6 @@ uuid = "1.1.2"
|
|||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
[dev-dependencies]
|
||||
azalea-client = { path = "../azalea-client" }
|
||||
|
|
|
@ -198,7 +198,7 @@ impl Instance {
|
|||
///
|
||||
/// ```
|
||||
/// # fn example(client: &azalea_client::Client) {
|
||||
/// client.find_block(client.position(), &azalea_registry::Block::Chest.into());
|
||||
/// client.world().read().find_block(client.position(), &azalea_registry::Block::Chest.into());
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn find_block(
|
||||
|
|
127
azalea/src/container.rs
Normal file
127
azalea/src/container.rs
Normal file
|
@ -0,0 +1,127 @@
|
|||
use std::fmt::Formatter;
|
||||
|
||||
use azalea_client::{
|
||||
inventory_plugin::{CloseContainerEvent, InventoryComponent, MenuOpenedEvent},
|
||||
Client, TickBroadcast,
|
||||
};
|
||||
use azalea_core::BlockPos;
|
||||
use azalea_inventory::{ItemSlot, Menu};
|
||||
use bevy_app::{App, Plugin};
|
||||
use bevy_ecs::{component::Component, prelude::EventReader, system::Commands};
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub struct ContainerPlugin;
|
||||
impl Plugin for ContainerPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.add_system(handle_menu_opened_event);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ContainerClientExt {
|
||||
async fn open_container(&mut self, pos: BlockPos) -> Option<ContainerHandle>;
|
||||
}
|
||||
|
||||
impl ContainerClientExt for Client {
|
||||
/// Open a container in the world, like a chest.
|
||||
///
|
||||
/// ```
|
||||
/// # use azalea::prelude::*;
|
||||
/// # async fn example(mut bot: azalea::Client) {
|
||||
/// let target_pos = bot
|
||||
/// .world()
|
||||
/// .read()
|
||||
/// .find_block(bot.position(), &azalea::Block::Chest.into());
|
||||
/// let Some(target_pos) = target_pos else {
|
||||
/// bot.chat("no chest found");
|
||||
/// return;
|
||||
/// };
|
||||
/// let container = bot.open_container(target_pos).await;
|
||||
/// # }
|
||||
/// ```
|
||||
async fn open_container(&mut self, pos: BlockPos) -> Option<ContainerHandle> {
|
||||
self.ecs
|
||||
.lock()
|
||||
.entity_mut(self.entity)
|
||||
.insert(WaitingForInventoryOpen);
|
||||
self.block_interact(pos);
|
||||
|
||||
let mut receiver = {
|
||||
let ecs = self.ecs.lock();
|
||||
let tick_broadcast = ecs.resource::<TickBroadcast>();
|
||||
tick_broadcast.subscribe()
|
||||
};
|
||||
while receiver.recv().await.is_ok() {
|
||||
let ecs = self.ecs.lock();
|
||||
if ecs.get::<WaitingForInventoryOpen>(self.entity).is_none() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let ecs = self.ecs.lock();
|
||||
let inventory = ecs
|
||||
.get::<InventoryComponent>(self.entity)
|
||||
.expect("no inventory");
|
||||
if inventory.id == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(ContainerHandle {
|
||||
id: inventory.id,
|
||||
client: self.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A handle to the open container. The container will be closed once this is
|
||||
/// dropped.
|
||||
pub struct ContainerHandle {
|
||||
pub id: i8,
|
||||
client: Client,
|
||||
}
|
||||
impl Drop for ContainerHandle {
|
||||
fn drop(&mut self) {
|
||||
self.client.ecs.lock().send_event(CloseContainerEvent {
|
||||
entity: self.client.entity,
|
||||
id: self.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
impl Debug for ContainerHandle {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("ContainerHandle")
|
||||
.field("id", &self.id)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
impl ContainerHandle {
|
||||
/// Returns the menu of the container. If the container is closed, this
|
||||
/// will return `None`.
|
||||
pub fn menu(&self) -> Option<Menu> {
|
||||
let ecs = self.client.ecs.lock();
|
||||
let inventory = ecs
|
||||
.get::<InventoryComponent>(self.client.entity)
|
||||
.expect("no inventory");
|
||||
if inventory.id == self.id {
|
||||
Some(inventory.container_menu.clone().unwrap())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the item slots in the container. If the container is closed,
|
||||
/// this will return `None`.
|
||||
pub fn contents(&self) -> Option<Vec<ItemSlot>> {
|
||||
self.menu().map(|menu| menu.contents())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component, Debug)]
|
||||
pub struct WaitingForInventoryOpen;
|
||||
|
||||
fn handle_menu_opened_event(mut commands: Commands, mut events: EventReader<MenuOpenedEvent>) {
|
||||
for event in events.iter() {
|
||||
commands
|
||||
.entity(event.entity)
|
||||
.remove::<WaitingForInventoryOpen>();
|
||||
}
|
||||
}
|
|
@ -1,7 +1,10 @@
|
|||
#![doc = include_str!("../README.md")]
|
||||
#![feature(async_closure)]
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(async_fn_in_trait)]
|
||||
|
||||
mod bot;
|
||||
mod container;
|
||||
pub mod pathfinder;
|
||||
pub mod prelude;
|
||||
pub mod swarm;
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
//! The Azalea prelude. Things that are necessary for a bare-bones bot are
|
||||
//! re-exported here.
|
||||
|
||||
pub use crate::{bot::BotClientExt, pathfinder::PathfinderClientExt, ClientBuilder};
|
||||
pub use crate::{
|
||||
bot::BotClientExt, container::ContainerClientExt, pathfinder::PathfinderClientExt,
|
||||
ClientBuilder,
|
||||
};
|
||||
pub use azalea_client::{Account, Client, Event};
|
||||
// this is necessary to make the macros that reference bevy_ecs work
|
||||
pub use crate::ecs as bevy_ecs;
|
||||
|
|
Loading…
Add table
Reference in a new issue