s_item.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "cpp_api/s_item.h"
  17. #include "cpp_api/s_internal.h"
  18. #include "common/c_converter.h"
  19. #include "common/c_content.h"
  20. #include "lua_api/l_item.h"
  21. #include "lua_api/l_inventory.h"
  22. #include "server.h"
  23. #include "log.h"
  24. #include "util/pointedthing.h"
  25. #include "inventory.h"
  26. #include "inventorymanager.h"
  27. #define WRAP_LUAERROR(e, detail) \
  28. LuaError(std::string(__FUNCTION__) + ": " + (e).what() + ". " detail)
  29. bool ScriptApiItem::item_OnDrop(ItemStack &item,
  30. ServerActiveObject *dropper, v3f pos)
  31. {
  32. SCRIPTAPI_PRECHECKHEADER
  33. int error_handler = PUSH_ERROR_HANDLER(L);
  34. // Push callback function on stack
  35. if (!getItemCallback(item.name.c_str(), "on_drop"))
  36. return false;
  37. // Call function
  38. LuaItemStack::create(L, item);
  39. objectrefGetOrCreate(L, dropper);
  40. pushFloatPos(L, pos);
  41. PCALL_RES(lua_pcall(L, 3, 1, error_handler));
  42. if (!lua_isnil(L, -1)) {
  43. try {
  44. item = read_item(L, -1, getServer()->idef());
  45. } catch (LuaError &e) {
  46. throw WRAP_LUAERROR(e, "item=" + item.name);
  47. }
  48. }
  49. lua_pop(L, 2); // Pop item and error handler
  50. return true;
  51. }
  52. bool ScriptApiItem::item_OnPlace(Optional<ItemStack> &ret_item,
  53. ServerActiveObject *placer, const PointedThing &pointed)
  54. {
  55. SCRIPTAPI_PRECHECKHEADER
  56. int error_handler = PUSH_ERROR_HANDLER(L);
  57. const ItemStack &item = *ret_item;
  58. // Push callback function on stack
  59. if (!getItemCallback(item.name.c_str(), "on_place"))
  60. return false;
  61. // Call function
  62. LuaItemStack::create(L, item);
  63. if (!placer)
  64. lua_pushnil(L);
  65. else
  66. objectrefGetOrCreate(L, placer);
  67. pushPointedThing(pointed);
  68. PCALL_RES(lua_pcall(L, 3, 1, error_handler));
  69. if (!lua_isnil(L, -1)) {
  70. try {
  71. ret_item = read_item(L, -1, getServer()->idef());
  72. } catch (LuaError &e) {
  73. throw WRAP_LUAERROR(e, "item=" + item.name);
  74. }
  75. } else {
  76. ret_item = nullopt;
  77. }
  78. lua_pop(L, 2); // Pop item and error handler
  79. return true;
  80. }
  81. bool ScriptApiItem::item_OnUse(Optional<ItemStack> &ret_item,
  82. ServerActiveObject *user, const PointedThing &pointed)
  83. {
  84. SCRIPTAPI_PRECHECKHEADER
  85. int error_handler = PUSH_ERROR_HANDLER(L);
  86. const ItemStack &item = *ret_item;
  87. // Push callback function on stack
  88. if (!getItemCallback(item.name.c_str(), "on_use"))
  89. return false;
  90. // Call function
  91. LuaItemStack::create(L, item);
  92. objectrefGetOrCreate(L, user);
  93. pushPointedThing(pointed);
  94. PCALL_RES(lua_pcall(L, 3, 1, error_handler));
  95. if(!lua_isnil(L, -1)) {
  96. try {
  97. ret_item = read_item(L, -1, getServer()->idef());
  98. } catch (LuaError &e) {
  99. throw WRAP_LUAERROR(e, "item=" + item.name);
  100. }
  101. } else {
  102. ret_item = nullopt;
  103. }
  104. lua_pop(L, 2); // Pop item and error handler
  105. return true;
  106. }
  107. bool ScriptApiItem::item_OnSecondaryUse(Optional<ItemStack> &ret_item,
  108. ServerActiveObject *user, const PointedThing &pointed)
  109. {
  110. SCRIPTAPI_PRECHECKHEADER
  111. int error_handler = PUSH_ERROR_HANDLER(L);
  112. const ItemStack &item = *ret_item;
  113. if (!getItemCallback(item.name.c_str(), "on_secondary_use"))
  114. return false;
  115. LuaItemStack::create(L, item);
  116. objectrefGetOrCreate(L, user);
  117. pushPointedThing(pointed);
  118. PCALL_RES(lua_pcall(L, 3, 1, error_handler));
  119. if (!lua_isnil(L, -1)) {
  120. try {
  121. ret_item = read_item(L, -1, getServer()->idef());
  122. } catch (LuaError &e) {
  123. throw WRAP_LUAERROR(e, "item=" + item.name);
  124. }
  125. } else {
  126. ret_item = nullopt;
  127. }
  128. lua_pop(L, 2); // Pop item and error handler
  129. return true;
  130. }
  131. bool ScriptApiItem::item_OnCraft(ItemStack &item, ServerActiveObject *user,
  132. const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
  133. {
  134. SCRIPTAPI_PRECHECKHEADER
  135. int error_handler = PUSH_ERROR_HANDLER(L);
  136. lua_getglobal(L, "core");
  137. lua_getfield(L, -1, "on_craft");
  138. LuaItemStack::create(L, item);
  139. objectrefGetOrCreate(L, user);
  140. // Push inventory list
  141. std::vector<ItemStack> items;
  142. for (u32 i = 0; i < old_craft_grid->getSize(); i++) {
  143. items.push_back(old_craft_grid->getItem(i));
  144. }
  145. push_items(L, items);
  146. InvRef::create(L, craft_inv);
  147. PCALL_RES(lua_pcall(L, 4, 1, error_handler));
  148. if (!lua_isnil(L, -1)) {
  149. try {
  150. item = read_item(L, -1, getServer()->idef());
  151. } catch (LuaError &e) {
  152. throw WRAP_LUAERROR(e, "item=" + item.name);
  153. }
  154. }
  155. lua_pop(L, 2); // Pop item and error handler
  156. return true;
  157. }
  158. bool ScriptApiItem::item_CraftPredict(ItemStack &item, ServerActiveObject *user,
  159. const InventoryList *old_craft_grid, const InventoryLocation &craft_inv)
  160. {
  161. SCRIPTAPI_PRECHECKHEADER
  162. sanity_check(old_craft_grid);
  163. int error_handler = PUSH_ERROR_HANDLER(L);
  164. lua_getglobal(L, "core");
  165. lua_getfield(L, -1, "craft_predict");
  166. LuaItemStack::create(L, item);
  167. objectrefGetOrCreate(L, user);
  168. //Push inventory list
  169. std::vector<ItemStack> items;
  170. for (u32 i = 0; i < old_craft_grid->getSize(); i++) {
  171. items.push_back(old_craft_grid->getItem(i));
  172. }
  173. push_items(L, items);
  174. InvRef::create(L, craft_inv);
  175. PCALL_RES(lua_pcall(L, 4, 1, error_handler));
  176. if (!lua_isnil(L, -1)) {
  177. try {
  178. item = read_item(L, -1, getServer()->idef());
  179. } catch (LuaError &e) {
  180. throw WRAP_LUAERROR(e, "item=" + item.name);
  181. }
  182. }
  183. lua_pop(L, 2); // Pop item and error handler
  184. return true;
  185. }
  186. // Retrieves core.registered_items[name][callbackname]
  187. // If that is nil or on error, return false and stack is unchanged
  188. // If that is a function, returns true and pushes the
  189. // function onto the stack
  190. // If core.registered_items[name] doesn't exist, core.nodedef_default
  191. // is tried instead so unknown items can still be manipulated to some degree
  192. bool ScriptApiItem::getItemCallback(const char *name, const char *callbackname,
  193. const v3s16 *p)
  194. {
  195. lua_State* L = getStack();
  196. lua_getglobal(L, "core");
  197. lua_getfield(L, -1, "registered_items");
  198. lua_remove(L, -2); // Remove core
  199. luaL_checktype(L, -1, LUA_TTABLE);
  200. lua_getfield(L, -1, name);
  201. lua_remove(L, -2); // Remove registered_items
  202. // Should be a table
  203. if (lua_type(L, -1) != LUA_TTABLE) {
  204. // Report error and clean up
  205. errorstream << "Item \"" << name << "\" not defined";
  206. if (p)
  207. errorstream << " at position " << PP(*p);
  208. errorstream << std::endl;
  209. lua_pop(L, 1);
  210. // Try core.nodedef_default instead
  211. lua_getglobal(L, "core");
  212. lua_getfield(L, -1, "nodedef_default");
  213. lua_remove(L, -2);
  214. luaL_checktype(L, -1, LUA_TTABLE);
  215. }
  216. setOriginFromTable(-1);
  217. lua_getfield(L, -1, callbackname);
  218. lua_remove(L, -2); // Remove item def
  219. // Should be a function or nil
  220. if (lua_type(L, -1) == LUA_TFUNCTION) {
  221. return true;
  222. }
  223. if (!lua_isnil(L, -1)) {
  224. errorstream << "Item \"" << name << "\" callback \""
  225. << callbackname << "\" is not a function" << std::endl;
  226. }
  227. lua_pop(L, 1);
  228. return false;
  229. }
  230. void ScriptApiItem::pushPointedThing(const PointedThing &pointed, bool hitpoint)
  231. {
  232. lua_State* L = getStack();
  233. push_pointed_thing(L, pointed, false, hitpoint);
  234. }