3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
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"
26 #include "server/serverinventorymgr.h"
27 #include "remoteplayer.h"
32 InvRef* InvRef::checkobject(lua_State *L, int narg)
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
40 Inventory* InvRef::getinv(lua_State *L, InvRef *ref)
42 return getServerInventoryMgr(L)->getInventory(ref->m_loc);
45 InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
49 Inventory *inv = getinv(L, ref);
52 return inv->getList(listname);
55 void InvRef::reportInventoryChange(lua_State *L, InvRef *ref)
57 // Inform other things that the inventory has changed
58 getServerInventoryMgr(L)->setInventoryModified(ref->m_loc);
64 int InvRef::gc_object(lua_State *L) {
65 InvRef *o = *(InvRef **)(lua_touserdata(L, 1));
70 // is_empty(self, listname) -> true/false
71 int InvRef::l_is_empty(lua_State *L)
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);
80 lua_pushboolean(L, true);
85 // get_size(self, listname)
86 int InvRef::l_get_size(lua_State *L)
89 InvRef *ref = checkobject(L, 1);
90 const char *listname = luaL_checkstring(L, 2);
91 InventoryList *list = getlist(L, ref, listname);
93 lua_pushinteger(L, list->getSize());
95 lua_pushinteger(L, 0);
100 // get_width(self, listname)
101 int InvRef::l_get_width(lua_State *L)
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);
108 lua_pushinteger(L, list->getWidth());
110 lua_pushinteger(L, 0);
115 // set_size(self, listname, size)
116 int InvRef::l_set_size(lua_State *L)
118 NO_MAP_LOCK_REQUIRED;
119 InvRef *ref = checkobject(L, 1);
120 const char *listname = luaL_checkstring(L, 2);
122 int newsize = luaL_checknumber(L, 3);
124 lua_pushboolean(L, false);
128 Inventory *inv = getinv(L, ref);
130 lua_pushboolean(L, false);
134 inv->deleteList(listname);
135 reportInventoryChange(L, ref);
136 lua_pushboolean(L, true);
139 InventoryList *list = inv->getList(listname);
141 list->setSize(newsize);
143 list = inv->addList(listname, newsize);
146 lua_pushboolean(L, false);
150 reportInventoryChange(L, ref);
151 lua_pushboolean(L, true);
155 // set_width(self, listname, size)
156 int InvRef::l_set_width(lua_State *L)
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);
166 InventoryList *list = inv->getList(listname);
168 list->setWidth(newwidth);
172 reportInventoryChange(L, ref);
176 // get_stack(self, listname, i) -> itemstack
177 int InvRef::l_get_stack(lua_State *L)
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);
185 if(list != NULL && i >= 0 && i < (int) list->getSize())
186 item = list->getItem(i);
187 LuaItemStack::create(L, item);
191 // set_stack(self, listname, i, stack) -> true/false
192 int InvRef::l_set_stack(lua_State *L)
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);
205 lua_pushboolean(L, false);
210 // get_list(self, listname) -> list or nil
211 int InvRef::l_get_list(lua_State *L)
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);
218 push_inventory_list(L, inv, listname);
225 // set_list(self, listname, list)
226 int InvRef::l_set_list(lua_State *L)
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);
235 InventoryList *list = inv->getList(listname);
237 read_inventory_list(L, 3, inv, listname,
238 getServer(L), list->getSize());
240 read_inventory_list(L, 3, inv, listname, getServer(L));
241 reportInventoryChange(L, ref);
245 // get_lists(self) -> list of InventoryLists
246 int InvRef::l_get_lists(lua_State *L)
248 NO_MAP_LOCK_REQUIRED;
249 InvRef *ref = checkobject(L, 1);
250 Inventory *inv = getinv(L, ref);
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);
266 // set_lists(self, lists)
267 int InvRef::l_set_lists(lua_State *L)
269 NO_MAP_LOCK_REQUIRED;
270 InvRef *ref = checkobject(L, 1);
271 Inventory *inv = getinv(L, ref);
276 // Make a temporary inventory in case reading fails
277 Inventory *tempInv(inv);
280 Server *server = getServer(L);
283 while (lua_next(L, 2)) {
284 const char *listname = lua_tostring(L, -2);
285 read_inventory_list(L, -1, tempInv, listname, server);
292 // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
293 // Returns the leftover stack
294 int InvRef::l_add_item(lua_State *L)
296 NO_MAP_LOCK_REQUIRED;
297 InvRef *ref = checkobject(L, 1);
298 const char *listname = luaL_checkstring(L, 2);
299 ItemStack item = read_item(L, 3, getServer(L)->idef());
300 InventoryList *list = getlist(L, ref, listname);
302 ItemStack leftover = list->addItem(item);
303 if(leftover.count != item.count)
304 reportInventoryChange(L, ref);
305 LuaItemStack::create(L, leftover);
307 LuaItemStack::create(L, item);
312 // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
313 // Returns true if the item completely fits into the list
314 int InvRef::l_room_for_item(lua_State *L)
316 NO_MAP_LOCK_REQUIRED;
317 InvRef *ref = checkobject(L, 1);
318 const char *listname = luaL_checkstring(L, 2);
319 ItemStack item = read_item(L, 3, getServer(L)->idef());
320 InventoryList *list = getlist(L, ref, listname);
322 lua_pushboolean(L, list->roomForItem(item));
324 lua_pushboolean(L, false);
329 // contains_item(self, listname, itemstack or itemstring or table or nil, [match_meta]) -> true/false
330 // Returns true if the list contains the given count of the given item
331 int InvRef::l_contains_item(lua_State *L)
333 NO_MAP_LOCK_REQUIRED;
334 InvRef *ref = checkobject(L, 1);
335 const char *listname = luaL_checkstring(L, 2);
336 ItemStack item = read_item(L, 3, getServer(L)->idef());
337 InventoryList *list = getlist(L, ref, listname);
338 bool match_meta = false;
339 if (lua_isboolean(L, 4))
340 match_meta = readParam<bool>(L, 4);
342 lua_pushboolean(L, list->containsItem(item, match_meta));
344 lua_pushboolean(L, false);
349 // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
350 // Returns the items that were actually removed
351 int InvRef::l_remove_item(lua_State *L)
353 NO_MAP_LOCK_REQUIRED;
354 InvRef *ref = checkobject(L, 1);
355 const char *listname = luaL_checkstring(L, 2);
356 ItemStack item = read_item(L, 3, getServer(L)->idef());
357 InventoryList *list = getlist(L, ref, listname);
359 ItemStack removed = list->removeItem(item);
361 reportInventoryChange(L, ref);
362 LuaItemStack::create(L, removed);
364 LuaItemStack::create(L, ItemStack());
369 // get_location() -> location (like get_inventory(location))
370 int InvRef::l_get_location(lua_State *L)
372 NO_MAP_LOCK_REQUIRED;
373 InvRef *ref = checkobject(L, 1);
374 const InventoryLocation &loc = ref->m_loc;
376 case InventoryLocation::PLAYER:
378 lua_pushstring(L, "player");
379 lua_setfield(L, -2, "type");
380 lua_pushstring(L, loc.name.c_str());
381 lua_setfield(L, -2, "name");
383 case InventoryLocation::NODEMETA:
385 lua_pushstring(L, "node");
386 lua_setfield(L, -2, "type");
387 push_v3s16(L, loc.p);
388 lua_setfield(L, -2, "pos");
390 case InventoryLocation::DETACHED:
392 lua_pushstring(L, "detached");
393 lua_setfield(L, -2, "type");
394 lua_pushstring(L, loc.name.c_str());
395 lua_setfield(L, -2, "name");
397 case InventoryLocation::UNDEFINED:
398 case InventoryLocation::CURRENT_PLAYER:
402 lua_pushstring(L, "undefined");
403 lua_setfield(L, -2, "type");
408 InvRef::InvRef(const InventoryLocation &loc):
413 // Creates an InvRef and leaves it on top of stack
414 // Not callable from Lua; all references are created on the C side.
415 void InvRef::create(lua_State *L, const InventoryLocation &loc)
417 NO_MAP_LOCK_REQUIRED;
418 InvRef *o = new InvRef(loc);
419 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
420 luaL_getmetatable(L, className);
421 lua_setmetatable(L, -2);
423 void InvRef::createPlayer(lua_State *L, RemotePlayer *player)
425 NO_MAP_LOCK_REQUIRED;
426 InventoryLocation loc;
427 loc.setPlayer(player->getName());
430 void InvRef::createNodeMeta(lua_State *L, v3s16 p)
432 InventoryLocation loc;
437 void InvRef::Register(lua_State *L)
440 int methodtable = lua_gettop(L);
441 luaL_newmetatable(L, className);
442 int metatable = lua_gettop(L);
444 lua_pushliteral(L, "__metatable");
445 lua_pushvalue(L, methodtable);
446 lua_settable(L, metatable); // hide metatable from Lua getmetatable()
448 lua_pushliteral(L, "__index");
449 lua_pushvalue(L, methodtable);
450 lua_settable(L, metatable);
452 lua_pushliteral(L, "__gc");
453 lua_pushcfunction(L, gc_object);
454 lua_settable(L, metatable);
456 lua_pop(L, 1); // drop metatable
458 luaL_openlib(L, 0, methods, 0); // fill methodtable
459 lua_pop(L, 1); // drop methodtable
461 // Cannot be created from Lua
462 //lua_register(L, className, create_object);
465 const char InvRef::className[] = "InvRef";
466 const luaL_Reg InvRef::methods[] = {
467 luamethod(InvRef, is_empty),
468 luamethod(InvRef, get_size),
469 luamethod(InvRef, set_size),
470 luamethod(InvRef, get_width),
471 luamethod(InvRef, set_width),
472 luamethod(InvRef, get_stack),
473 luamethod(InvRef, set_stack),
474 luamethod(InvRef, get_list),
475 luamethod(InvRef, set_list),
476 luamethod(InvRef, get_lists),
477 luamethod(InvRef, set_lists),
478 luamethod(InvRef, add_item),
479 luamethod(InvRef, room_for_item),
480 luamethod(InvRef, contains_item),
481 luamethod(InvRef, remove_item),
482 luamethod(InvRef, get_location),
486 // get_inventory(location)
487 int ModApiInventory::l_get_inventory(lua_State *L)
489 InventoryLocation loc;
491 lua_getfield(L, 1, "type");
492 std::string type = luaL_checkstring(L, -1);
497 lua_getfield(L, 1, "pos");
498 v3s16 pos = check_v3s16(L, -1);
499 loc.setNodeMeta(pos);
501 if (getServerInventoryMgr(L)->getInventory(loc) != NULL)
502 InvRef::create(L, loc);
508 NO_MAP_LOCK_REQUIRED;
509 if (type == "player") {
510 lua_getfield(L, 1, "name");
511 loc.setPlayer(luaL_checkstring(L, -1));
513 } else if (type == "detached") {
514 lua_getfield(L, 1, "name");
515 loc.setDetached(luaL_checkstring(L, -1));
519 if (getServerInventoryMgr(L)->getInventory(loc) != NULL)
520 InvRef::create(L, loc);
524 // END NO_MAP_LOCK_REQUIRED;
528 // create_detached_inventory_raw(name, [player_name])
529 int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
531 NO_MAP_LOCK_REQUIRED;
532 const char *name = luaL_checkstring(L, 1);
533 std::string player = readParam<std::string>(L, 2, "");
534 if (getServerInventoryMgr(L)->createDetachedInventory(name, getServer(L)->idef(), player) != NULL) {
535 InventoryLocation loc;
536 loc.setDetached(name);
537 InvRef::create(L, loc);
544 // remove_detached_inventory_raw(name)
545 int ModApiInventory::l_remove_detached_inventory_raw(lua_State *L)
547 NO_MAP_LOCK_REQUIRED;
548 const std::string &name = luaL_checkstring(L, 1);
549 lua_pushboolean(L, getServerInventoryMgr(L)->removeDetachedInventory(name));
553 void ModApiInventory::Initialize(lua_State *L, int top)
555 API_FCT(create_detached_inventory_raw);
556 API_FCT(remove_detached_inventory_raw);
557 API_FCT(get_inventory);