X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fcraftdef.cpp;h=922ea345ee5b73c92560e42f110c9c65aa743954;hb=b4df0d67dd9fca20df632f0247b97f8370757a3c;hp=67c3ae62ac39205be2f37abc7f15457c1aba58d2;hpb=3f8eb5e0d0a7dd30bfd6b805d6c03e0f45182e9a;p=minetest.git diff --git a/src/craftdef.cpp b/src/craftdef.cpp index 67c3ae62a..922ea345e 100644 --- a/src/craftdef.cpp +++ b/src/craftdef.cpp @@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/serialize.h" #include "util/string.h" #include "util/numeric.h" -#include "strfnd.h" +#include "util/strfnd.h" #include "exceptions.h" inline bool isGroupRecipeStr(const std::string &rec_name) @@ -49,17 +49,17 @@ static u64 getHashForGrid(CraftHashType type, const std::vector &gr 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] != "") { - 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] != "") + for (const std::string &grid_name : grid_names) + if (!grid_name.empty()) cnt++; return cnt; } case CRAFT_HASH_TYPE_UNHASHED: @@ -90,7 +90,7 @@ static bool inputItemMatchesRecipe(const std::string &inp_name, all_groups_match = false; break; } - } while (!f.atend()); + } while (!f.at_end()); if (all_groups_match) return true; } @@ -112,9 +112,8 @@ static std::vector craftGetItemNames( const std::vector &itemstrings, IGameDef *gamedef) { std::vector result; - for (std::vector::size_type i = 0; - i < itemstrings.size(); i++) { - result.push_back(craftGetItemName(itemstrings[i], gamedef)); + for (const auto &itemstring : itemstrings) { + result.push_back(craftGetItemName(itemstring, gamedef)); } return result; } @@ -124,9 +123,8 @@ static std::vector craftGetItemNames( const std::vector &items, IGameDef *gamedef) { std::vector result; - for (std::vector::size_type i = 0; - i < items.size(); i++) { - result.push_back(items[i].name); + for (const auto &item : items) { + result.push_back(item.name); } return result; } @@ -136,10 +134,9 @@ static std::vector craftGetItems( const std::vector &items, IGameDef *gamedef) { std::vector result; - for (std::vector::size_type i = 0; - i < items.size(); i++) { - result.push_back(ItemStack(std::string(items[i]), (u16)1, - (u16)0, "", gamedef->getItemDefManager())); + for (const auto &item : items) { + result.emplace_back(std::string(item), (u16)1, + (u16)0, gamedef->getItemDefManager()); } return result; } @@ -153,10 +150,9 @@ static bool craftGetBounds(const std::vector &items, unsigned int w bool success = false; unsigned int x = 0; unsigned int y = 0; - for (std::vector::size_type i = 0; - i < items.size(); i++) { + for (const std::string &item : items) { // Is this an actual item? - if (items[i] != "") { + if (!item.empty()) { if (!success) { // This is the first nonempty item min_x = max_x = x; @@ -183,10 +179,9 @@ static bool craftGetBounds(const std::vector &items, unsigned int w // Removes 1 from each item stack static void craftDecrementInput(CraftInput &input, IGameDef *gamedef) { - for (std::vector::size_type i = 0; - i < input.items.size(); i++) { - if (input.items[i].count != 0) - input.items[i].remove(1); + for (auto &item : input.items) { + if (item.count != 0) + item.remove(1); } } @@ -206,28 +201,25 @@ static void craftDecrementOrReplaceInput(CraftInput &input, // Make a copy of the replacements pair list std::vector > pairs = replacements.pairs; - for (std::vector::size_type i = 0; - i < input.items.size(); i++) { - ItemStack &item = input.items[i]; + for (auto &item : input.items) { // Find an appropriate replacement bool found_replacement = false; - for (std::vector >::iterator - j = pairs.begin(); - j != pairs.end(); ++j) { + for (auto j = pairs.begin(); j != pairs.end(); ++j) { if (inputItemMatchesRecipe(item.name, j->first, gamedef->idef())) { if (item.count == 1) { item.deSerialize(j->second, gamedef->idef()); found_replacement = true; pairs.erase(j); break; - } else { - ItemStack rep; - rep.deSerialize(j->second, gamedef->idef()); - item.remove(1); - found_replacement = true; - output_replacements.push_back(rep); - break; } + + ItemStack rep; + rep.deSerialize(j->second, gamedef->idef()); + item.remove(1); + found_replacement = true; + output_replacements.push_back(rep); + break; + } } // No replacement was found, simply decrement count by one @@ -311,9 +303,7 @@ std::string CraftReplacements::dump() const std::ostringstream os(std::ios::binary); os<<"{"; const char *sep = ""; - for (std::vector >::size_type i = 0; - i < pairs.size(); i++) { - const std::pair &repl_p = pairs[i]; + for (const auto &repl_p : pairs) { os << sep << '"' << (repl_p.first) << "\"=>\"" << (repl_p.second) << '"'; @@ -343,7 +333,7 @@ bool CraftDefinitionShaped::check(const CraftInput &input, IGameDef *gamedef) co if (inp_width == 0) return false; while (inp_names.size() % inp_width != 0) - inp_names.push_back(""); + inp_names.emplace_back(""); // Get input bounds unsigned int inp_min_x = 0, inp_max_x = 0, inp_min_y = 0, inp_max_y = 0; @@ -362,7 +352,7 @@ bool CraftDefinitionShaped::check(const CraftInput &input, IGameDef *gamedef) co if (rec_width == 0) return false; while (rec_names.size() % rec_width != 0) - rec_names.push_back(""); + rec_names.emplace_back(""); // Get recipe bounds unsigned int rec_min_x=0, rec_max_x=0, rec_min_y=0, rec_max_y=0; @@ -418,16 +408,16 @@ CraftHashType CraftDefinitionShaped::getHashType() const { assert(hash_inited); // Pre-condition bool has_group = false; - for (size_t i = 0; i < recipe_names.size(); i++) { - if (isGroupRecipeStr(recipe_names[i])) { + for (const auto &recipe_name : recipe_names) { + if (isGroupRecipeStr(recipe_name)) { has_group = true; break; } } if (has_group) return CRAFT_HASH_TYPE_COUNT; - else - return CRAFT_HASH_TYPE_ITEM_NAMES; + + return CRAFT_HASH_TYPE_ITEM_NAMES; } u64 CraftDefinitionShaped::getHash(CraftHashType type) const @@ -474,10 +464,8 @@ bool CraftDefinitionShapeless::check(const CraftInput &input, IGameDef *gamedef) // Filter empty items out of input std::vector input_filtered; - for (std::vector::size_type i = 0; - i < input.items.size(); i++) { - const ItemStack &item = input.items[i]; - if (item.name != "") + for (const auto &item : input.items) { + if (!item.name.empty()) input_filtered.push_back(item.name); } @@ -540,16 +528,16 @@ CraftHashType CraftDefinitionShapeless::getHashType() const { assert(hash_inited); // Pre-condition bool has_group = false; - for (size_t i = 0; i < recipe_names.size(); i++) { - if (isGroupRecipeStr(recipe_names[i])) { + for (const auto &recipe_name : recipe_names) { + if (isGroupRecipeStr(recipe_name)) { has_group = true; break; } } if (has_group) return CRAFT_HASH_TYPE_COUNT; - else - return CRAFT_HASH_TYPE_ITEM_NAMES; + + return CRAFT_HASH_TYPE_ITEM_NAMES; } u64 CraftDefinitionShapeless::getHash(CraftHashType type) const @@ -622,9 +610,7 @@ bool CraftDefinitionToolRepair::check(const CraftInput &input, IGameDef *gamedef ItemStack item1; ItemStack item2; - for (std::vector::size_type i = 0; - i < input.items.size(); i++) { - const ItemStack &item = input.items[i]; + for (const auto &item : input.items) { if (!item.empty()) { if (item1.empty()) item1 = item; @@ -642,9 +628,7 @@ CraftOutput CraftDefinitionToolRepair::getOutput(const CraftInput &input, IGameD { ItemStack item1; ItemStack item2; - for (std::vector::size_type i = 0; - i < input.items.size(); i++) { - const ItemStack &item = input.items[i]; + for (const auto &item : input.items) { if (!item.empty()) { if (item1.empty()) item1 = item; @@ -659,7 +643,7 @@ CraftOutput CraftDefinitionToolRepair::getOutput(const CraftInput &input, IGameD CraftInput CraftDefinitionToolRepair::getInput(const CraftOutput &output, IGameDef *gamedef) const { std::vector stack; - stack.push_back(ItemStack()); + stack.emplace_back(); return CraftInput(CRAFT_METHOD_COOKING, additional_wear, stack); } @@ -692,10 +676,9 @@ bool CraftDefinitionCooking::check(const CraftInput &input, IGameDef *gamedef) c // Filter empty items out of input std::vector input_filtered; - for (std::vector::size_type i = 0; - i < input.items.size(); i++) { - const std::string &name = input.items[i].name; - if (name != "") + for (const auto &item : input.items) { + const std::string &name = item.name; + if (!name.empty()) input_filtered.push_back(name); } @@ -733,21 +716,23 @@ CraftHashType CraftDefinitionCooking::getHashType() const { if (isGroupRecipeStr(recipe_name)) return CRAFT_HASH_TYPE_COUNT; - else - return CRAFT_HASH_TYPE_ITEM_NAMES; + + return CRAFT_HASH_TYPE_ITEM_NAMES; } u64 CraftDefinitionCooking::getHash(CraftHashType type) const { if (type == CRAFT_HASH_TYPE_ITEM_NAMES) { return getHashForString(recipe_name); - } else if (type == CRAFT_HASH_TYPE_COUNT) { + } + + 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) @@ -784,10 +769,9 @@ bool CraftDefinitionFuel::check(const CraftInput &input, IGameDef *gamedef) cons // Filter empty items out of input std::vector input_filtered; - for (std::vector::size_type i = 0; - i < input.items.size(); i++) { - const std::string &name = input.items[i].name; - if (name != "") + for (const auto &item : input.items) { + const std::string &name = item.name; + if (!name.empty()) input_filtered.push_back(name); } @@ -825,21 +809,23 @@ CraftHashType CraftDefinitionFuel::getHashType() const { if (isGroupRecipeStr(recipe_name)) return CRAFT_HASH_TYPE_COUNT; - else - return CRAFT_HASH_TYPE_ITEM_NAMES; + + return CRAFT_HASH_TYPE_ITEM_NAMES; } u64 CraftDefinitionFuel::getHash(CraftHashType type) const { if (type == CRAFT_HASH_TYPE_ITEM_NAMES) { return getHashForString(recipe_name); - } else if (type == CRAFT_HASH_TYPE_COUNT) { + } + + 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) @@ -884,9 +870,8 @@ class CCraftDefManager: public IWritableCraftDefManager // If all input items are empty, abort. bool all_empty = true; - for (std::vector::size_type i = 0; - i < input.items.size(); i++) { - if (!input.items[i].empty()) { + for (const auto &item : input.items) { + if (!item.empty()) { all_empty = false; break; } @@ -906,8 +891,7 @@ class CCraftDefManager: public IWritableCraftDefManager // We'd like to do "const [...] hash_collisions = m_craft_defs[type][hash];" // but that doesn't compile for some reason. This does. - std::map >::const_iterator - col_iter = (m_craft_defs[type]).find(hash); + auto col_iter = (m_craft_defs[type]).find(hash); if (col_iter == (m_craft_defs[type]).end()) continue; @@ -923,8 +907,19 @@ class CCraftDefManager: public IWritableCraftDefManager << " against " << def->dump() << std::endl;*/ if (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; + } + // Get output, then decrement input (if requested) - output = def->getOutput(input, gamedef); + output = out; + if (decrementInput) def->decrementInput(input, output_replacement, gamedef); /*errorstream << "Check RETURNS TRUE" << std::endl;*/ @@ -940,8 +935,7 @@ class CCraftDefManager: public IWritableCraftDefManager { std::vector recipes; - std::map >::const_iterator - vec_iter = m_output_craft_definitions.find(output.item); + auto vec_iter = m_output_craft_definitions.find(output.item); if (vec_iter == m_output_craft_definitions.end()) return recipes; @@ -960,14 +954,96 @@ class CCraftDefManager: public IWritableCraftDefManager return recipes; } + + virtual bool clearCraftRecipesByOutput(const CraftOutput &output, IGameDef *gamedef) + { + auto vec_iter = m_output_craft_definitions.find(output.item); + + if (vec_iter == m_output_craft_definitions.end()) + return false; + + std::vector &vec = vec_iter->second; + for (auto def : vec) { + // Recipes are not yet hashed at this point + std::vector &unhashed_inputs_vec = m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0]; + std::vector new_vec_by_input; + /* We will preallocate necessary memory addresses, so we don't need to reallocate them later. + This would save us some performance. */ + new_vec_by_input.reserve(unhashed_inputs_vec.size()); + for (auto &i2 : unhashed_inputs_vec) { + if (def != i2) { + new_vec_by_input.push_back(i2); + } + } + m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0].swap(new_vec_by_input); + } + m_output_craft_definitions.erase(output.item); + return true; + } + + virtual bool clearCraftRecipesByInput(CraftMethod craft_method, unsigned int craft_grid_width, + const std::vector &recipe, IGameDef *gamedef) + { + bool all_empty = true; + for (const auto &i : recipe) { + if (!i.empty()) { + all_empty = false; + break; + } + } + if (all_empty) + return false; + + CraftInput input(craft_method, craft_grid_width, craftGetItems(recipe, gamedef)); + // Recipes are not yet hashed at this point + std::vector &unhashed_inputs_vec = m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0]; + std::vector new_vec_by_input; + bool got_hit = false; + for (std::vector::size_type + i = unhashed_inputs_vec.size(); i > 0; i--) { + CraftDefinition *def = unhashed_inputs_vec[i - 1]; + /* If the input doesn't match the recipe definition, this recipe definition later + will be added back in source map. */ + if (!def->check(input, gamedef)) { + new_vec_by_input.push_back(def); + continue; + } + CraftOutput output = def->getOutput(input, gamedef); + got_hit = true; + auto vec_iter = m_output_craft_definitions.find(output.item); + if (vec_iter == m_output_craft_definitions.end()) + continue; + std::vector &vec = vec_iter->second; + std::vector new_vec_by_output; + /* We will preallocate necessary memory addresses, so we don't need + to reallocate them later. This would save us some performance. */ + new_vec_by_output.reserve(vec.size()); + for (auto &vec_i : vec) { + /* If pointers from map by input and output are not same, + we will add 'CraftDefinition*' to a new vector. */ + if (def != vec_i) { + /* Adding dereferenced iterator value (which are + 'CraftDefinition' reference) to a new vector. */ + new_vec_by_output.push_back(vec_i); + } + } + // Swaps assigned to current key value with new vector for output map. + m_output_craft_definitions[output.item].swap(new_vec_by_output); + } + if (got_hit) + // Swaps value with new vector for input map. + m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0].swap(new_vec_by_input); + + return got_hit; + } + virtual std::string dump() const { std::ostringstream os(std::ios::binary); os << "Crafting definitions:\n"; for (int type = 0; type <= craft_hash_type_max; ++type) { - for (std::map >::const_iterator - it = (m_craft_defs[type]).begin(); - it != (m_craft_defs[type]).end(); ++it) { + for (auto it = m_craft_defs[type].begin(); + it != m_craft_defs[type].end(); ++it) { for (std::vector::size_type i = 0; i < it->second.size(); i++) { os << "type " << type @@ -993,15 +1069,11 @@ class CCraftDefManager: public IWritableCraftDefManager virtual void clear() { for (int type = 0; type <= craft_hash_type_max; ++type) { - for (std::map >::iterator - it = m_craft_defs[type].begin(); - it != m_craft_defs[type].end(); ++it) { - for (std::vector::iterator - iit = it->second.begin(); - iit != it->second.end(); ++iit) { - delete *iit; + for (auto &it : m_craft_defs[type]) { + for (auto &iit : it.second) { + delete iit; } - it->second.clear(); + it.second.clear(); } m_craft_defs[type].clear(); } @@ -1012,10 +1084,7 @@ class CCraftDefManager: public IWritableCraftDefManager // Move the CraftDefs from the unhashed layer into layers higher up. std::vector &unhashed = m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0]; - for (std::vector::size_type i = 0; - i < unhashed.size(); i++) { - CraftDefinition *def = unhashed[i]; - + for (auto def : unhashed) { // Initialize and get the definition's hash def->initHash(gamedef); CraftHashType type = def->getHashType(); @@ -1036,4 +1105,3 @@ IWritableCraftDefManager* createCraftDefManager() { return new CCraftDefManager(); } -