Skip to content

Commit 281e9f3

Browse files
Foghrye4est31
authored andcommittedJul 5, 2016
Adding minetest.clear_craft
Modifications by est31: grammar fixes in doc + error messages and a little style fix, no functional change.
1 parent 7a53205 commit 281e9f3

File tree

5 files changed

+178
-1
lines changed

5 files changed

+178
-1
lines changed
 

Diff for: ‎doc/lua_api.txt

+8
Original file line numberDiff line numberDiff line change
@@ -1847,6 +1847,14 @@ Call these functions only at load time!
18471847
* `minetest.register_craftitem(name, item definition)`
18481848
* `minetest.register_alias(name, convert_to)`
18491849
* `minetest.register_craft(recipe)`
1850+
* Check recipe table syntax for different types below.
1851+
* `minetest.clear_craft(recipe)`
1852+
* Will erase existing craft based either on output item or on input recipe.
1853+
* Specify either output or input only. If you specify both, input will be ignored. For input use the same recipe table
1854+
syntax as for `minetest.register_craft(recipe)`. For output specify only the item, without a quantity.
1855+
* If no erase candidate could be found, Lua exception will be thrown.
1856+
* Warning! The type field ("shaped","cooking" or any other) will be ignored if the recipe
1857+
contains output. Erasing is then done independently from the crafting method.
18501858
* `minetest.register_ore(ore definition)`
18511859
* `minetest.register_decoration(decoration definition)`
18521860
* `minetest.override_item(name, redefinition)`

Diff for: ‎src/craftdef.cpp

+90
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,96 @@ class CCraftDefManager: public IWritableCraftDefManager
960960

961961
return recipes;
962962
}
963+
964+
virtual bool clearCraftRecipesByOutput(const CraftOutput &output, IGameDef *gamedef)
965+
{
966+
std::map<std::string, std::vector<CraftDefinition*> >::iterator vec_iter =
967+
m_output_craft_definitions.find(output.item);
968+
969+
if (vec_iter == m_output_craft_definitions.end())
970+
return false;
971+
972+
std::vector<CraftDefinition*> &vec = vec_iter->second;
973+
for (std::vector<CraftDefinition*>::iterator i = vec.begin();
974+
i != vec.end(); ++i) {
975+
CraftDefinition *def = *i;
976+
// Recipes are not yet hashed at this point
977+
std::vector<CraftDefinition*> &unhashed_inputs_vec = m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0];
978+
std::vector<CraftDefinition*> new_vec_by_input;
979+
/* We will preallocate necessary memory addresses, so we don't need to reallocate them later.
980+
This would save us some performance. */
981+
new_vec_by_input.reserve(unhashed_inputs_vec.size());
982+
for (std::vector<CraftDefinition*>::iterator i2 = unhashed_inputs_vec.begin();
983+
i2 != unhashed_inputs_vec.end(); ++i2) {
984+
if (def != *i2) {
985+
new_vec_by_input.push_back(*i2);
986+
}
987+
}
988+
m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0].swap(new_vec_by_input);
989+
}
990+
m_output_craft_definitions.erase(output.item);
991+
return true;
992+
}
993+
994+
virtual bool clearCraftRecipesByInput(CraftMethod craft_method, unsigned int craft_grid_width,
995+
const std::vector<std::string> &recipe, IGameDef *gamedef)
996+
{
997+
bool all_empty = true;
998+
for (std::vector<std::string>::size_type i = 0;
999+
i < recipe.size(); i++) {
1000+
if (!recipe[i].empty()) {
1001+
all_empty = false;
1002+
break;
1003+
}
1004+
}
1005+
if (all_empty)
1006+
return false;
1007+
1008+
CraftInput input(craft_method, craft_grid_width, craftGetItems(recipe, gamedef));
1009+
// Recipes are not yet hashed at this point
1010+
std::vector<CraftDefinition*> &unhashed_inputs_vec = m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0];
1011+
std::vector<CraftDefinition*> new_vec_by_input;
1012+
bool got_hit = false;
1013+
for (std::vector<CraftDefinition*>::size_type
1014+
i = unhashed_inputs_vec.size(); i > 0; i--) {
1015+
CraftDefinition *def = unhashed_inputs_vec[i - 1];
1016+
/* If the input doesn't match the recipe definition, this recipe definition later
1017+
will be added back in source map. */
1018+
if (!def->check(input, gamedef)) {
1019+
new_vec_by_input.push_back(def);
1020+
continue;
1021+
}
1022+
CraftOutput output = def->getOutput(input, gamedef);
1023+
got_hit = true;
1024+
std::map<std::string, std::vector<CraftDefinition*> >::iterator
1025+
vec_iter = m_output_craft_definitions.find(output.item);
1026+
if (vec_iter == m_output_craft_definitions.end())
1027+
continue;
1028+
std::vector<CraftDefinition*> &vec = vec_iter->second;
1029+
std::vector<CraftDefinition*> new_vec_by_output;
1030+
/* We will preallocate necessary memory addresses, so we don't need
1031+
to reallocate them later. This would save us some performance. */
1032+
new_vec_by_output.reserve(vec.size());
1033+
for (std::vector<CraftDefinition*>::iterator i = vec.begin();
1034+
i != vec.end(); ++i) {
1035+
/* If pointers from map by input and output are not same,
1036+
we will add 'CraftDefinition*' to a new vector. */
1037+
if (def != *i) {
1038+
/* Adding dereferenced iterator value (which are
1039+
'CraftDefinition' reference) to a new vector. */
1040+
new_vec_by_output.push_back(*i);
1041+
}
1042+
}
1043+
// Swaps assigned to current key value with new vector for output map.
1044+
m_output_craft_definitions[output.item].swap(new_vec_by_output);
1045+
}
1046+
if (got_hit)
1047+
// Swaps value with new vector for input map.
1048+
m_craft_defs[(int) CRAFT_HASH_TYPE_UNHASHED][0].swap(new_vec_by_input);
1049+
1050+
return got_hit;
1051+
}
1052+
9631053
virtual std::string dump() const
9641054
{
9651055
std::ostringstream os(std::ios::binary);

Diff for: ‎src/craftdef.h

+4
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,10 @@ class IWritableCraftDefManager : public ICraftDefManager
426426
virtual std::vector<CraftDefinition*> getCraftRecipes(CraftOutput &output,
427427
IGameDef *gamedef, unsigned limit=0) const=0;
428428

429+
virtual bool clearCraftRecipesByOutput(const CraftOutput &output, IGameDef *gamedef) = 0;
430+
virtual bool clearCraftRecipesByInput(CraftMethod craft_method,
431+
unsigned int craft_grid_width, const std::vector<std::string> &recipe, IGameDef *gamedef) = 0;
432+
429433
// Print crafting recipes for debugging
430434
virtual std::string dump() const=0;
431435

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

+75-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ struct EnumString ModApiCraft::es_CraftMethod[] =
3434
{0, NULL},
3535
};
3636

