mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'qwertycrackers' into 'master'
Add a `debug_items` chat command that gives all debug items. See merge request veloren/veloren!641
This commit is contained in:
commit
5a73554aa1
@ -5,12 +5,20 @@ pub use item::{Debug, Item, ItemKind, Tool};
|
||||
|
||||
use crate::assets;
|
||||
use specs::{Component, HashMapStorage, NullStorage};
|
||||
use std::ops::Not;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||
pub struct Inventory {
|
||||
pub slots: Vec<Option<Item>>,
|
||||
}
|
||||
|
||||
/// Errors which the methods on `Inventory` produce
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
/// The inventory is full and items could not be added. The extra items have been returned.
|
||||
Full(Vec<Item>),
|
||||
}
|
||||
|
||||
impl Inventory {
|
||||
pub fn slots(&self) -> &[Option<Item>] {
|
||||
&self.slots
|
||||
@ -32,6 +40,45 @@ impl Inventory {
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a series of items to inventory, returning any which do not fit as an error.
|
||||
pub fn push_all<I: Iterator<Item = Item>>(&mut self, mut items: I) -> Result<(), Error> {
|
||||
// Vec doesn't allocate for zero elements so this should be cheap
|
||||
let mut leftovers = Vec::new();
|
||||
let mut slots = self.slots.iter_mut();
|
||||
for item in &mut items {
|
||||
if let Some(slot) = slots.find(|slot| slot.is_none()) {
|
||||
slot.replace(item);
|
||||
} else {
|
||||
leftovers.push(item);
|
||||
}
|
||||
}
|
||||
if leftovers.len() > 0 {
|
||||
Err(Error::Full(leftovers))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a series of items to an inventory without giving duplicates. (n * m complexity)
|
||||
///
|
||||
/// Error if inventory cannot contain the items (is full), returning the un-added items.
|
||||
/// This is a lazy inefficient implementation, as it iterates over the inventory more times
|
||||
/// than necessary (n^2) and with the proper structure wouldn't need to iterate at all, but because
|
||||
/// this should be fairly cold code, clarity has been favored over efficiency.
|
||||
pub fn push_all_unique<I: Iterator<Item = Item>>(&mut self, mut items: I) -> Result<(), Error> {
|
||||
let mut leftovers = Vec::new();
|
||||
for item in &mut items {
|
||||
if self.contains(&item).not() {
|
||||
self.push(item).map(|overflow| leftovers.push(overflow));
|
||||
} // else drop item if it was already in
|
||||
}
|
||||
if leftovers.len() > 0 {
|
||||
Err(Error::Full(leftovers))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Replaces an item in a specific slot of the inventory. Returns the old item or the same item again if that slot
|
||||
/// was not found.
|
||||
pub fn insert(&mut self, cell: usize, item: Item) -> Result<Option<Item>, Item> {
|
||||
@ -49,6 +96,16 @@ impl Inventory {
|
||||
self.slots.iter().all(|slot| slot.is_some())
|
||||
}
|
||||
|
||||
/// O(n) count the number of items in this inventory.
|
||||
pub fn count(&self) -> usize {
|
||||
self.slots.iter().filter_map(|slot| slot.as_ref()).count()
|
||||
}
|
||||
|
||||
/// O(n) check if an item is in this inventory.
|
||||
pub fn contains(&self, item: &Item) -> bool {
|
||||
self.slots.iter().any(|slot| slot.as_ref() == Some(item))
|
||||
}
|
||||
|
||||
/// Get content of a slot
|
||||
pub fn get(&self, cell: usize) -> Option<&Item> {
|
||||
self.slots.get(cell).and_then(Option::as_ref)
|
||||
@ -89,3 +146,6 @@ pub struct InventoryUpdate;
|
||||
impl Component for InventoryUpdate {
|
||||
type Storage = NullStorage<Self>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
69
common/src/comp/inventory/test.rs
Normal file
69
common/src/comp/inventory/test.rs
Normal file
@ -0,0 +1,69 @@
|
||||
use super::*;
|
||||
use lazy_static::lazy_static;
|
||||
lazy_static! {
|
||||
static ref TEST_ITEMS: Vec<Item> = vec![
|
||||
assets::load_expect_cloned("common.items.debug.boost"),
|
||||
assets::load_expect_cloned("common.items.debug.possess")
|
||||
];
|
||||
}
|
||||
/// The `Default` inventory should contain two items
|
||||
#[test]
|
||||
fn create_default_count() {
|
||||
assert_eq!(Inventory::default().count(), 2)
|
||||
}
|
||||
|
||||
/// Attempting to push into a full inventory should return the same item.
|
||||
#[test]
|
||||
fn push_full() {
|
||||
let mut inv = Inventory {
|
||||
slots: TEST_ITEMS.iter().map(|a| Some(a.clone())).collect(),
|
||||
};
|
||||
assert_eq!(
|
||||
inv.push(TEST_ITEMS[0].clone()).unwrap(),
|
||||
TEST_ITEMS[0].clone()
|
||||
)
|
||||
}
|
||||
|
||||
/// Attempting to push a series into a full inventory should return them all.
|
||||
#[test]
|
||||
fn push_all_full() {
|
||||
let mut inv = Inventory {
|
||||
slots: TEST_ITEMS.iter().map(|a| Some(a.clone())).collect(),
|
||||
};
|
||||
let Error::Full(leftovers) = inv
|
||||
.push_all(TEST_ITEMS.iter().map(|a| a.clone()))
|
||||
.expect_err("Pushing into a full inventory somehow worked!");
|
||||
assert_eq!(leftovers, TEST_ITEMS.clone())
|
||||
}
|
||||
|
||||
/// Attempting to push uniquely into an inventory containing all the items should work fine.
|
||||
#[test]
|
||||
fn push_unique_all_full() {
|
||||
let mut inv = Inventory {
|
||||
slots: TEST_ITEMS.iter().map(|a| Some(a.clone())).collect(),
|
||||
};
|
||||
inv.push_all_unique(TEST_ITEMS.iter().map(|a| a.clone()))
|
||||
.expect("Pushing unique items into an inventory that already contains them didn't work!");
|
||||
}
|
||||
|
||||
/// Attempting to push uniquely into an inventory containing all the items should work fine.
|
||||
#[test]
|
||||
fn push_all_empty() {
|
||||
let mut inv = Inventory {
|
||||
slots: vec![None, None],
|
||||
};
|
||||
inv.push_all(TEST_ITEMS.iter().map(|a| a.clone()))
|
||||
.expect("Pushing items into an empty inventory didn't work!");
|
||||
}
|
||||
|
||||
/// Attempting to push uniquely into an inventory containing all the items should work fine.
|
||||
#[test]
|
||||
fn push_all_unique_empty() {
|
||||
let mut inv = Inventory {
|
||||
slots: vec![None, None],
|
||||
};
|
||||
inv.push_all_unique(TEST_ITEMS.iter().map(|a| a.clone()))
|
||||
.expect(
|
||||
"Pushing unique items into an empty inventory that didn't contain them didn't work!",
|
||||
);
|
||||
}
|
@ -238,6 +238,14 @@ lazy_static! {
|
||||
true,
|
||||
handle_remove_lights,
|
||||
),
|
||||
ChatCommand::new(
|
||||
"debug",
|
||||
"",
|
||||
"/debug : Place all debug items into your pack.",
|
||||
true,
|
||||
handle_debug,
|
||||
),
|
||||
|
||||
];
|
||||
}
|
||||
fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &ChatCommand) {
|
||||
@ -257,6 +265,7 @@ fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &C
|
||||
server.notify_client(entity, ServerMsg::private(String::from("Invalid item!")));
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
||||
if let Ok((x, y, z)) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32) {
|
||||
match server.state.read_component_cloned::<comp::Pos>(entity) {
|
||||
@ -988,6 +997,31 @@ fn handle_exp(server: &mut Server, entity: EcsEntity, args: String, action: &Cha
|
||||
}
|
||||
}
|
||||
|
||||
use common::comp::Item;
|
||||
fn handle_debug(server: &mut Server, entity: EcsEntity, _args: String, _action: &ChatCommand) {
|
||||
if let Ok(items) = assets::load_glob::<Item>("common.items.debug.*") {
|
||||
server
|
||||
.state()
|
||||
.ecs()
|
||||
.write_storage::<comp::Inventory>()
|
||||
.get_mut(entity)
|
||||
// TODO: Consider writing a `load_glob_cloned` in `assets` and using that here
|
||||
.map(|inv| inv.push_all_unique(items.iter().map(|item| item.as_ref().clone())));
|
||||
let _ = server
|
||||
.state
|
||||
.ecs()
|
||||
.write_storage::<comp::InventoryUpdate>()
|
||||
.insert(entity, comp::InventoryUpdate);
|
||||
} else {
|
||||
server.notify_client(
|
||||
entity,
|
||||
ServerMsg::private(String::from(
|
||||
"Debug items not found? Something is very broken.",
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_remove_lights(
|
||||
server: &mut Server,
|
||||
entity: EcsEntity,
|
||||
|
Loading…
Reference in New Issue
Block a user