^ output.item = ItemStack, if unsuccessful: empty ItemStack
^ output.time = number, if unsuccessful: 0
^ decremented_input = like input
+minetest.get_craft_recipe(output) -> input
+^ output is a node or item type such as 'default:torch'
+^ input.method = 'normal' or 'cooking' or 'fuel'
+^ input.width = for example 3
+^ input.items = for example { stack 1, stack 2, stack 3, stack 4,
+ stack 5, stack 6, stack 7, stack 8, stack 9 }
+^ input.items = nil if no recipe found
Defaults for the on_* item definition functions:
(These return the leftover itemstack)
// Exact name
if(inp_name == rec_name)
return true;
-
+
// Group
if(rec_name.substr(0,6) == "group:" && idef->isKnown(inp_name)){
std::string rec_group = rec_name.substr(6);
if(itemgroup_get(def.groups, rec_group) != 0)
return true;
}
-
+
// Didn't match
return false;
}
return result;
}
+// convert a list of item names, to ItemStacks.
+static std::vector<ItemStack> craftGetItems(
+ const std::vector<std::string> &items, IGameDef *gamedef)
+{
+ std::vector<ItemStack> result;
+ for(std::vector<std::string>::const_iterator
+ i = items.begin();
+ i != items.end(); i++)
+ {
+ result.push_back(ItemStack(std::string(*i),(u16)1,(u16)0,"",gamedef->getItemDefManager()));
+ }
+ return result;
+}
+
// Compute bounding rectangle given a matrix of items
// Returns false if every item is ""
static bool craftGetBounds(const std::vector<std::string> &items, unsigned int width,
return CraftOutput(output, 0);
}
+CraftInput CraftDefinitionShaped::getInput(const CraftOutput &output, IGameDef *gamedef) const
+{
+ return CraftInput(CRAFT_METHOD_NORMAL,width,craftGetItems(recipe,gamedef));
+}
+
void CraftDefinitionShaped::decrementInput(CraftInput &input, IGameDef *gamedef) const
{
craftDecrementOrReplaceInput(input, replacements, gamedef);
return CraftOutput(output, 0);
}
+CraftInput CraftDefinitionShapeless::getInput(const CraftOutput &output, IGameDef *gamedef) const
+{
+ return CraftInput(CRAFT_METHOD_NORMAL,0,craftGetItems(recipe,gamedef));
+}
+
void CraftDefinitionShapeless::decrementInput(CraftInput &input, IGameDef *gamedef) const
{
craftDecrementOrReplaceInput(input, replacements, gamedef);
return CraftOutput(repaired.getItemString(), 0);
}
+CraftInput CraftDefinitionToolRepair::getInput(const CraftOutput &output, IGameDef *gamedef) const
+{
+ std::vector<ItemStack> stack;
+ stack.push_back(ItemStack());
+ return CraftInput(CRAFT_METHOD_COOKING,additional_wear,stack);
+}
+
void CraftDefinitionToolRepair::decrementInput(CraftInput &input, IGameDef *gamedef) const
{
craftDecrementInput(input, gamedef);
return CraftOutput(output, cooktime);
}
+CraftInput CraftDefinitionCooking::getInput(const CraftOutput &output, IGameDef *gamedef) const
+{
+ std::vector<std::string> rec;
+ rec.push_back(recipe);
+ return CraftInput(CRAFT_METHOD_COOKING,cooktime,craftGetItems(rec,gamedef));
+}
+
void CraftDefinitionCooking::decrementInput(CraftInput &input, IGameDef *gamedef) const
{
craftDecrementOrReplaceInput(input, replacements, gamedef);
return CraftOutput("", burntime);
}
+CraftInput CraftDefinitionFuel::getInput(const CraftOutput &output, IGameDef *gamedef) const
+{
+ std::vector<std::string> rec;
+ rec.push_back(recipe);
+ return CraftInput(CRAFT_METHOD_COOKING,(int)burntime,craftGetItems(rec,gamedef));
+}
+
void CraftDefinitionFuel::decrementInput(CraftInput &input, IGameDef *gamedef) const
{
craftDecrementOrReplaceInput(input, replacements, gamedef);
}
return false;
}
+ virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
+ IGameDef *gamedef) const
+ {
+ CraftOutput tmpout;
+ tmpout.item = "";
+ tmpout.time = 0;
+
+ // If output item is empty, abort.
+ if(output.item.empty())
+ return false;
+
+ // Walk crafting definitions from back to front, so that later
+ // definitions can override earlier ones.
+ for(std::vector<CraftDefinition*>::const_reverse_iterator
+ i = m_craft_definitions.rbegin();
+ i != m_craft_definitions.rend(); i++)
+ {
+ CraftDefinition *def = *i;
+
+ /*infostream<<"Checking "<<input.dump()<<std::endl
+ <<" against "<<def->dump()<<std::endl;*/
+
+ try {
+ tmpout = def->getOutput(input, gamedef);
+ if(tmpout.item.substr(0,output.item.length()) == output.item)
+ {
+ // Get output, then decrement input (if requested)
+ input = def->getInput(output, gamedef);
+ return true;
+ }
+ }
+ catch(SerializationError &e)
+ {
+ errorstream<<"getCraftResult: ERROR: "
+ <<"Serialization error in recipe "
+ <<def->dump()<<std::endl;
+ // then go on with the next craft definition
+ }
+ }
+ return false;
+ }
virtual std::string dump() const
{
std::ostringstream os(std::ios::binary);
// 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;
+ // the inverse of the above
+ virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const=0;
// Decreases count of every input item
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const=0;
virtual std::string getName() const;
virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+ virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
virtual std::string dump() const;
virtual std::string getName() const;
virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+ virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
virtual std::string dump() const;
virtual std::string getName() const;
virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+ virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
virtual std::string dump() const;
virtual std::string getName() const;
virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+ virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
virtual std::string dump() const;
virtual std::string getName() const;
virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(const CraftInput &input, IGameDef *gamedef) const;
+ virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const;
virtual std::string dump() const;
// The main crafting function
virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
bool decrementInput, IGameDef *gamedef) const=0;
+ virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
+ IGameDef *gamedef) const=0;
// Print crafting recipes for debugging
virtual std::string dump() const=0;
// The main crafting function
virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
bool decrementInput, IGameDef *gamedef) const=0;
+ virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
+ IGameDef *gamedef) const=0;
// Print crafting recipes for debugging
virtual std::string dump() const=0;
return 2;
}
+// get_craft_recipe(result item)
+static int l_get_craft_recipe(lua_State *L)
+{
+ int k = 0;
+ char tmp[20];
+ int input_i = 1;
+ std::string o_item = luaL_checkstring(L,input_i);
+
+ IGameDef *gdef = get_server(L);
+ ICraftDefManager *cdef = gdef->cdef();
+ CraftInput input;
+ CraftOutput output(o_item,0);
+ bool got = cdef->getCraftRecipe(input, output, gdef);
+ lua_newtable(L); // output table
+ if(got){
+ lua_newtable(L);
+ for(std::vector<ItemStack>::const_iterator
+ i = input.items.begin();
+ i != input.items.end(); i++, k++)
+ {
+ if (i->empty())
+ {
+ continue;
+ }
+ sprintf(tmp,"%d",k);
+ lua_pushstring(L,tmp);
+ lua_pushstring(L,i->name.c_str());
+ lua_settable(L, -3);
+ }
+ lua_setfield(L, -2, "items");
+ setintfield(L, -1, "width", input.width);
+ switch (input.method) {
+ case CRAFT_METHOD_NORMAL:
+ lua_pushstring(L,"noraml");
+ break;
+ case CRAFT_METHOD_COOKING:
+ lua_pushstring(L,"cooking");
+ break;
+ case CRAFT_METHOD_FUEL:
+ lua_pushstring(L,"fuel");
+ break;
+ default:
+ lua_pushstring(L,"unknown");
+ }
+ lua_setfield(L, -2, "type");
+ } else {
+ lua_pushnil(L);
+ lua_setfield(L, -2, "items");
+ setintfield(L, -1, "width", 0);
+ }
+ return 1;
+}
+
static const struct luaL_Reg minetest_f [] = {
{"debug", l_debug},
{"log", l_log},
{"get_password_hash", l_get_password_hash},
{"notify_authentication_modified", l_notify_authentication_modified},
{"get_craft_result", l_get_craft_result},
+ {"get_craft_recipe", l_get_craft_recipe},
{NULL, NULL}
};