Fix bug when craft input isn't replaced

This commit is contained in:
TeTpaAka 2015-06-02 20:30:04 +02:00 committed by est31
parent 0b76e85a71
commit 17ba584fe2
7 changed files with 128 additions and 59 deletions

@ -2077,6 +2077,8 @@ and `minetest.auth_reload` call the authetification handler.
`{ stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9 }` `{ stack1, stack2, stack3, stack4, stack 5, stack 6, stack 7, stack 8, stack 9 }`
* `output.item` = `ItemStack`, if unsuccessful: empty `ItemStack` * `output.item` = `ItemStack`, if unsuccessful: empty `ItemStack`
* `output.time` = a number, if unsuccessful: `0` * `output.time` = a number, if unsuccessful: `0`
* `output.replacements` = list of `ItemStack`s that couldn't be placed in
`decremented_input.items`
* `decremented_input` = like `input` * `decremented_input` = like `input`
* `minetest.get_craft_recipe(output)`: returns input * `minetest.get_craft_recipe(output)`: returns input
* returns last registered recipe for output item (node) * returns last registered recipe for output item (node)

@ -199,6 +199,7 @@ static void craftDecrementInput(CraftInput &input, IGameDef *gamedef)
// Example: if replacements contains the pair ("bucket:bucket_water", "bucket:bucket_empty"), // Example: if replacements contains the pair ("bucket:bucket_water", "bucket:bucket_empty"),
// a water bucket will not be removed but replaced by an empty bucket. // a water bucket will not be removed but replaced by an empty bucket.
static void craftDecrementOrReplaceInput(CraftInput &input, static void craftDecrementOrReplaceInput(CraftInput &input,
std::vector<ItemStack> &output_replacements,
const CraftReplacements &replacements, const CraftReplacements &replacements,
IGameDef *gamedef) IGameDef *gamedef)
{ {
@ -213,26 +214,30 @@ static void craftDecrementOrReplaceInput(CraftInput &input,
for (std::vector<ItemStack>::iterator for (std::vector<ItemStack>::iterator
it = input.items.begin(); it = input.items.begin();
it != input.items.end(); it++) { it != input.items.end(); it++) {
if (it->count == 1) {
// Find an appropriate replacement // Find an appropriate replacement
bool found_replacement = false; bool found_replacement = false;
for (std::vector<std::pair<std::string, std::string> >::iterator for (std::vector<std::pair<std::string, std::string> >::iterator
j = pairs.begin(); j = pairs.begin();
j != pairs.end(); j++) { j != pairs.end(); j++) {
if (it->name == craftGetItemName(j->first, gamedef)) { if (it->name == craftGetItemName(j->first, gamedef)) {
if (it->count == 1) {
it->deSerialize(j->second, gamedef->idef()); it->deSerialize(j->second, gamedef->idef());
found_replacement = true; found_replacement = true;
pairs.erase(j); pairs.erase(j);
break; break;
} else {
ItemStack rep;
rep.deSerialize(j->second, gamedef->idef());
it->remove(1);
found_replacement = true;
output_replacements.push_back(rep);
break;
}
} }
} }
// No replacement was found, simply decrement count to zero // No replacement was found, simply decrement count to zero
if (!found_replacement) if (!found_replacement)
it->remove(1); it->remove(1);
} else if (it->count >= 2) {
// Ignore replacements for items with count >= 2
it->remove(1);
}
} }
} }
@ -408,9 +413,10 @@ CraftInput CraftDefinitionShaped::getInput(const CraftOutput &output, IGameDef *
return CraftInput(CRAFT_METHOD_NORMAL,width,craftGetItems(recipe,gamedef)); return CraftInput(CRAFT_METHOD_NORMAL,width,craftGetItems(recipe,gamedef));
} }
void CraftDefinitionShaped::decrementInput(CraftInput &input, IGameDef *gamedef) const void CraftDefinitionShaped::decrementInput(CraftInput &input, std::vector<ItemStack> &output_replacements,
IGameDef *gamedef) const
{ {
craftDecrementOrReplaceInput(input, replacements, gamedef); craftDecrementOrReplaceInput(input, output_replacements, replacements, gamedef);
} }
CraftHashType CraftDefinitionShaped::getHashType() const CraftHashType CraftDefinitionShaped::getHashType() const
@ -529,9 +535,10 @@ CraftInput CraftDefinitionShapeless::getInput(const CraftOutput &output, IGameDe
return CraftInput(CRAFT_METHOD_NORMAL, 0, craftGetItems(recipe, gamedef)); return CraftInput(CRAFT_METHOD_NORMAL, 0, craftGetItems(recipe, gamedef));
} }
void CraftDefinitionShapeless::decrementInput(CraftInput &input, IGameDef *gamedef) const void CraftDefinitionShapeless::decrementInput(CraftInput &input, std::vector<ItemStack> &output_replacements,
IGameDef *gamedef) const
{ {
craftDecrementOrReplaceInput(input, replacements, gamedef); craftDecrementOrReplaceInput(input, output_replacements, replacements, gamedef);
} }
CraftHashType CraftDefinitionShapeless::getHashType() const CraftHashType CraftDefinitionShapeless::getHashType() const
@ -661,7 +668,8 @@ CraftInput CraftDefinitionToolRepair::getInput(const CraftOutput &output, IGameD
return CraftInput(CRAFT_METHOD_COOKING, additional_wear, stack); return CraftInput(CRAFT_METHOD_COOKING, additional_wear, stack);
} }
void CraftDefinitionToolRepair::decrementInput(CraftInput &input, IGameDef *gamedef) const void CraftDefinitionToolRepair::decrementInput(CraftInput &input, std::vector<ItemStack> &output_replacements,
IGameDef *gamedef) const
{ {
craftDecrementInput(input, gamedef); craftDecrementInput(input, gamedef);
} }
@ -720,9 +728,10 @@ CraftInput CraftDefinitionCooking::getInput(const CraftOutput &output, IGameDef
return CraftInput(CRAFT_METHOD_COOKING,cooktime,craftGetItems(rec,gamedef)); return CraftInput(CRAFT_METHOD_COOKING,cooktime,craftGetItems(rec,gamedef));
} }
void CraftDefinitionCooking::decrementInput(CraftInput &input, IGameDef *gamedef) const void CraftDefinitionCooking::decrementInput(CraftInput &input, std::vector<ItemStack> &output_replacements,
IGameDef *gamedef) const
{ {
craftDecrementOrReplaceInput(input, replacements, gamedef); craftDecrementOrReplaceInput(input, output_replacements, replacements, gamedef);
} }
CraftHashType CraftDefinitionCooking::getHashType() const CraftHashType CraftDefinitionCooking::getHashType() const
@ -811,9 +820,10 @@ CraftInput CraftDefinitionFuel::getInput(const CraftOutput &output, IGameDef *ga
return CraftInput(CRAFT_METHOD_COOKING,(int)burntime,craftGetItems(rec,gamedef)); return CraftInput(CRAFT_METHOD_COOKING,(int)burntime,craftGetItems(rec,gamedef));
} }
void CraftDefinitionFuel::decrementInput(CraftInput &input, IGameDef *gamedef) const void CraftDefinitionFuel::decrementInput(CraftInput &input, std::vector<ItemStack> &output_replacements,
IGameDef *gamedef) const
{ {
craftDecrementOrReplaceInput(input, replacements, gamedef); craftDecrementOrReplaceInput(input, output_replacements, replacements, gamedef);
} }
CraftHashType CraftDefinitionFuel::getHashType() const CraftHashType CraftDefinitionFuel::getHashType() const
@ -871,7 +881,8 @@ public:
} }
virtual bool getCraftResult(CraftInput &input, CraftOutput &output, virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
bool decrementInput, IGameDef *gamedef) const std::vector<ItemStack> &output_replacement, bool decrementInput,
IGameDef *gamedef) const
{ {
output.item = ""; output.item = "";
output.time = 0; output.time = 0;
@ -922,7 +933,7 @@ public:
// Get output, then decrement input (if requested) // Get output, then decrement input (if requested)
output = def->getOutput(input, gamedef); output = def->getOutput(input, gamedef);
if (decrementInput) if (decrementInput)
def->decrementInput(input, gamedef); def->decrementInput(input, output_replacement, gamedef);
/*errorstream << "Check RETURNS TRUE" << std::endl;*/ /*errorstream << "Check RETURNS TRUE" << std::endl;*/
return true; return true;
} }

