1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 14:26:04 +00:00

inventory/container tracking works

This commit is contained in:
mat 2023-02-06 22:30:55 -06:00
parent e43cbc09c2
commit 8db5b81f4c
9 changed files with 84 additions and 14 deletions

1
Cargo.lock generated
View file

@ -309,6 +309,7 @@ dependencies = [
"azalea-buf",
"azalea-chat",
"azalea-nbt",
"azalea-registry",
"bevy_ecs",
"uuid",
]

View file

@ -1,7 +1,7 @@
pub use crate::chat::ChatPacket;
use crate::{
events::{Event, EventPlugin, LocalPlayerEvents},
inventory::InventoryComponent,
inventory::{InventoryComponent, InventoryPlugin},
local_player::{
death_event, update_in_loaded_chunk, GameProfileComponent, LocalPlayer, PhysicsState,
},
@ -575,5 +575,6 @@ impl PluginGroup for DefaultPlugins {
.add(PhysicsPlugin)
.add(EventPlugin)
.add(TaskPoolPlugin::default())
.add(InventoryPlugin)
}
}

View file

@ -1,7 +1,21 @@
use azalea_core::Slot;
use azalea_ecs::component::Component;
use azalea_ecs::{
app::{App, Plugin},
component::Component,
entity::Entity,
event::EventReader,
system::Query,
};
use azalea_inventory::Menu;
pub struct InventoryPlugin;
impl Plugin for InventoryPlugin {
fn build(&self, app: &mut App) {
app.add_event::<ClientSideCloseContainerEvent>()
.add_system(handle_client_side_close_container_event);
}
}
/// A component present on all local players that have an inventory.
#[derive(Component)]
pub struct InventoryComponent {
@ -34,7 +48,19 @@ impl InventoryComponent {
/// Returns the currently active menu. If a container is open it'll return
/// [`Self::container_menu`], otherwise [`Self::inventory_menu`].
pub fn menu(&self) -> &azalea_inventory::Menu {
&self.container_menu.unwrap_or(self.inventory_menu)
if let Some(menu) = &self.container_menu {
menu
} else {
&self.inventory_menu
}
}
pub fn menu_mut(&mut self) -> &mut azalea_inventory::Menu {
if let Some(menu) = &mut self.container_menu {
menu
} else {
&mut self.inventory_menu
}
}
}
impl Default for InventoryComponent {
@ -48,3 +74,20 @@ impl Default for InventoryComponent {
}
}
}
/// Close a container without notifying the server.
///
/// Note that this also gets fired from [`CloseContainerEvent`].
pub struct ClientSideCloseContainerEvent {
pub entity: Entity,
}
fn handle_client_side_close_container_event(
mut events: EventReader<ClientSideCloseContainerEvent>,
mut query: Query<&mut InventoryComponent>,
) {
for event in events.iter() {
let mut inventory = query.get_mut(event.entity).unwrap();
inventory.container_menu = None;
inventory.id = 0;
}
}

View file