37-
3837
// helper for register_craft
3938
bool ModApiCraft::readCraftRecipeShaped(lua_State *L, int index,
4039
int &width, std::vector<std::string> &recipe)
@@ -281,6 +280,80 @@ int ModApiCraft::l_register_craft(lua_State *L)
281280
return 0; /* number of results */
282281
}
283282

283+
// clear_craft({[output=item], [recipe={{item00,item10},{item01,item11}}])
284+
int ModApiCraft::l_clear_craft(lua_State *L)
285+
{
286+
NO_MAP_LOCK_REQUIRED;
287+
luaL_checktype(L, 1, LUA_TTABLE);
288+
int table = 1;
289+
290+
// Get the writable craft definition manager from the server
291+
IWritableCraftDefManager *craftdef =
292+
getServer(L)->getWritableCraftDefManager();
293+
294+
std::string output = getstringfield_default(L, table, "output", "");
295+
std::string type = getstringfield_default(L, table, "type", "shaped");
296+
CraftOutput c_output(output, 0);
297+
if (output != "") {
298+
if (craftdef->clearCraftRecipesByOutput(c_output, getServer(L)))
299+
return 0;
300+
else
301+
throw LuaError("No craft recipe known for output"
302+
" (output=\"" + output + "\")");
303+
}
304+
std::vector<std::string> recipe;
305+
int width = 0;
306+
CraftMethod method = CRAFT_METHOD_NORMAL;
307+
/*
308+
CraftDefinitionShaped
309+
*/
310+
if (type == "shaped") {
311+
lua_getfield(L, table, "recipe");
312+
if (lua_isnil(L, -1))
313+
throw LuaError("Either output or recipe has to be defined");
314+
if (!readCraftRecipeShaped(L, -1, width, recipe))
315+
throw LuaError("Invalid crafting recipe");
316+
}
317+
/*
318+
CraftDefinitionShapeless
319+
*/
320+
else if (type == "shapeless") {
321+
lua_getfield(L, table, "recipe");
322+
if (lua_isnil(L, -1))
323+
throw LuaError("Either output or recipe has to be defined");
324+
if (!readCraftRecipeShapeless(L, -1, recipe))
325+
throw LuaError("Invalid crafting recipe");
326+
}
327+
/*
328+
CraftDefinitionCooking
329+
*/
330+
else if (type == "cooking") {
331+
method = CRAFT_METHOD_COOKING;
332+
std::string rec = getstringfield_default(L, table, "recipe", "");
333+
if (rec == "")
334+
throw LuaError("Crafting definition (cooking)"
335+
" is missing a recipe");
336+
recipe.push_back(rec);
337+
}
338+
/*
339+
CraftDefinitionFuel
340+
*/
341+
else if (type == "fuel") {
342+
method = CRAFT_METHOD_FUEL;
343+
std::string rec = getstringfield_default(L, table, "recipe", "");
344+
if (rec == "")
345+
throw LuaError("Crafting definition (fuel)"
346+
" is missing a recipe");
347+
recipe.push_back(rec);
348+
} else {
349+
throw LuaError("Unknown crafting definition type: \"" + type + "\"");
350+
}
351+
if (!craftdef->clearCraftRecipesByInput(method, width, recipe, getServer(L)))
352+
throw LuaError("No crafting specified for input");
353+
lua_pop(L, 1);
354+
return 0;
355+
}
356+
284357
// get_craft_result(input)
285358
int ModApiCraft::l_get_craft_result(lua_State *L)
286359
{
@@ -431,4 +504,5 @@ void ModApiCraft::Initialize(lua_State *L, int top)
431504
API_FCT(get_craft_recipe);
432505
API_FCT(get_craft_result);
433506
API_FCT(register_craft);
507+
API_FCT(clear_craft);
434508
}

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

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class ModApiCraft : public ModApiBase {
3333
static int l_get_craft_recipe(lua_State *L);
3434
static int l_get_all_craft_recipes(lua_State *L);
3535
static int l_get_craft_result(lua_State *L);
36+
static int l_clear_craft(lua_State *L);
3637

3738
static bool readCraftReplacements(lua_State *L, int index,
3839
CraftReplacements &replacements);

0 commit comments

Comments
 (0)
Please sign in to comment.