Items with components can now have their name modified by the components. Also addressed more review. NO ASSETS

This commit is contained in:
Sam 2021-11-23 12:45:19 -05:00
parent 524845b661
commit 81c83c5e83
9 changed files with 85 additions and 61 deletions

View File

@ -50,6 +50,7 @@ impl<T: ItemDesc> From<&T> for ItemKey {
} }
}, },
ModularComponent::ToolSecondaryComponent { .. } => { ModularComponent::ToolSecondaryComponent { .. } => {
// TODO: Maybe use a different ItemKey?
ItemKey::Tool(item_definition_id.to_owned()) ItemKey::Tool(item_definition_id.to_owned())
}, },
} }

View File

@ -219,7 +219,6 @@ impl TagExampleInfo for Material {
#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
pub enum ItemTag { pub enum ItemTag {
Leather,
Material(Material), Material(Material),
MaterialKind(MaterialKind), MaterialKind(MaterialKind),
Cultist, Cultist,
@ -237,7 +236,6 @@ impl TagExampleInfo for ItemTag {
match self { match self {
ItemTag::Material(material) => material.name(), ItemTag::Material(material) => material.name(),
ItemTag::MaterialKind(material_kind) => material_kind.into(), ItemTag::MaterialKind(material_kind) => material_kind.into(),
ItemTag::Leather => "leather",
ItemTag::Cultist => "cultist", ItemTag::Cultist => "cultist",
ItemTag::Potion => "potion", ItemTag::Potion => "potion",
ItemTag::Food => "food", ItemTag::Food => "food",
@ -254,7 +252,6 @@ impl TagExampleInfo for ItemTag {
match self { match self {
ItemTag::Material(_) => "common.items.tag_examples.placeholder", ItemTag::Material(_) => "common.items.tag_examples.placeholder",
ItemTag::MaterialKind(_) => "common.items.tag_examples.placeholder", ItemTag::MaterialKind(_) => "common.items.tag_examples.placeholder",
ItemTag::Leather => "common.items.tag_examples.leather",
ItemTag::Cultist => "common.items.tag_examples.cultist", ItemTag::Cultist => "common.items.tag_examples.cultist",
ItemTag::Potion => "common.items.tag_examples.placeholder", ItemTag::Potion => "common.items.tag_examples.placeholder",
ItemTag::Food => "common.items.tag_examples.placeholder", ItemTag::Food => "common.items.tag_examples.placeholder",
@ -715,8 +712,8 @@ impl Item {
ItemBase::Raw(Arc::<ItemDef>::load_cloned(asset)?) ItemBase::Raw(Arc::<ItemDef>::load_cloned(asset)?)
}; };
// TODO: Get msm and ability_map less hackily // TODO: Get msm and ability_map less hackily
let msm = MaterialStatManifest::default(); let msm = MaterialStatManifest::load().read();
let ability_map = AbilityMap::default(); let ability_map = AbilityMap::load().read();
Ok(Item::new_from_item_base( Ok(Item::new_from_item_base(
inner_item, inner_item,
Vec::new(), Vec::new(),
@ -862,15 +859,15 @@ impl Item {
} }
} }
pub fn matches_recipe_input(&self, recipe_input: &RecipeInput) -> bool { pub fn matches_recipe_input(&self, recipe_input: &RecipeInput, amount: u32) -> bool {
match recipe_input { match recipe_input {
RecipeInput::Item(item_def) => self.is_same_item_def(item_def), RecipeInput::Item(item_def) => self.is_same_item_def(item_def),
RecipeInput::Tag(tag) => self.tags().contains(tag), RecipeInput::Tag(tag) => self.tags().contains(tag),
RecipeInput::TagSameItem(tag, amount) => { RecipeInput::TagSameItem(tag) => {
self.tags().contains(tag) && u32::from(self.amount) >= *amount self.tags().contains(tag) && u32::from(self.amount) >= amount
}, },
RecipeInput::ListSameItem(item_defs, amount) => item_defs.iter().any(|item_def| { RecipeInput::ListSameItem(item_defs) => item_defs.iter().any(|item_def| {
self.is_same_item_def(item_def) && u32::from(self.amount) >= *amount self.is_same_item_def(item_def) && u32::from(self.amount) >= amount
}), }),
} }
} }
@ -893,7 +890,13 @@ impl Item {
pub fn name(&self) -> Cow<str> { pub fn name(&self) -> Cow<str> {
match &self.item_base { match &self.item_base {
ItemBase::Raw(item_def) => Cow::Borrowed(&item_def.name), ItemBase::Raw(item_def) => {
if self.components.is_empty() {
Cow::Borrowed(&item_def.name)
} else {
modular::modify_name(&item_def.name, self)
}
},
ItemBase::Modular(mod_base) => mod_base.generate_name(self.components()), ItemBase::Modular(mod_base) => mod_base.generate_name(self.components()),
} }
} }
@ -911,7 +914,7 @@ impl Item {
ItemBase::Raw(item_def) => Cow::Borrowed(&item_def.kind), ItemBase::Raw(item_def) => Cow::Borrowed(&item_def.kind),
ItemBase::Modular(mod_base) => { ItemBase::Modular(mod_base) => {
// TODO: Try to move further upward // TODO: Try to move further upward
let msm = MaterialStatManifest::default(); let msm = MaterialStatManifest::load().read();
mod_base.kind(self.components(), &msm) mod_base.kind(self.components(), &msm)
}, },

View File

@ -1,5 +1,5 @@
use super::{ use super::{
tool::{self, AbilitySpec, Hands, MaterialStatManifest}, tool::{self, AbilityMap, AbilitySpec, Hands, MaterialStatManifest},
Item, ItemBase, ItemDef, ItemDesc, ItemKind, Material, Quality, ToolKind, Item, ItemBase, ItemDef, ItemDesc, ItemKind, Material, Quality, ToolKind,
}; };
use crate::{assets::AssetExt, recipe}; use crate::{assets::AssetExt, recipe};
@ -287,8 +287,8 @@ pub fn random_weapon(
) -> Result<Item, ModularWeaponCreationError> { ) -> Result<Item, ModularWeaponCreationError> {
if let Some(material_id) = material.asset_identifier() { if let Some(material_id) = material.asset_identifier() {
// Loads default ability map and material stat manifest for later use // Loads default ability map and material stat manifest for later use
let ability_map = Default::default(); let ability_map = AbilityMap::load().read();
let msm = Default::default(); let msm = MaterialStatManifest::load().read();
let mut rng = thread_rng(); let mut rng = thread_rng();
@ -351,6 +351,25 @@ pub fn random_weapon(
} }
} }
pub fn modify_name<'a>(item_name: &'a str, item: &'a Item) -> Cow<'a, str> {
if let ItemKind::ModularComponent(_) = &*item.kind() {
if let Some(material_name) = item
.components()
.iter()
.find_map(|comp| match &*comp.kind() {
ItemKind::Ingredient { descriptor, .. } => Some(descriptor.to_owned()),
_ => None,
})
{
Cow::Owned(format!("{} {}", material_name, item_name))
} else {
Cow::Borrowed(item_name)
}
} else {
Cow::Borrowed(item_name)
}
}
/// This is used as a key to uniquely identify the modular weapon in asset /// This is used as a key to uniquely identify the modular weapon in asset
/// manifests in voxygen (Main component, material, hands) /// manifests in voxygen (Main component, material, hands)
pub type ModularWeaponKey = (String, String, Hands); pub type ModularWeaponKey = (String, String, Hands);

View File

@ -2,7 +2,7 @@
// version in voxygen\src\meta.rs in order to reset save files to being empty // version in voxygen\src\meta.rs in order to reset save files to being empty
use crate::{ use crate::{
assets::{self, Asset, AssetExt}, assets::{self, Asset, AssetExt, AssetHandle},
comp::{skills::Skill, CharacterAbility}, comp::{skills::Skill, CharacterAbility},
}; };
use hashbrown::HashMap; use hashbrown::HashMap;
@ -217,6 +217,10 @@ impl DivAssign<usize> for Stats {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MaterialStatManifest(pub HashMap<String, Stats>); pub struct MaterialStatManifest(pub HashMap<String, Stats>);
impl MaterialStatManifest {
pub fn load() -> AssetHandle<Self> { Self::load_expect("common.material_stats_manifest") }
}
// This could be a Compound that also loads the keys, but the RecipeBook // This could be a Compound that also loads the keys, but the RecipeBook
// Compound impl already does that, so checking for existence here is redundant. // Compound impl already does that, so checking for existence here is redundant.
impl Asset for MaterialStatManifest { impl Asset for MaterialStatManifest {
@ -225,13 +229,6 @@ impl Asset for MaterialStatManifest {
const EXTENSION: &'static str = "ron"; const EXTENSION: &'static str = "ron";
} }
impl Default for MaterialStatManifest {
fn default() -> MaterialStatManifest {
// TODO: Don't do this, loading a default should have no ability to panic
MaterialStatManifest::load_expect_cloned("common.material_stats_manifest")
}
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Tool { pub struct Tool {
pub kind: ToolKind, pub kind: ToolKind,
@ -348,16 +345,9 @@ pub struct AbilityItem {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AbilityMap<T = AbilityItem>(HashMap<AbilitySpec, AbilitySet<T>>); pub struct AbilityMap<T = AbilityItem>(HashMap<AbilitySpec, AbilitySet<T>>);
impl Default for AbilityMap { impl AbilityMap {
fn default() -> Self { pub fn load() -> AssetHandle<Self> {
// TODO: Revert to old default Self::load_expect("common.abilities.ability_set_manifest")
if let Ok(map) = Self::load_cloned("common.abilities.ability_set_manifest") {
map
} else {
let mut map = HashMap::new();
map.insert(AbilitySpec::Tool(ToolKind::Empty), AbilitySet::default());
AbilityMap(map)
}
} }
} }

View File

@ -22,13 +22,19 @@ pub enum RecipeInput {
/// Similar to RecipeInput::Tag(_), but all items must be the same. /// Similar to RecipeInput::Tag(_), but all items must be the same.
/// Specifically this means that a mix of different items with the tag /// Specifically this means that a mix of different items with the tag
/// cannot be used. /// cannot be used.
TagSameItem(ItemTag, u32), /// TODO: Currently requires that all items must be in the same slot.
/// Eventually should be reworked so that items can be spread over multiple
/// slots.
TagSameItem(ItemTag),
/// List is similar to tag, but has items defined in centralized file /// List is similar to tag, but has items defined in centralized file
/// Similar to RecipeInput::TagSameItem(_), all items must be the same, they /// Similar to RecipeInput::TagSameItem(_), all items must be the same, they
/// cannot be a mix of different items defined in the list. /// cannot be a mix of different items defined in the list.
// Intent of using List over Tag is to make it harder for tag to be innocuously added to an // Intent of using List over Tag is to make it harder for tag to be innocuously added to an
// item breaking a recipe // item breaking a recipe
ListSameItem(Vec<Arc<ItemDef>>, u32), /// TODO: Currently requires that all items must be in the same slot.
/// Eventually should be reworked so that items can be spread over multiple
/// slots.
ListSameItem(Vec<Arc<ItemDef>>),
} }
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
@ -62,7 +68,8 @@ impl Recipe {
self.inputs self.inputs
.iter() .iter()
.enumerate() .enumerate()
.for_each(|(i, (input, mut required, mut is_component))| { .for_each(|(i, (input, amount, mut is_component))| {
let mut required = *amount;
// Check used for recipes that have an input that is not consumed, e.g. // Check used for recipes that have an input that is not consumed, e.g.
// craftsman hammer // craftsman hammer
let mut contains_any = false; let mut contains_any = false;
@ -75,7 +82,7 @@ impl Recipe {
// Checks that the item in the slot can be used for the input // Checks that the item in the slot can be used for the input
if let Some(item) = inv if let Some(item) = inv
.get(*slot) .get(*slot)
.filter(|item| item.matches_recipe_input(input)) .filter(|item| item.matches_recipe_input(input, *amount))
{ {
// Gets the number of items claimed from the slot, or sets to 0 if slot has // Gets the number of items claimed from the slot, or sets to 0 if slot has
// not been claimed by another input yet // not been claimed by another input yet
@ -165,14 +172,15 @@ impl Recipe {
// The inputs to a recipe that have missing items, and the amount missing // The inputs to a recipe that have missing items, and the amount missing
let mut missing = Vec::<(&RecipeInput, u32)>::new(); let mut missing = Vec::<(&RecipeInput, u32)>::new();
for (i, (input, mut needed, _)) in self.inputs().enumerate() { for (i, (input, amount, _)) in self.inputs().enumerate() {
let mut needed = amount;
let mut contains_any = false; let mut contains_any = false;
// Checks through every slot, filtering to only those that contain items that // Checks through every slot, filtering to only those that contain items that
// can satisfy the input // can satisfy the input
for (inv_slot_id, slot) in inv.slots_with_id() { for (inv_slot_id, slot) in inv.slots_with_id() {
if let Some(item) = slot if let Some(item) = slot
.as_ref() .as_ref()
.filter(|item| item.matches_recipe_input(&*input)) .filter(|item| item.matches_recipe_input(&*input, amount))
{ {
let claim = slot_claims.entry(inv_slot_id).or_insert(0); let claim = slot_claims.entry(inv_slot_id).or_insert(0);
slots.push((i as u32, inv_slot_id)); slots.push((i as u32, inv_slot_id));
@ -390,14 +398,14 @@ impl assets::Compound for RecipeBook {
let def = match &input { let def = match &input {
RawRecipeInput::Item(name) => RecipeInput::Item(Arc::<ItemDef>::load_cloned(name)?), RawRecipeInput::Item(name) => RecipeInput::Item(Arc::<ItemDef>::load_cloned(name)?),
RawRecipeInput::Tag(tag) => RecipeInput::Tag(*tag), RawRecipeInput::Tag(tag) => RecipeInput::Tag(*tag),
RawRecipeInput::TagSameItem(tag) => RecipeInput::TagSameItem(*tag, *amount), RawRecipeInput::TagSameItem(tag) => RecipeInput::TagSameItem(*tag),
RawRecipeInput::ListSameItem(list) => { RawRecipeInput::ListSameItem(list) => {
let assets = &ItemList::load_expect(list).read().0; let assets = &ItemList::load_expect(list).read().0;
let items = assets let items = assets
.iter() .iter()
.map(|asset| Arc::<ItemDef>::load_expect_cloned(asset)) .map(|asset| Arc::<ItemDef>::load_expect_cloned(asset))
.collect(); .collect();
RecipeInput::ListSameItem(items, *amount) RecipeInput::ListSameItem(items)
}, },
}; };
Ok((def, *amount, *is_mod_comp)) Ok((def, *amount, *is_mod_comp))

View File

@ -43,7 +43,7 @@ pub struct ReadData<'a> {
stats: ReadStorage<'a, Stats>, stats: ReadStorage<'a, Stats>,
skill_sets: ReadStorage<'a, SkillSet>, skill_sets: ReadStorage<'a, SkillSet>,
active_abilities: ReadStorage<'a, ActiveAbilities>, active_abilities: ReadStorage<'a, ActiveAbilities>,
msm: Read<'a, MaterialStatManifest>, msm: ReadExpect<'a, MaterialStatManifest>,
combos: ReadStorage<'a, Combo>, combos: ReadStorage<'a, Combo>,
alignments: ReadStorage<'a, comp::Alignment>, alignments: ReadStorage<'a, comp::Alignment>,
terrain: ReadExpect<'a, TerrainGrid>, terrain: ReadExpect<'a, TerrainGrid>,

View File

@ -73,7 +73,7 @@ use common::{
calendar::Calendar, calendar::Calendar,
character::CharacterId, character::CharacterId,
cmd::ChatCommand, cmd::ChatCommand,
comp::{self, item::MaterialStatManifest}, comp,
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
recipe::default_recipe_book, recipe::default_recipe_book,
resources::{BattleMode, Time, TimeOfDay}, resources::{BattleMode, Time, TimeOfDay},
@ -310,7 +310,7 @@ impl Server {
); );
state.ecs_mut().insert(ability_map); state.ecs_mut().insert(ability_map);
let msm = comp::inventory::item::MaterialStatManifest::default(); let msm = comp::inventory::item::MaterialStatManifest::load().cloned();
state.ecs_mut().insert(msm); state.ecs_mut().insert(msm);
state.ecs_mut().insert(CharacterLoader::new( state.ecs_mut().insert(CharacterLoader::new(
@ -1087,7 +1087,11 @@ impl Server {
client_timeout: self.settings().client_timeout, client_timeout: self.settings().client_timeout,
world_map: self.map.clone(), world_map: self.map.clone(),
recipe_book: default_recipe_book().cloned(), recipe_book: default_recipe_book().cloned(),
material_stats: MaterialStatManifest::default(), material_stats: (&*self
.state
.ecs()
.read_resource::<comp::item::tool::MaterialStatManifest>())
.clone(),
ability_map: (&*self ability_map: (&*self
.state .state
.ecs() .ecs()

View File

@ -36,8 +36,9 @@ pub struct ItemModelPair {
// shouldn't matter unless someone's hot-reloading material stats on the live // shouldn't matter unless someone's hot-reloading material stats on the live
// server // server
lazy_static! { lazy_static! {
pub static ref MATERIAL_STATS_MANIFEST: MaterialStatManifest = MaterialStatManifest::default(); pub static ref MATERIAL_STATS_MANIFEST: MaterialStatManifest =
pub static ref ABILITY_MAP: AbilityMap = AbilityMap::default(); MaterialStatManifest::load().cloned();
pub static ref ABILITY_MAP: AbilityMap = AbilityMap::load().cloned();
} }
/// Returns a vector that contains all item rows to upsert; parent is /// Returns a vector that contains all item rows to upsert; parent is

View File

@ -198,12 +198,10 @@ impl CraftingTab {
}, },
CraftingTab::Glider => matches!(&*item.kind(), ItemKind::Glider(_)), CraftingTab::Glider => matches!(&*item.kind(), ItemKind::Glider(_)),
CraftingTab::Potion => item.tags().contains(&ItemTag::Potion), CraftingTab::Potion => item.tags().contains(&ItemTag::Potion),
CraftingTab::ProcessedMaterial => item.tags().iter().any(|tag| { CraftingTab::ProcessedMaterial => item
matches!( .tags()
tag, .iter()
&ItemTag::MaterialKind(_) | &ItemTag::Leather | &ItemTag::BaseMaterial .any(|tag| matches!(tag, &ItemTag::MaterialKind(_) | &ItemTag::BaseMaterial)),
)
}),
CraftingTab::Bag => item.tags().contains(&ItemTag::Bag), CraftingTab::Bag => item.tags().contains(&ItemTag::Bag),
CraftingTab::Tool => item.tags().contains(&ItemTag::CraftingTool), CraftingTab::Tool => item.tags().contains(&ItemTag::CraftingTool),
CraftingTab::Utility => item.tags().contains(&ItemTag::Utility), CraftingTab::Utility => item.tags().contains(&ItemTag::Utility),
@ -469,10 +467,10 @@ impl<'a> Widget for Crafting<'a> {
let input_name = match input { let input_name = match input {
RecipeInput::Item(def) => def.name(), RecipeInput::Item(def) => def.name(),
RecipeInput::Tag(tag) => Cow::Borrowed(tag.name()), RecipeInput::Tag(tag) => Cow::Borrowed(tag.name()),
RecipeInput::TagSameItem(tag, _) => Cow::Borrowed(tag.name()), RecipeInput::TagSameItem(tag) => Cow::Borrowed(tag.name()),
// Works, but probably will have some...interesting false positives // Works, but probably will have some...interesting false positives
// Code reviewers probably required to do magic to make not hacky // Code reviewers probably required to do magic to make not hacky
RecipeInput::ListSameItem(defs, _) => { RecipeInput::ListSameItem(defs) => {
Cow::Owned(defs.iter().map(|def| def.name()).collect()) Cow::Owned(defs.iter().map(|def| def.name()).collect())
}, },
} }
@ -914,13 +912,13 @@ impl<'a> Widget for Crafting<'a> {
for (i, (recipe_input, amount, _)) in recipe.inputs.iter().enumerate() { for (i, (recipe_input, amount, _)) in recipe.inputs.iter().enumerate() {
let item_def = match recipe_input { let item_def = match recipe_input {
RecipeInput::Item(item_def) => Arc::clone(item_def), RecipeInput::Item(item_def) => Arc::clone(item_def),
RecipeInput::Tag(tag) | RecipeInput::TagSameItem(tag, _) => { RecipeInput::Tag(tag) | RecipeInput::TagSameItem(tag) => {
Arc::<ItemDef>::load_expect_cloned( Arc::<ItemDef>::load_expect_cloned(
self.inventory self.inventory
.slots() .slots()
.find_map(|slot| { .find_map(|slot| {
slot.as_ref().and_then(|item| { slot.as_ref().and_then(|item| {
if item.matches_recipe_input(recipe_input) { if item.matches_recipe_input(recipe_input, *amount) {
Some(item.item_definition_id()) Some(item.item_definition_id())
} else { } else {
None None
@ -930,12 +928,12 @@ impl<'a> Widget for Crafting<'a> {
.unwrap_or_else(|| tag.exemplar_identifier()), .unwrap_or_else(|| tag.exemplar_identifier()),
) )
}, },
RecipeInput::ListSameItem(item_defs, _) => Arc::<ItemDef>::load_expect_cloned( RecipeInput::ListSameItem(item_defs) => Arc::<ItemDef>::load_expect_cloned(
self.inventory self.inventory
.slots() .slots()
.find_map(|slot| { .find_map(|slot| {
slot.as_ref().and_then(|item| { slot.as_ref().and_then(|item| {
if item.matches_recipe_input(recipe_input) { if item.matches_recipe_input(recipe_input, *amount) {
Some(item.item_definition_id()) Some(item.item_definition_id())
} else { } else {
None None
@ -1047,10 +1045,10 @@ impl<'a> Widget for Crafting<'a> {
// Ingredients // Ingredients
let name = match recipe_input { let name = match recipe_input {
RecipeInput::Item(_) => item_def.name().to_string(), RecipeInput::Item(_) => item_def.name().to_string(),
RecipeInput::Tag(tag) | RecipeInput::TagSameItem(tag, _) => { RecipeInput::Tag(tag) | RecipeInput::TagSameItem(tag) => {
format!("Any {} item", tag.name()) format!("Any {} item", tag.name())
}, },
RecipeInput::ListSameItem(item_defs, _) => { RecipeInput::ListSameItem(item_defs) => {
format!( format!(
"Any of {}", "Any of {}",
item_defs.iter().map(|def| def.name()).collect::<String>() item_defs.iter().map(|def| def.name()).collect::<String>()