diff --git a/src/craftdef.cpp b/src/craftdef.cpp index 64e2f742..9482fce6 100644 --- a/src/craftdef.cpp +++ b/src/craftdef.cpp @@ -432,7 +432,13 @@ void CraftDefinitionShaped::initHash(IGameDef *gamedef) break; } } - hash_type = has_group ? CRAFT_HASH_TYPE_COUNT : CRAFT_HASH_TYPE_ITEM_NAMES; + if (has_group) { + hash_type = CRAFT_HASH_TYPE_COUNT; + priority = SHAPED_AND_GROUPS; + } else { + hash_type = CRAFT_HASH_TYPE_ITEM_NAMES; + priority = SHAPED; + } } std::string CraftDefinitionShaped::dump() const @@ -543,7 +549,13 @@ void CraftDefinitionShapeless::initHash(IGameDef *gamedef) break; } } - hash_type = has_group ? CRAFT_HASH_TYPE_COUNT : CRAFT_HASH_TYPE_ITEM_NAMES; + if (has_group) { + hash_type = CRAFT_HASH_TYPE_COUNT; + priority = SHAPELESS_AND_GROUPS; + } else { + hash_type = CRAFT_HASH_TYPE_ITEM_NAMES; + priority = SHAPELESS; + } } std::string CraftDefinitionShapeless::dump() const @@ -723,10 +735,13 @@ void CraftDefinitionCooking::initHash(IGameDef *gamedef) hash_inited = true; recipe_name = craftGetItemName(recipe, gamedef); - if (isGroupRecipeStr(recipe_name)) + if (isGroupRecipeStr(recipe_name)) { hash_type = CRAFT_HASH_TYPE_COUNT; - else + priority = SHAPELESS_AND_GROUPS; + } else { hash_type = CRAFT_HASH_TYPE_ITEM_NAMES; + priority = SHAPELESS; + } } std::string CraftDefinitionCooking::dump() const @@ -813,10 +828,13 @@ void CraftDefinitionFuel::initHash(IGameDef *gamedef) hash_inited = true; recipe_name = craftGetItemName(recipe, gamedef); - if (isGroupRecipeStr(recipe_name)) + if (isGroupRecipeStr(recipe_name)) { hash_type = CRAFT_HASH_TYPE_COUNT; - else + priority = SHAPELESS_AND_GROUPS; + } else { hash_type = CRAFT_HASH_TYPE_ITEM_NAMES; + priority = SHAPELESS; + } } std::string CraftDefinitionFuel::dump() const @@ -867,7 +885,11 @@ public: input_names = craftGetItemNames(input.items, gamedef); std::sort(input_names.begin(), input_names.end()); - // Try hash types with increasing collision rate, and return if found. + // Try hash types with increasing collision rate + // while remembering the latest, highest priority recipe. + CraftDefinition::RecipePriority priority_best = + CraftDefinition::NO_RECIPE; + CraftDefinition *def_best = nullptr; for (int type = 0; type <= craft_hash_type_max; type++) { u64 hash = getHashForGrid((CraftHashType) type, input_names); @@ -890,7 +912,9 @@ public: /*errorstream << "Checking " << input.dump() << std::endl << " against " << def->dump() << std::endl;*/ - if (def->check(input, gamedef)) { + 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; @@ -901,17 +925,17 @@ public: continue; } - // Get output, then decrement input (if requested) output = out; - - if (decrementInput) - def->decrementInput(input, output_replacement, gamedef); - /*errorstream << "Check RETURNS TRUE" << std::endl;*/ - return true; + priority_best = priority; + def_best = def; } } } - return false; + if (priority_best == CraftDefinition::NO_RECIPE) + return false; + if (decrementInput) + def_best->decrementInput(input, output_replacement, gamedef); + return true; } virtual std::vector getCraftRecipes(CraftOutput &output, diff --git a/src/craftdef.h b/src/craftdef.h index 140321f0..d8ad2eb2 100644 --- a/src/craftdef.h +++ b/src/craftdef.h @@ -132,6 +132,23 @@ struct CraftReplacements class CraftDefinition { public: + /* + Craft recipe priorities, from low to high + + Recipes are searched from latest to first. + If a recipe with higher priority than a previous found one is + encountered, it is selected instead. + */ + enum RecipePriority + { + NO_RECIPE, + TOOLREPAIR, + SHAPELESS_AND_GROUPS, + SHAPELESS, + SHAPED_AND_GROUPS, + SHAPED, + }; + CraftDefinition() = default; virtual ~CraftDefinition() = default; @@ -140,6 +157,10 @@ public: // Checks whether the recipe is applicable virtual bool check(const CraftInput &input, IGameDef *gamedef) const=0; + RecipePriority getPriority() const + { + return priority; + } // Returns the output structure, meaning depends on crafting method // The implementation can assume that check(input) returns true virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const=0; @@ -162,6 +183,7 @@ public: protected: CraftHashType hash_type; + RecipePriority priority; }; /* @@ -283,6 +305,7 @@ public: virtual void initHash(IGameDef *gamedef) { hash_type = CRAFT_HASH_TYPE_COUNT; + priority = TOOLREPAIR; } virtual std::string dump() const;