@ -150,7 +150,8 @@ public:
// the inverse of the above // the inverse of the above
virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const=0; virtual CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const=0;
// Decreases count of every input item // Decreases count of every input item
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const=0; virtual void decrementInput(CraftInput &input,
std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const=0;
virtual CraftHashType getHashType() const = 0; virtual CraftHashType getHashType() const = 0;
virtual u64 getHash(CraftHashType type) const = 0; virtual u64 getHash(CraftHashType type) const = 0;
@ -187,7 +188,8 @@ public:
virtual bool check(const CraftInput &input, IGameDef *gamedef) const; virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(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 CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const; virtual void decrementInput(CraftInput &input,
std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const;
virtual CraftHashType getHashType() const; virtual CraftHashType getHashType() const;
virtual u64 getHash(CraftHashType type) const; virtual u64 getHash(CraftHashType type) const;
@ -235,7 +237,8 @@ public:
virtual bool check(const CraftInput &input, IGameDef *gamedef) const; virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(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 CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const; virtual void decrementInput(CraftInput &input,
std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const;
virtual CraftHashType getHashType() const; virtual CraftHashType getHashType() const;
virtual u64 getHash(CraftHashType type) const; virtual u64 getHash(CraftHashType type) const;
@ -278,7 +281,8 @@ public:
virtual bool check(const CraftInput &input, IGameDef *gamedef) const; virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(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 CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const; virtual void decrementInput(CraftInput &input,
std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const;
virtual CraftHashType getHashType() const { return CRAFT_HASH_TYPE_COUNT; } virtual CraftHashType getHashType() const { return CRAFT_HASH_TYPE_COUNT; }
virtual u64 getHash(CraftHashType type) const { return 2; } virtual u64 getHash(CraftHashType type) const { return 2; }
@ -320,7 +324,8 @@ public:
virtual bool check(const CraftInput &input, IGameDef *gamedef) const; virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(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 CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const; virtual void decrementInput(CraftInput &input,
std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const;
virtual CraftHashType getHashType() const; virtual CraftHashType getHashType() const;
virtual u64 getHash(CraftHashType type) const; virtual u64 getHash(CraftHashType type) const;
@ -365,7 +370,8 @@ public:
virtual bool check(const CraftInput &input, IGameDef *gamedef) const; virtual bool check(const CraftInput &input, IGameDef *gamedef) const;
virtual CraftOutput getOutput(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 CraftInput getInput(const CraftOutput &output, IGameDef *gamedef) const;
virtual void decrementInput(CraftInput &input, IGameDef *gamedef) const; virtual void decrementInput(CraftInput &input,
std::vector<ItemStack> &output_replacements, IGameDef *gamedef) const;
virtual CraftHashType getHashType() const; virtual CraftHashType getHashType() const;
virtual u64 getHash(CraftHashType type) const; virtual u64 getHash(CraftHashType type) const;
@ -398,6 +404,7 @@ public:
// The main crafting function // The main crafting function
virtual bool getCraftResult(CraftInput &input, CraftOutput &output, virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
std::vector<ItemStack> &output_replacements,
bool decrementInput, IGameDef *gamedef) const=0; bool decrementInput, IGameDef *gamedef) const=0;
virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output, virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
IGameDef *gamedef, unsigned limit=0) const=0; IGameDef *gamedef, unsigned limit=0) const=0;
@ -414,6 +421,7 @@ public:
// The main crafting function // The main crafting function
virtual bool getCraftResult(CraftInput &input, CraftOutput &output, virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
std::vector<ItemStack> &output_replacements,
bool decrementInput, IGameDef *gamedef) const=0; bool decrementInput, IGameDef *gamedef) const=0;
virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output, virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
IGameDef *gamedef, unsigned limit=0) const=0; IGameDef *gamedef, unsigned limit=0) const=0;

@ -691,7 +691,8 @@ ICraftAction::ICraftAction(std::istream &is)
craft_inv.deSerialize(ts); craft_inv.deSerialize(ts);
} }
void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef) void ICraftAction::apply(InventoryManager *mgr,
ServerActiveObject *player, IGameDef *gamedef)
{ {
Inventory *inv_craft = mgr->getInventory(craft_inv); Inventory *inv_craft = mgr->getInventory(craft_inv);
@ -703,6 +704,7 @@ void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGam
InventoryList *list_craft = inv_craft->getList("craft"); InventoryList *list_craft = inv_craft->getList("craft");
InventoryList *list_craftresult = inv_craft->getList("craftresult"); InventoryList *list_craftresult = inv_craft->getList("craftresult");
InventoryList *list_main = inv_craft->getList("main");
/* /*
If a list doesn't exist or the source item doesn't exist If a list doesn't exist or the source item doesn't exist
@ -726,20 +728,36 @@ void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGam
ItemStack crafted; ItemStack crafted;
ItemStack craftresultitem; ItemStack craftresultitem;
int count_remaining = count; int count_remaining = count;
getCraftingResult(inv_craft, crafted, false, gamedef); std::vector<ItemStack> output_replacements;
getCraftingResult(inv_craft, crafted, output_replacements, false, gamedef);
PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv); PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv);
bool found = !crafted.empty(); bool found = !crafted.empty();
while(found && list_craftresult->itemFits(0, crafted)) while (found && list_craftresult->itemFits(0, crafted)) {
{
InventoryList saved_craft_list = *list_craft; InventoryList saved_craft_list = *list_craft;
std::vector<ItemStack> temp;
// Decrement input and add crafting output // Decrement input and add crafting output
getCraftingResult(inv_craft, crafted, true, gamedef); getCraftingResult(inv_craft, crafted, temp, true, gamedef);
PLAYER_TO_SA(player)->item_OnCraft(crafted, player, &saved_craft_list, craft_inv); PLAYER_TO_SA(player)->item_OnCraft(crafted, player, &saved_craft_list, craft_inv);
list_craftresult->addItem(0, crafted); list_craftresult->addItem(0, crafted);
mgr->setInventoryModified(craft_inv); mgr->setInventoryModified(craft_inv);
// Add the new replacements to the list
IItemDefManager *itemdef = gamedef->getItemDefManager();
for (std::vector<ItemStack>::iterator it = temp.begin();
it != temp.end(); it++) {
for (std::vector<ItemStack>::iterator jt = output_replacements.begin();
jt != output_replacements.end(); jt++) {
if (it->name == jt->name) {
*it = jt->addItem(*it, itemdef);
if (it->empty())
continue;
}
}
output_replacements.push_back(*it);
}
actionstream << player->getDescription() actionstream << player->getDescription()
<< " crafts " << " crafts "
<< crafted.getItemString() << crafted.getItemString()
@ -752,11 +770,33 @@ void ICraftAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGam
count_remaining--; count_remaining--;
// Get next crafting result // Get next crafting result
found = getCraftingResult(inv_craft, crafted, false, gamedef); found = getCraftingResult(inv_craft, crafted, temp, false, gamedef);
PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv); PLAYER_TO_SA(player)->item_CraftPredict(crafted, player, list_craft, craft_inv);
found = !crafted.empty(); found = !crafted.empty();
} }
// Put the replacements in the inventory or drop them on the floor, if
// the invenotry is full
for (std::vector<ItemStack>::iterator it = output_replacements.begin();
it != output_replacements.end(); it++) {
if (list_main)
*it = list_main->addItem(*it);
if (it->empty())
continue;
u16 count = it->count;
do {
PLAYER_TO_SA(player)->item_OnDrop(*it, player,
player->getBasePosition() + v3f(0,1,0));
if (count >= it->count) {
errorstream << "Couldn't drop replacement stack " <<
it->getItemString() << " because drop loop didn't "
"decrease count." << std::endl;
break;
}
} while (!it->empty());
}
infostream<<"ICraftAction::apply(): crafted " infostream<<"ICraftAction::apply(): crafted "
<<" craft_inv=\""<<craft_inv.dump()<<"\"" <<" craft_inv=\""<<craft_inv.dump()<<"\""
<<std::endl; <<std::endl;
@ -771,6 +811,7 @@ void ICraftAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
// Crafting helper // Crafting helper
bool getCraftingResult(Inventory *inv, ItemStack& result, bool getCraftingResult(Inventory *inv, ItemStack& result,
std::vector<ItemStack> &output_replacements,
bool decrementInput, IGameDef *gamedef) bool decrementInput, IGameDef *gamedef)
{ {
DSTACK(__FUNCTION_NAME); DSTACK(__FUNCTION_NAME);
@ -792,7 +833,7 @@ bool getCraftingResult(Inventory *inv, ItemStack& result,
// Find out what is crafted and add it to result item slot // Find out what is crafted and add it to result item slot
CraftOutput co; CraftOutput co;
bool found = gamedef->getCraftDefManager()->getCraftResult( bool found = gamedef->getCraftDefManager()->getCraftResult(
ci, co, decrementInput, gamedef); ci, co, output_replacements, decrementInput, gamedef);
if(found) if(found)
result.deSerialize(co.item, gamedef->getItemDefManager()); result.deSerialize(co.item, gamedef->getItemDefManager());

@ -242,6 +242,7 @@ struct ICraftAction : public InventoryAction
// Crafting helper // Crafting helper
bool getCraftingResult(Inventory *inv, ItemStack& result, bool getCraftingResult(Inventory *inv, ItemStack& result,
std::vector<ItemStack> &output_replacements,
bool decrementInput, IGameDef *gamedef); bool decrementInput, IGameDef *gamedef);
#endif #endif

@ -303,7 +303,8 @@ int ModApiCraft::l_get_craft_result(lua_State *L)
ICraftDefManager *cdef = gdef->cdef(); ICraftDefManager *cdef = gdef->cdef();
CraftInput input(method, width, items); CraftInput input(method, width, items);
CraftOutput output; CraftOutput output;
bool got = cdef->getCraftResult(input, output, true, gdef); std::vector<ItemStack> output_replacements;
bool got = cdef->getCraftResult(input, output, output_replacements, true, gdef);
lua_newtable(L); // output table lua_newtable(L); // output table
if (got) { if (got) {
ItemStack item; ItemStack item;
@ -311,10 +312,14 @@ int ModApiCraft::l_get_craft_result(lua_State *L)
LuaItemStack::create(L, item); LuaItemStack::create(L, item);
lua_setfield(L, -2, "item"); lua_setfield(L, -2, "item");
setintfield(L, -1, "time", output.time); setintfield(L, -1, "time", output.time);
push_items(L, output_replacements);
lua_setfield(L, -2, "replacements");
} else { } else {
LuaItemStack::create(L, ItemStack()); LuaItemStack::create(L, ItemStack());
lua_setfield(L, -2, "item"); lua_setfield(L, -2, "item");
setintfield(L, -1, "time", 0); setintfield(L, -1, "time", 0);
lua_newtable(L);
lua_setfield(L, -2, "replacements");
} }
lua_newtable(L); // decremented input table lua_newtable(L); // decremented input table
lua_pushstring(L, method_s.c_str()); lua_pushstring(L, method_s.c_str());

@ -2698,7 +2698,8 @@ void Server::UpdateCrafting(Player* player)
ItemStack preview; ItemStack preview;
InventoryLocation loc; InventoryLocation loc;
loc.setPlayer(player->getName()); loc.setPlayer(player->getName());
getCraftingResult(&player->inventory, preview, false, this); std::vector<ItemStack> output_replacements;
getCraftingResult(&player->inventory, preview, output_replacements, false, this);
m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc); m_env->getScriptIface()->item_CraftPredict(preview, player->getPlayerSAO(), (&player->inventory)->getList("craft"), loc);
// Put the new preview in // Put the new preview in