return str_starts_with(rec_name, std::string("group:"));
}
+static bool hasGroupItem(const std::vector<std::string> &recipe)
+{
+ for (const auto &item : recipe) {
+ if (isGroupRecipeStr(item))
+ return true;
+ }
+ return false;
+}
+
inline u64 getHashForString(const std::string &recipe_str)
{
/*errorstream << "Hashing craft string \"" << recipe_str << '"';*/
case CRAFT_HASH_TYPE_ITEM_NAMES: {
std::ostringstream os;
bool is_first = true;
- for (size_t i = 0; i < grid_names.size(); i++) {
- if (!grid_names[i].empty()) {
- os << (is_first ? "" : "\n") << grid_names[i];
+ for (const std::string &grid_name : grid_names) {
+ if (!grid_name.empty()) {
+ os << (is_first ? "" : "\n") << grid_name;
is_first = false;
}
}
return getHashForString(os.str());
} case CRAFT_HASH_TYPE_COUNT: {
u64 cnt = 0;
- for (size_t i = 0; i < grid_names.size(); i++)
- if (!grid_names[i].empty())
+ for (const std::string &grid_name : grid_names)
+ if (!grid_name.empty())
cnt++;
return cnt;
} case CRAFT_HASH_TYPE_UNHASHED:
const std::vector<std::string> &itemstrings, IGameDef *gamedef)
{
std::vector<std::string> result;
+ result.reserve(itemstrings.size());
for (const auto &itemstring : itemstrings) {
result.push_back(craftGetItemName(itemstring, gamedef));
}
const std::vector<ItemStack> &items, IGameDef *gamedef)
{
std::vector<std::string> result;
+ result.reserve(items.size());
for (const auto &item : items) {
result.push_back(item.name);
}
const std::vector<std::string> &items, IGameDef *gamedef)
{
std::vector<ItemStack> result;
+ result.reserve(items.size());
for (const auto &item : items) {
result.emplace_back(std::string(item), (u16)1,
(u16)0, gamedef->getItemDefManager());
bool success = false;
unsigned int x = 0;
unsigned int y = 0;
- for (std::vector<std::string>::size_type i = 0;
- i < items.size(); i++) {
+ for (const std::string &item : items) {
// Is this an actual item?
- if (!items[i].empty()) {
+ if (!item.empty()) {
if (!success) {
// This is the first nonempty item
min_x = max_x = x;
CraftDefinitionShaped
*/
+CraftDefinitionShaped::CraftDefinitionShaped(
+ const std::string &output_,
+ unsigned int width_,
+ const std::vector<std::string> &recipe_,
+ const CraftReplacements &replacements_):
+ output(output_), width(width_), recipe(recipe_), replacements(replacements_)
+{
+ if (hasGroupItem(recipe))
+ priority = PRIORITY_SHAPED_AND_GROUPS;
+ else
+ priority = PRIORITY_SHAPED;
+}
+
std::string CraftDefinitionShaped::getName() const
{
return "shaped";
craftDecrementOrReplaceInput(input, output_replacements, replacements, gamedef);
}
-CraftHashType CraftDefinitionShaped::getHashType() const
-{
- assert(hash_inited); // Pre-condition
- bool has_group = false;
- for (const auto &recipe_name : recipe_names) {
- if (isGroupRecipeStr(recipe_name)) {
- has_group = true;
- break;
- }
- }
- if (has_group)
- return CRAFT_HASH_TYPE_COUNT;
-
- return CRAFT_HASH_TYPE_ITEM_NAMES;
-}
-
u64 CraftDefinitionShaped::getHash(CraftHashType type) const
{
assert(hash_inited); // Pre-condition
return;
hash_inited = true;
recipe_names = craftGetItemNames(recipe, gamedef);
+
+ if (hasGroupItem(recipe_names))
+ hash_type = CRAFT_HASH_TYPE_COUNT;
+ else
+ hash_type = CRAFT_HASH_TYPE_ITEM_NAMES;
}
std::string CraftDefinitionShaped::dump() const
CraftDefinitionShapeless
*/
+CraftDefinitionShapeless::CraftDefinitionShapeless(
+ const std::string &output_,
+ const std::vector<std::string> &recipe_,
+ const CraftReplacements &replacements_):
+ output(output_), recipe(recipe_), replacements(replacements_)
+{
+ if (hasGroupItem(recipe))
+ priority = PRIORITY_SHAPELESS_AND_GROUPS;
+ else
+ priority = PRIORITY_SHAPELESS;
+}
+
std::string CraftDefinitionShapeless::getName() const
{
return "shapeless";
craftDecrementOrReplaceInput(input, output_replacements, replacements, gamedef);
}
-CraftHashType CraftDefinitionShapeless::getHashType() const
-{
- assert(hash_inited); // Pre-condition
- bool has_group = false;
- for (const auto &recipe_name : recipe_names) {
- if (isGroupRecipeStr(recipe_name)) {
- has_group = true;
- break;
- }
- }
- if (has_group)
- return CRAFT_HASH_TYPE_COUNT;
-
- return CRAFT_HASH_TYPE_ITEM_NAMES;
-}
-
u64 CraftDefinitionShapeless::getHash(CraftHashType type) const
{
assert(hash_inited); // Pre-condition
hash_inited = true;
recipe_names = craftGetItemNames(recipe, gamedef);
std::sort(recipe_names.begin(), recipe_names.end());
+
+ if (hasGroupItem(recipe_names))
+ hash_type = CRAFT_HASH_TYPE_COUNT;
+ else
+ hash_type = CRAFT_HASH_TYPE_ITEM_NAMES;
}
std::string CraftDefinitionShapeless::dump() const
CraftDefinitionToolRepair
*/
+CraftDefinitionToolRepair::CraftDefinitionToolRepair(float additional_wear_):
+ additional_wear(additional_wear_)
+{
+ priority = PRIORITY_TOOLREPAIR;
+}
+
static ItemStack craftToolRepair(
const ItemStack &item1,
const ItemStack &item2,
IItemDefManager *idef = gamedef->idef();
if (item1.count != 1 || item2.count != 1 || item1.name != item2.name
|| idef->get(item1.name).type != ITEM_TOOL
- || idef->get(item2.name).type != ITEM_TOOL) {
+ || itemgroup_get(idef->get(item1.name).groups, "disable_repair") == 1) {
// Failure
return ItemStack();
}
CraftDefinitionCooking
*/
+CraftDefinitionCooking::CraftDefinitionCooking(
+ const std::string &output_,
+ const std::string &recipe_,
+ float cooktime_,
+ const CraftReplacements &replacements_):
+ output(output_), recipe(recipe_), cooktime(cooktime_), replacements(replacements_)
+{
+ if (isGroupRecipeStr(recipe))
+ priority = PRIORITY_SHAPELESS_AND_GROUPS;
+ else
+ priority = PRIORITY_SHAPELESS;
+}
+
std::string CraftDefinitionCooking::getName() const
{
return "cooking";
craftDecrementOrReplaceInput(input, output_replacements, replacements, gamedef);
}
-CraftHashType CraftDefinitionCooking::getHashType() const
-{
- if (isGroupRecipeStr(recipe_name))
- return CRAFT_HASH_TYPE_COUNT;
-
- return CRAFT_HASH_TYPE_ITEM_NAMES;
-}
-
u64 CraftDefinitionCooking::getHash(CraftHashType type) const
{
if (type == CRAFT_HASH_TYPE_ITEM_NAMES) {
return getHashForString(recipe_name);
}
+
if (type == CRAFT_HASH_TYPE_COUNT) {
return 1;
- } else {
- //illegal hash type for this CraftDefinition (pre-condition)
- assert(false);
- return 0;
}
+
+ // illegal hash type for this CraftDefinition (pre-condition)
+ assert(false);
+ return 0;
}
void CraftDefinitionCooking::initHash(IGameDef *gamedef)
return;
hash_inited = true;
recipe_name = craftGetItemName(recipe, gamedef);
+
+ if (isGroupRecipeStr(recipe_name))
+ hash_type = CRAFT_HASH_TYPE_COUNT;
+ else
+ hash_type = CRAFT_HASH_TYPE_ITEM_NAMES;
}
std::string CraftDefinitionCooking::dump() const
CraftDefinitionFuel
*/
+CraftDefinitionFuel::CraftDefinitionFuel(
+ const std::string &recipe_,
+ float burntime_,
+ const CraftReplacements &replacements_):
+ recipe(recipe_), burntime(burntime_), replacements(replacements_)
+{
+ if (isGroupRecipeStr(recipe_name))
+ priority = PRIORITY_SHAPELESS_AND_GROUPS;
+ else
+ priority = PRIORITY_SHAPELESS;
+}
+
std::string CraftDefinitionFuel::getName() const
{
return "fuel";
craftDecrementOrReplaceInput(input, output_replacements, replacements, gamedef);
}
-CraftHashType CraftDefinitionFuel::getHashType() const
-{
- if (isGroupRecipeStr(recipe_name))
- return CRAFT_HASH_TYPE_COUNT;
-
- return CRAFT_HASH_TYPE_ITEM_NAMES;
-}
-
u64 CraftDefinitionFuel::getHash(CraftHashType type) const
{
if (type == CRAFT_HASH_TYPE_ITEM_NAMES) {
if (type == CRAFT_HASH_TYPE_COUNT) {
return 1;
- } else {
- //illegal hash type for this CraftDefinition (pre-condition)
- assert(false);
- return 0;
}
+
+ // illegal hash type for this CraftDefinition (pre-condition)
+ assert(false);
+ return 0;
}
void CraftDefinitionFuel::initHash(IGameDef *gamedef)
return;
hash_inited = true;
recipe_name = craftGetItemName(recipe, gamedef);
+
+ if (isGroupRecipeStr(recipe_name))
+ hash_type = CRAFT_HASH_TYPE_COUNT;
+ else
+ hash_type = CRAFT_HASH_TYPE_ITEM_NAMES;
}
+
std::string CraftDefinitionFuel::dump() const
{
std::ostringstream os(std::ios::binary);
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::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 " << input.dump() << std::endl
<< " against " << def->dump() << std::endl;*/
- if (def->check(input, gamedef)) {
- // Get output, then decrement input (if requested)
- output = def->getOutput(input, gamedef);
- if (decrementInput)
- def->decrementInput(input, output_replacement, gamedef);
- /*errorstream << "Check RETURNS TRUE" << std::endl;*/
- return true;
+ 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;
}
}
}
- return false;
+ if (priority_best == CraftDefinition::PRIORITY_NO_RECIPE)
+ return false;
+ if (decrementInput)
+ def_best->decrementInput(input, output_replacement, gamedef);
+ return true;
}
virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
{
for (int type = 0; type <= craft_hash_type_max; ++type) {
for (auto &it : m_craft_defs[type]) {
- for (auto iit = it.second.begin();
- iit != it.second.end(); ++iit) {
- delete *iit;
+ for (auto &iit : it.second) {
+ delete iit;
}
it.second.clear();
}
unhashed.clear();
}
private:
- //TODO: change both maps to unordered_map when c++11 can be used
- std::vector<std::map<u64, std::vector<CraftDefinition*> > > m_craft_defs;
- std::map<std::string, std::vector<CraftDefinition*> > m_output_craft_definitions;
+ std::vector<std::unordered_map<u64, std::vector<CraftDefinition*> > >
+ m_craft_defs;
+ std::unordered_map<std::string, std::vector<CraftDefinition*> >
+ m_output_craft_definitions;
};
IWritableCraftDefManager* createCraftDefManager()