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 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);
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)
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);
303 ItemStack leftover = list->addItem(item);
304 if(leftover.count != item.count)
305 reportInventoryChange(L, ref);
306 LuaItemStack::create(L, leftover);
308 LuaItemStack::create(L, item);
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)
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);
323 lua_pushboolean(L, list->roomForItem(item));
325 lua_pushboolean(L, false);
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)
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);
343 lua_pushboolean(L, list->containsItem(item, match_meta));
345 lua_pushboolean(L, false);
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)
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);
360 ItemStack removed = list->removeItem(item);
362 reportInventoryChange(L, ref);
363 LuaItemStack::create(L, removed);
365 LuaItemStack::create(L, ItemStack());
370 // get_location() -> location (like get_inventory(location))
371 int InvRef::l_get_location(lua_State *L)
373 NO_MAP_LOCK_REQUIRED;
374 InvRef *ref = checkobject(L, 1);
375 const InventoryLocation &loc = ref->m_loc;
377 case InventoryLocation::PLAYER:
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");
384 case InventoryLocation::NODEMETA:
386 lua_pushstring(L, "node");
387 lua_setfield(L, -2, "type");
388 push_v3s16(L, loc.p);
389 lua_setfield(L, -2, "pos");
391 case InventoryLocation::DETACHED:
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");
398 case InventoryLocation::UNDEFINED:
399 case InventoryLocation::CURRENT_PLAYER:
403 lua_pushstring(L, "undefined");
404 lua_setfield(L, -2, "type");
409 InvRef::InvRef(const InventoryLocation &loc):
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)
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);
424 void InvRef::createPlayer(lua_State *L, RemotePlayer *player)
426 NO_MAP_LOCK_REQUIRED;
427 InventoryLocation loc;
428 loc.setPlayer(player->getName());
431 void InvRef::createNodeMeta(lua_State *L, v3s16 p)
433 InventoryLocation loc;
438 void InvRef::Register(lua_State *L)
441 int methodtable = lua_gettop(L);
442 luaL_newmetatable(L, className);
443 int metatable = lua_gettop(L);
445 lua_pushliteral(L, "__metatable");
446 lua_pushvalue(L, methodtable);
447 lua_settable(L, metatable); // hide metatable from Lua getmetatable()
449 lua_pushliteral(L, "__index");
450 lua_pushvalue(L, methodtable);
451 lua_settable(L, metatable);
453 lua_pushliteral(L, "__gc");
454 lua_pushcfunction(L, gc_object);
455 lua_settable(L, metatable);
457 lua_pop(L, 1); // drop metatable
459 luaL_openlib(L, 0, methods, 0); // fill methodtable
460 lua_pop(L, 1); // drop methodtable
462 // Cannot be created from Lua
463 //lua_register(L, className, create_object);
466 const char InvRef::className[] = "InvRef";
467 const luaL_Reg InvRef::methods[] = {
468 luamethod(InvRef, is_empty),
469 luamethod(InvRef, get_size),
470 luamethod(InvRef, set_size),
471 luamethod(InvRef, get_width),
472 luamethod(InvRef, set_width),
473 luamethod(InvRef, get_stack),
474 luamethod(InvRef, set_stack),
475 luamethod(InvRef, get_list),
476 luamethod(InvRef, set_list),
477 luamethod(InvRef, get_lists),
478 luamethod(InvRef, set_lists),
479 luamethod(InvRef, add_item),
480 luamethod(InvRef, room_for_item),
481 luamethod(InvRef, contains_item),
482 luamethod(InvRef, remove_item),
483 luamethod(InvRef, get_location),
487 // get_inventory(location)
488 int ModApiInventory::l_get_inventory(lua_State *L)
490 InventoryLocation loc;
492 lua_getfield(L, 1, "type");
493 std::string type = luaL_checkstring(L, -1);
498 lua_getfield(L, 1, "pos");
499 v3s16 pos = check_v3s16(L, -1);
500 loc.setNodeMeta(pos);
502 if (getServerInventoryMgr(L)->getInventory(loc) != NULL)
503 InvRef::create(L, loc);
509 NO_MAP_LOCK_REQUIRED;
510 if (type == "player") {
511 lua_getfield(L, 1, "name");
512 loc.setPlayer(luaL_checkstring(L, -1));
514 } else if (type == "detached") {
515 lua_getfield(L, 1, "name");
516 loc.setDetached(luaL_checkstring(L, -1));
520 if (getServerInventoryMgr(L)->getInventory(loc) != NULL)
521 InvRef::create(L, loc);
525 // END NO_MAP_LOCK_REQUIRED;
529 // create_detached_inventory_raw(name, [player_name])
530 int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
532 NO_MAP_LOCK_REQUIRED;
533 const char *name = luaL_checkstring(L, 1);
534 std::string player = readParam<std::string>(L, 2, "");
535 if (getServerInventoryMgr(L)->createDetachedInventory(name, getServer(L)->idef(), player) != NULL) {
536 InventoryLocation loc;
537 loc.setDetached(name);
538 InvRef::create(L, loc);
545 // remove_detached_inventory_raw(name)
546 int ModApiInventory::l_remove_detached_inventory_raw(lua_State *L)
548 NO_MAP_LOCK_REQUIRED;
549 const std::string &name = luaL_checkstring(L, 1);
550 lua_pushboolean(L, getServerInventoryMgr(L)->removeDetachedInventory(name));
554 void ModApiInventory::Initialize(lua_State *L, int top)
556 API_FCT(create_detached_inventory_raw);
557 API_FCT(remove_detached_inventory_raw);
558 API_FCT(get_inventory);