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 "cpp_api/scriptapi.h"
21 #include "common/c_converter.h"
22 #include "common/c_content.h"
23 #include "lua_api/l_inventory.h"
24 #include "lua_api/l_item.h"
25 #include "common/c_internal.h"
28 #include "inventorymanager.h"
33 InvRef* InvRef::checkobject(lua_State *L, int narg)
35 luaL_checktype(L, narg, LUA_TUSERDATA);
36 void *ud = luaL_checkudata(L, narg, className);
37 if(!ud) luaL_typerror(L, narg, className);
38 return *(InvRef**)ud; // unbox pointer
41 Inventory* InvRef::getinv(lua_State *L, InvRef *ref)
43 return STACK_TO_SERVER(L)->getInventory(ref->m_loc);
46 InventoryList* InvRef::getlist(lua_State *L, InvRef *ref,
50 Inventory *inv = getinv(L, ref);
53 return inv->getList(listname);
56 void InvRef::reportInventoryChange(lua_State *L, InvRef *ref)
58 // Inform other things that the inventory has changed
59 STACK_TO_SERVER(L)->setInventoryModified(ref->m_loc);
65 int InvRef::gc_object(lua_State *L) {
66 InvRef *o = *(InvRef **)(lua_touserdata(L, 1));
71 // is_empty(self, listname) -> true/false
72 int InvRef::l_is_empty(lua_State *L)
75 InvRef *ref = checkobject(L, 1);
76 const char *listname = luaL_checkstring(L, 2);
77 InventoryList *list = getlist(L, ref, listname);
78 if(list && list->getUsedSlots() > 0){
79 lua_pushboolean(L, false);
81 lua_pushboolean(L, true);
86 // get_size(self, listname)
87 int InvRef::l_get_size(lua_State *L)
90 InvRef *ref = checkobject(L, 1);
91 const char *listname = luaL_checkstring(L, 2);
92 InventoryList *list = getlist(L, ref, listname);
94 lua_pushinteger(L, list->getSize());
96 lua_pushinteger(L, 0);
101 // get_width(self, listname)
102 int InvRef::l_get_width(lua_State *L)
104 NO_MAP_LOCK_REQUIRED;
105 InvRef *ref = checkobject(L, 1);
106 const char *listname = luaL_checkstring(L, 2);
107 InventoryList *list = getlist(L, ref, listname);
109 lua_pushinteger(L, list->getWidth());
111 lua_pushinteger(L, 0);
116 // set_size(self, listname, size)
117 int InvRef::l_set_size(lua_State *L)
119 NO_MAP_LOCK_REQUIRED;
120 InvRef *ref = checkobject(L, 1);
121 const char *listname = luaL_checkstring(L, 2);
122 int newsize = luaL_checknumber(L, 3);
123 Inventory *inv = getinv(L, ref);
128 inv->deleteList(listname);
129 reportInventoryChange(L, ref);
132 InventoryList *list = inv->getList(listname);
134 list->setSize(newsize);
136 list = inv->addList(listname, newsize);
138 reportInventoryChange(L, ref);
142 // set_width(self, listname, size)
143 int InvRef::l_set_width(lua_State *L)
145 NO_MAP_LOCK_REQUIRED;
146 InvRef *ref = checkobject(L, 1);
147 const char *listname = luaL_checkstring(L, 2);
148 int newwidth = luaL_checknumber(L, 3);
149 Inventory *inv = getinv(L, ref);
153 InventoryList *list = inv->getList(listname);
155 list->setWidth(newwidth);
159 reportInventoryChange(L, ref);
163 // get_stack(self, listname, i) -> itemstack
164 int InvRef::l_get_stack(lua_State *L)
166 NO_MAP_LOCK_REQUIRED;
167 InvRef *ref = checkobject(L, 1);
168 const char *listname = luaL_checkstring(L, 2);
169 int i = luaL_checknumber(L, 3) - 1;
170 InventoryList *list = getlist(L, ref, listname);
172 if(list != NULL && i >= 0 && i < (int) list->getSize())
173 item = list->getItem(i);
174 LuaItemStack::create(L, item);
178 // set_stack(self, listname, i, stack) -> true/false
179 int InvRef::l_set_stack(lua_State *L)
181 NO_MAP_LOCK_REQUIRED;
182 InvRef *ref = checkobject(L, 1);
183 const char *listname = luaL_checkstring(L, 2);
184 int i = luaL_checknumber(L, 3) - 1;
185 ItemStack newitem = read_item(L, 4,STACK_TO_SERVER(L));
186 InventoryList *list = getlist(L, ref, listname);
187 if(list != NULL && i >= 0 && i < (int) list->getSize()){
188 list->changeItem(i, newitem);
189 reportInventoryChange(L, ref);
190 lua_pushboolean(L, true);
192 lua_pushboolean(L, false);
197 // get_list(self, listname) -> list or nil
198 int InvRef::l_get_list(lua_State *L)
200 NO_MAP_LOCK_REQUIRED;
201 InvRef *ref = checkobject(L, 1);
202 const char *listname = luaL_checkstring(L, 2);
203 Inventory *inv = getinv(L, ref);
205 push_inventory_list(inv, listname, L);
212 // set_list(self, listname, list)
213 int InvRef::l_set_list(lua_State *L)
215 NO_MAP_LOCK_REQUIRED;
216 InvRef *ref = checkobject(L, 1);
217 const char *listname = luaL_checkstring(L, 2);
218 Inventory *inv = getinv(L, ref);
222 InventoryList *list = inv->getList(listname);
224 read_inventory_list(inv, listname, L, 3,
225 STACK_TO_SERVER(L),list->getSize());
227 read_inventory_list(inv, listname, L, 3,STACK_TO_SERVER(L));
228 reportInventoryChange(L, ref);
232 // add_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
233 // Returns the leftover stack
234 int InvRef::l_add_item(lua_State *L)
236 NO_MAP_LOCK_REQUIRED;
237 InvRef *ref = checkobject(L, 1);
238 const char *listname = luaL_checkstring(L, 2);
239 ItemStack item = read_item(L, 3,STACK_TO_SERVER(L));
240 InventoryList *list = getlist(L, ref, listname);
242 ItemStack leftover = list->addItem(item);
243 if(leftover.count != item.count)
244 reportInventoryChange(L, ref);
245 LuaItemStack::create(L, leftover);
247 LuaItemStack::create(L, item);
252 // room_for_item(self, listname, itemstack or itemstring or table or nil) -> true/false
253 // Returns true if the item completely fits into the list
254 int InvRef::l_room_for_item(lua_State *L)
256 NO_MAP_LOCK_REQUIRED;
257 InvRef *ref = checkobject(L, 1);
258 const char *listname = luaL_checkstring(L, 2);
259 ItemStack item = read_item(L, 3,STACK_TO_SERVER(L));
260 InventoryList *list = getlist(L, ref, listname);
262 lua_pushboolean(L, list->roomForItem(item));
264 lua_pushboolean(L, false);
269 // contains_item(self, listname, itemstack or itemstring or table or nil) -> true/false
270 // Returns true if the list contains the given count of the given item name
271 int InvRef::l_contains_item(lua_State *L)
273 NO_MAP_LOCK_REQUIRED;
274 InvRef *ref = checkobject(L, 1);
275 const char *listname = luaL_checkstring(L, 2);
276 ItemStack item = read_item(L, 3, STACK_TO_SERVER(L));
277 InventoryList *list = getlist(L, ref, listname);
279 lua_pushboolean(L, list->containsItem(item));
281 lua_pushboolean(L, false);
286 // remove_item(self, listname, itemstack or itemstring or table or nil) -> itemstack
287 // Returns the items that were actually removed
288 int InvRef::l_remove_item(lua_State *L)
290 NO_MAP_LOCK_REQUIRED;
291 InvRef *ref = checkobject(L, 1);
292 const char *listname = luaL_checkstring(L, 2);
293 ItemStack item = read_item(L, 3,STACK_TO_SERVER(L));
294 InventoryList *list = getlist(L, ref, listname);
296 ItemStack removed = list->removeItem(item);
298 reportInventoryChange(L, ref);
299 LuaItemStack::create(L, removed);
301 LuaItemStack::create(L, ItemStack());
306 // get_location() -> location (like minetest.get_inventory(location))
307 int InvRef::l_get_location(lua_State *L)
309 NO_MAP_LOCK_REQUIRED;
310 InvRef *ref = checkobject(L, 1);
311 const InventoryLocation &loc = ref->m_loc;
313 case InventoryLocation::PLAYER:
315 lua_pushstring(L, "player");
316 lua_setfield(L, -2, "type");
317 lua_pushstring(L, loc.name.c_str());
318 lua_setfield(L, -2, "name");
320 case InventoryLocation::NODEMETA:
322 lua_pushstring(L, "node");
323 lua_setfield(L, -2, "type");
324 push_v3s16(L, loc.p);
325 lua_setfield(L, -2, "pos");
327 case InventoryLocation::DETACHED:
329 lua_pushstring(L, "detached");
330 lua_setfield(L, -2, "type");
331 lua_pushstring(L, loc.name.c_str());
332 lua_setfield(L, -2, "name");
334 case InventoryLocation::UNDEFINED:
335 case InventoryLocation::CURRENT_PLAYER:
339 lua_pushstring(L, "undefined");
340 lua_setfield(L, -2, "type");
345 InvRef::InvRef(const InventoryLocation &loc):
354 // Creates an InvRef and leaves it on top of stack
355 // Not callable from Lua; all references are created on the C side.
356 void InvRef::create(lua_State *L, const InventoryLocation &loc)
358 NO_MAP_LOCK_REQUIRED;
359 InvRef *o = new InvRef(loc);
360 *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
361 luaL_getmetatable(L, className);
362 lua_setmetatable(L, -2);
364 void InvRef::createPlayer(lua_State *L, Player *player)
366 NO_MAP_LOCK_REQUIRED;
367 InventoryLocation loc;
368 loc.setPlayer(player->getName());
371 void InvRef::createNodeMeta(lua_State *L, v3s16 p)
373 InventoryLocation loc;
378 void InvRef::Register(lua_State *L)
381 int methodtable = lua_gettop(L);
382 luaL_newmetatable(L, className);
383 int metatable = lua_gettop(L);
385 lua_pushliteral(L, "__metatable");
386 lua_pushvalue(L, methodtable);
387 lua_settable(L, metatable); // hide metatable from Lua getmetatable()
389 lua_pushliteral(L, "__index");
390 lua_pushvalue(L, methodtable);
391 lua_settable(L, metatable);
393 lua_pushliteral(L, "__gc");
394 lua_pushcfunction(L, gc_object);
395 lua_settable(L, metatable);
397 lua_pop(L, 1); // drop metatable
399 luaL_openlib(L, 0, methods, 0); // fill methodtable
400 lua_pop(L, 1); // drop methodtable
402 // Cannot be created from Lua
403 //lua_register(L, className, create_object);
406 const char InvRef::className[] = "InvRef";
407 const luaL_reg InvRef::methods[] = {
408 luamethod(InvRef, is_empty),
409 luamethod(InvRef, get_size),
410 luamethod(InvRef, set_size),
411 luamethod(InvRef, get_width),
412 luamethod(InvRef, set_width),
413 luamethod(InvRef, get_stack),
414 luamethod(InvRef, set_stack),
415 luamethod(InvRef, get_list),
416 luamethod(InvRef, set_list),
417 luamethod(InvRef, add_item),
418 luamethod(InvRef, room_for_item),
419 luamethod(InvRef, contains_item),
420 luamethod(InvRef, remove_item),
421 luamethod(InvRef, get_location),
425 // get_inventory(location)
426 int ModApiInventory::l_get_inventory(lua_State *L)
428 InventoryLocation loc;
430 std::string type = checkstringfield(L, 1, "type");
433 lua_getfield(L, 1, "pos");
434 v3s16 pos = check_v3s16(L, -1);
435 loc.setNodeMeta(pos);
437 if(getServer(L)->getInventory(loc) != NULL)
438 InvRef::create(L, loc);
443 NO_MAP_LOCK_REQUIRED;
444 if(type == "player"){
445 std::string name = checkstringfield(L, 1, "name");
447 } else if(type == "detached"){
448 std::string name = checkstringfield(L, 1, "name");
449 loc.setDetached(name);
452 if(getServer(L)->getInventory(loc) != NULL)
453 InvRef::create(L, loc);
457 // END NO_MAP_LOCK_REQUIRED;
461 // create_detached_inventory_raw(name)
462 int ModApiInventory::l_create_detached_inventory_raw(lua_State *L)
464 NO_MAP_LOCK_REQUIRED;
465 const char *name = luaL_checkstring(L, 1);
466 if(getServer(L)->createDetachedInventory(name) != NULL){
467 InventoryLocation loc;
468 loc.setDetached(name);
469 InvRef::create(L, loc);
476 bool ModApiInventory::Initialize(lua_State *L, int top) {
479 retval &= API_FCT(create_detached_inventory_raw);
480 retval &= API_FCT(get_inventory);
487 ModApiInventory::ModApiInventory()
492 ModApiInventory modapiinventory_prototype;