Skip to content

Commit 03e0dd3

Browse files
gregorycukwolekr
authored andcommittedMar 21, 2015
Optimize minetest.get_(all)_craft_recipe(s)
Signed off by: ShadowNinja, kwolekr
1 parent 1e4fb80 commit 03e0dd3

File tree

3 files changed

+107
-180
lines changed

3 files changed

+107
-180
lines changed
 

Diff for: ‎src/craftdef.cpp

+28-75
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
2727
#include "gamedef.h"
2828
#include "inventory.h"
2929
#include "util/serialize.h"
30+
#include "util/numeric.h"
3031
#include "strfnd.h"
3132
#include "exceptions.h"
3233

@@ -931,85 +932,30 @@ class CCraftDefManager: public IWritableCraftDefManager
931932
}
932933
return false;
933934
}
934-
virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
935-
IGameDef *gamedef) const
936-
{
937-
CraftOutput tmpout;
938-
tmpout.item = "";
939-
tmpout.time = 0;
940-
941-
// If output item is empty, abort.
942-
if(output.item.empty())
943-
return false;
944-
945-
// Walk crafting definitions from back to front, so that later
946-
// definitions can override earlier ones.
947-
for(std::vector<CraftDefinition*>::const_reverse_iterator
948-
i = m_craft_definitions.rbegin();
949-
i != m_craft_definitions.rend(); i++)
950-
{
951-
CraftDefinition *def = *i;
952-
953-
/*infostream<<"Checking "<<input.dump()<<std::endl
954-
<<" against "<<def->dump()<<std::endl;*/
955935

956-
try {
957-
tmpout = def->getOutput(input, gamedef);
958-
if((tmpout.item.substr(0,output.item.length()) == output.item) &&
959-
((tmpout.item[output.item.length()] == 0) ||
960-
(tmpout.item[output.item.length()] == ' ')))
961-
{
962-
// Get output, then decrement input (if requested)
963-
input = def->getInput(output, gamedef);
964-
return true;
965-
}
966-
}
967-
catch(SerializationError &e)
968-
{
969-
errorstream<<"getCraftResult: ERROR: "
970-
<<"Serialization error in recipe "
971-
<<def->dump()<<std::endl;
972-
// then go on with the next craft definition
973-
}
974-
}
975-
return false;
976-
}
977936
virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
978-
IGameDef *gamedef) const
937+
IGameDef *gamedef, unsigned limit=0) const
979938
{
980-
std::vector<CraftDefinition*> recipes_list;
981-
CraftInput input;
982-
CraftOutput tmpout;
983-
tmpout.item = "";
984-
tmpout.time = 0;
939+
std::vector<CraftDefinition*> recipes;
985940

986-
for(std::vector<CraftDefinition*>::const_reverse_iterator
987-
i = m_craft_definitions.rbegin();
988-
i != m_craft_definitions.rend(); i++)
989-
{
990-
CraftDefinition *def = *i;
941+
std::map<std::string, std::vector<CraftDefinition*> >::const_iterator
942+
vec_iter = m_output_craft_definitions.find(output.item);
991943

992-
/*infostream<<"Checking "<<input.dump()<<std::endl
993-
<<" against "<<def->dump()<<std::endl;*/
944+
if (vec_iter == m_output_craft_definitions.end())
945+
return recipes;
994946

995-
try {
996-
tmpout = def->getOutput(input, gamedef);
997-
if(tmpout.item.substr(0,output.item.length()) == output.item)
998-
{
999-
// Get output, then decrement input (if requested)
1000-
input = def->getInput(output, gamedef);
1001-
recipes_list.push_back(*i);
1002-
}
1003-
}
1004-
catch(SerializationError &e)
1005-
{
1006-
errorstream<<"getCraftResult: ERROR: "
1007-
<<"Serialization error in recipe "
1008-
<<def->dump()<<std::endl;
1009-
// then go on with the next craft definition
1010-
}
947+
const std::vector<CraftDefinition*> &vec = vec_iter->second;
948+
949+
recipes.reserve(limit ? MYMIN(limit, vec.size()) : vec.size());
950+
951+
for (std::vector<CraftDefinition*>::const_reverse_iterator
952+
it = vec.rbegin(); it != vec.rend(); ++it) {
953+
if (limit && recipes.size() >= limit)
954+
break;
955+
recipes.push_back(*it);
1011956
}
1012-
return recipes_list;
957+
958+
return recipes;
1013959
}
1014960
virtual std::string dump() const
1015961
{
@@ -1023,11 +969,16 @@ class CCraftDefManager: public IWritableCraftDefManager
1023969
}
1024970
return os.str();
1025971
}
1026-
virtual void registerCraft(CraftDefinition *def)
972+
virtual void registerCraft(CraftDefinition *def, IGameDef *gamedef)
1027973
{
1028974
verbosestream<<"registerCraft: registering craft definition: "
1029975
<<def->dump()<<std::endl;
1030976
m_craft_definitions.push_back(def);
977+
978+
CraftInput input;
979+
std::string output_name = craftGetItemName(
980+
def->getOutput(input, gamedef).item, gamedef);
981+
m_output_craft_definitions[output_name].push_back(def);
1031982
}
1032983
virtual void clear()
1033984
{
@@ -1037,6 +988,7 @@ class CCraftDefManager: public IWritableCraftDefManager
1037988
delete *i;
1038989
}
1039990
m_craft_definitions.clear();
991+
m_output_craft_definitions.clear();
1040992
}
1041993
virtual void serialize(std::ostream &os) const
1042994
{
@@ -1053,7 +1005,7 @@ class CCraftDefManager: public IWritableCraftDefManager
10531005
os<<serializeString(tmp_os.str());
10541006
}
10551007
}
1056-
virtual void deSerialize(std::istream &is)
1008+
virtual void deSerialize(std::istream &is, IGameDef *gamedef)
10571009
{
10581010
// Clear everything
10591011
clear();
@@ -1067,11 +1019,12 @@ class CCraftDefManager: public IWritableCraftDefManager
10671019
std::istringstream tmp_is(deSerializeString(is), std::ios::binary);
10681020
CraftDefinition *def = CraftDefinition::deSerialize(tmp_is);
10691021
// Register
1070-
registerCraft(def);
1022+
registerCraft(def, gamedef);
10711023
}
10721024
}
10731025
private:
10741026
std::vector<CraftDefinition*> m_craft_definitions;
1027+
std::map<std::string, std::vector<CraftDefinition*> > m_output_craft_definitions;
10751028
};
10761029

