mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01:00 
			
		
		
		
	Prioritise craft recipes
When multiple recipes are applicable, the recipes are prioritised in this order: toolrepair < shapeless with groups < shapeless < shaped with groups < shaped For cooking and fuel, items are prioritised over item groups
This commit is contained in:
		@@ -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<CraftDefinition*> getCraftRecipes(CraftOutput &output,
 | 
			
		||||
 
 | 
			
		||||
@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user