/*MinetestCopyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>This program is free software; you can redistribute it and/or modifyit under the terms of the GNU Lesser General Public License as published bythe 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 ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See theGNU Lesser General Public License for more details.You should have received a copy of the GNU Lesser General Public License alongwith this program; if not, write to the Free Software Foundation, Inc.,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.*/#include"cpp_api/s_item.h"#include"cpp_api/s_internal.h"#include"common/c_converter.h"#include"common/c_content.h"#include"lua_api/l_item.h"#include"lua_api/l_inventory.h"#include"server.h"#include"log.h"#include"util/pointedthing.h"#include"inventory.h"#include"inventorymanager.h"boolScriptApiItem::item_OnDrop(ItemStack &item,
ServerActiveObject *dropper, v3f pos){
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stackif(!getItemCallback(item.name.c_str(),"on_drop"))return false;// Call functionLuaItemStack::create(L, item);objectrefGetOrCreate(L, dropper);pushFloatPos(L, pos);if(lua_pcall(L,3,1, m_errorhandler))scriptError();if(!lua_isnil(L, -1)) {try{
item =read_item(L,-1,getServer());}catch(LuaError &e) {throwLuaError(std::string(e.what()) +". item="+ item.name);}}lua_pop(L,1);// Pop itemreturn true;}boolScriptApiItem::item_OnPlace(ItemStack &item,
ServerActiveObject *placer,const PointedThing &pointed){
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stackif(!getItemCallback(item.name.c_str(),"on_place"))return false;// Call functionLuaItemStack::create(L, item);objectrefGetOrCreate(L, placer);pushPointedThing(pointed);if(lua_pcall(L,3,1, m_errorhandler))scriptError();if(!lua_isnil(L, -1)) {try{
item =read_item(L,-1,getServer());}catch(LuaError &e) {throwLuaError(std::string(e.what()) +". item="+ item.name);}}lua_pop(L,1);// Pop itemreturn true;}boolScriptApiItem::item_OnUse(ItemStack &item,
ServerActiveObject *user,const PointedThing &pointed){
SCRIPTAPI_PRECHECKHEADER
// Push callback function on stackif(!getItemCallback(item.name.c_str(),"on_use"))return false;// Call functionLuaItemStack::create(L, item);objectrefGetOrCreate(L, user);pushPointedThing(pointed);if(lua_pcall(L,3,1, m_errorhandler))scriptError();if(!lua_isnil(L, -1)) {try{
item =read_item(L,-1,getServer());}catch(LuaError &e) {throwLuaError(std::string(e.what()) +". item="+ item.name);}}lua_pop(L,1);// Pop itemreturn true;}boolScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,const InventoryList *old_craft_grid,const InventoryLocation &craft_inv){
SCRIPTAPI_PRECHECKHEADER
lua_getglobal(L,"core");lua_getfield(L, -1,"on_craft");LuaItemStack::create(L, item);objectrefGetOrCreate(L, user);// Push inventory liststd::vector<ItemStack> items;for(u32 i =0; i < old_craft_grid->getSize(); i++) {
items.push_back(old_craft_grid->getItem(i));}push_items(L, items);InvRef::create(L, craft_inv);if(lua_pcall(L,4,1, m_errorhandler))scriptError();if(!lua_isnil(L, -1)) {try{
item =read_item(L,-1,getServer());}catch(LuaError &e) {throwLuaError(std::string(e.what()) +". item="+ item.name);}}lua_pop(L,1);// Pop itemreturn true;}boolScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,const InventoryList *old_craft_grid,const InventoryLocation &craft_inv){
SCRIPTAPI_PRECHECKHEADER
lua_getglobal(L,"core");lua_getfield(L, -1,"craft_predict");LuaItemStack::create(L, item);objectrefGetOrCreate(L, user);//Push inventory liststd::vector<ItemStack> items;for(u32 i =0; i < old_craft_grid->getSize(); i++) {
items.push_back(old_craft_grid->getItem(i));}push_items(L, items);InvRef::create(L, craft_inv);if(lua_pcall(L,4,1, m_errorhandler))scriptError();if(!lua_isnil(L, -1)) {try{
item =read_item(L,-1,getServer());}catch(LuaError &e) {throwLuaError(std::string(e.what()) +". item="+ item.name);}}lua_pop(L,1);// Pop itemreturn true;}// Retrieves core.registered_items[name][callbackname]// If that is nil or on error, return false and stack is unchanged// If that is a function, returns true and pushes the// function onto the stack// If core.registered_items[name] doesn't exist, core.nodedef_default// is tried instead so unknown items can still be manipulated to some degreeboolScriptApiItem::getItemCallback(const char*name,const char*callbackname){
lua_State* L =getStack();lua_getglobal(L,"core");lua_getfield(L, -1,"registered_items");lua_remove(L, -2);// Remove coreluaL_checktype(L, -1, LUA_TTABLE);lua_getfield(L, -1, name);lua_remove(L, -2);// Remove registered_items// Should be a tableif(lua_type(L, -1) != LUA_TTABLE){// Report error and clean up
errorstream <<"Item\""<< name <<"\"not defined"<<std::endl;lua_pop(L,1);// Try core.nodedef_default insteadlua_getglobal(L,"core");lua_getfield(L, -1,"nodedef_default");lua_remove(L, -2);luaL_checktype(L, -1, LUA_TTABLE);}lua_getfield(L, -1, callbackname);lua_remove(L, -2);// Remove item def// Should be a function or nilif(lua_type(L, -1) == LUA_TFUNCTION) {return true;}else if(!lua_isnil(L, -1)) {
errorstream <<"Item\""<< name <<"\"callback\""<< callbackname <<"\"is not a function"<<std::endl;}lua_pop(L,1);return false;}voidScriptApiItem::pushPointedThing(const PointedThing& pointed){
lua_State* L =getStack();lua_newtable(L);if(pointed.type == POINTEDTHING_NODE){lua_pushstring(L,"node");lua_setfield(L, -2,"type");push_v3s16(L, pointed.node_undersurface);lua_setfield(L, -2,"under");push_v3s16(L, pointed.node_abovesurface);lua_setfield(L, -2,"above");}else if(pointed.type == POINTEDTHING_OBJECT){lua_pushstring(L,"object");lua_setfield(L, -2,"type");objectrefGet(L, pointed.object_id);lua_setfield(L, -2,"ref");}else{lua_pushstring(L,"nothing");lua_setfield(L, -2,"type");}}