X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fcraftdef.cpp;h=8aa8099306bec44b268b833367851bdacdc91bc7;hb=1d4a2a6ea7608a9fbe8de07dde8a48476c9f5e0d;hp=bad0d393b2bf76ff38e84c53184aa32985b664cd;hpb=87b9cdab07f70a7f2dd6531650242b0893eb5930;p=minetest.git diff --git a/src/craftdef.cpp b/src/craftdef.cpp index bad0d393b..8aa809930 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,10 +112,8 @@ static std::vector craftGetItemNames( const std::vector &itemstrings, IGameDef *gamedef) { std::vector result; - for (std::vector::const_iterator - it = itemstrings.begin(); - it != itemstrings.end(); it++) { - result.push_back(craftGetItemName(*it, gamedef)); + for (const auto &itemstring : itemstrings) { + result.push_back(craftGetItemName(itemstring, gamedef)); } return result; } @@ -125,10 +123,8 @@ static std::vector craftGetItemNames( const std::vector &items, IGameDef *gamedef) { std::vector result; - for (std::vector::const_iterator - it = items.begin(); - it != items.end(); it++) { - result.push_back(it->name); + for (const auto &item : items) { + result.push_back(item.name); } return result; } @@ -138,11 +134,9 @@ static std::vector craftGetItems( const std::vector &items, IGameDef *gamedef) { std::vector result; - for (std::vector::const_iterator - it = items.begin(); - it != items.end(); it++) { - result.push_back(ItemStack(std::string(*it), (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; } @@ -156,11 +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::const_iterator - it = items.begin(); - it != items.end(); it++) { + for (const std::string &item : items) { // Is this an actual item? - if (*it != "") { + if (!item.empty()) { if (!success) { // This is the first nonempty item min_x = max_x = x; @@ -187,11 +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::iterator - it = input.items.begin(); - it != input.items.end(); it++) { - if (it->count != 0) - it->remove(1); + for (auto &item : input.items) { + if (item.count != 0) + item.remove(1); } } @@ -211,33 +201,30 @@ static void craftDecrementOrReplaceInput(CraftInput &input, // Make a copy of the replacements pair list std::vector > pairs = replacements.pairs; - for (std::vector::iterator - it = input.items.begin(); - it != input.items.end(); it++) { + for (auto &item : input.items) { // Find an appropriate replacement bool found_replacement = false; - for (std::vector >::iterator - j = pairs.begin(); - j != pairs.end(); j++) { - if (it->name == craftGetItemName(j->first, gamedef)) { - if (it->count == 1) { - it->deSerialize(j->second, gamedef->idef()); + 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()); - it->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 - if (!found_replacement && it->count > 0) - it->remove(1); + if (!found_replacement && item.count > 0) + item.remove(1); } } @@ -246,18 +233,17 @@ static std::string craftDumpMatrix(const std::vector &items, unsigned int width) { std::ostringstream os(std::ios::binary); - os<<"{ "; + os << "{ "; unsigned int x = 0; - for(std::vector::const_iterator - it = items.begin(); - it != items.end(); it++, x++) { + for(std::vector::size_type i = 0; + i < items.size(); i++, x++) { if (x == width) { - os<<"; "; + os << "; "; x = 0; } else if (x != 0) { - os<<","; + os << ","; } - os << '"' << (*it) << '"'; + os << '"' << items[i] << '"'; } os << " }"; return os.str(); @@ -270,16 +256,15 @@ std::string craftDumpMatrix(const std::vector &items, std::ostringstream os(std::ios::binary); os << "{ "; unsigned int x = 0; - for (std::vector::const_iterator - it = items.begin(); - it != items.end(); it++, x++) { + for (std::vector::size_type i = 0; + i < items.size(); i++, x++) { if (x == width) { os << "; "; x = 0; } else if (x != 0) { - os<<","; + os << ","; } - os << '"' << (it->getItemString()) << '"'; + os << '"' << (items[i].getItemString()) << '"'; } os << " }"; return os.str(); @@ -318,10 +303,10 @@ std::string CraftReplacements::dump() const std::ostringstream os(std::ios::binary); os<<"{"; const char *sep = ""; - for (std::vector >::const_iterator - it = pairs.begin(); - it != pairs.end(); it++) { - os << sep << '"' << (it->first) << "\"=>\"" << (it->second) << '"'; + for (const auto &repl_p : pairs) { + os << sep + << '"' << (repl_p.first) + << "\"=>\"" << (repl_p.second) << '"'; sep = ","; } os << "}"; @@ -348,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; @@ -367,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; @@ -423,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 @@ -479,11 +464,9 @@ bool CraftDefinitionShapeless::check(const CraftInput &input, IGameDef *gamedef) // Filter empty items out of input std::vector input_filtered; - for (std::vector::const_iterator - it = input.items.begin(); - it != input.items.end(); it++) { - if (it->name != "") - input_filtered.push_back(it->name); + for (const auto &item : input.items) { + if (!item.name.empty()) + input_filtered.push_back(item.name); } // If there is a wrong number of items in input, no match @@ -545,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 @@ -627,14 +610,12 @@ bool CraftDefinitionToolRepair::check(const CraftInput &input, IGameDef *gamedef ItemStack item1; ItemStack item2; - for (std::vector::const_iterator - it = input.items.begin(); - it != input.items.end(); it++) { - if (!it->empty()) { + for (const auto &item : input.items) { + if (!item.empty()) { if (item1.empty()) - item1 = *it; + item1 = item; else if (item2.empty()) - item2 = *it; + item2 = item; else return false; } @@ -647,14 +628,12 @@ CraftOutput CraftDefinitionToolRepair::getOutput(const CraftInput &input, IGameD { ItemStack item1; ItemStack item2; - for (std::vector::const_iterator - it = input.items.begin(); - it != input.items.end(); it++) { - if (!it->empty()) { + for (const auto &item : input.items) { + if (!item.empty()) { if (item1.empty()) - item1 = *it; + item1 = item; else if (item2.empty()) - item2 = *it; + item2 = item; } } ItemStack repaired = craftToolRepair(item1, item2, additional_wear, gamedef); @@ -664,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); } @@ -697,11 +676,10 @@ bool CraftDefinitionCooking::check(const CraftInput &input, IGameDef *gamedef) c // Filter empty items out of input std::vector input_filtered; - for (std::vector::const_iterator - it = input.items.begin(); - it != input.items.end(); it++) { - if (it->name != "") - input_filtered.push_back(it->name); + for (const auto &item : input.items) { + const std::string &name = item.name; + if (!name.empty()) + input_filtered.push_back(name); } // If there is a wrong number of items in input, no match @@ -738,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) @@ -789,11 +769,10 @@ bool CraftDefinitionFuel::check(const CraftInput &input, IGameDef *gamedef) cons // Filter empty items out of input std::vector input_filtered; - for (std::vector::const_iterator - it = input.items.begin(); - it != input.items.end(); it++) { - if (it->name != "") - input_filtered.push_back(it->name); + for (const auto &item : input.items) { + const std::string &name = item.name; + if (!name.empty()) + input_filtered.push_back(name); } // If there is a wrong number of items in input, no match @@ -830,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) @@ -889,10 +870,8 @@ class CCraftDefManager: public IWritableCraftDefManager // If all input items are empty, abort. bool all_empty = true; - for (std::vector::const_iterator - it = input.items.begin(); - it != input.items.end(); it++) { - if (!it->empty()) { + for (const auto &item : input.items) { + if (!item.empty()) { all_empty = false; break; } @@ -912,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; @@ -921,10 +899,9 @@ class CCraftDefManager: public IWritableCraftDefManager const std::vector &hash_collisions = col_iter->second; // Walk crafting definitions from back to front, so that later // definitions can override earlier ones. - for (std::vector::const_reverse_iterator - it = hash_collisions.rbegin(); - it != hash_collisions.rend(); it++) { - CraftDefinition *def = *it; + for (std::vector::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;*/ @@ -947,8 +924,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; @@ -957,26 +933,112 @@ class CCraftDefManager: public IWritableCraftDefManager recipes.reserve(limit ? MYMIN(limit, vec.size()) : vec.size()); - for (std::vector::const_reverse_iterator - it = vec.rbegin(); it != vec.rend(); ++it) { + for (std::vector::size_type i = vec.size(); + i > 0; i--) { + CraftDefinition *def = vec[i - 1]; if (limit && recipes.size() >= limit) break; - recipes.push_back(*it); + recipes.push_back(def); } 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 (std::vector::const_iterator - iit = it->second.begin(); iit != it->second.end(); iit++) { - os << "type " << type << " hash " << it->first << (*iit)->dump() << "\n"; + for (int type = 0; type <= craft_hash_type_max; ++type) { + 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 + << " hash " << it->first + << " def " << it->second[i]->dump() + << "\n"; } } } @@ -995,15 +1057,12 @@ 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 (int type = 0; type <= craft_hash_type_max; ++type) { + 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,11 +1071,9 @@ class CCraftDefManager: public IWritableCraftDefManager virtual void initHashes(IGameDef *gamedef) { // Move the CraftDefs from the unhashed layer into layers higher up. - for (std::vector::iterator - it = (m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0]).begin(); - it != (m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0]).end(); it++) { - CraftDefinition *def = *it; - + std::vector &unhashed = + m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0]; + for (auto def : unhashed) { // Initialize and get the definition's hash def->initHash(gamedef); CraftHashType type = def->getHashType(); @@ -1025,7 +1082,7 @@ class CCraftDefManager: public IWritableCraftDefManager // Enter the definition m_craft_defs[type][hash].push_back(def); } - m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0].clear(); + unhashed.clear(); } private: //TODO: change both maps to unordered_map when c++11 can be used @@ -1037,4 +1094,3 @@ IWritableCraftDefManager* createCraftDefManager() { return new CCraftDefManager(); } -