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 "remoteplayer.h"
31 InvRef* InvRef::checkobject(lua_State *L, int narg)
33 luaL_checktype(L, narg, LUA_TUSERDATA);
34 void *ud = luaL_checkudata(L, narg, className);
35 if(!ud) luaL_typerror(L, narg, className);
36 return *(InvRef**)ud; // unbox pointer
39 Inventory* InvRef::getinv(lua_State *L, InvRef *ref)
41 return getServer(L)->getInventory(ref->m_loc);
44 InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
48 Inventory *inv = getinv(L, ref);
51 return inv->getList(listname);
54 void InvRef::reportInventoryChange(lua_State *L, InvRef *ref)
56 // Inform other things that the inventory has changed
57 getServer(L)->setInventoryModified(ref->m_loc);
63 int InvRef::gc_object(lua_State *L) {
64 InvRef *o = *(InvRef **)(lua_touserdata(L, 1));
69 // is_empty(self, listname) -> true/false
70 int InvRef::l_is_empty(lua_State *L)
73 InvRef *ref = checkobject(L, 1);
74 const char *listname = luaL_checkstring(L, 2);
75 InventoryList *list = getlist(L, ref, listname);
76 if(list && list->getUsedSlots() > 0){
77 lua_pushboolean(L, false);
79 lua_pushboolean(L, true);
84 // get_size(self, listname)
85 int InvRef::l_get_size(lua_State *L)
88 InvRef *ref = checkobject(L, 1);
89 const char *listname = luaL_checkstring(L, 2);
90 InventoryList *list = getlist(L, ref, listname);
92 lua_pushinteger(L, list->getSize());
94 lua_pushinteger(L, 0);
99 // get_width(self, listname)
100 int InvRef::l_get_width(lua_State *L)
102 NO_MAP_LOCK_REQUIRED;
103 InvRef *ref = checkobject(L, 1);
104 const char *listname = luaL_checkstring(L, 2);
105 InventoryList *list = getlist(L, ref, listname);
107 lua_pushinteger(L, list->getWidth());
109 lua_pushinteger(L, 0);
114 // set_size(self, listname, size)
115 int InvRef::l_set_size(lua_State *L)
117 NO_MAP_LOCK_REQUIRED;
118 InvRef *ref = checkobject(L, 1);
119 const char *listname = luaL_checkstring(L, 2);
121 int newsize = luaL_checknumber(L, 3);
123 lua_pushboolean(L, false);
127 Inventory *inv = getinv(L, ref);
129 lua_pushboolean(L, false);
133 inv->deleteList(listname);
134 reportInventoryChange(L, ref);
135 lua_pushboolean(L, true);
138 InventoryList *list = inv->getList(listname);
140 list->setSize(newsize);
142 list = inv->addList(listname, newsize);
145 lua_pushboolean(L, false);
149 reportInventoryChange(L, ref);
150 lua_pushboolean(L, true);
154 // set_width(self, listname, size)
155 int InvRef::l_set_width(lua_State *L)
157 NO_MAP_LOCK_REQUIRED;
158 InvRef *ref = checkobject(L, 1);
159 const char *listname = luaL_checkstring(L, 2);
160 int newwidth = luaL_checknumber(L, 3);
161 Inventory *inv = getinv(L, ref);
165 InventoryList *list = inv->getList(listname);
167 list->setWidth(newwidth);
171 reportInventoryChange(L, ref);
175 // get_stack(self, listname, i) -> itemstack
176 int InvRef::l_get_stack(lua_State *L)
178 NO_MAP_LOCK_REQUIRED;
179 InvRef *ref = checkobject(L, 1);
180 const char *listname = luaL_checkstring(L, 2);
181 int i = luaL_checknumber(L, 3) - 1;
182 InventoryList *list = getlist(L, ref, listname);
184 if(list != NULL && i >= 0 && i < (int) list->getSize())
185 item = list->getItem(i);
186 LuaItemStack::create(L, item);
190 // set_stack(self, listname, i, stack) -> true/false
191 int InvRef::l_set_stack(lua_State *L)
193 NO_MAP_LOCK_REQUIRED;
194 InvRef *ref = checkobject(L, 1);
195 const char *listname = luaL_checkstring(L, 2);
196 int i = luaL_checknumber(L, 3) - 1;
197 ItemStack newitem = read_item(L, 4, getServer(L)->idef());
198 InventoryList *list = getlist(L, ref, listname);
199 if(list != NULL && i >= 0 && i < (int) list->getSize()){
200 list->changeItem(i, newitem);
201 reportInventoryChange(L, ref);
202 lua_pushboolean(L, true);
204 lua_pushboolean(L, false);
209 // get_list(self, listname) -> list or nil
210 int InvRef::l_get_list(lua_State *L)
212 NO_MAP_LOCK_REQUIRED;
213 InvRef *ref = checkobject(L, 1);
214 const char *listname = luaL_checkstring(L, 2);
215 Inventory *inv = getinv(L, ref);
217 push_inventory_list(L, inv, listname);
224 // set_list(self, listname, list)
225 int InvRef::l_set_list(lua_State *L)
227 NO_MAP_LOCK_REQUIRED;
228 InvRef *ref = checkobject(L, 1);
229 const char *listname = luaL_checkstring(L, 2);
230 Inventory *inv = getinv(L, ref);
234 InventoryList *list = inv->getList(listname);
236 read_inventory_list(L, 3, inv, listname,
237 getServer(L), list->getSize());
239 read_inventory_list(L, 3, inv, listname, getServer(L));
240 reportInventoryChange(L, ref);
244 // get_lists(self) -> list of InventoryLists
245 int InvRef::l_get_lists(lua_State *L)
247 NO_MAP_LOCK_REQUIRED;
248 InvRef *ref = checkobject(L, 1);
249 Inventory *inv = getinv(L, ref);
253 std::vector<const InventoryList*> lists = inv->getLists();
254 std::vector<const InventoryList*>::iterator iter = lists.begin();
255 lua_createtable(L, 0, lists.size());
256 for (; iter != lists.end(); iter++) {
257 const char* name = (*iter)->getName().c_str();
258 lua_pushstring(L, name);
259 push_inventory_list(L, inv, name);
265 // set_lists(self, lists)
266 int InvRef::l_set_lists(lua_State *L)
268 NO_MAP_LOCK_REQUIRED;
269 InvRef *ref = checkobject(L, 1);
270 Inventory *inv = getinv(L, ref);
275 // Make a temporary inventory in case reading fails
276 Inventory *tempInv(inv);
279 Server *server = getServer(L);
282 while (lua_next(L, 2)) {
283 const char *listname = lua_tostring(L, -2);
284 read_inventory_list(L, -1, tempInv, listname, server);
291 // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
292 // Returns the leftover stack
293 int InvRef::l_add_item(lua_State *L)
295 NO_MAP_LOCK_REQUIRED;
296 InvRef *ref = checkobject(L, 1);
297 const char *listname = luaL_checkstring(L, 2);
298 ItemStack item = read_item(L, 3, getServer(L)->idef());
299 InventoryList *list = getlist(L, ref, listname);
301 ItemStack leftover = list->addItem(item);
302 if(leftover.count != item.count)
303 reportInventoryChange(L, ref);
304 LuaItemStack::create(L, leftover);
306 LuaItemStack::create(L, item);
311 // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
312 // Returns true if the item completely fits into the list
313 int InvRef::l_room_for_item(lua_State *L)
315 NO_MAP_LOCK_REQUIRED;
316 InvRef *ref = checkobject(L, 1);
317 const char *listname = luaL_checkstring(L, 2);
318 ItemStack item = read_item(L, 3, getServer(L)->idef());
319 InventoryList *list = getlist(L, ref, listname);
321 lua_pushboolean(L, list->roomForItem(item));
323 lua_pushboolean(L, false);
328 // contains_item(self, listname, itemstack or itemstring or table or nil, [match_meta]) -> true/false
329 // Returns true if the list contains the given count of the given item
330 int InvRef::l_contains_item(lua_State *L)
332 NO_MAP_LOCK_REQUIRED;
333 InvRef *ref = checkobject(L, 1);
334 const char *listname = luaL_checkstring(L, 2);
335 ItemStack item = read_item(L, 3, getServer(L)->idef());
336 InventoryList *list = getlist(L, ref, listname);
337 bool match_meta = false;
338 if (lua_isboolean(L, 4))
339 match_meta = lua_toboolean(L, 4);
341 lua_pushboolean(L, list->containsItem(item, match_meta));
343 lua_pushboolean(L, false);
348 // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
349 // Returns the items that were actually removed
350 int InvRef::l_remove_item(lua_State *L)
352 NO_MAP_LOCK_REQUIRED;
353 InvRef *ref = checkobject(L, 1);
354 const char *listname = luaL_checkstring(L, 2);
355 ItemStack item = read_item(L, 3, getServer(L)->idef());
356 InventoryList *list = getlist(L, ref, listname);
358 ItemStack removed = list->removeItem(item);
360 reportInventoryChange(L, ref);
361 LuaItemStack::create(L, removed);
363 LuaItemStack::create(L, ItemStack());
368 // get_location() -> location (like get_inventory(location))
369 int InvRef::l_get_location(lua_State *L)
371 NO_MAP_LOCK_REQUIRED;
372 InvRef *ref = checkobject(L, 1);
373 const InventoryLocation &loc = ref->m_loc;
375 case InventoryLocation::PLAYER:
377 lua_pushstring(L, "player");
378 lua_setfield(L, -2, "type");
379 lua_pushstring(L, loc.name.c_str());
380 lua_setfield(L, -2, "name");
382 case InventoryLocation::NODEMETA:
384 lua_pushstring(L, "node");
385 lua_setfield(L, -2, "type");
386 push_v3s16(L, loc.p);
387 lua_setfield(L, -2, "pos");
389 case InventoryLocation::DETACHED:
391 lua_pushstring(L, "detached");
392 lua_setfield(L, -2, "type");
393 lua_pushstring(L, loc.name.c_str());
394 lua_setfield(L, -2, "name");
396 case InventoryLocation::UNDEFINED:
397 case InventoryLocation::CURRENT_PLAYER:
401 lua_pushstring(L, "undefined");
402 lua_setfield(L, -2, "type");
407 InvRef::InvRef(const InventoryLocation &loc):
412 // Creates an InvRef and leaves it on top of stack
413 // Not callable from Lua; all references are created on the C side.
414 void InvRef::create(lua_State *L, const InventoryLocation &loc)
416 NO_MAP_LOCK_REQUIRED;
417 InvRef *o = new InvRef(loc);
418 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
419 luaL_getmetatable(L, className);
420 lua_setmetatable(L, -2);
422 void InvRef::createPlayer(lua_State *L, RemotePlayer *player)
424 NO_MAP_LOCK_REQUIRED;
425 InventoryLocation loc;
426 loc.setPlayer(player->getName());
429 void InvRef::createNodeMeta(lua_State *L, v3s16 p)
431 InventoryLocation loc;
436 void InvRef::Register(lua_State *L)
439 int methodtable = lua_gettop(L);
440 luaL_newmetatable(L, className);
441 int metatable = lua_gettop(L);
443 lua_pushliteral(L, "__metatable");
444 lua_pushvalue(L, methodtable);
445 lua_settable(L, metatable); // hide metatable from Lua getmetatable()
447 lua_pushliteral(L, "__index");
448 lua_pushvalue(L, methodtable);
449 lua_settable(L, metatable);
451 lua_pushliteral(L, "__gc");
452 lua_pushcfunction(L, gc_object);
453 lua_settable(L, metatable);
455 lua_pop(L, 1); // drop metatable
457 luaL_openlib(L, 0, methods, 0); // fill methodtable
458 lua_pop(L, 1); // drop methodtable
460 // Cannot be created from Lua
461 //lua_register(L, className, create_object);
464 const char InvRef::className[] = "InvRef";
465 const luaL_Reg InvRef::methods[] = {
466 luamethod(InvRef, is_empty),
467 luamethod(InvRef, get_size),
468 luamethod(InvRef, set_size),
469 luamethod(InvRef, get_width),
470 luamethod(InvRef, set_width),
471 luamethod(InvRef, get_stack),
472 luamethod(InvRef, set_stack),
473 luamethod(InvRef, get_list),
474 luamethod(InvRef, set_list),
475 luamethod(InvRef, get_lists),
476 luamethod(InvRef, set_lists),
477 luamethod(InvRef, add_item),
478 luamethod(InvRef, room_for_item),
479 luamethod(InvRef, contains_item),
480 luamethod(InvRef, remove_item),
481 luamethod(InvRef, get_location),
485 // get_inventory(location)
486 int ModApiInventory::l_get_inventory(lua_State *L)
488 InventoryLocation loc;
490 std::string type = checkstringfield(L, 1, "type");
494 lua_getfield(L, 1, "pos");
495 v3s16 pos = check_v3s16(L, -1);
496 loc.setNodeMeta(pos);
498 if (getServer(L)->getInventory(loc) != NULL)
499 InvRef::create(L, loc);
505 NO_MAP_LOCK_REQUIRED;
506 if (type == "player") {
507 std::string name = checkstringfield(L, 1, "name");
509 } else if (type == "detached") {
510 std::string name = checkstringfield(L, 1, "name");
511 loc.setDetached(name);
514 if (getServer(L)->getInventory(loc) != NULL)
515 InvRef::create(L, loc);
519 // END NO_MAP_LOCK_REQUIRED;
523 // create_detached_inventory_raw(name, [player_name])
524 int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
526 NO_MAP_LOCK_REQUIRED;
527 const char *name = luaL_checkstring(L, 1);
528 const char *player = lua_isstring(L, 2) ? lua_tostring(L, 2) : "";
529 if (getServer(L)->createDetachedInventory(name, player) != NULL) {
530 InventoryLocation loc;
531 loc.setDetached(name);
532 InvRef::create(L, loc);
539 void ModApiInventory::Initialize(lua_State *L, int top)
541 API_FCT(create_detached_inventory_raw);
542 API_FCT(get_inventory);