10771030
IWritableCraftDefManager* createCraftDefManager()

Diff for: ‎src/craftdef.h

+4-8
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,8 @@ class ICraftDefManager
356356
// The main crafting function
357357
virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
358358
bool decrementInput, IGameDef *gamedef) const=0;
359-
virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
360-
IGameDef *gamedef) const=0;
361359
virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
362-
IGameDef *gamedef) const=0;
360+
IGameDef *gamedef, unsigned limit=0) const=0;
363361

364362
// Print crafting recipes for debugging
365363
virtual std::string dump() const=0;
@@ -376,22 +374,20 @@ class IWritableCraftDefManager : public ICraftDefManager
376374
// The main crafting function
377375
virtual bool getCraftResult(CraftInput &input, CraftOutput &output,
378376
bool decrementInput, IGameDef *gamedef) const=0;
379-
virtual bool getCraftRecipe(CraftInput &input, CraftOutput &output,
380-
IGameDef *gamedef) const=0;
381377
virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
382-
IGameDef *gamedef) const=0;
378+
IGameDef *gamedef, unsigned limit=0) const=0;
383379

384380
// Print crafting recipes for debugging
385381
virtual std::string dump() const=0;
386382

387383
// Add a crafting definition.
388384
// After calling this, the pointer belongs to the manager.
389-
virtual void registerCraft(CraftDefinition *def)=0;
385+
virtual void registerCraft(CraftDefinition *def, IGameDef *gamedef) = 0;
390386
// Delete all crafting definitions
391387
virtual void clear()=0;
392388

393389
virtual void serialize(std::ostream &os) const=0;
394-
virtual void deSerialize(std::istream &is)=0;
390+
virtual void deSerialize(std::istream &is, IGameDef *gamedef) = 0;
395391
};
396392

397393
IWritableCraftDefManager* createCraftDefManager();

Diff for: ‎src/script/lua_api/l_craft.cpp

+75-97
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ int ModApiCraft::l_register_craft(lua_State *L)
173173

