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"
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);
120 int newsize = luaL_checknumber(L, 3);
121 Inventory *inv = getinv(L, ref);
126 inv->deleteList(listname);
127 reportInventoryChange(L, ref);
130 InventoryList *list = inv->getList(listname);
132 list->setSize(newsize);
134 list = inv->addList(listname, newsize);
136 reportInventoryChange(L, ref);
140 // set_width(self, listname, size)
141 int InvRef::l_set_width(lua_State *L)
143 NO_MAP_LOCK_REQUIRED;
144 InvRef *ref = checkobject(L, 1);
145 const char *listname = luaL_checkstring(L, 2);
146 int newwidth = luaL_checknumber(L, 3);
147 Inventory *inv = getinv(L, ref);
151 InventoryList *list = inv->getList(listname);
153 list->setWidth(newwidth);
157 reportInventoryChange(L, ref);
161 // get_stack(self, listname, i) -> itemstack
162 int InvRef::l_get_stack(lua_State *L)
164 NO_MAP_LOCK_REQUIRED;
165 InvRef *ref = checkobject(L, 1);
166 const char *listname = luaL_checkstring(L, 2);
167 int i = luaL_checknumber(L, 3) - 1;
168 InventoryList *list = getlist(L, ref, listname);
170 if(list != NULL && i >= 0 && i < (int) list->getSize())
171 item = list->getItem(i);
172 LuaItemStack::create(L, item);
176 // set_stack(self, listname, i, stack) -> true/false
177 int InvRef::l_set_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 ItemStack newitem = read_item(L, 4, getServer(L));
184 InventoryList *list = getlist(L, ref, listname);
185 if(list != NULL && i >= 0 && i < (int) list->getSize()){
186 list->changeItem(i, newitem);
187 reportInventoryChange(L, ref);
188 lua_pushboolean(L, true);
190 lua_pushboolean(L, false);
195 // get_list(self, listname) -> list or nil
196 int InvRef::l_get_list(lua_State *L)
198 NO_MAP_LOCK_REQUIRED;
199 InvRef *ref = checkobject(L, 1);
200 const char *listname = luaL_checkstring(L, 2);
201 Inventory *inv = getinv(L, ref);
203 push_inventory_list(L, inv, listname);
210 // set_list(self, listname, list)
211 int InvRef::l_set_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);
220 InventoryList *list = inv->getList(listname);
222 read_inventory_list(L, 3, inv, listname,
223 getServer(L), list->getSize());
225 read_inventory_list(L, 3, inv, listname, getServer(L));
226 reportInventoryChange(L, ref);
230 // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
231 // Returns the leftover stack
232 int InvRef::l_add_item(lua_State *L)
234 NO_MAP_LOCK_REQUIRED;
235 InvRef *ref = checkobject(L, 1);
236 const char *listname = luaL_checkstring(L, 2);
237 ItemStack item = read_item(L, 3, getServer(L));
238 InventoryList *list = getlist(L, ref, listname);
240 ItemStack leftover = list->addItem(item);
241 if(leftover.count != item.count)
242 reportInventoryChange(L, ref);
243 LuaItemStack::create(L, leftover);
245 LuaItemStack::create(L, item);
250 // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
251 // Returns true if the item completely fits into the list
252 int InvRef::l_room_for_item(lua_State *L)
254 NO_MAP_LOCK_REQUIRED;
255 InvRef *ref = checkobject(L, 1);
256 const char *listname = luaL_checkstring(L, 2);
257 ItemStack item = read_item(L, 3, getServer(L));
258 InventoryList *list = getlist(L, ref, listname);
260 lua_pushboolean(L, list->roomForItem(item));
262 lua_pushboolean(L, false);
267 // contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
268 // Returns true if the list contains the given count of the given item name
269 int InvRef::l_contains_item(lua_State *L)
271 NO_MAP_LOCK_REQUIRED;
272 InvRef *ref = checkobject(L, 1);
273 const char *listname = luaL_checkstring(L, 2);
274 ItemStack item = read_item(L, 3, getServer(L));
275 InventoryList *list = getlist(L, ref, listname);
277 lua_pushboolean(L, list->containsItem(item));
279 lua_pushboolean(L, false);
284 // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
285 // Returns the items that were actually removed
286 int InvRef::l_remove_item(lua_State *L)
288 NO_MAP_LOCK_REQUIRED;
289 InvRef *ref = checkobject(L, 1);
290 const char *listname = luaL_checkstring(L, 2);
291 ItemStack item = read_item(L, 3, getServer(L));
292 InventoryList *list = getlist(L, ref, listname);
294 ItemStack removed = list->removeItem(item);
296 reportInventoryChange(L, ref);
297 LuaItemStack::create(L, removed);
299 LuaItemStack::create(L, ItemStack());
304 // get_location() -> location (like minetest.get_inventory(location))
305 int InvRef::l_get_location(lua_State *L)
307 NO_MAP_LOCK_REQUIRED;
308 InvRef *ref = checkobject(L, 1);
309 const InventoryLocation &loc = ref->m_loc;
311 case InventoryLocation::PLAYER:
313 lua_pushstring(L, "player");
314 lua_setfield(L, -2, "type");
315 lua_pushstring(L, loc.name.c_str());
316 lua_setfield(L, -2, "name");
318 case InventoryLocation::NODEMETA:
320 lua_pushstring(L, "node");
321 lua_setfield(L, -2, "type");
322 push_v3s16(L, loc.p);
323 lua_setfield(L, -2, "pos");
325 case InventoryLocation::DETACHED:
327 lua_pushstring(L, "detached");
328 lua_setfield(L, -2, "type");
329 lua_pushstring(L, loc.name.c_str());
330 lua_setfield(L, -2, "name");
332 case InventoryLocation::UNDEFINED:
333 case InventoryLocation::CURRENT_PLAYER:
337 lua_pushstring(L, "undefined");
338 lua_setfield(L, -2, "type");
343 InvRef::InvRef(const InventoryLocation &loc):
352 // Creates an InvRef and leaves it on top of stack
353 // Not callable from Lua; all references are created on the C side.
354 void InvRef::create(lua_State *L, const InventoryLocation &loc)
356 NO_MAP_LOCK_REQUIRED;
357 InvRef *o = new InvRef(loc);
358 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
359 luaL_getmetatable(L, className);
360 lua_setmetatable(L, -2);
362 void InvRef::createPlayer(lua_State *L, Player *player)
364 NO_MAP_LOCK_REQUIRED;
365 InventoryLocation loc;
366 loc.setPlayer(player->getName());
369 void InvRef::createNodeMeta(lua_State *L, v3s16 p)
371 InventoryLocation loc;
376 void InvRef::Register(lua_State *L)
379 int methodtable = lua_gettop(L);
380 luaL_newmetatable(L, className);
381 int metatable = lua_gettop(L);
383 lua_pushliteral(L, "__metatable");
384 lua_pushvalue(L, methodtable);
385 lua_settable(L, metatable); // hide metatable from Lua getmetatable()
387 lua_pushliteral(L, "__index");
388 lua_pushvalue(L, methodtable);
389 lua_settable(L, metatable);
391 lua_pushliteral(L, "__gc");
392 lua_pushcfunction(L, gc_object);
393 lua_settable(L, metatable);
395 lua_pop(L, 1); // drop metatable
397 luaL_openlib(L, 0, methods, 0); // fill methodtable
398 lua_pop(L, 1); // drop methodtable
400 // Cannot be created from Lua
401 //lua_register(L, className, create_object);
404 const char InvRef::className[] = "InvRef";
405 const luaL_reg InvRef::methods[] = {
406 luamethod(InvRef, is_empty),
407 luamethod(InvRef, get_size),
408 luamethod(InvRef, set_size),
409 luamethod(InvRef, get_width),
410 luamethod(InvRef, set_width),
411 luamethod(InvRef, get_stack),
412 luamethod(InvRef, set_stack),
413 luamethod(InvRef, get_list),
414 luamethod(InvRef, set_list),
415 luamethod(InvRef, add_item),
416 luamethod(InvRef, room_for_item),
417 luamethod(InvRef, contains_item),
418 luamethod(InvRef, remove_item),
419 luamethod(InvRef, get_location),
423 // get_inventory(location)
424 int ModApiInventory::l_get_inventory(lua_State *L)
426 InventoryLocation loc;
428 std::string type = checkstringfield(L, 1, "type");
431 lua_getfield(L, 1, "pos");
432 v3s16 pos = check_v3s16(L, -1);
433 loc.setNodeMeta(pos);
435 if(getServer(L)->getInventory(loc) != NULL)
436 InvRef::create(L, loc);
441 NO_MAP_LOCK_REQUIRED;
442 if(type == "player"){
443 std::string name = checkstringfield(L, 1, "name");
445 } else if(type == "detached"){
446 std::string name = checkstringfield(L, 1, "name");
447 loc.setDetached(name);
450 if(getServer(L)->getInventory(loc) != NULL)
451 InvRef::create(L, loc);
455 // END NO_MAP_LOCK_REQUIRED;
459 // create_detached_inventory_raw(name)
460 int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
462 NO_MAP_LOCK_REQUIRED;
463 const char *name = luaL_checkstring(L, 1);
464 if(getServer(L)->createDetachedInventory(name) != NULL){
465 InventoryLocation loc;
466 loc.setDetached(name);
467 InvRef::create(L, loc);
474 void ModApiInventory::Initialize(lua_State *L, int top)
476 API_FCT(create_detached_inventory_raw);
477 API_FCT(get_inventory);