X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fcraftdef.cpp;h=21060519839072636a897a13efb31c58645c535b;hb=e1142ee57f2d7b59a86f6d0d72ae043844bc3121;hp=922ea345ee5b73c92560e42f110c9c65aa743954;hpb=90e7d42375918636bf65fd6273675a576530778d;p=minetest.git diff --git a/src/craftdef.cpp b/src/craftdef.cpp index 922ea345e..210605198 100644 --- a/src/craftdef.cpp +++ b/src/craftdef.cpp @@ -37,6 +37,15 @@ inline bool isGroupRecipeStr(const std::string &rec_name) return str_starts_with(rec_name, std::string("group:")); } +static bool hasGroupItem(const std::vector &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 << '"';*/ @@ -112,6 +121,7 @@ static std::vector craftGetItemNames( const std::vector &itemstrings, IGameDef *gamedef) { std::vector result; + result.reserve(itemstrings.size()); for (const auto &itemstring : itemstrings) { result.push_back(craftGetItemName(itemstring, gamedef)); } @@ -123,6 +133,7 @@ static std::vector craftGetItemNames( const std::vector &items, IGameDef *gamedef) { std::vector result; + result.reserve(items.size()); for (const auto &item : items) { result.push_back(item.name); } @@ -134,6 +145,7 @@ static std::vector craftGetItems( const std::vector &items, IGameDef *gamedef) { std::vector result; + result.reserve(items.size()); for (const auto &item : items) { result.emplace_back(std::string(item), (u16)1, (u16)0, gamedef->getItemDefManager()); @@ -275,6 +287,15 @@ std::string craftDumpMatrix(const std::vector &items, CraftInput */ +bool CraftInput::empty() const +{ + for (const auto &item : items) { + if (!item.empty()) + return false; + } + return true; +} + std::string CraftInput::dump() const { std::ostringstream os(std::ios::binary); @@ -317,6 +338,19 @@ std::string CraftReplacements::dump() const CraftDefinitionShaped */ +CraftDefinitionShaped::CraftDefinitionShaped( + const std::string &output_, + unsigned int width_, + const std::vector &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"; @@ -404,22 +438,6 @@ void CraftDefinitionShaped::decrementInput(CraftInput &input, std::vector &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"; @@ -524,22 +559,6 @@ void CraftDefinitionShapeless::decrementInput(CraftInput &input, std::vectoridef(); 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(); } @@ -664,6 +694,19 @@ std::string CraftDefinitionToolRepair::dump() const 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"; @@ -712,14 +755,6 @@ void CraftDefinitionCooking::decrementInput(CraftInput &input, std::vector &output_replacement, bool decrementInput, IGameDef *gamedef) const { - output.item = ""; - output.time = 0; - - // If all input items are empty, abort. - bool all_empty = true; - for (const auto &item : input.items) { - if (!item.empty()) { - all_empty = false; - break; - } - } - if (all_empty) + if (input.empty()) return false; std::vector input_names; 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); @@ -906,7 +949,9 @@ class CCraftDefManager: public IWritableCraftDefManager /*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; @@ -917,17 +962,17 @@ class CCraftDefManager: public IWritableCraftDefManager 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::PRIORITY_NO_RECIPE) + return false; + if (decrementInput) + def_best->decrementInput(input, output_replacement, gamedef); + return true; } virtual std::vector getCraftRecipes(CraftOutput &output, @@ -955,84 +1000,48 @@ class CCraftDefManager: public IWritableCraftDefManager return recipes; } - virtual bool clearCraftRecipesByOutput(const CraftOutput &output, IGameDef *gamedef) + virtual bool clearCraftsByOutput(const CraftOutput &output, IGameDef *gamedef) { - auto vec_iter = m_output_craft_definitions.find(output.item); + auto to_clear = m_output_craft_definitions.find(output.item); - if (vec_iter == m_output_craft_definitions.end()) + if (to_clear == m_output_craft_definitions.end()) return false; - std::vector &vec = vec_iter->second; - for (auto def : vec) { + for (auto def : to_clear->second) { // 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); + std::vector &defs = m_craft_defs[(int)CRAFT_HASH_TYPE_UNHASHED][0]; + defs.erase(std::remove(defs.begin(), defs.end(), def), defs.end()); + delete def; } - m_output_craft_definitions.erase(output.item); + m_output_craft_definitions.erase(to_clear); return true; } - virtual bool clearCraftRecipesByInput(CraftMethod craft_method, unsigned int craft_grid_width, - const std::vector &recipe, IGameDef *gamedef) + virtual bool clearCraftsByInput(const CraftInput &input, IGameDef *gamedef) { - bool all_empty = true; - for (const auto &i : recipe) { - if (!i.empty()) { - all_empty = false; - break; - } - } - if (all_empty) + if (input.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; + std::vector &defs = m_craft_defs[(int)CRAFT_HASH_TYPE_UNHASHED][0]; + std::vector new_defs; 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. */ + for (auto def : defs) { if (!def->check(input, gamedef)) { - new_vec_by_input.push_back(def); + new_defs.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()) + std::string output = def->getOutput(input, gamedef).item; + delete def; + auto it = m_output_craft_definitions.find(craftGetItemName(output, gamedef)); + if (it == 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); + std::vector &outdefs = it->second; + outdefs.erase(std::remove(outdefs.begin(), outdefs.end(), def), outdefs.end()); } 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); + defs.swap(new_defs); return got_hit; } @@ -1057,8 +1066,8 @@ class CCraftDefManager: public IWritableCraftDefManager } virtual void registerCraft(CraftDefinition *def, IGameDef *gamedef) { - verbosestream << "registerCraft: registering craft definition: " - << def->dump() << std::endl; + TRACESTREAM(<< "registerCraft: registering craft definition: " + << def->dump() << std::endl); m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0].push_back(def); CraftInput input; @@ -1096,9 +1105,10 @@ class CCraftDefManager: public IWritableCraftDefManager unhashed.clear(); } private: - //TODO: change both maps to unordered_map when c++11 can be used - std::vector > > m_craft_defs; - std::map > m_output_craft_definitions; + std::vector > > + m_craft_defs; + std::unordered_map > + m_output_craft_definitions; }; IWritableCraftDefManager* createCraftDefManager()