- // Walk crafting definitions from back to front, so that later
- // definitions can override earlier ones.
- for(std::vector<CraftDefinition*>::const_reverse_iterator
- i = m_craft_definitions.rbegin();
- i != m_craft_definitions.rend(); i++)
- {
- CraftDefinition *def = *i;
-
- /*infostream<<"Checking "<<input.dump()<<std::endl
- <<" against "<<def->dump()<<std::endl;*/
-
- try {
- if(def->check(input, gamedef))
- {
- // Get output, then decrement input (if requested)
- output = def->getOutput(input, gamedef);
- if(decrementInput)
- def->decrementInput(input, gamedef);
- return true;
+ std::vector<std::string> input_names;
+ input_names = craftGetItemNames(input.items, gamedef);
+ std::sort(input_names.begin(), input_names.end());
+
+ // Try hash types with increasing collision rate
+ // while remembering the latest, highest priority recipe.
+ CraftDefinition::RecipePriority priority_best =
+ CraftDefinition::PRIORITY_NO_RECIPE;
+ CraftDefinition *def_best = nullptr;
+ for (int type = 0; type <= craft_hash_type_max; type++) {
+ u64 hash = getHashForGrid((CraftHashType) type, input_names);
+
+ /*errorstream << "Checking type " << type << " with hash " << hash << std::endl;*/
+
+ // We'd like to do "const [...] hash_collisions = m_craft_defs[type][hash];"
+ // but that doesn't compile for some reason. This does.
+ auto col_iter = (m_craft_defs[type]).find(hash);
+
+ if (col_iter == (m_craft_defs[type]).end())
+ continue;
+
+ const std::vector<CraftDefinition*> &hash_collisions = col_iter->second;
+ // Walk crafting definitions from back to front, so that later
+ // definitions can override earlier ones.
+ for (std::vector<CraftDefinition*>::size_type
+ i = hash_collisions.size(); i > 0; i--) {
+ CraftDefinition *def = hash_collisions[i - 1];
+
+ /*errorstream << "Checking " << input.dump() << std::endl
+ << " against " << def->dump() << std::endl;*/
+
+ CraftDefinition::RecipePriority priority = def->getPriority();
+ if (priority > priority_best
+ && def->check(input, gamedef)) {
+ // Check if the crafted node/item exists
+ CraftOutput out = def->getOutput(input, gamedef);
+ ItemStack is;
+ is.deSerialize(out.item, gamedef->idef());
+ if (!is.isKnown(gamedef->idef())) {
+ infostream << "trying to craft non-existent "
+ << out.item << ", ignoring recipe" << std::endl;
+ continue;
+ }
+
+ output = out;
+ priority_best = priority;
+ def_best = def;