]> git.lizzy.rs Git - minetest.git/blob - src/script/lua_api/l_inventory.cpp
Remove a few unused functions reported by callcatcher (#11658)
[minetest.git] / src / script / lua_api / l_inventory.cpp
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 "lua_api/l_inventory.h"
21 #include "lua_api/l_internal.h"
22 #include "lua_api/l_item.h"
23 #include "common/c_converter.h"
24 #include "common/c_content.h"
25 #include "server.h"
26 #include "server/serverinventorymgr.h"
27 #include "remoteplayer.h"
28
29 /*
30         InvRef
31 */
32 InvRef* InvRef::checkobject(lua_State *L, int narg)
33 {
34         luaL_checktype(L, narg, LUA_TUSERDATA);
35         void *ud = luaL_checkudata(L, narg, className);
36         if(!ud) luaL_typerror(L, narg, className);
37         return *(InvRef**)ud;  // unbox pointer
38 }
39
40 Inventory* InvRef::getinv(lua_State *L, InvRef *ref)
41 {
42         return getServerInventoryMgr(L)->getInventory(ref->m_loc);
43 }
44
45 InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
46                 const char *listname)
47 {
48         NO_MAP_LOCK_REQUIRED;
49         Inventory *inv = getinv(L, ref);
50         if(!inv)
51                 return NULL;
52         return inv->getList(listname);
53 }
54
55 void InvRef::reportInventoryChange(lua_State *L, InvRef *ref)
56 {
57         // Inform other things that the inventory has changed
58         getServerInventoryMgr(L)->setInventoryModified(ref->m_loc);
59 }
60
61 // Exported functions
62
63 // garbage collector
64 int InvRef::gc_object(lua_State *L) {
65         InvRef *o = *(InvRef **)(lua_touserdata(L, 1));
66         delete o;
67         return 0;
68 }
69
70 // is_empty(self, listname) -> true/false
71 int InvRef::l_is_empty(lua_State *L)
72 {
73         NO_MAP_LOCK_REQUIRED;
74         InvRef *ref = checkobject(L, 1);
75         const char *listname = luaL_checkstring(L, 2);
76         InventoryList *list = getlist(L, ref, listname);
77         if(list && list->getUsedSlots() > 0){
78                 lua_pushboolean(L, false);
79         } else {
80                 lua_pushboolean(L, true);
81         }
82         return 1;
83 }
84
85 // get_size(self, listname)
86 int InvRef::l_get_size(lua_State *L)
87 {
88         NO_MAP_LOCK_REQUIRED;
89         InvRef *ref = checkobject(L, 1);
90         const char *listname = luaL_checkstring(L, 2);
91         InventoryList *list = getlist(L, ref, listname);
92         if(list){
93                 lua_pushinteger(L, list->getSize());
94         } else {
95                 lua_pushinteger(L, 0);
96         }
97         return 1;
98 }
99
100 // get_width(self, listname)
101 int InvRef::l_get_width(lua_State *L)
102 {
103         NO_MAP_LOCK_REQUIRED;
104         InvRef *ref = checkobject(L, 1);
105         const char *listname = luaL_checkstring(L, 2);
106         InventoryList *list = getlist(L, ref, listname);
107         if(list){
108                 lua_pushinteger(L, list->getWidth());
109         } else {
110                 lua_pushinteger(L, 0);
111         }
112         return 1;
113 }
114
115 // set_size(self, listname, size)
116 int InvRef::l_set_size(lua_State *L)
117 {
118         NO_MAP_LOCK_REQUIRED;
119         InvRef *ref = checkobject(L, 1);
120         const char *listname = luaL_checkstring(L, 2);
121
122         int newsize = luaL_checknumber(L, 3);
123         if (newsize < 0) {
124                 lua_pushboolean(L, false);
125                 return 1;
126         }
127
128         Inventory *inv = getinv(L, ref);
129         if(inv == NULL){
130                 lua_pushboolean(L, false);
131                 return 1;
132         }
133         if(newsize == 0){
134                 inv->deleteList(listname);
135                 reportInventoryChange(L, ref);
136                 lua_pushboolean(L, true);
137                 return 1;
138         }
139         InventoryList *list = inv->getList(listname);
140         if(list){
141                 list->setSize(newsize);
142         } else {
143                 list = inv->addList(listname, newsize);
144                 if (!list)
145                 {
146                         lua_pushboolean(L, false);
147                         return 1;
148                 }
149         }
150         reportInventoryChange(L, ref);
151         lua_pushboolean(L, true);
152         return 1;
153 }
154
155 // set_width(self, listname, size)
156 int InvRef::l_set_width(lua_State *L)
157 {
158         NO_MAP_LOCK_REQUIRED;
159         InvRef *ref = checkobject(L, 1);
160         const char *listname = luaL_checkstring(L, 2);
161         int newwidth = luaL_checknumber(L, 3);
162         Inventory *inv = getinv(L, ref);
163         if(inv == NULL){
164                 return 0;
165         }
166         InventoryList *list = inv->getList(listname);
167         if(list){
168                 list->setWidth(newwidth);
169         } else {
170                 return 0;
171         }
172         reportInventoryChange(L, ref);
173         return 0;
174 }
175
176 // get_stack(self, listname, i) -> itemstack
177 int InvRef::l_get_stack(lua_State *L)
178 {
179         NO_MAP_LOCK_REQUIRED;
180         InvRef *ref = checkobject(L, 1);
181         const char *listname = luaL_checkstring(L, 2);
182         int i = luaL_checknumber(L, 3) - 1;
183         InventoryList *list = getlist(L, ref, listname);
184         ItemStack item;
185         if(list != NULL && i >= 0 && i < (int) list->getSize())
186                 item = list->getItem(i);
187         LuaItemStack::create(L, item);
188         return 1;
189 }
190
191 // set_stack(self, listname, i, stack) -> true/false
192 int InvRef::l_set_stack(lua_State *L)
193 {
194         NO_MAP_LOCK_REQUIRED;
195         InvRef *ref = checkobject(L, 1);
196         const char *listname = luaL_checkstring(L, 2);
197         int i = luaL_checknumber(L, 3) - 1;
198         ItemStack newitem = read_item(L, 4, getServer(L)->idef());
199         InventoryList *list = getlist(L, ref, listname);
200         if(list != NULL && i >= 0 && i < (int) list->getSize()){
201                 list->changeItem(i, newitem);
202                 reportInventoryChange(L, ref);
203                 lua_pushboolean(L, true);
204         } else {
205                 lua_pushboolean(L, false);
206         }
207         return 1;
208 }
209
210 // get_list(self, listname) -> list or nil
211 int InvRef::l_get_list(lua_State *L)
212 {
213         NO_MAP_LOCK_REQUIRED;
214         InvRef *ref = checkobject(L, 1);
215         const char *listname = luaL_checkstring(L, 2);
216         Inventory *inv = getinv(L, ref);
217         if(inv){
218                 push_inventory_list(L, inv, listname);
219         } else {
220                 lua_pushnil(L);
221         }
222         return 1;
223 }
224
225 // set_list(self, listname, list)
226 int InvRef::l_set_list(lua_State *L)
227 {
228         NO_MAP_LOCK_REQUIRED;
229         InvRef *ref = checkobject(L, 1);
230         const char *listname = luaL_checkstring(L, 2);
231         Inventory *inv = getinv(L, ref);
232         if(inv == NULL){
233                 return 0;
234         }
235         InventoryList *list = inv->getList(listname);
236         if(list)
237                 read_inventory_list(L, 3, inv, listname,
238                                 getServer(L), list->getSize());
239         else
240                 read_inventory_list(L, 3, inv, listname, getServer(L));
241         reportInventoryChange(L, ref);
242         return 0;
243 }
244
245 // get_lists(self) -> list of InventoryLists
246 int InvRef::l_get_lists(lua_State *L)
247 {
248         NO_MAP_LOCK_REQUIRED;
249         InvRef *ref = checkobject(L, 1);
250         Inventory *inv = getinv(L, ref);
251         if (!inv) {
252                 return 0;
253         }
254         std::vector<const InventoryList*> lists = inv->getLists();
255         std::vector<const InventoryList*>::iterator iter = lists.begin();
256         lua_createtable(L, 0, lists.size());
257         for (; iter != lists.end(); iter++) {
258                 const char* name = (*iter)->getName().c_str();
259                 lua_pushstring(L, name);
260                 push_inventory_list(L, inv, name);
261                 lua_rawset(L, -3);
262         }
263         return 1;
264 }
265
266 // set_lists(self, lists)
267 int InvRef::l_set_lists(lua_State *L)
268 {
269         NO_MAP_LOCK_REQUIRED;
270         InvRef *ref = checkobject(L, 1);
271         Inventory *inv = getinv(L, ref);
272         if (!inv) {
273                 return 0;
274         }
275
276         // Make a temporary inventory in case reading fails
277         Inventory *tempInv(inv);
278         tempInv->clear();
279
280         Server *server = getServer(L);
281
282         lua_pushnil(L);
283         luaL_checktype(L, 2, LUA_TTABLE);
284         while (lua_next(L, 2)) {
285                 const char *listname = lua_tostring(L, -2);
286                 read_inventory_list(L, -1, tempInv, listname, server);
287                 lua_pop(L, 1);
288         }
289         inv = tempInv;
290         return 0;
291 }
292
293 // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
294 // Returns the leftover stack
295 int InvRef::l_add_item(lua_State *L)
296 {
297         NO_MAP_LOCK_REQUIRED;
298         InvRef *ref = checkobject(L, 1);
299         const char *listname = luaL_checkstring(L, 2);
300         ItemStack item = read_item(L, 3, getServer(L)->idef());
301         InventoryList *list = getlist(L, ref, listname);
302         if(list){
303                 ItemStack leftover = list->addItem(item);
304                 if(leftover.count != item.count)
305                         reportInventoryChange(L, ref);
306                 LuaItemStack::create(L, leftover);
307         } else {
308                 LuaItemStack::create(L, item);
309         }
310         return 1;
311 }
312
313 // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
314 // Returns true if the item completely fits into the list
315 int InvRef::l_room_for_item(lua_State *L)
316 {
317         NO_MAP_LOCK_REQUIRED;
318         InvRef *ref = checkobject(L, 1);
319         const char *listname = luaL_checkstring(L, 2);
320         ItemStack item = read_item(L, 3, getServer(L)->idef());
321         InventoryList *list = getlist(L, ref, listname);
322         if(list){
323                 lua_pushboolean(L, list->roomForItem(item));
324         } else {
325                 lua_pushboolean(L, false);
326         }
327         return 1;
328 }
329
330 // contains_item(self, listname, itemstack or itemstring or table or nil, [match_meta]) -> true/false
331 // Returns true if the list contains the given count of the given item
332 int InvRef::l_contains_item(lua_State *L)
333 {
334         NO_MAP_LOCK_REQUIRED;
335         InvRef *ref = checkobject(L, 1);
336         const char *listname = luaL_checkstring(L, 2);
337         ItemStack item = read_item(L, 3, getServer(L)->idef());
338         InventoryList *list = getlist(L, ref, listname);
339         bool match_meta = false;
340         if (lua_isboolean(L, 4))
341                 match_meta = readParam<bool>(L, 4);
342         if (list) {
343                 lua_pushboolean(L, list->containsItem(item, match_meta));
344         } else {
345                 lua_pushboolean(L, false);
346         }
347         return 1;
348 }
349
350 // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
351 // Returns the items that were actually removed
352 int InvRef::l_remove_item(lua_State *L)
353 {
354         NO_MAP_LOCK_REQUIRED;
355         InvRef *ref = checkobject(L, 1);
356         const char *listname = luaL_checkstring(L, 2);
357         ItemStack item = read_item(L, 3, getServer(L)->idef());
358         InventoryList *list = getlist(L, ref, listname);
359         if(list){
360                 ItemStack removed = list->removeItem(item);
361                 if(!removed.empty())
362                         reportInventoryChange(L, ref);
363                 LuaItemStack::create(L, removed);
364         } else {
365                 LuaItemStack::create(L, ItemStack());
366         }
367         return 1;
368 }
369
370 // get_location() -> location (like get_inventory(location))
371 int InvRef::l_get_location(lua_State *L)
372 {
373         NO_MAP_LOCK_REQUIRED;
374         InvRef *ref = checkobject(L, 1);
375         const InventoryLocation &loc = ref->m_loc;
376         switch(loc.type){
377         case InventoryLocation::PLAYER:
378                 lua_newtable(L);
379                 lua_pushstring(L, "player");
380                 lua_setfield(L, -2, "type");
381                 lua_pushstring(L, loc.name.c_str());
382                 lua_setfield(L, -2, "name");
383                 return 1;
384         case InventoryLocation::NODEMETA:
385                 lua_newtable(L);
386                 lua_pushstring(L, "node");
387                 lua_setfield(L, -2, "type");
388                 push_v3s16(L, loc.p);
389                 lua_setfield(L, -2, "pos");
390                 return 1;
391         case InventoryLocation::DETACHED:
392                 lua_newtable(L);
393                 lua_pushstring(L, "detached");
394                 lua_setfield(L, -2, "type");
395                 lua_pushstring(L, loc.name.c_str());
396                 lua_setfield(L, -2, "name");
397                 return 1;
398         case InventoryLocation::UNDEFINED:
399         case InventoryLocation::CURRENT_PLAYER:
400                 break;
401         }
402         lua_newtable(L);
403         lua_pushstring(L, "undefined");
404         lua_setfield(L, -2, "type");
405         return 1;
406 }
407
408
409 InvRef::InvRef(const InventoryLocation &loc):
410         m_loc(loc)
411 {
412 }
413
414 // Creates an InvRef and leaves it on top of stack
415 // Not callable from Lua; all references are created on the C side.
416 void InvRef::create(lua_State *L, const InventoryLocation &loc)
417 {
418         NO_MAP_LOCK_REQUIRED;
419         InvRef *o = new InvRef(loc);
420         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
421         luaL_getmetatable(L, className);
422         lua_setmetatable(L, -2);
423 }
424
425 void InvRef::Register(lua_State *L)
426 {
427         lua_newtable(L);
428         int methodtable = lua_gettop(L);
429         luaL_newmetatable(L, className);
430         int metatable = lua_gettop(L);
431
432         lua_pushliteral(L, "__metatable");
433         lua_pushvalue(L, methodtable);
434         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
435
436         lua_pushliteral(L, "__index");
437         lua_pushvalue(L, methodtable);
438         lua_settable(L, metatable);
439
440         lua_pushliteral(L, "__gc");
441         lua_pushcfunction(L, gc_object);
442         lua_settable(L, metatable);
443
444         lua_pop(L, 1);  // drop metatable
445
446         luaL_register(L, nullptr, methods);  // fill methodtable
447         lua_pop(L, 1);  // drop methodtable
448
449         // Cannot be created from Lua
450         //lua_register(L, className, create_object);
451 }
452
453 const char InvRef::className[] = "InvRef";
454 const luaL_Reg InvRef::methods[] = {
455         luamethod(InvRef, is_empty),
456         luamethod(InvRef, get_size),
457         luamethod(InvRef, set_size),
458         luamethod(InvRef, get_width),
459         luamethod(InvRef, set_width),
460         luamethod(InvRef, get_stack),
461         luamethod(InvRef, set_stack),
462         luamethod(InvRef, get_list),
463         luamethod(InvRef, set_list),
464         luamethod(InvRef, get_lists),
465         luamethod(InvRef, set_lists),
466         luamethod(InvRef, add_item),
467         luamethod(InvRef, room_for_item),
468         luamethod(InvRef, contains_item),
469         luamethod(InvRef, remove_item),
470         luamethod(InvRef, get_location),
471         {0,0}
472 };
473
474 // get_inventory(location)
475 int ModApiInventory::l_get_inventory(lua_State *L)
476 {
477         InventoryLocation loc;
478
479         lua_getfield(L, 1, "type");
480         std::string type = luaL_checkstring(L, -1);
481         lua_pop(L, 1);
482
483         if(type == "node"){
484                 MAP_LOCK_REQUIRED;
485                 lua_getfield(L, 1, "pos");
486                 v3s16 pos = check_v3s16(L, -1);
487                 loc.setNodeMeta(pos);
488
489                 if (getServerInventoryMgr(L)->getInventory(loc) != NULL)
490                         InvRef::create(L, loc);
491                 else
492                         lua_pushnil(L);
493                 return 1;
494         }
495
496         NO_MAP_LOCK_REQUIRED;
497         if (type == "player") {
498                 lua_getfield(L, 1, "name");
499                 loc.setPlayer(luaL_checkstring(L, -1));
500                 lua_pop(L, 1);
501         } else if (type == "detached") {
502                 lua_getfield(L, 1, "name");
503                 loc.setDetached(luaL_checkstring(L, -1));
504                 lua_pop(L, 1);
505         }
506
507         if (getServerInventoryMgr(L)->getInventory(loc) != NULL)
508                 InvRef::create(L, loc);
509         else
510                 lua_pushnil(L);
511         return 1;
512         // END NO_MAP_LOCK_REQUIRED;
513
514 }
515
516 // create_detached_inventory_raw(name, [player_name])
517 int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
518 {
519         NO_MAP_LOCK_REQUIRED;
520         const char *name = luaL_checkstring(L, 1);
521         std::string player = readParam<std::string>(L, 2, "");
522         if (getServerInventoryMgr(L)->createDetachedInventory(name, getServer(L)->idef(), player) != NULL) {
523                 InventoryLocation loc;
524                 loc.setDetached(name);
525                 InvRef::create(L, loc);
526         } else {
527                 lua_pushnil(L);
528         }
529         return 1;
530 }
531
532 // remove_detached_inventory_raw(name)
533 int ModApiInventory::l_remove_detached_inventory_raw(lua_State *L)
534 {
535         NO_MAP_LOCK_REQUIRED;
536         const std::string &name = luaL_checkstring(L, 1);
537         lua_pushboolean(L, getServerInventoryMgr(L)->removeDetachedInventory(name));
538         return 1;
539 }
540
541 void ModApiInventory::Initialize(lua_State *L, int top)
542 {
543         API_FCT(create_detached_inventory_raw);
544         API_FCT(remove_detached_inventory_raw);
545         API_FCT(get_inventory);
546 }