mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Avoid duplicate searches in the inventory for required items when
interacting with sprites and rustfmt decides to format a bunch of stuff... * Add PartialEq impls between ItemDefinitionId<'_> and ItemDefinitionIdOwned. * Remove unused Serialize and Deserialize derives from ItemDefinitionId<'_> * Add Inventory::get_slot_of_item_by_def_id which acts like Inventory::get_slot_of_item but accepts a ItemDefinitionIdOwned reference instead of an Item reference. * Add some TODOs for some potential optimizations * Rustfmt decided now was the time to format some random stuff I didn't touch. Maybe I fixed something it was getting stuck on???? But some files I didn't make any changes (although might have inadvertantly saved them when viewing in editor (with fmt on save)). * InvSlotId passed to SpriteInteract character state instead of refinding the item in the inventory (if it moved we simply give up on the state as if the requirements weren't met). (overall in this change 3 searches for the item in the inventory are reduced to a single one)
This commit is contained in:
parent
93eab4791d
commit
0d8aa16d89
@ -462,7 +462,10 @@ impl ItemBase {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
// TODO: could this theorectically hold a ref to the actual components and
|
||||
// lazily get their IDs for hash/partialeq/debug/to_owned/etc? (i.e. eliminating
|
||||
// `Vec`s)
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ItemDefinitionId<'a> {
|
||||
Simple(&'a str),
|
||||
Modular {
|
||||
@ -1291,6 +1294,38 @@ pub fn try_all_item_defs() -> Result<Vec<String>, Error> {
|
||||
Ok(defs.ids().map(|id| id.to_string()).collect())
|
||||
}
|
||||
|
||||
impl PartialEq<ItemDefinitionId<'_>> for ItemDefinitionIdOwned {
|
||||
fn eq(&self, other: &ItemDefinitionId<'_>) -> bool {
|
||||
use ItemDefinitionId as DefId;
|
||||
match self {
|
||||
Self::Simple(simple) => {
|
||||
matches!(other, DefId::Simple(other_simple) if simple == other_simple)
|
||||
},
|
||||
Self::Modular {
|
||||
pseudo_base,
|
||||
components,
|
||||
} => matches!(
|
||||
other,
|
||||
DefId::Modular { pseudo_base: other_base, components: other_comps }
|
||||
if pseudo_base == other_base && components == other_comps
|
||||
),
|
||||
Self::Compound {
|
||||
simple_base,
|
||||
components,
|
||||
} => matches!(
|
||||
other,
|
||||
DefId::Compound { simple_base: other_base, components: other_comps }
|
||||
if simple_base == other_base && components == other_comps
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<ItemDefinitionIdOwned> for ItemDefinitionId<'_> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &ItemDefinitionIdOwned) -> bool { other == self }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -408,6 +408,21 @@ impl Inventory {
|
||||
.map(|(slot, _)| slot)
|
||||
}
|
||||
|
||||
pub fn get_slot_of_item_by_def_id(
|
||||
&self,
|
||||
item_def_id: &item::ItemDefinitionIdOwned,
|
||||
) -> Option<InvSlotId> {
|
||||
self.slots_with_id()
|
||||
.find(|&(_, it)| {
|
||||
if let Some(it) = it {
|
||||
it.item_definition_id() == *item_def_id
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.map(|(slot, _)| slot)
|
||||
}
|
||||
|
||||
/// Get content of a slot
|
||||
pub fn get(&self, inv_slot_id: InvSlotId) -> Option<&Item> {
|
||||
self.slot(inv_slot_id).and_then(Option::as_ref)
|
||||
|
@ -456,6 +456,7 @@ struct EqualitySet {
|
||||
|
||||
impl EqualitySet {
|
||||
fn canonical<'a>(&'a self, item_name: &'a ItemDefinitionIdOwned) -> &'a ItemDefinitionIdOwned {
|
||||
// TODO: use hashbrown Equivalent trait to avoid needing owned item def here
|
||||
let canonical_itemname = self
|
||||
.equivalence_class
|
||||
.get(item_name)
|
||||
@ -996,7 +997,7 @@ impl TradePricing {
|
||||
result
|
||||
}
|
||||
|
||||
fn get_materials_impl(&self, item: &ItemDefinitionId) -> Option<MaterialUse> {
|
||||
fn get_materials_impl(&self, item: &ItemDefinitionId<'_>) -> Option<MaterialUse> {
|
||||
self.price_lookup(&item.to_owned()).cloned()
|
||||
}
|
||||
|
||||
@ -1012,7 +1013,7 @@ impl TradePricing {
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_materials(item: &ItemDefinitionId) -> Option<MaterialUse> {
|
||||
pub fn get_materials(item: &ItemDefinitionId<'_>) -> Option<MaterialUse> {
|
||||
TRADE_PRICING.get_materials_impl(item)
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
use super::utils::*;
|
||||
use crate::{
|
||||
comp::{
|
||||
character_state::OutputEvents,
|
||||
item::{Item, ItemDefinitionIdOwned},
|
||||
character_state::OutputEvents, inventory::slot::InvSlotId, item::ItemDefinitionIdOwned,
|
||||
CharacterState, InventoryManip, StateUpdate,
|
||||
},
|
||||
event::{LocalEvent, ServerEvent},
|
||||
@ -33,8 +32,13 @@ pub struct StaticData {
|
||||
/// Was sneaking
|
||||
pub was_sneak: bool,
|
||||
/// The item required to interact with the sprite, if one was required
|
||||
// If second field is true, item should be consumed on collection
|
||||
pub required_item: Option<(ItemDefinitionIdOwned, bool)>,
|
||||
///
|
||||
/// The second field is the slot that the required item was in when this
|
||||
/// state was created. If it isn't in this slot anymore the interaction will
|
||||
/// fail.
|
||||
///
|
||||
/// If third field is true, item should be consumed on collection
|
||||
pub required_item: Option<(ItemDefinitionIdOwned, InvSlotId, bool)>,
|
||||
/// Miscellaneous information about the ability
|
||||
pub ability_info: AbilityInfo,
|
||||
}
|
||||
@ -97,32 +101,20 @@ impl CharacterBehavior for Data {
|
||||
}
|
||||
} else {
|
||||
// Create inventory manipulation event
|
||||
let required_item =
|
||||
self.static_data
|
||||
.required_item
|
||||
.as_ref()
|
||||
.and_then(|(i, consume)| {
|
||||
Some((
|
||||
Item::new_from_item_definition_id(
|
||||
i.as_ref(),
|
||||
data.ability_map,
|
||||
data.msm,
|
||||
)
|
||||
.ok()?,
|
||||
*consume,
|
||||
))
|
||||
});
|
||||
let has_required_item =
|
||||
required_item.as_ref().map_or(true, |(item, _consume)| {
|
||||
data.inventory.map_or(false, |inv| inv.contains(item))
|
||||
let (has_required_item, inv_slot) = self
|
||||
.static_data
|
||||
.required_item
|
||||
.as_ref()
|
||||
.map_or((true, None), |&(ref item_def_id, slot, consume)| {
|
||||
// Check that required item is still in expected slot
|
||||
let has_item = data
|
||||
.inventory
|
||||
.and_then(|inv| inv.get(slot))
|
||||
.map_or(false, |item| item.item_definition_id() == *item_def_id);
|
||||
|
||||
(has_item, has_item.then_some((slot, consume)))
|
||||
});
|
||||
if has_required_item {
|
||||
let inv_slot = required_item.and_then(|(item, consume)| {
|
||||
Some((
|
||||
data.inventory.and_then(|inv| inv.get_slot_of_item(&item))?,
|
||||
consume,
|
||||
))
|
||||
});
|
||||
let inv_manip = InventoryManip::Collect {
|
||||
sprite_pos: self.static_data.sprite_pos,
|
||||
required_item: inv_slot,
|
||||
|
@ -7,7 +7,7 @@ use crate::{
|
||||
character_state::OutputEvents,
|
||||
controller::InventoryManip,
|
||||
inventory::slot::{ArmorSlot, EquipSlot, Slot},
|
||||
item::{armor::Friction, tool::AbilityContext, Hands, Item, ItemKind, ToolKind},
|
||||
item::{armor::Friction, tool::AbilityContext, Hands, ItemKind, ToolKind},
|
||||
quadruped_low, quadruped_medium, quadruped_small,
|
||||
skills::{Skill, SwimSkill, SKILL_MODIFIERS},
|
||||
theropod, Body, CharacterAbility, CharacterState, Density, InputAttr, InputKind,
|
||||
@ -918,24 +918,28 @@ pub fn handle_manipulate_loadout(
|
||||
UnlockKind::Requires(item) => Some((item, false)),
|
||||
UnlockKind::Consumes(item) => Some((item, true)),
|
||||
});
|
||||
let has_required_items = required_item
|
||||
.as_ref()
|
||||
.and_then(|(i, _consume)| {
|
||||
Item::new_from_item_definition_id(
|
||||
i.as_ref(),
|
||||
data.ability_map,
|
||||
data.msm,
|
||||
)
|
||||
.ok()
|
||||
})
|
||||
.map_or(true, |i| {
|
||||
data.inventory.map_or(false, |inv| inv.contains(&i))
|
||||
});
|
||||
|
||||
// None: An required items exist but no available
|
||||
// Some(None): No required items
|
||||
// Some(Some(_)): Required items satisfied, contains info about them
|
||||
let has_required_items = match required_item {
|
||||
Some((item_id, consume)) => {
|
||||
if let Some(slot) = data
|
||||
.inventory
|
||||
.and_then(|inv| inv.get_slot_of_item_by_def_id(&item_id))
|
||||
{
|
||||
Some(Some((item_id, slot, consume)))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
None => Some(None),
|
||||
};
|
||||
|
||||
// If path can be found between entity interacting with sprite and entity, start
|
||||
// interaction with sprite
|
||||
if not_blocked_by_terrain {
|
||||
if has_required_items {
|
||||
if let Some(required_item) = has_required_items {
|
||||
// If the sprite is collectible, enter the sprite interaction character
|
||||
// state TODO: Handle cases for sprite being
|
||||
// interactible, but not collectible (none currently
|
||||
|
Loading…
Reference in New Issue
Block a user