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 crate::assets;
|
||||||
use specs::{Component, HashMapStorage, NullStorage};
|
use specs::{Component, HashMapStorage, NullStorage};
|
||||||
|
use std::ops::Not;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
|
||||||
pub struct Inventory {
|
pub struct Inventory {
|
||||||
pub slots: Vec<Option<Item>>,
|
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 {
|
impl Inventory {
|
||||||
pub fn slots(&self) -> &[Option<Item>] {
|
pub fn slots(&self) -> &[Option<Item>] {
|
||||||
&self.slots
|
&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
|
/// 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.
|
/// was not found.
|
||||||
pub fn insert(&mut self, cell: usize, item: Item) -> Result<Option<Item>, Item> {
|
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())
|
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
|
/// Get content of a slot
|
||||||
pub fn get(&self, cell: usize) -> Option<&Item> {
|
pub fn get(&self, cell: usize) -> Option<&Item> {
|
||||||
self.slots.get(cell).and_then(Option::as_ref)
|
self.slots.get(cell).and_then(Option::as_ref)
|
||||||
@ -89,3 +146,6 @@ pub struct InventoryUpdate;
|
|||||||
impl Component for InventoryUpdate {
|
impl Component for InventoryUpdate {
|
||||||
type Storage = NullStorage<Self>;
|
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,
|
true,
|
||||||
handle_remove_lights,
|
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) {
|
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!")));
|
server.notify_client(entity, ServerMsg::private(String::from("Invalid item!")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {
|
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) {
|
if let Ok((x, y, z)) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32) {
|
||||||
match server.state.read_component_cloned::<comp::Pos>(entity) {
|
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(
|
fn handle_remove_lights(
|
||||||
server: &mut Server,
|
server: &mut Server,
|
||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
|
Loading…
Reference in New Issue
Block a user