mirror of
https://github.com/italicsjenga/valence.git
synced 2025-01-10 06:41:30 +11:00
Better consume
for inventories (#147)
- rework `consume_one` into `consume` - update `consume_one_held_item` to `consume_held_item` to match `consume` - remove an unnecessary clone Originally, I was planning on removing this function altogether. After thinking about it for a bit though, I think it provides enough of a convenience for end users to warrant keeping it. This also implements the fix that was originally in #124
This commit is contained in:
parent
f4714cf255
commit
a885b949da
|
@ -199,20 +199,20 @@ impl Config for Game {
|
||||||
if let Some(held_block_kind) = stack.item.to_block_kind() {
|
if let Some(held_block_kind) = stack.item.to_block_kind() {
|
||||||
let block_to_place = BlockState::from_kind(held_block_kind);
|
let block_to_place = BlockState::from_kind(held_block_kind);
|
||||||
|
|
||||||
if world
|
if client.game_mode() == GameMode::Creative
|
||||||
.chunks
|
|| client.consume_held_item(1).is_ok()
|
||||||
.block_state(location)
|
|
||||||
.map(|s| s.is_replaceable())
|
|
||||||
.unwrap_or(false)
|
|
||||||
{
|
{
|
||||||
world.chunks.set_block_state(location, block_to_place);
|
if world
|
||||||
} else {
|
.chunks
|
||||||
let place_at = location.get_in_direction(face);
|
.block_state(location)
|
||||||
world.chunks.set_block_state(place_at, block_to_place);
|
.map(|s| s.is_replaceable())
|
||||||
}
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
if client.game_mode() != GameMode::Creative {
|
world.chunks.set_block_state(location, block_to_place);
|
||||||
client.consume_one_held_item();
|
} else {
|
||||||
|
let place_at = location.get_in_direction(face);
|
||||||
|
world.chunks.set_block_state(place_at, block_to_place);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,8 @@ use crate::entity::{
|
||||||
};
|
};
|
||||||
use crate::ident::Ident;
|
use crate::ident::Ident;
|
||||||
use crate::inventory::{
|
use crate::inventory::{
|
||||||
Inventories, Inventory, InventoryDirtyable, InventoryId, PlayerInventory, WindowInventory,
|
Inventories, Inventory, InventoryDirtyable, InventoryError, InventoryId, PlayerInventory,
|
||||||
|
WindowInventory,
|
||||||
};
|
};
|
||||||
use crate::item::ItemStack;
|
use crate::item::ItemStack;
|
||||||
use crate::player_list::{PlayerListId, PlayerLists};
|
use crate::player_list::{PlayerListId, PlayerLists};
|
||||||
|
@ -794,9 +795,10 @@ impl<C: Config> Client<C> {
|
||||||
self.inventory.slot(self.selected_hotbar_slot)
|
self.inventory.slot(self.selected_hotbar_slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consume a single item from the stack that the client is holding.
|
/// Consume items from the stack in the client's inventory that the client
|
||||||
pub fn consume_one_held_item(&mut self) {
|
/// is holding.
|
||||||
self.inventory.consume_one(self.selected_hotbar_slot);
|
pub fn consume_held_item(&mut self, amount: impl Into<u8>) -> Result<(), InventoryError> {
|
||||||
|
self.inventory.consume(self.selected_hotbar_slot, amount)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Makes the client open a window displaying the given inventory.
|
/// Makes the client open a window displaying the given inventory.
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
use std::ops::Range;
|
use std::ops::Range;
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::item::ItemStack;
|
use crate::item::ItemStack;
|
||||||
use crate::protocol::{SlotId, VarInt};
|
use crate::protocol::{SlotId, VarInt};
|
||||||
use crate::slab_versioned::{Key, VersionedSlab};
|
use crate::slab_versioned::{Key, VersionedSlab};
|
||||||
|
@ -23,17 +25,33 @@ pub trait Inventory {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume_one(&mut self, slot_id: SlotId) {
|
/// Decreases the count for stack in the slot by amount. If there is not
|
||||||
let mut slot = self.slot(slot_id).cloned();
|
/// enough items in the stack to perform the operation, then it will fail.
|
||||||
if let Some(stack) = slot.as_mut() {
|
///
|
||||||
stack.set_count(stack.count() - 1);
|
/// Returns `Ok` if the stack had enough items, and the operation was
|
||||||
let slot = if stack.count() == 0 {
|
/// carried out. Otherwise, it returns `Err` if `amount > stack.count()`,
|
||||||
|
/// and no changes were made to the inventory.
|
||||||
|
#[allow(clippy::unnecessary_unwrap)]
|
||||||
|
fn consume(&mut self, slot_id: SlotId, amount: impl Into<u8>) -> Result<(), InventoryError> {
|
||||||
|
let amount: u8 = amount.into();
|
||||||
|
let slot = self.slot(slot_id).cloned();
|
||||||
|
if slot.is_some() {
|
||||||
|
// Intentionally not using `if let` so stack can be moved out of the slot as mut
|
||||||
|
// to avoid another clone later.
|
||||||
|
let mut stack = slot.unwrap();
|
||||||
|
if amount > stack.count() {
|
||||||
|
return Err(InventoryError);
|
||||||
|
}
|
||||||
|
let slot = if amount == stack.count() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
stack.set_count(stack.count() - amount);
|
||||||
Some(stack)
|
Some(stack)
|
||||||
};
|
};
|
||||||
self.set_slot(slot_id, slot.cloned());
|
|
||||||
|
self.set_slot(slot_id, slot);
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,6 +269,10 @@ impl Inventories {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[error("InventoryError")]
|
||||||
|
pub struct InventoryError;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -264,4 +286,18 @@ mod test {
|
||||||
assert_eq!(inv.slot(9), slot.as_ref());
|
assert_eq!(inv.slot(9), slot.as_ref());
|
||||||
assert_eq!(prev, None);
|
assert_eq!(prev, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_consume() {
|
||||||
|
let mut inv = PlayerInventory::new();
|
||||||
|
let slot_id = 9;
|
||||||
|
let slot = Some(ItemStack::new(ItemKind::Bone, 12, None));
|
||||||
|
inv.set_slot(slot_id, slot);
|
||||||
|
assert!(matches!(inv.consume(slot_id, 2), Ok(_)));
|
||||||
|
assert_eq!(inv.slot(slot_id).unwrap().count(), 10);
|
||||||
|
assert!(matches!(inv.consume(slot_id, 20), Err(_)));
|
||||||
|
assert_eq!(inv.slot(slot_id).unwrap().count(), 10);
|
||||||
|
assert!(matches!(inv.consume(slot_id, 10), Ok(_)));
|
||||||
|
assert_eq!(inv.slot(slot_id), None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue