aboutsummaryrefslogtreecommitdiff
path: root/azalea-inventory/src/slot.rs
diff options
context:
space:
mode:
authormat <27899617+mat-1@users.noreply.github.com>2023-05-03 20:57:27 -0500
committerGitHub <noreply@github.com>2023-05-03 20:57:27 -0500
commit634cb8d72c6608512aedba19e5cd669104bc35ea (patch)
treef8e76ce9eb43403d29cc0cbcf9a4f51522419dc2 /azalea-inventory/src/slot.rs
parent1fb4418f2c9cbd004c64c2f23d2d0352ee12c0e5 (diff)
downloadazalea-drasl-634cb8d72c6608512aedba19e5cd669104bc35ea.tar.xz
Inventory (#48)
* start adding azalea-inventory * design more of how inventories are defined * start working on az-inv-macros * inventory macro works * start adding inventory codegen * update some deps * add inventory codegen * manually write inventory menus * put the inventories in Client * start on containersetcontent * inventory menu should hopefully work * checks in containersetcontent * format a comment * move some variant matches * inventory.rs * inventory stuff * more inventory stuff * inventory/container tracking works * start adding interact function * sequence number * start adding HitResultComponent * implement traverse_blocks * start adding clip * add clip function * update_hit_result_component * start trying to fix * fix * make some stuff simpler * clippy * lever * chest * container handle * fix ambiguity * fix some doc tests * move some container stuff from az-client to azalea * clicking container * start implementing simulate_click * keep working on simulate click * implement more of simulate_click this is really boring * inventory fixes * start implementing shift clicking * fix panic in azalea-chat i hope * shift clicking implemented * more inventory stuff * fix items not showing in containers sometimes * fix test * fix all warnings * remove a println --------- Co-authored-by: mat <git@matdoes.dev>
Diffstat (limited to 'azalea-inventory/src/slot.rs')
-rw-r--r--azalea-inventory/src/slot.rs146
1 files changed, 146 insertions, 0 deletions
diff --git a/azalea-inventory/src/slot.rs b/azalea-inventory/src/slot.rs
new file mode 100644
index 00000000..cef555d7
--- /dev/null
+++ b/azalea-inventory/src/slot.rs
@@ -0,0 +1,146 @@
+use azalea_buf::{BufReadError, McBuf, McBufReadable, McBufWritable};
+use azalea_nbt::Nbt;
+use std::io::{Cursor, Write};
+
+/// Either an item in an inventory or nothing.
+#[derive(Debug, Clone, Default, PartialEq)]
+pub enum ItemSlot {
+ #[default]
+ Empty,
+ Present(ItemSlotData),
+}
+
+impl ItemSlot {
+ /// Check if the slot is ItemSlot::Empty, if the count is <= 0, or if the
+ /// item is air.
+ ///
+ /// This is the opposite of [`ItemSlot::is_present`].
+ pub fn is_empty(&self) -> bool {
+ match self {
+ ItemSlot::Empty => true,
+ ItemSlot::Present(item) => item.is_empty(),
+ }
+ }
+ /// Check if the slot is not ItemSlot::Empty, if the count is > 0, and if
+ /// the item is not air.
+ ///
+ /// This is the opposite of [`ItemSlot::is_empty`].
+ pub fn is_present(&self) -> bool {
+ !self.is_empty()
+ }
+
+ /// Return the amount of the item in the slot, or 0 if the slot is empty.
+ ///
+ /// Note that it's possible for the count to be zero or negative when the
+ /// slot is present.
+ pub fn count(&self) -> i8 {
+ match self {
+ ItemSlot::Empty => 0,
+ ItemSlot::Present(i) => i.count,
+ }
+ }
+
+ /// Remove `count` items from this slot, returning the removed items.
+ pub fn split(&mut self, count: u8) -> ItemSlot {
+ match self {
+ ItemSlot::Empty => ItemSlot::Empty,
+ ItemSlot::Present(i) => {
+ let returning = i.split(count);
+ if i.is_empty() {
+ *self = ItemSlot::Empty;
+ }
+ ItemSlot::Present(returning)
+ }
+ }
+ }
+
+ /// Get the `kind` of the item in this slot, or
+ /// [`azalea_registry::Item::Air`]
+ pub fn kind(&self) -> azalea_registry::Item {
+ match self {
+ ItemSlot::Empty => azalea_registry::Item::Air,
+ ItemSlot::Present(i) => i.kind,
+ }
+ }
+
+ /// Update whether this slot is empty, based on the count.
+ pub fn update_empty(&mut self) {
+ if let ItemSlot::Present(i) = self {
+ if i.is_empty() {
+ *self = ItemSlot::Empty;
+ }
+ }
+ }
+}
+
+/// An item in an inventory, with a count and NBT. Usually you want [`ItemSlot`]
+/// or [`azalea_registry::Item`] instead.
+#[derive(Debug, Clone, McBuf, PartialEq)]
+pub struct ItemSlotData {
+ pub kind: azalea_registry::Item,
+ /// The amount of the item in this slot.
+ ///
+ /// The count can be zero or negative, but this is rare.
+ pub count: i8,
+ pub nbt: Nbt,
+}
+
+impl ItemSlotData {
+ /// Remove `count` items from this slot, returning the removed items.
+ pub fn split(&mut self, count: u8) -> ItemSlotData {
+ let returning_count = i8::min(count as i8, self.count);
+ let mut returning = self.clone();
+ returning.count = returning_count;
+ self.count -= returning_count;
+ returning
+ }
+
+ /// Check if the count of the item is <= 0 or if the item is air.
+ pub fn is_empty(&self) -> bool {
+ self.count <= 0 || self.kind == azalea_registry::Item::Air
+ }
+
+ /// Whether this item is the same as another item, ignoring the count.
+ ///
+ /// ```
+ /// # use azalea_inventory::ItemSlotData;
+ /// # use azalea_registry::Item;
+ /// let mut a = ItemSlotData {
+ /// kind: Item::Stone,
+ /// count: 1,
+ /// nbt: Default::default(),
+ /// };
+ /// let mut b = ItemSlotData {
+ /// kind: Item::Stone,
+ /// count: 2,
+ /// nbt: Default::default(),
+ /// };
+ /// assert!(a.is_same_item_and_nbt(&b));
+ ///
+ /// b.kind = Item::Dirt;
+ /// assert!(!a.is_same_item_and_nbt(&b));
+ /// ```
+ pub fn is_same_item_and_nbt(&self, other: &ItemSlotData) -> bool {
+ self.kind == other.kind && self.nbt == other.nbt
+ }
+}
+
+impl McBufReadable for ItemSlot {
+ fn read_from(buf: &mut Cursor<&[u8]>) -> Result<Self, BufReadError> {
+ let slot = Option::<ItemSlotData>::read_from(buf)?;
+ Ok(slot.map_or(ItemSlot::Empty, ItemSlot::Present))
+ }
+}
+
+impl McBufWritable for ItemSlot {
+ fn write_into(&self, buf: &mut impl Write) -> Result<(), std::io::Error> {
+ match self {
+ ItemSlot::Empty => false.write_into(buf)?,
+ ItemSlot::Present(i) => {
+ true.write_into(buf)?;
+ i.write_into(buf)?;
+ }
+ };
+ Ok(())
+ }
+}