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,19 +965,15 @@ impl Item {
pub fn ability_spec(&self) -> Option<Cow<AbilitySpec>> {
match &self.item_base {
ItemBase::Raw(item_def) => {
item_def
.ability_spec
.as_ref()
.map(Cow::Borrowed)
.or_else(|| {
// If no custom ability set is specified, fall back to abilityset of tool
// kind.
if let ItemKind::Tool(tool) = &item_def.kind {
Some(Cow::Owned(AbilitySpec::Tool(tool.kind)))
} else {
None
}
})
item_def.ability_spec.as_ref().map(Cow::Borrowed).or({
// If no custom ability set is specified, fall back to abilityset of tool
// kind.
if let ItemKind::Tool(tool) = &item_def.kind {
Some(Cow::Owned(AbilitySpec::Tool(tool.kind)))
} else {
None
}
})
},
ItemBase::Modular(mod_base) => mod_base.ability_spec(self.components()),
}

View File

@ -812,11 +812,12 @@ mod tests {
assert!((lootsum2 - 1.0).abs() < 1e-4);
// 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
// table can also be fixed by properly integrating modular weapons into
// 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);
}

View File

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

View File

@ -1940,8 +1940,8 @@ where
if target_inventory.free_slots() < count {
return Err("Inventory doesn't have enough slots".to_owned());
}
let mut rng = thread_rng();
for (item_id, quantity) in kit {
let mut rng = thread_rng();
let mut item = match &item_id {
KitSpec::Item(item_id) => comp::Item::new_from_asset(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;
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 wood_comp_recipe = make_psuedo_recipe(SpriteKind::CraftingBench);
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();
modular_entries.insert(
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)
.parent(state.ids.window_frame)
.set(state.ids.btn_craft, ui)
.was_clicked() && can_perform
.was_clicked()
&& can_perform
{
match recipe_kind {
RecipeKind::ModularWeapon => {
@ -1501,7 +1505,7 @@ impl<'a> Widget for Crafting<'a> {
})
})
.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(