From 03e0dd33a847a83d975282c6caf6b926306e7b57 Mon Sep 17 00:00:00 2001 From: gregorycu Date: Tue, 27 Jan 2015 00:46:55 +1100 Subject: [PATCH] Optimize minetest.get_(all)_craft_recipe(s) Signed off by: ShadowNinja, kwolekr --- src/craftdef.cpp | 103 ++++++-------------- src/craftdef.h | 12 +-- src/script/lua_api/l_craft.cpp | 172 ++++++++++++++------------------- 3 files changed, 107 insertions(+), 180 deletions(-) diff --git a/src/craftdef.cpp b/src/craftdef.cpp index 80937ccb..bca16a4c 100644 --- a/src/craftdef.cpp +++ b/src/craftdef.cpp @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "gamedef.h" #include "inventory.h" #include "util/serialize.h" +#include "util/numeric.h" #include "strfnd.h" #include "exceptions.h" @@ -931,85 +932,30 @@ public: } 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::const_reverse_iterator - i = m_craft_definitions.rbegin(); - i != m_craft_definitions.rend(); i++) - { - CraftDefinition *def = *i; - - /*infostream<<"Checking "<dump()<getOutput(input, gamedef); - if((tmpout.item.substr(0,output.item.length()) == output.item) && - ((tmpout.item[output.item.length()] == 0) || - (tmpout.item[output.item.length()] == ' '))) - { - // Get output, then decrement input (if requested) - input = def->getInput(output, gamedef); - return true; - } - } - catch(SerializationError &e) - { - errorstream<<"getCraftResult: ERROR: " - <<"Serialization error in recipe " - <dump()< getCraftRecipes(CraftOutput &output, - IGameDef *gamedef) const + IGameDef *gamedef, unsigned limit=0) const { - std::vector recipes_list; - CraftInput input; - CraftOutput tmpout; - tmpout.item = ""; - tmpout.time = 0; + std::vector recipes; - for(std::vector::const_reverse_iterator - i = m_craft_definitions.rbegin(); - i != m_craft_definitions.rend(); i++) - { - CraftDefinition *def = *i; + std::map >::const_iterator + vec_iter = m_output_craft_definitions.find(output.item); - /*infostream<<"Checking "<dump()<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); - recipes_list.push_back(*i); - } - } - catch(SerializationError &e) - { - errorstream<<"getCraftResult: ERROR: " - <<"Serialization error in recipe " - <dump()< &vec = vec_iter->second; + + recipes.reserve(limit ? MYMIN(limit, vec.size()) : vec.size()); + + for (std::vector::const_reverse_iterator + it = vec.rbegin(); it != vec.rend(); ++it) { + if (limit && recipes.size() >= limit) + break; + recipes.push_back(*it); } - return recipes_list; + + return recipes; } virtual std::string dump() const { @@ -1023,11 +969,16 @@ public: } return os.str(); } - virtual void registerCraft(CraftDefinition *def) + virtual void registerCraft(CraftDefinition *def, IGameDef *gamedef) { verbosestream<<"registerCraft: registering craft definition: " <dump()<getOutput(input, gamedef).item, gamedef); + m_output_craft_definitions[output_name].push_back(def); } virtual void clear() { @@ -1037,6 +988,7 @@ public: delete *i; } m_craft_definitions.clear(); + m_output_craft_definitions.clear(); } virtual void serialize(std::ostream &os) const { @@ -1053,7 +1005,7 @@ public: os< m_craft_definitions; + std::map > m_output_craft_definitions; }; IWritableCraftDefManager* createCraftDefManager() diff --git a/src/craftdef.h b/src/craftdef.h index 14dc5300..7902a2e2 100644 --- a/src/craftdef.h +++ b/src/craftdef.h @@ -356,10 +356,8 @@ public: // 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; virtual std::vector getCraftRecipes(CraftOutput &output, - IGameDef *gamedef) const=0; + IGameDef *gamedef, unsigned limit=0) const=0; // Print crafting recipes for debugging virtual std::string dump() const=0; @@ -376,22 +374,20 @@ public: // 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; virtual std::vector getCraftRecipes(CraftOutput &output, - IGameDef *gamedef) const=0; + IGameDef *gamedef, unsigned limit=0) const=0; // Print crafting recipes for debugging virtual std::string dump() const=0; // Add a crafting definition. // After calling this, the pointer belongs to the manager. - virtual void registerCraft(CraftDefinition *def)=0; + virtual void registerCraft(CraftDefinition *def, IGameDef *gamedef) = 0; // Delete all crafting definitions virtual void clear()=0; virtual void serialize(std::ostream &os) const=0; - virtual void deSerialize(std::istream &is)=0; + virtual void deSerialize(std::istream &is, IGameDef *gamedef) = 0; }; IWritableCraftDefManager* createCraftDefManager(); diff --git a/src/script/lua_api/l_craft.cpp b/src/script/lua_api/l_craft.cpp index 8f8efbfb..40342871 100644 --- a/src/script/lua_api/l_craft.cpp +++ b/src/script/lua_api/l_craft.cpp @@ -173,7 +173,7 @@ int ModApiCraft::l_register_craft(lua_State *L) CraftDefinition *def = new CraftDefinitionShaped( output, width, recipe, replacements); - craftdef->registerCraft(def); + craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionShapeless @@ -205,7 +205,7 @@ int ModApiCraft::l_register_craft(lua_State *L) CraftDefinition *def = new CraftDefinitionShapeless( output, recipe, replacements); - craftdef->registerCraft(def); + craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionToolRepair @@ -216,7 +216,7 @@ int ModApiCraft::l_register_craft(lua_State *L) CraftDefinition *def = new CraftDefinitionToolRepair( additional_wear); - craftdef->registerCraft(def); + craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionCooking @@ -246,7 +246,7 @@ int ModApiCraft::l_register_craft(lua_State *L) CraftDefinition *def = new CraftDefinitionCooking( output, recipe, cooktime, replacements); - craftdef->registerCraft(def); + craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionFuel @@ -270,7 +270,7 @@ int ModApiCraft::l_register_craft(lua_State *L) CraftDefinition *def = new CraftDefinitionFuel( recipe, burntime, replacements); - craftdef->registerCraft(def); + craftdef->registerCraft(def, getServer(L)); } else { @@ -326,56 +326,80 @@ int ModApiCraft::l_get_craft_result(lua_State *L) return 2; } + +void push_craft_recipe(lua_State *L, IGameDef *gdef, + const CraftDefinition *recipe, + const CraftOutput &tmpout) +{ + CraftInput input = recipe->getInput(tmpout, gdef); + CraftOutput output = recipe->getOutput(input, gdef); + + lua_newtable(L); // items + std::vector::const_iterator iter = input.items.begin(); + for (u16 j = 1; iter != input.items.end(); iter++, j++) { + if (iter->empty()) + continue; + lua_pushstring(L, iter->name.c_str()); + lua_rawseti(L, -2, j); + } + lua_setfield(L, -2, "items"); + setintfield(L, -1, "width", input.width); + switch (input.method) { + case CRAFT_METHOD_NORMAL: + lua_pushstring(L, "normal"); + 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"); + lua_pushstring(L, tmpout.item.c_str()); + lua_setfield(L, -2, "output"); +} + +void push_craft_recipes(lua_State *L, IGameDef *gdef, + const std::vector &recipes, + const CraftOutput &output) +{ + lua_createtable(L, recipes.size(), 0); + + if (recipes.empty()) { + lua_pushnil(L); + return; + } + + std::vector::const_iterator it = recipes.begin(); + for (unsigned i = 0; it != recipes.end(); ++it) { + lua_newtable(L); + push_craft_recipe(L, gdef, *it, output); + lua_rawseti(L, -2, ++i); + } +} + + // get_craft_recipe(result item) int ModApiCraft::l_get_craft_recipe(lua_State *L) { NO_MAP_LOCK_REQUIRED; - int k = 1; - int input_i = 1; - std::string o_item = luaL_checkstring(L,input_i); + std::string item = luaL_checkstring(L, 1); + Server *server = getServer(L); + CraftOutput output(item, 0); + std::vector recipes = server->cdef() + ->getCraftRecipes(output, server, 1); - IGameDef *gdef = getServer(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::const_iterator - i = input.items.begin(); - i != input.items.end(); i++, k++) - { - if (i->empty()) - { - continue; - } - lua_pushinteger(L,k); - 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,"normal"); - 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 { + if (recipes.empty()) { lua_pushnil(L); lua_setfield(L, -2, "items"); setintfield(L, -1, "width", 0); + return 1; } + push_craft_recipe(L, server, recipes[0], output); return 1; } @@ -384,59 +408,13 @@ int ModApiCraft::l_get_all_craft_recipes(lua_State *L) { NO_MAP_LOCK_REQUIRED; - std::string o_item = luaL_checkstring(L,1); - IGameDef *gdef = getServer(L); - ICraftDefManager *cdef = gdef->cdef(); - CraftInput input; - CraftOutput output(o_item,0); - std::vector recipes_list; - recipes_list = cdef->getCraftRecipes(output, gdef); - if (recipes_list.empty()) { - lua_pushnil(L); - return 1; - } + std::string item = luaL_checkstring(L, 1); + Server *server = getServer(L); + CraftOutput output(item, 0); + std::vector recipes = server->cdef() + ->getCraftRecipes(output, server); - lua_createtable(L, recipes_list.size(), 0); - std::vector::const_iterator iter = recipes_list.begin(); - for (u16 i = 0; iter != recipes_list.end(); iter++) { - CraftOutput tmpout; - tmpout.item = ""; - tmpout.time = 0; - tmpout = (*iter)->getOutput(input, gdef); - std::string query = tmpout.item; - char *fmtpos, *fmt = &query[0]; - if (strtok_r(fmt, " ", &fmtpos) == output.item) { - input = (*iter)->getInput(output, gdef); - lua_newtable(L); - lua_newtable(L); // items - std::vector::const_iterator iter = input.items.begin(); - for (u16 j = 1; iter != input.items.end(); iter++, j++) { - if (iter->empty()) - continue; - lua_pushstring(L, iter->name.c_str()); - lua_rawseti(L, -2, j); - } - lua_setfield(L, -2, "items"); - setintfield(L, -1, "width", input.width); - switch (input.method) { - case CRAFT_METHOD_NORMAL: - lua_pushstring(L, "normal"); - 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"); - lua_pushstring(L, &tmpout.item[0]); - lua_setfield(L, -2, "output"); - lua_rawseti(L, -2, ++i); - } - } + push_craft_recipes(L, server, recipes, output); return 1; }