174174
CraftDefinition *def = new CraftDefinitionShaped(
175175
output, width, recipe, replacements);
176-
craftdef->registerCraft(def);
176+
craftdef->registerCraft(def, getServer(L));
177177
}
178178
/*
179179
CraftDefinitionShapeless
@@ -205,7 +205,7 @@ int ModApiCraft::l_register_craft(lua_State *L)
205205

206206
CraftDefinition *def = new CraftDefinitionShapeless(
207207
output, recipe, replacements);
208-
craftdef->registerCraft(def);
208+
craftdef->registerCraft(def, getServer(L));
209209
}
210210
/*
211211
CraftDefinitionToolRepair
@@ -216,7 +216,7 @@ int ModApiCraft::l_register_craft(lua_State *L)
216216

217217
CraftDefinition *def = new CraftDefinitionToolRepair(
218218
additional_wear);
219-
craftdef->registerCraft(def);
219+
craftdef->registerCraft(def, getServer(L));
220220
}
221221
/*
222222
CraftDefinitionCooking
@@ -246,7 +246,7 @@ int ModApiCraft::l_register_craft(lua_State *L)
246246

247247
CraftDefinition *def = new CraftDefinitionCooking(
248248
output, recipe, cooktime, replacements);
249-
craftdef->registerCraft(def);
249+
craftdef->registerCraft(def, getServer(L));
250250
}
251251
/*
252252
CraftDefinitionFuel
@@ -270,7 +270,7 @@ int ModApiCraft::l_register_craft(lua_State *L)
270270

271271
CraftDefinition *def = new CraftDefinitionFuel(
272272
recipe, burntime, replacements);
273-
craftdef->registerCraft(def);
273+
craftdef->registerCraft(def, getServer(L));
274274
}
275275
else
276276
{
@@ -326,56 +326,80 @@ int ModApiCraft::l_get_craft_result(lua_State *L)
326326
return 2;
327327
}
328328

329+
330+
void push_craft_recipe(lua_State *L, IGameDef *gdef,
331+
const CraftDefinition *recipe,
332+
const CraftOutput &tmpout)
333+
{
334+
CraftInput input = recipe->getInput(tmpout, gdef);
335+
CraftOutput output = recipe->getOutput(input, gdef);
336+
337+
lua_newtable(L); // items
338+
std::vector<ItemStack>::const_iterator iter = input.items.begin();
339+
for (u16 j = 1; iter != input.items.end(); iter++, j++) {
340+
if (iter->empty())
341+
continue;
342+
lua_pushstring(L, iter->name.c_str());
343+
lua_rawseti(L, -2, j);
344+
}
345+
lua_setfield(L, -2, "items");
346+
setintfield(L, -1, "width", input.width);
347+
switch (input.method) {
348+
case CRAFT_METHOD_NORMAL:
349+
lua_pushstring(L, "normal");
350+
break;
351+
case CRAFT_METHOD_COOKING:
352+
lua_pushstring(L, "cooking");
353+
break;
354+
case CRAFT_METHOD_FUEL:
355+
lua_pushstring(L, "fuel");
356+
break;
357+
default:
358+
lua_pushstring(L, "unknown");
359+
}
360+
lua_setfield(L, -2, "type");
361+
lua_pushstring(L, tmpout.item.c_str());
362+
lua_setfield(L, -2, "output");
363+
}
364+
365+
void push_craft_recipes(lua_State *L, IGameDef *gdef,
366+
const std::vector<CraftDefinition*> &recipes,
367+
const CraftOutput &output)
368+
{
369+
lua_createtable(L, recipes.size(), 0);
370+
371+
if (recipes.empty()) {
372+
lua_pushnil(L);
373+
return;
374+
}
375+
376+
std::vector<CraftDefinition*>::const_iterator it = recipes.begin();
377+
for (unsigned i = 0; it != recipes.end(); ++it) {
378+
lua_newtable(L);
379+
push_craft_recipe(L, gdef, *it, output);
380+
lua_rawseti(L, -2, ++i);
381+
}
382+
}
383+
384+
329385
// get_craft_recipe(result item)
330386
int ModApiCraft::l_get_craft_recipe(lua_State *L)
331387
{
332388
NO_MAP_LOCK_REQUIRED;
333389

334-
int k = 1;
335-
int input_i = 1;
336-
std::string o_item = luaL_checkstring(L,input_i);
390+
std::string item = luaL_checkstring(L, 1);
391+
Server *server = getServer(L);
392+
CraftOutput output(item, 0);
393+
std::vector<CraftDefinition*> recipes = server->cdef()
394+
->getCraftRecipes(output, server, 1);
337395

338-
IGameDef *gdef = getServer(L);
339-
ICraftDefManager *cdef = gdef->cdef();
340-
CraftInput input;
341-
CraftOutput output(o_item,0);
342-
bool got = cdef->getCraftRecipe(input, output, gdef);
343-
lua_newtable(L); // output table
344-
if(got){
345-
lua_newtable(L);
346-
for(std::vector<ItemStack>::const_iterator
347-
i = input.items.begin();
348-
i != input.items.end(); i++, k++)
349-
{
350-
if (i->empty())
351-
{
352-
continue;
353-
}
354-
lua_pushinteger(L,k);
355-
lua_pushstring(L,i->name.c_str());
356-
lua_settable(L, -3);
357-
}
358-
lua_setfield(L, -2, "items");
359-
setintfield(L, -1, "width", input.width);
360-
switch (input.method) {
361-
case CRAFT_METHOD_NORMAL:
362-
lua_pushstring(L,"normal");
363-
break;
364-
case CRAFT_METHOD_COOKING:
365-
lua_pushstring(L,"cooking");
366-
break;
367-
case CRAFT_METHOD_FUEL:
368-
lua_pushstring(L,"fuel");
369-
break;
370-
default:
371-
lua_pushstring(L,"unknown");
372-
}
373-
lua_setfield(L, -2, "type");
374-
} else {
396+
if (recipes.empty()) {
375397
lua_pushnil(L);
376398
lua_setfield(L, -2, "items");
377399
setintfield(L, -1, "width", 0);
400+
return 1;
378401
}
402+
push_craft_recipe(L, server, recipes[0], output);
379403
return 1;
380404
}
381405

@@ -384,59 +408,13 @@ int ModApiCraft::l_get_all_craft_recipes(lua_State *L)
384408
{
385409
NO_MAP_LOCK_REQUIRED;
386410

387-
std::string o_item = luaL_checkstring(L,1);
388-
IGameDef *gdef = getServer(L);
389-
ICraftDefManager *cdef = gdef->cdef();
390-
CraftInput input;
391-
CraftOutput output(o_item,0);
392-
std::vector<CraftDefinition*> recipes_list;
393-
recipes_list = cdef->getCraftRecipes(output, gdef);
394-
if (recipes_list.empty()) {
395-
lua_pushnil(L);
396-
return 1;
397-
}
411+
std::string item = luaL_checkstring(L, 1);
412+
Server *server = getServer(L);
413+
CraftOutput output(item, 0);
414+
std::vector<CraftDefinition*> recipes = server->cdef()
415+
->getCraftRecipes(output, server);
398416

399-
lua_createtable(L, recipes_list.size(), 0);
400-
std::vector<CraftDefinition*>::const_iterator iter = recipes_list.begin();
401-
for (u16 i = 0; iter != recipes_list.end(); iter++) {
402-
CraftOutput tmpout;
403-
tmpout.item = "";
404-
tmpout.time = 0;
405-
tmpout = (*iter)->getOutput(input, gdef);
406-
std::string query = tmpout.item;
407-
char *fmtpos, *fmt = &query[0];
408-
if (strtok_r(fmt, " ", &fmtpos) == output.item) {
409-
input = (*iter)->getInput(output, gdef);
410-
lua_newtable(L);
411-
lua_newtable(L); // items
412-
std::vector<ItemStack>::const_iterator iter = input.items.begin();
413-
for (u16 j = 1; iter != input.items.end(); iter++, j++) {
414-
if (iter->empty())
415-
continue;
416-
lua_pushstring(L, iter->name.c_str());
417-
lua_rawseti(L, -2, j);
418-
}
419-
lua_setfield(L, -2, "items");
420-
setintfield(L, -1, "width", input.width);
421-
switch (input.method) {
422-
case CRAFT_METHOD_NORMAL:
423-
lua_pushstring(L, "normal");
424-
break;
425-
case CRAFT_METHOD_COOKING:
426-
lua_pushstring(L, "cooking");
427-
break;
428-
case CRAFT_METHOD_FUEL:
429-
lua_pushstring(L, "fuel");
430-
break;
431-
default:
432-
lua_pushstring(L, "unknown");
433-
}
434-
lua_setfield(L, -2, "type");
435-
lua_pushstring(L, &tmpout.item[0]);
436-
lua_setfield(L, -2, "output");
437-
lua_rawseti(L, -2, ++i);
438-
}
439-
}
417+
push_craft_recipes(L, server, recipes, output);
440418
return 1;
441419
}
442420

0 commit comments

Comments
 (0)
Please sign in to comment.