mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 23:44:38 +00:00
more inventory stuff
This commit is contained in:
parent
8faae3b6be
commit
e43cbc09c2
6 changed files with 71 additions and 82 deletions
|
@ -1,7 +1,7 @@
|
|||
pub use crate::chat::ChatPacket;
|
||||
use crate::{
|
||||
events::{Event, EventPlugin, LocalPlayerEvents},
|
||||
inventory::{ActiveContainer, InventoryMenu},
|
||||
inventory::InventoryComponent,
|
||||
local_player::{
|
||||
death_event, update_in_loaded_chunk, GameProfileComponent, LocalPlayer, PhysicsState,
|
||||
},
|
||||
|
@ -214,8 +214,7 @@ impl Client {
|
|||
PhysicsState::default(),
|
||||
Local,
|
||||
LocalPlayerEvents(tx),
|
||||
InventoryMenu::default(),
|
||||
ActiveContainer::default(),
|
||||
InventoryComponent::default(),
|
||||
));
|
||||
|
||||
Ok((client, rx))
|
||||
|
|
|
@ -1,70 +1,48 @@
|
|||
use std::fmt;
|
||||
|
||||
use azalea_core::{Slot, SlotData};
|
||||
use azalea_core::Slot;
|
||||
use azalea_ecs::component::Component;
|
||||
use azalea_inventory::Menu;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
|
||||
/// A component that contains the player's inventory menu. This is guaranteed to
|
||||
/// be a `Menu::Player`.
|
||||
///
|
||||
/// We keep it as a [`Menu`] since `Menu` has some useful functions that bare
|
||||
/// [`azalea_inventory::Player`] doesn't have.
|
||||
#[derive(Component, Deref, DerefMut)]
|
||||
pub struct InventoryMenu(azalea_inventory::Menu);
|
||||
impl Default for InventoryMenu {
|
||||
fn default() -> Self {
|
||||
InventoryMenu(Menu::Player(azalea_inventory::Player::default()))
|
||||
}
|
||||
}
|
||||
impl InventoryMenu {
|
||||
pub fn as_player(self) -> &azalea_inventory::Player {
|
||||
if let Menu::Player(player) = &self.0 {
|
||||
player
|
||||
} else {
|
||||
unreachable!("InventoryMenu must always be a Menu::Player")
|
||||
}
|
||||
}
|
||||
}
|
||||
impl fmt::Debug for InventoryMenu {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_tuple("InventoryMenu")
|
||||
.field(&self.as_player())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
impl Clone for InventoryMenu {
|
||||
fn clone(&self) -> Self {
|
||||
InventoryMenu(Menu::Player(self.as_player().clone()))
|
||||
}
|
||||
}
|
||||
|
||||
/// A component that contains information about the container that's currently
|
||||
/// open.
|
||||
/// It will be present on all players that can have a container open.
|
||||
/// A component present on all local players that have an inventory.
|
||||
#[derive(Component)]
|
||||
pub struct ActiveContainer {
|
||||
pub struct InventoryComponent {
|
||||
/// A component that contains the player's inventory menu. This is
|
||||
/// guaranteed to be a `Menu::Player`.
|
||||
///
|
||||
/// We keep it as a [`Menu`] since `Menu` has some useful functions that
|
||||
/// bare [`azalea_inventory::Player`] doesn't have.
|
||||
pub inventory_menu: azalea_inventory::Menu,
|
||||
|
||||
/// The ID of the container that's currently open. Its value is not
|
||||
/// guaranteed to be anything specific, and may change every time you open a
|
||||
/// container (unless it's 0, in which case it means that no container is
|
||||
/// open).
|
||||
pub id: u8,
|
||||
pub menu: azalea_inventory::Menu,
|
||||
|
||||
pub id: i8,
|
||||
/// The current container menu that the player has open. If no container is
|
||||
/// open, this will be `None`.
|
||||
pub container_menu: Option<azalea_inventory::Menu>,
|
||||
/// The item that is currently held by the cursor. `Slot::Empty` if nothing
|
||||
/// is currently being held.
|
||||
pub carried: Slot,
|
||||
/// An identifier used by the server to track client inventory desyncs.
|
||||
pub state_id: u32,
|
||||
// minecraft also has these fields, but i don't need they're necessary?:
|
||||
// private final NonNullList<ItemStack> remoteSlots;
|
||||
// private final IntList remoteDataSlots;
|
||||
// private ItemStack remoteCarried;
|
||||
}
|
||||
impl Default for ActiveContainer {
|
||||
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)
|
||||
}
|
||||
}
|
||||
impl Default for InventoryComponent {
|
||||
fn default() -> Self {
|
||||
ActiveContainer {
|
||||
InventoryComponent {
|
||||
inventory_menu: Menu::Player(azalea_inventory::Player::default()),
|
||||
id: 0,
|
||||
menu: Menu::Player(azalea_inventory::Player::default()),
|
||||
container_menu: None,
|
||||
carried: Slot::Empty,
|
||||
state_id: 0,
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{collections::HashSet, io::Cursor, sync::Arc};
|
||||
|
||||
use azalea_core::{ChunkPos, ResourceLocation, Slot, Vec3};
|
||||
use azalea_core::{ChunkPos, ResourceLocation, Vec3};
|
||||
use azalea_ecs::{
|
||||
app::{App, Plugin},
|
||||
component::Component,
|
||||
|
@ -35,7 +35,7 @@ use parking_lot::Mutex;
|
|||
use tokio::sync::mpsc;
|
||||
|
||||
use crate::{
|
||||
inventory::{ActiveContainer, InventoryMenu},
|
||||
inventory::InventoryComponent,
|
||||
local_player::{GameProfileComponent, LocalPlayer},
|
||||
ChatPacket, ClientInformation, PlayerInfo,
|
||||
};
|
||||
|
@ -620,34 +620,26 @@ fn handle_packets(ecs: &mut Ecs) {
|
|||
ClientboundGamePacket::ContainerSetContent(p) => {
|
||||
debug!("Got container set content packet {:?}", p);
|
||||
|
||||
let mut system_state: SystemState<
|
||||
Query<(&mut InventoryMenu, Option<&mut ActiveContainer>)>,
|
||||
> = SystemState::new(ecs);
|
||||
let mut system_state: SystemState<Query<&mut InventoryComponent>> =
|
||||
SystemState::new(ecs);
|
||||
let mut query = system_state.get_mut(ecs);
|
||||
let (mut inventory_menu, open_container) =
|
||||
query.get_mut(player_entity).unwrap();
|
||||
let mut inventory = query.get_mut(player_entity).unwrap();
|
||||
|
||||
// container id 0 is always the player's inventory
|
||||
if p.container_id == 0 {
|
||||
// this is just so it has the same type as the `else` block
|
||||
for (i, slot) in p.items.iter().enumerate() {
|
||||
if let Some(slot_mut) = inventory_menu.slot_mut(i) {
|
||||
if let Some(slot_mut) = inventory.inventory_menu.slot_mut(i) {
|
||||
*slot_mut = slot.clone();
|
||||
}
|
||||
}
|
||||
} else if let Some(mut open_container) = open_container {
|
||||
if open_container.id == p.container_id {
|
||||
for (i, slot) in p.items.iter().enumerate() {
|
||||
if let Some(slot_mut) = open_container.menu.slot_mut(i) {
|
||||
*slot_mut = slot.clone();
|
||||
}
|
||||
} else if inventory.id == p.container_id {
|
||||
let mut menu = inventory.menu();
|
||||
for (i, slot) in p.items.iter().enumerate() {
|
||||
if let Some(slot_mut) = menu.slot_mut(i) {
|
||||
*slot_mut = slot.clone();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warn!(
|
||||
"ContainerSetPacket was received with id {} but no container was open",
|
||||
p.container_id
|
||||
);
|
||||
}
|
||||
}
|
||||
ClientboundGamePacket::ContainerSetData(p) => {
|
||||
|
@ -656,29 +648,34 @@ fn handle_packets(ecs: &mut Ecs) {
|
|||
ClientboundGamePacket::ContainerSetSlot(p) => {
|
||||
debug!("Got container set slot packet {:?}", p);
|
||||
|
||||
let mut system_state: SystemState<
|
||||
Query<(&mut InventoryMenu, &mut ActiveContainer)>,
|
||||
> = SystemState::new(ecs);
|
||||
let mut system_state: SystemState<Query<&mut InventoryComponent>> =
|
||||
SystemState::new(ecs);
|
||||
let mut query = system_state.get_mut(ecs);
|
||||
let (mut inventory_menu, mut active_container) =
|
||||
query.get_mut(player_entity).unwrap();
|
||||
let mut inventory = query.get_mut(player_entity).unwrap();
|
||||
|
||||
if p.container_id == -1 {
|
||||
// -1 means carried item
|
||||
active_container.carried = p.item_stack.clone();
|
||||
inventory.carried = p.item_stack.clone();
|
||||
} else if p.container_id == -2 {
|
||||
if let Some(mut slot) = inventory_menu.slot_mut(p.slot.into()) {
|
||||
if let Some(mut slot) = inventory.inventory_menu.slot_mut(p.slot.into()) {
|
||||
*slot = p.item_stack.clone();
|
||||
}
|
||||
} else {
|
||||
let is_creative_mode_and_inventory_closed = false;
|
||||
// technically minecraft has slightly different behavior here if you're in
|
||||
// creative mode and have your inventory open
|
||||
if p.container_id == 0
|
||||
&& inventory_menu.as_player().is_hotbar_slot(p.slot.into())
|
||||
&& azalea_inventory::Player::is_hotbar_slot(p.slot.into())
|
||||
{
|
||||
if let Slot::Present(item) = p.item_stack {
|
||||
// TODO container stuff
|
||||
// minecraft also sets a "pop time" here which is used for an animation
|
||||
// but that's not really necessary
|
||||
if let Some(slot) = inventory.inventory_menu.slot_mut(p.slot.into()) {
|
||||
*slot = p.item_stack.clone();
|
||||
}
|
||||
} else if p.container_id == inventory.id
|
||||
&& (p.container_id != 0 || !is_creative_mode_and_inventory_closed)
|
||||
{
|
||||
var2.containerMenu.setItem(var4, var1.getStateId(), var3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ pub fn generate(input: &DeclareMenus) -> TokenStream {
|
|||
quote! {
|
||||
impl Player {
|
||||
/// Returns whether the given protocol index is in the player's hotbar.
|
||||
pub fn is_hotbar_slot(&self, i: usize) -> bool {
|
||||
pub fn is_hotbar_slot(i: usize) -> bool {
|
||||
i >= #hotbar_slot_start && i <= #hotbar_slot_end
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,3 +140,18 @@ declare_menus! {
|
|||
result: 1,
|
||||
},
|
||||
}
|
||||
|
||||
impl Menu {
|
||||
/// Get the [`Player`] from this [`Menu`].
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Will panic if the menu isn't `Menu::Player`.
|
||||
pub fn as_player(&self) -> &Player {
|
||||
if let Menu::Player(player) = &self {
|
||||
player
|
||||
} else {
|
||||
unreachable!("Called `Menu::as_player` on a menu that wasn't `Player`.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use azalea_protocol_macros::ClientboundGamePacket;
|
|||
|
||||
#[derive(Clone, Debug, McBuf, ClientboundGamePacket)]
|
||||
pub struct ClientboundContainerSetContentPacket {
|
||||
pub container_id: u8,
|
||||
pub container_id: i8,
|
||||
#[var]
|
||||
pub state_id: u32,
|
||||
pub items: Vec<Slot>,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue