Changed component recipe book to generate some stuff automatically to avoid potential for stuff inside to become unsynced (no assets).

This commit is contained in:
Sam 2022-05-05 13:25:29 -04:00
parent 49ff094286
commit 37442b638c
6 changed files with 94 additions and 132 deletions

View File

@ -965,11 +965,7 @@ impl Item {
pub fn ability_spec(&self) -> Option<Cow<AbilitySpec>> { pub fn ability_spec(&self) -> Option<Cow<AbilitySpec>> {
match &self.item_base { match &self.item_base {
ItemBase::Raw(item_def) => { ItemBase::Raw(item_def) => {
item_def item_def.ability_spec.as_ref().map(Cow::Borrowed).or({
.ability_spec
.as_ref()
.map(Cow::Borrowed)
.or_else(|| {
// If no custom ability set is specified, fall back to abilityset of tool // If no custom ability set is specified, fall back to abilityset of tool
// kind. // kind.
if let ItemKind::Tool(tool) = &item_def.kind { if let ItemKind::Tool(tool) = &item_def.kind {

View File

@ -812,11 +812,12 @@ mod tests {
assert!((lootsum2 - 1.0).abs() < 1e-4); assert!((lootsum2 - 1.0).abs() < 1e-4);
// highly nested // highly nested
// let loot3 = expand_loot_table("common.loot_tables.creature.biped_large.wendigo");
// let lootsum3 = loot3.iter().fold(0.0, |s, i| s + i.0);
// TODO: Re-enable this. See note at top of test (though this specific // TODO: Re-enable this. See note at top of test (though this specific
// table can also be fixed by properly integrating modular weapons into // table can also be fixed by properly integrating modular weapons into
// probability files) // probability files)
// let loot3 =
// expand_loot_table("common.loot_tables.creature.biped_large.wendigo");
// let lootsum3 = loot3.iter().fold(0.0, |s, i| s + i.0);
// assert!((lootsum3 - 1.0).abs() < 1e-5); // assert!((lootsum3 - 1.0).abs() < 1e-5);
} }

View File

@ -372,6 +372,25 @@ pub enum RawRecipeInput {
ListSameItem(String), ListSameItem(String),
} }
impl RawRecipeInput {
fn load_recipe_input(&self) -> Result<RecipeInput, assets::Error> {
let input = match self {
RawRecipeInput::Item(name) => RecipeInput::Item(Arc::<ItemDef>::load_cloned(name)?),
RawRecipeInput::Tag(tag) => RecipeInput::Tag(*tag),
RawRecipeInput::TagSameItem(tag) => RecipeInput::TagSameItem(*tag),
RawRecipeInput::ListSameItem(list) => {
let assets = &ItemList::load_expect(list).read().0;
let items = assets
.iter()
.map(|asset| Arc::<ItemDef>::load_expect_cloned(asset))
.collect();
RecipeInput::ListSameItem(items)
},
};
Ok(input)
}
}
#[derive(Clone, Deserialize)] #[derive(Clone, Deserialize)]
pub(crate) struct RawRecipe { pub(crate) struct RawRecipe {
pub(crate) output: (String, u32), pub(crate) output: (String, u32),
@ -392,7 +411,7 @@ impl assets::Asset for RawRecipeBook {
} }
#[derive(Deserialize, Clone)] #[derive(Deserialize, Clone)]
pub struct ItemList(Vec<String>); struct ItemList(Vec<String>);
impl assets::Asset for ItemList { impl assets::Asset for ItemList {
type Loader = assets::RonLoader; type Loader = assets::RonLoader;
@ -415,19 +434,7 @@ impl assets::Compound for RecipeBook {
fn load_recipe_input( fn load_recipe_input(
(input, amount, is_mod_comp): &(RawRecipeInput, u32, bool), (input, amount, is_mod_comp): &(RawRecipeInput, u32, bool),
) -> Result<(RecipeInput, u32, bool), assets::Error> { ) -> Result<(RecipeInput, u32, bool), assets::Error> {
let def = match &input { let def = input.load_recipe_input()?;
RawRecipeInput::Item(name) => RecipeInput::Item(Arc::<ItemDef>::load_cloned(name)?),
RawRecipeInput::Tag(tag) => RecipeInput::Tag(*tag),
RawRecipeInput::TagSameItem(tag) => RecipeInput::TagSameItem(*tag),
RawRecipeInput::ListSameItem(list) => {
let assets = &ItemList::load_expect(list).read().0;
let items = assets
.iter()
.map(|asset| Arc::<ItemDef>::load_expect_cloned(asset))
.collect();
RecipeInput::ListSameItem(items)
},
};
Ok((def, *amount, *is_mod_comp)) Ok((def, *amount, *is_mod_comp))
} }
@ -478,7 +485,7 @@ impl ComponentRecipeBook {
#[derive(Clone, Deserialize)] #[derive(Clone, Deserialize)]
#[serde(transparent)] #[serde(transparent)]
struct RawComponentRecipeBook(HashMap<ComponentKey, RawComponentRecipe>); struct RawComponentRecipeBook(Vec<RawComponentRecipe>);
impl assets::Asset for RawComponentRecipeBook { impl assets::Asset for RawComponentRecipeBook {
type Loader = assets::RonLoader; type Loader = assets::RonLoader;
@ -494,7 +501,7 @@ pub struct ComponentKey {
pub toolkind: ToolKind, pub toolkind: ToolKind,
/// Refers to the item definition id of the material /// Refers to the item definition id of the material
pub material: String, pub material: String,
/// Refers to the item definition id of the material /// Refers to the item definition id of the modifier
pub modifier: Option<String>, pub modifier: Option<String>,
} }
@ -671,10 +678,6 @@ impl ComponentRecipe {
pub fn inputs(&self) -> impl ExactSizeIterator<Item = (&RecipeInput, u32)> { pub fn inputs(&self) -> impl ExactSizeIterator<Item = (&RecipeInput, u32)> {
pub struct ComponentRecipeInputsIterator<'a> { pub struct ComponentRecipeInputsIterator<'a> {
// material: bool,
// modifier: bool,
// index: usize,
// recipe: &'a ComponentRecipe,
material: Option<&'a (RecipeInput, u32)>, material: Option<&'a (RecipeInput, u32)>,
modifier: Option<&'a (RecipeInput, u32)>, modifier: Option<&'a (RecipeInput, u32)>,
additional_inputs: std::slice::Iter<'a, (RecipeInput, u32)>, additional_inputs: std::slice::Iter<'a, (RecipeInput, u32)>,
@ -684,21 +687,6 @@ impl ComponentRecipe {
type Item = &'a (RecipeInput, u32); type Item = &'a (RecipeInput, u32);
fn next(&mut self) -> Option<&'a (RecipeInput, u32)> { fn next(&mut self) -> Option<&'a (RecipeInput, u32)> {
// if !self.material {
// self.material = true;
// Some(&self.recipe.material)
// } else if !self.modifier {
// self.modifier = true;
// if self.recipe.modifier.is_some() {
// self.recipe.modifier.as_ref()
// } else {
// self.index += 1;
// self.recipe.additional_inputs.get(self.index - 1)
// }
// } else {
// self.index += 1;
// self.recipe.additional_inputs.get(self.index - 1)
// }
self.material self.material
.take() .take()
.or_else(|| self.modifier.take()) .or_else(|| self.modifier.take())
@ -712,10 +700,6 @@ impl ComponentRecipe {
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
ComponentRecipeInputsIterator { ComponentRecipeInputsIterator {
// material: false,
// modifier: false,
// index: 0,
// recipe: self,
material: Some(&self.material), material: Some(&self.material),
modifier: self.modifier.as_ref(), modifier: self.modifier.as_ref(),
additional_inputs: self.additional_inputs.as_slice().iter(), additional_inputs: self.additional_inputs.as_slice().iter(),
@ -725,8 +709,6 @@ impl ComponentRecipe {
impl<'a> ExactSizeIterator for ComponentRecipeInputsIterator<'a> { impl<'a> ExactSizeIterator for ComponentRecipeInputsIterator<'a> {
fn len(&self) -> usize { fn len(&self) -> usize {
// 1 + self.recipe.modifier.is_some() as usize +
// self.recipe.additional_inputs.len()
self.material.is_some() as usize self.material.is_some() as usize
+ self.modifier.is_some() as usize + self.modifier.is_some() as usize
+ self.additional_inputs.len() + self.additional_inputs.len()
@ -740,8 +722,10 @@ impl ComponentRecipe {
#[derive(Clone, Deserialize)] #[derive(Clone, Deserialize)]
struct RawComponentRecipe { struct RawComponentRecipe {
output: RawComponentOutput, output: RawComponentOutput,
material: (RawRecipeInput, u32), /// String refers to an item definition id
modifier: Option<(RawRecipeInput, u32)>, material: (String, u32),
/// String refers to an item definition id
modifier: Option<(String, u32)>,
additional_inputs: Vec<(RawRecipeInput, u32)>, additional_inputs: Vec<(RawRecipeInput, u32)>,
craft_sprite: Option<SpriteKind>, craft_sprite: Option<SpriteKind>,
} }
@ -756,10 +740,9 @@ enum ComponentOutput {
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
enum RawComponentOutput { enum RawComponentOutput {
ItemComponents { /// Creates the primary component of a modular tool. Assumes that the
item: String, /// material used is the only component in the item.
components: Vec<String>, ToolPrimaryComponent { toolkind: ToolKind, item: String },
},
} }
impl assets::Compound for ComponentRecipeBook { impl assets::Compound for ComponentRecipeBook {
@ -768,42 +751,54 @@ impl assets::Compound for ComponentRecipeBook {
specifier: &str, specifier: &str,
) -> Result<Self, assets::BoxedError> { ) -> Result<Self, assets::BoxedError> {
#[inline] #[inline]
fn load_recipe_input( fn load_recipe_key(raw_recipe: &RawComponentRecipe) -> ComponentKey {
(input, amount): &(RawRecipeInput, u32), match &raw_recipe.output {
) -> Result<(RecipeInput, u32), assets::Error> { RawComponentOutput::ToolPrimaryComponent { toolkind, item: _ } => {
let def = match &input { let material = String::from(&raw_recipe.material.0);
RawRecipeInput::Item(name) => RecipeInput::Item(Arc::<ItemDef>::load_cloned(name)?), let modifier = raw_recipe
RawRecipeInput::Tag(tag) => RecipeInput::Tag(*tag), .modifier
RawRecipeInput::TagSameItem(tag) => RecipeInput::TagSameItem(*tag), .as_ref()
RawRecipeInput::ListSameItem(list) => { .map(|(modifier, _amount)| String::from(modifier));
let assets = &ItemList::load_expect(list).read().0; ComponentKey {
let items = assets toolkind: *toolkind,
.iter() material,
.map(|asset| Arc::<ItemDef>::load_expect_cloned(asset)) modifier,
.collect(); }
RecipeInput::ListSameItem(items)
}, },
}; }
Ok((def, *amount))
} }
#[inline] #[inline]
fn load_recipe_output( fn load_recipe(raw_recipe: &RawComponentRecipe) -> Result<ComponentRecipe, assets::Error> {
output: &RawComponentOutput, let output = match &raw_recipe.output {
) -> Result<ComponentOutput, assets::Error> { RawComponentOutput::ToolPrimaryComponent { toolkind: _, item } => {
let def = match &output { let item = Arc::<ItemDef>::load_cloned(item)?;
RawComponentOutput::ItemComponents { let components = vec![Arc::<ItemDef>::load_cloned(&raw_recipe.material.0)?];
item: def, ComponentOutput::ItemComponents { item, components }
components: defs,
} => ComponentOutput::ItemComponents {
item: Arc::<ItemDef>::load_cloned(def)?,
components: defs
.iter()
.map(|def| Arc::<ItemDef>::load_cloned(def))
.collect::<Result<Vec<_>, _>>()?,
}, },
}; };
Ok(def) let material = (
RecipeInput::Item(Arc::<ItemDef>::load_cloned(&raw_recipe.material.0)?),
raw_recipe.material.1,
);
let modifier = if let Some((modifier, amount)) = &raw_recipe.modifier {
let modifier = Arc::<ItemDef>::load_cloned(modifier)?;
Some((RecipeInput::Item(modifier), *amount))
} else {
None
};
let additional_inputs = raw_recipe
.additional_inputs
.iter()
.map(|(input, amount)| input.load_recipe_input().map(|input| (input, *amount)))
.collect::<Result<Vec<_>, _>>()?;
Ok(ComponentRecipe {
output,
material,
modifier,
additional_inputs,
craft_sprite: raw_recipe.craft_sprite,
})
} }
let raw = cache.load::<RawComponentRecipeBook>(specifier)?.cloned(); let raw = cache.load::<RawComponentRecipeBook>(specifier)?.cloned();
@ -811,33 +806,9 @@ impl assets::Compound for ComponentRecipeBook {
let recipes = raw let recipes = raw
.0 .0
.iter() .iter()
.map( .map(|raw_recipe| {
|( load_recipe(raw_recipe).map(|recipe| (load_recipe_key(raw_recipe), recipe))
key, })
RawComponentRecipe {
output,
material,
modifier,
additional_inputs,
craft_sprite,
},
)| {
let additional_inputs = additional_inputs
.iter()
.map(load_recipe_input)
.collect::<Result<Vec<_>, _>>()?;
let material = load_recipe_input(material)?;
let modifier = modifier.as_ref().map(load_recipe_input).transpose()?;
let output = load_recipe_output(output)?;
Ok((key.clone(), ComponentRecipe {
output,
material,
modifier,
additional_inputs,
craft_sprite: *craft_sprite,
}))
},
)
.collect::<Result<_, assets::Error>>()?; .collect::<Result<_, assets::Error>>()?;
Ok(ComponentRecipeBook { recipes }) Ok(ComponentRecipeBook { recipes })

View File

@ -1940,8 +1940,8 @@ where
if target_inventory.free_slots() < count { if target_inventory.free_slots() < count {
return Err("Inventory doesn't have enough slots".to_owned()); return Err("Inventory doesn't have enough slots".to_owned());
} }
for (item_id, quantity) in kit {
let mut rng = thread_rng(); let mut rng = thread_rng();
for (item_id, quantity) in kit {
let mut item = match &item_id { let mut item = match &item_id {
KitSpec::Item(item_id) => comp::Item::new_from_asset(item_id) KitSpec::Item(item_id) => comp::Item::new_from_asset(item_id)
.map_err(|_| format!("Unknown item: {:#?}", item_id))?, .map_err(|_| format!("Unknown item: {:#?}", item_id))?,

View File

@ -882,13 +882,3 @@ FROM item_graph
WHERE parent_pseudo_id IS NOT NULL; WHERE parent_pseudo_id IS NOT NULL;
PRAGMA defer_foreign_keys = false; PRAGMA defer_foreign_keys = false;
SELECT i.item_id,
i.item_id,
i.parent_container_item_id,
t.new_item_definition_id,
t.pseudo_id,
parent_pseudo_id
FROM _temp_modular_component_items t
JOIN item i ON (i.item_definition_id = t.new_item_definition_id)
WHERE t.parent_pseudo_id IS NULL;

View File

@ -511,6 +511,9 @@ impl<'a> Widget for Crafting<'a> {
let metal_comp_recipe = make_psuedo_recipe(SpriteKind::Anvil); let metal_comp_recipe = make_psuedo_recipe(SpriteKind::Anvil);
let wood_comp_recipe = make_psuedo_recipe(SpriteKind::CraftingBench); let wood_comp_recipe = make_psuedo_recipe(SpriteKind::CraftingBench);
let modular_entries = { let modular_entries = {
// A BTreeMap is used over a HashMap as when a HashMap is used, the UI shuffles
// the positions of these every tick, so a BTreeMap is necessary to keep it
// ordered.
let mut modular_entries = BTreeMap::new(); let mut modular_entries = BTreeMap::new();
modular_entries.insert( modular_entries.insert(
String::from("veloren.core.pseudo_recipe.modular_weapon"), String::from("veloren.core.pseudo_recipe.modular_weapon"),
@ -1288,7 +1291,8 @@ impl<'a> Widget for Crafting<'a> {
.mid_bottom_with_margin_on(state.ids.align_ing, -31.0) .mid_bottom_with_margin_on(state.ids.align_ing, -31.0)
.parent(state.ids.window_frame) .parent(state.ids.window_frame)
.set(state.ids.btn_craft, ui) .set(state.ids.btn_craft, ui)
.was_clicked() && can_perform .was_clicked()
&& can_perform
{ {
match recipe_kind { match recipe_kind {
RecipeKind::ModularWeapon => { RecipeKind::ModularWeapon => {
@ -1501,7 +1505,7 @@ impl<'a> Widget for Crafting<'a> {
}) })
}) })
.or_else(|| tag.exemplar_identifier()) .or_else(|| tag.exemplar_identifier())
.unwrap_or_else(|| "common.items.weapons.empty.empty"), .unwrap_or("common.items.weapons.empty.empty"),
) )
}, },
RecipeInput::ListSameItem(item_defs) => Arc::<ItemDef>::load_expect_cloned( RecipeInput::ListSameItem(item_defs) => Arc::<ItemDef>::load_expect_cloned(