@ -35,7 +35,7 @@ use parking_lot::Mutex;
use tokio::sync::mpsc;
use crate::{
inventory::InventoryComponent,
inventory::{ClientSideCloseContainerEvent, InventoryComponent},
local_player::{GameProfileComponent, LocalPlayer},
ChatPacket, ClientInformation, PlayerInfo,
};
@ -634,7 +634,7 @@ fn handle_packets(ecs: &mut Ecs) {
}
}
} else if inventory.id == p.container_id {
let mut menu = inventory.menu();
let menu = inventory.menu_mut();
for (i, slot) in p.items.iter().enumerate() {
if let Some(slot_mut) = menu.slot_mut(i) {
*slot_mut = slot.clone();
@ -644,6 +644,17 @@ fn handle_packets(ecs: &mut Ecs) {
}
ClientboundGamePacket::ContainerSetData(p) => {
debug!("Got container set data packet {:?}", p);
// let mut system_state: SystemState<Query<&mut
// InventoryComponent>> =
// SystemState::new(ecs);
// let mut query = system_state.get_mut(ecs);
// let mut inventory =
// query.get_mut(player_entity).unwrap();
// TODO: handle ContainerSetData packet
// this is used for various things like the furnace progress
// bar
// see https://wiki.vg/Protocol#Set_Container_Property
}
ClientboundGamePacket::ContainerSetSlot(p) => {
debug!("Got container set slot packet {:?}", p);
@ -657,7 +668,7 @@ fn handle_packets(ecs: &mut Ecs) {
// -1 means carried item
inventory.carried = p.item_stack.clone();
} else if p.container_id == -2 {
if let Some(mut slot) = inventory.inventory_menu.slot_mut(p.slot.into()) {
if let Some(slot) = inventory.inventory_menu.slot_mut(p.slot.into()) {
*slot = p.item_stack.clone();
}
} else {
@ -675,11 +686,23 @@ fn handle_packets(ecs: &mut Ecs) {
} else if p.container_id == inventory.id
&& (p.container_id != 0 || !is_creative_mode_and_inventory_closed)
{
var2.containerMenu.setItem(var4, var1.getStateId(), var3);
// var2.containerMenu.setItem(var4, var1.getStateId(), var3);
if let Some(slot) = inventory.menu_mut().slot_mut(p.slot.into()) {
*slot = p.item_stack.clone();
inventory.state_id = p.state_id;
}
}
}
}
ClientboundGamePacket::ContainerClose(_) => {}
ClientboundGamePacket::ContainerClose(_p) => {
// there's p.container_id but minecraft doesn't actually check it
let mut system_state: SystemState<EventWriter<ClientSideCloseContainerEvent>> =
SystemState::new(ecs);
let mut client_side_close_container_events = system_state.get_mut(ecs);
client_side_close_container_events.send(ClientSideCloseContainerEvent {
entity: player_entity,
})
}
ClientboundGamePacket::SetHealth(p) => {
debug!("Got set health packet {:?}", p);

View file

@ -12,6 +12,7 @@ version = "0.5.0"
azalea-buf = {path = "../azalea-buf", version = "^0.5.0"}
azalea-chat = {path = "../azalea-chat", version = "^0.5.0"}
azalea-nbt = {path = "../azalea-nbt", version = "^0.5.0"}
azalea-registry = {path = "../azalea-registry", version = "^0.5.0"}
bevy_ecs = {version = "0.9.1", default-features = false, optional = true}
uuid = "^1.1.2"

View file

@ -13,8 +13,7 @@ pub enum Slot {
#[derive(Debug, Clone, McBuf)]
pub struct SlotData {
#[var]
pub id: u32,
pub id: azalea_registry::Item,
pub count: u8,
pub nbt: Tag,
}

View file

@ -23,6 +23,7 @@ pub fn generate(input: &DeclareMenus) -> TokenStream {
#player_fields
}
#[derive(Clone, Debug)]
pub enum Menu {
Player(Player),
#variants

View file

@ -3,7 +3,7 @@ use azalea_protocol_macros::ClientboundGamePacket;
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
pub struct ClientboundContainerSetDataPacket {
pub container_id: u8,
pub container_id: i8,
pub id: u16,
pub value: u16,
}

View file

@ -5,7 +5,7 @@
use azalea::ecs::query::With;
use azalea::entity::metadata::Player;
use azalea::entity::Position;
use azalea::inventory::InventoryMenu;
use azalea::inventory::InventoryComponent;
use azalea::pathfinder::BlockPosGoal;
use azalea::{prelude::*, BlockPos, GameProfileComponent, Swarm, SwarmEvent, WalkDirection};
use azalea::{Account, Client, Event};
@ -144,8 +144,9 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result<
std::thread::sleep(Duration::from_millis(1000));
}
"inventory" => {
let inventory = bot.component::<InventoryMenu>();
println!("inventory: {inventory:?}");
let mut ecs = bot.ecs.lock();
let inventory = bot.query::<&InventoryComponent>(&mut ecs);
println!("inventory: {:?}", inventory.menu());
}
_ => {}
}