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