aboutsummaryrefslogtreecommitdiff
path: root/src/script
Commit message (Expand)AuthorAge
* Fix HTTP API not being available in async mainmenu (#10086)rubenwardy2020-06-22
* Add warning when disabling secure.enable_security (#9943)rubenwardy2020-06-20
* Make shading of CAOs optional (#10033)Danila Shutov2020-06-16
* Exposing the zoom key to Lua API (#9903)Lars Müller2020-06-13
* Server pushing media at runtime (#9961)sfan52020-06-13
* LuaItemStack: Add __tostring metamethod (#8785)Paul Ouellette2020-06-09
* Fix Lua panic when error() message is not a stringPaul Ouellette2020-06-07
* Add HTTP API to main menu (#9998)rubenwardy2020-06-06
* Lua API: Log incorrect parameter types as error (#9954)SmallJoker2020-06-01
* Value copy / allocation optimizations mostly in server, SAO and serialize codesfan52020-05-27
* Implement spawning particles with node texture appearancesfan52020-05-23
* Add on_authplayer callback and 'last_login' to on_joinplayer (#9574)sorcerykid2020-05-23
* Modernize include guards and add missing ones (#9898)Awkor2020-05-23
* Check for valid base64 before decoding (#9904)Lejo12020-05-22
* Cleanup of particle & particlespawner structures and code (#9893)sfan52020-05-22
* Allow more than 255 biomes, document new maximum (#9855)Paramat2020-05-20
* CSM: Fix crashing minetest.get_item_def()sfan52020-05-20
* Rework functionality of leveled nodes (#9852)Wuzzy2020-05-19
* Add core.open_url() to main menu API (#8592)rubenwardy2020-05-17
* CSM: Bugfixes to camera:get_pos() and camera:get_fov()sfan52020-05-14
* Damage texture modifier (#9833)Lars Müller2020-05-11
* Add support for statbar “off state” icons (#9462)Wuzzy2020-05-11
* Server class code cleanups (#9769)Loïc Blot2020-05-07
* Expose collided objects in moveresultsfan52020-05-06
* Fix remaining issues with mapgen scriptapisfan52020-05-05
* Give the Mapgen on each EmergeThread its own Biome/Ore/Deco/SchemManager copysfan52020-05-05
* Sky API: Rename *_tint to fog_*_tint for consistencySmallJoker2020-05-05
* Rename moveresult speed to velocitySmallJoker2020-05-05
* Auto delete MetaData when = 0 (#8770)Lejo2020-05-02
* set_fov: Add support for time-based transitions (#9705)ANAND2020-05-02
* Allow connection info to be missing from minetest.get_player_information() (#...sfan52020-05-01
* Give the online lua mainmenu also the client_list and mods (#8691)Lejo2020-05-01
* Expose collision information to LuaEntity on_stepsfan52020-04-27
* Forbid object:attach(obj, ...) (#9762)Loïc Blot2020-04-27
* Script: Enforce type checks if not nil (#9748)SmallJoker2020-04-27
* script: Put getGuiEngine() inside a client-only #ifdefsfan52020-04-27
* script: Fix add_entity returning unusable ref if object deleted in on_activatesfan52020-04-27
* Add server side translations capability (#9733)EvidenceB Kidscode2020-04-25
* Fix configuration caching in log_deprecated (#9697)HybridDog2020-04-22
* Fix alias handling of get_content_id (#9712)sfan52020-04-19
* script: Move SAO usability check so that it covers all functions (#9698)sfan52020-04-18
* Optimize get_objects_inside_radius calls (#9671)Loïc Blot2020-04-16
* Fix parsing JSON with large integers (#9674)sfan52020-04-15
* scriptapi: Some small optimizations to value pushing (#9669)sfan52020-04-14
* Improve waypoints and add image variant (#9480)Lars Müller2020-04-11
* Formspecs: Add state-selection to style elements (#9378)Hugues Ross2020-04-11
* Fix broken config check in 659245asfan52020-04-11
* Reduce ServerEnvironment propagation (#9642)Loïc Blot2020-04-11
* Drop content_sao.{cpp,h}Loic Blot2020-04-11
* Move PlayerSAO to dedicated filesLoic Blot2020-04-11
an class="hl com">Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "lua_api/l_craft.h" #include "lua_api/l_internal.h" #include "lua_api/l_item.h" #include "common/c_converter.h" #include "common/c_content.h" #include "server.h" #include "craftdef.h" struct EnumString ModApiCraft::es_CraftMethod[] = { {CRAFT_METHOD_NORMAL, "normal"}, {CRAFT_METHOD_COOKING, "cooking"}, {CRAFT_METHOD_FUEL, "fuel"}, {0, NULL}, }; // helper for register_craft bool ModApiCraft::readCraftRecipeShaped(lua_State *L, int index, int &width, std::vector<std::string> &recipe) { if(index < 0) index = lua_gettop(L) + 1 + index; if(!lua_istable(L, index)) return false; lua_pushnil(L); int rowcount = 0; while(lua_next(L, index) != 0){ int colcount = 0; // key at index -2 and value at index -1 if(!lua_istable(L, -1)) return false; int table2 = lua_gettop(L); lua_pushnil(L); while(lua_next(L, table2) != 0){ // key at index -2 and value at index -1 if(!lua_isstring(L, -1)) return false; recipe.push_back(lua_tostring(L, -1)); // removes value, keeps key for next iteration lua_pop(L, 1); colcount++; } if(rowcount == 0){ width = colcount; } else { if(colcount != width) return false; } // removes value, keeps key for next iteration lua_pop(L, 1); rowcount++; } return width != 0; } // helper for register_craft bool ModApiCraft::readCraftRecipeShapeless(lua_State *L, int index, std::vector<std::string> &recipe) { if(index < 0) index = lua_gettop(L) + 1 + index; if(!lua_istable(L, index)) return false; lua_pushnil(L); while(lua_next(L, index) != 0){ // key at index -2 and value at index -1 if(!lua_isstring(L, -1)) return false; recipe.push_back(lua_tostring(L, -1)); // removes value, keeps key for next iteration lua_pop(L, 1); } return true; } // helper for register_craft bool ModApiCraft::readCraftReplacements(lua_State *L, int index, CraftReplacements &replacements) { if(index < 0) index = lua_gettop(L) + 1 + index; if(!lua_istable(L, index)) return false; lua_pushnil(L); while(lua_next(L, index) != 0){ // key at index -2 and value at index -1 if(!lua_istable(L, -1)) return false; lua_rawgeti(L, -1, 1); if(!lua_isstring(L, -1)) return false; std::string replace_from = lua_tostring(L, -1); lua_pop(L, 1); lua_rawgeti(L, -1, 2); if(!lua_isstring(L, -1)) return false; std::string replace_to = lua_tostring(L, -1); lua_pop(L, 1); replacements.pairs.push_back( std::make_pair(replace_from, replace_to)); // removes value, keeps key for next iteration lua_pop(L, 1); } return true; } // register_craft({output=item, recipe={{item00,item10},{item01,item11}}) int ModApiCraft::l_register_craft(lua_State *L) { NO_MAP_LOCK_REQUIRED; //infostream<<"register_craft"<<std::endl; luaL_checktype(L, 1, LUA_TTABLE); int table = 1; // Get the writable craft definition manager from the server IWritableCraftDefManager *craftdef = getServer(L)->getWritableCraftDefManager(); std::string type = getstringfield_default(L, table, "type", "shaped"); /* CraftDefinitionShaped */ if(type == "shaped"){ std::string output = getstringfield_default(L, table, "output", ""); if(output == "") throw LuaError("Crafting definition is missing an output"); int width = 0; std::vector<std::string> recipe; lua_getfield(L, table, "recipe"); if(lua_isnil(L, -1)) throw LuaError("Crafting definition is missing a recipe" " (output=\"" + output + "\")"); if(!readCraftRecipeShaped(L, -1, width, recipe)) throw LuaError("Invalid crafting recipe" " (output=\"" + output + "\")"); CraftReplacements replacements; lua_getfield(L, table, "replacements"); if(!lua_isnil(L, -1)) { if(!readCraftReplacements(L, -1, replacements)) throw LuaError("Invalid replacements" " (output=\"" + output + "\")"); } CraftDefinition *def = new CraftDefinitionShaped( output, width, recipe, replacements); craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionShapeless */ else if(type == "shapeless"){ std::string output = getstringfield_default(L, table, "output", ""); if(output == "") throw LuaError("Crafting definition (shapeless)" " is missing an output"); std::vector<std::string> recipe; lua_getfield(L, table, "recipe"); if(lua_isnil(L, -1)) throw LuaError("Crafting definition (shapeless)" " is missing a recipe" " (output=\"" + output + "\")"); if(!readCraftRecipeShapeless(L, -1, recipe)) throw LuaError("Invalid crafting recipe" " (output=\"" + output + "\")"); CraftReplacements replacements; lua_getfield(L, table, "replacements"); if(!lua_isnil(L, -1)) { if(!readCraftReplacements(L, -1, replacements)) throw LuaError("Invalid replacements" " (output=\"" + output + "\")"); } CraftDefinition *def = new CraftDefinitionShapeless( output, recipe, replacements); craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionToolRepair */ else if(type == "toolrepair"){ float additional_wear = getfloatfield_default(L, table, "additional_wear", 0.0); CraftDefinition *def = new CraftDefinitionToolRepair( additional_wear); craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionCooking */ else if(type == "cooking"){ std::string output = getstringfield_default(L, table, "output", ""); if(output == "") throw LuaError("Crafting definition (cooking)" " is missing an output"); std::string recipe = getstringfield_default(L, table, "recipe", ""); if(recipe == "") throw LuaError("Crafting definition (cooking)" " is missing a recipe" " (output=\"" + output + "\")"); float cooktime = getfloatfield_default(L, table, "cooktime", 3.0); CraftReplacements replacements; lua_getfield(L, table, "replacements"); if(!lua_isnil(L, -1)) { if(!readCraftReplacements(L, -1, replacements)) throw LuaError("Invalid replacements" " (cooking output=\"" + output + "\")"); } CraftDefinition *def = new CraftDefinitionCooking( output, recipe, cooktime, replacements); craftdef->registerCraft(def, getServer(L)); } /* CraftDefinitionFuel */ else if(type == "fuel"){ std::string recipe = getstringfield_default(L, table, "recipe", ""); if(recipe == "") throw LuaError("Crafting definition (fuel)" " is missing a recipe"); float burntime = getfloatfield_default(L, table, "burntime", 1.0); CraftReplacements replacements; lua_getfield(L, table, "replacements"); if(!lua_isnil(L, -1)) { if(!readCraftReplacements(L, -1, replacements)) throw LuaError("Invalid replacements" " (fuel recipe=\"" + recipe + "\")"); } CraftDefinition *def = new CraftDefinitionFuel( recipe, burntime, replacements); craftdef->registerCraft(def, getServer(L)); } else { throw LuaError("Unknown crafting definition type: \"" + type + "\""); } lua_pop(L, 1); return 0; /* number of results */ } // get_craft_result(input) int ModApiCraft::l_get_craft_result(lua_State *L) { NO_MAP_LOCK_REQUIRED; int input_i = 1; std::string method_s = getstringfield_default(L, input_i, "method", "normal"); enum CraftMethod method = (CraftMethod)getenumfield(L, input_i, "method", es_CraftMethod, CRAFT_METHOD_NORMAL); int width = 1; lua_getfield(L, input_i, "width"); if(lua_isnumber(L, -1)) width = luaL_checkinteger(L, -1); lua_pop(L, 1); lua_getfield(L, input_i, "items"); std::vector<ItemStack> items = read_items(L, -1,getServer(L)); lua_pop(L, 1); // items IGameDef *gdef = getServer(L); ICraftDefManager *cdef = gdef->cdef(); CraftInput input(method, width, items); CraftOutput output; bool got = cdef->getCraftResult(input, output, true, gdef); lua_newtable(L); // output table if(got){ ItemStack item; item.deSerialize(output.item, gdef->idef()); LuaItemStack::create(L, item); lua_setfield(L, -2, "item"); setintfield(L, -1, "time", output.time); } else { LuaItemStack::create(L, ItemStack()); lua_setfield(L, -2, "item"); setintfield(L, -1, "time", 0); } lua_newtable(L); // decremented input table lua_pushstring(L, method_s.c_str()); lua_setfield(L, -2, "method"); lua_pushinteger(L, width); lua_setfield(L, -2, "width"); push_items(L, input.items); lua_setfield(L, -2, "items"); 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<ItemStack>::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<CraftDefinition*> &recipes, const CraftOutput &output) { lua_createtable(L, recipes.size(), 0); if (recipes.empty()) { lua_pushnil(L); return; } std::vector<CraftDefinition*>::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; std::string item = luaL_checkstring(L, 1); Server *server = getServer(L); CraftOutput output(item, 0); std::vector<CraftDefinition*> recipes = server->cdef() ->getCraftRecipes(output, server, 1); lua_createtable(L, 1, 0); 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; } // get_all_craft_recipes(result item) int ModApiCraft::l_get_all_craft_recipes(lua_State *L) { NO_MAP_LOCK_REQUIRED; std::string item = luaL_checkstring(L, 1); Server *server = getServer(L); CraftOutput output(item, 0); std::vector<CraftDefinition*> recipes = server->cdef() ->getCraftRecipes(output, server); push_craft_recipes(L, server, recipes, output); return 1; } void ModApiCraft::Initialize(lua_State *L, int top) { API_FCT(get_all_craft_recipes); API_FCT(get_craft_recipe); API_FCT(get_craft_result); API_FCT(register_craft); }