mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01:00 
			
		
		
		
	Add InvRef and InvStack (currently untested and unusable)
This commit is contained in:
		@@ -94,6 +94,7 @@ configure_file(
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
set(common_SRCS
 | 
			
		||||
	inventorymanager.cpp
 | 
			
		||||
	mods.cpp
 | 
			
		||||
	serverremoteplayer.cpp
 | 
			
		||||
	content_abm.cpp
 | 
			
		||||
 
 | 
			
		||||
@@ -1782,6 +1782,34 @@ InventoryContext *Client::getInventoryContext()
 | 
			
		||||
	return &m_inventory_context;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Inventory* Client::getInventory(const InventoryLocation &loc)
 | 
			
		||||
{
 | 
			
		||||
	switch(loc.type){
 | 
			
		||||
	case InventoryLocation::UNDEFINED:
 | 
			
		||||
	{}
 | 
			
		||||
	break;
 | 
			
		||||
	case InventoryLocation::PLAYER:
 | 
			
		||||
	{
 | 
			
		||||
		Player *player = m_env.getPlayer(loc.name.c_str());
 | 
			
		||||
		if(!player)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return &player->inventory;
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
	case InventoryLocation::NODEMETA:
 | 
			
		||||
	{
 | 
			
		||||
		NodeMetadata *meta = m_env.getMap().getNodeMetadata(loc.p);
 | 
			
		||||
		if(!meta)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return meta->getInventory();
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
	default:
 | 
			
		||||
		assert(0);
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
#if 0
 | 
			
		||||
Inventory* Client::getInventory(InventoryContext *c, std::string id)
 | 
			
		||||
{
 | 
			
		||||
	if(id == "current_player")
 | 
			
		||||
@@ -1810,6 +1838,7 @@ Inventory* Client::getInventory(InventoryContext *c, std::string id)
 | 
			
		||||
	infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
void Client::inventoryAction(InventoryAction *a)
 | 
			
		||||
{
 | 
			
		||||
	sendInventoryAction(a);
 | 
			
		||||
 
 | 
			
		||||
@@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include "clientobject.h"
 | 
			
		||||
#include "utility.h" // For IntervalLimiter
 | 
			
		||||
#include "gamedef.h"
 | 
			
		||||
#include "inventorymanager.h"
 | 
			
		||||
 | 
			
		||||
struct MeshMakeData;
 | 
			
		||||
class IGameDef;
 | 
			
		||||
@@ -245,7 +246,9 @@ public:
 | 
			
		||||
	
 | 
			
		||||
	InventoryContext *getInventoryContext();
 | 
			
		||||
 | 
			
		||||
	Inventory* getInventory(InventoryContext *c, std::string id);
 | 
			
		||||
	/* InventoryManager interface */
 | 
			
		||||
	Inventory* getInventory(const InventoryLocation &loc);
 | 
			
		||||
	//Inventory* getInventory(InventoryContext *c, std::string id);
 | 
			
		||||
	void inventoryAction(InventoryAction *a);
 | 
			
		||||
 | 
			
		||||
	// Gets closest object pointed by the shootline
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include "utility.h"
 | 
			
		||||
#include "gamedef.h"
 | 
			
		||||
#include "inventory.h"
 | 
			
		||||
#include "inventorymanager.h" // checkItemCombination
 | 
			
		||||
 | 
			
		||||
CraftPointerInput::~CraftPointerInput()
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include <IGUIStaticText.h>
 | 
			
		||||
#include <IGUIFont.h>
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "inventorymanager.h"
 | 
			
		||||
 | 
			
		||||
void drawInventoryItem(video::IVideoDriver *driver,
 | 
			
		||||
		gui::IGUIFont *font,
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include "modalMenu.h"
 | 
			
		||||
 | 
			
		||||
class ITextureSource;
 | 
			
		||||
class InventoryContext;
 | 
			
		||||
class InventoryManager;
 | 
			
		||||
 | 
			
		||||
void drawInventoryItem(video::IVideoDriver *driver,
 | 
			
		||||
		gui::IGUIFont *font,
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include "scriptapi.h"
 | 
			
		||||
#include "strfnd.h"
 | 
			
		||||
#include "nameidmapping.h" // For loading legacy MaterialItems
 | 
			
		||||
#include "serverremoteplayer.h"
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	InventoryItem
 | 
			
		||||
@@ -567,6 +566,22 @@ void InventoryList::clearItems()
 | 
			
		||||
	//setDirty(true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void InventoryList::setSize(u32 newsize)
 | 
			
		||||
{
 | 
			
		||||
	if(newsize < m_items.size()){
 | 
			
		||||
		for(u32 i=newsize; i<m_items.size(); i++){
 | 
			
		||||
			if(m_items[i])
 | 
			
		||||
				delete m_items[i];
 | 
			
		||||
		}
 | 
			
		||||
		m_items.erase(newsize, m_items.size() - newsize);
 | 
			
		||||
	} else {
 | 
			
		||||
		for(u32 i=m_items.size(); i<newsize; i++){
 | 
			
		||||
			m_items.push_back(NULL);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	m_size = newsize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void InventoryList::serialize(std::ostream &os) const
 | 
			
		||||
{
 | 
			
		||||
	//os.imbue(std::locale("C"));
 | 
			
		||||
@@ -1041,458 +1056,4 @@ const s32 Inventory::getListIndex(const std::string &name) const
 | 
			
		||||
	return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	InventoryAction
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
InventoryAction * InventoryAction::deSerialize(std::istream &is)
 | 
			
		||||
{
 | 
			
		||||
	std::string type;
 | 
			
		||||
	std::getline(is, type, ' ');
 | 
			
		||||
 | 
			
		||||
	InventoryAction *a = NULL;
 | 
			
		||||
 | 
			
		||||
	if(type == "Move")
 | 
			
		||||
	{
 | 
			
		||||
		a = new IMoveAction(is);
 | 
			
		||||
	}
 | 
			
		||||
	else if(type == "Drop")
 | 
			
		||||
	{
 | 
			
		||||
		a = new IDropAction(is);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return a;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static std::string describeC(const struct InventoryContext *c)
 | 
			
		||||
{
 | 
			
		||||
	if(c->current_player == NULL)
 | 
			
		||||
		return "current_player=NULL";
 | 
			
		||||
	else
 | 
			
		||||
		return std::string("current_player=") + c->current_player->getName();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IMoveAction::IMoveAction(std::istream &is)
 | 
			
		||||
{
 | 
			
		||||
	std::string ts;
 | 
			
		||||
 | 
			
		||||
	std::getline(is, ts, ' ');
 | 
			
		||||
	count = stoi(ts);
 | 
			
		||||
 | 
			
		||||
	std::getline(is, from_inv, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, from_list, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, ts, ' ');
 | 
			
		||||
	from_i = stoi(ts);
 | 
			
		||||
 | 
			
		||||
	std::getline(is, to_inv, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, to_list, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, ts, ' ');
 | 
			
		||||
	to_i = stoi(ts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
 | 
			
		||||
		ServerEnvironment *env)
 | 
			
		||||
{
 | 
			
		||||
	Inventory *inv_from = mgr->getInventory(c, from_inv);
 | 
			
		||||
	Inventory *inv_to = mgr->getInventory(c, to_inv);
 | 
			
		||||
	
 | 
			
		||||
	if(!inv_from){
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: source inventory not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", to_inv=\""<<to_inv<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if(!inv_to){
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: "
 | 
			
		||||
				"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", to_inv=\""<<to_inv<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	InventoryList *list_from = inv_from->getList(from_list);
 | 
			
		||||
	InventoryList *list_to = inv_to->getList(to_list);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		If a list doesn't exist or the source item doesn't exist
 | 
			
		||||
	*/
 | 
			
		||||
	if(!list_from){
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: source list not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", from_list=\""<<from_list<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if(!list_to){
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: destination list not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], to_inv=\""<<to_inv<<"\""
 | 
			
		||||
				<<", to_list=\""<<to_list<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if(list_from->getItem(from_i) == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: source item not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", from_list=\""<<from_list<<"\""
 | 
			
		||||
				<<" from_i="<<from_i<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
		If the source and the destination slots are the same
 | 
			
		||||
	*/
 | 
			
		||||
	if(inv_from == inv_to && list_from == list_to && from_i == to_i)
 | 
			
		||||
	{
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
 | 
			
		||||
				<<"are the same: inv=\""<<from_inv<<"\" list=\""<<from_list
 | 
			
		||||
				<<"\" i="<<from_i<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Take item from source list
 | 
			
		||||
	InventoryItem *item1 = NULL;
 | 
			
		||||
	if(count == 0)
 | 
			
		||||
		item1 = list_from->changeItem(from_i, NULL);
 | 
			
		||||
	else
 | 
			
		||||
		item1 = list_from->takeItem(from_i, count);
 | 
			
		||||
 | 
			
		||||
	// Try to add the item to destination list
 | 
			
		||||
	InventoryItem *olditem = item1;
 | 
			
		||||
	item1 = list_to->addItem(to_i, item1);
 | 
			
		||||
 | 
			
		||||
	// If something is returned, the item was not fully added
 | 
			
		||||
	if(item1 != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		// If olditem is returned, nothing was added.
 | 
			
		||||
		bool nothing_added = (item1 == olditem);
 | 
			
		||||
		
 | 
			
		||||
		// If something else is returned, part of the item was left unadded.
 | 
			
		||||
		// Add the other part back to the source item
 | 
			
		||||
		list_from->addItem(from_i, item1);
 | 
			
		||||
 | 
			
		||||
		// If olditem is returned, nothing was added.
 | 
			
		||||
		// Swap the items
 | 
			
		||||
		if(nothing_added)
 | 
			
		||||
		{
 | 
			
		||||
			// Take item from source list
 | 
			
		||||
			item1 = list_from->changeItem(from_i, NULL);
 | 
			
		||||
			// Adding was not possible, swap the items.
 | 
			
		||||
			InventoryItem *item2 = list_to->changeItem(to_i, item1);
 | 
			
		||||
			// Put item from destination list to the source list
 | 
			
		||||
			list_from->changeItem(from_i, item2);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mgr->inventoryModified(c, from_inv);
 | 
			
		||||
	if(from_inv != to_inv)
 | 
			
		||||
		mgr->inventoryModified(c, to_inv);
 | 
			
		||||
	
 | 
			
		||||
	infostream<<"IMoveAction::apply(): moved at "
 | 
			
		||||
			<<"["<<describeC(c)<<"]"
 | 
			
		||||
			<<" from inv=\""<<from_inv<<"\""
 | 
			
		||||
			<<" list=\""<<from_list<<"\""
 | 
			
		||||
			<<" i="<<from_i
 | 
			
		||||
			<<" to inv=\""<<to_inv<<"\""
 | 
			
		||||
			<<" list=\""<<to_list<<"\""
 | 
			
		||||
			<<" i="<<to_i
 | 
			
		||||
			<<std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IDropAction::IDropAction(std::istream &is)
 | 
			
		||||
{
 | 
			
		||||
	std::string ts;
 | 
			
		||||
 | 
			
		||||
	std::getline(is, ts, ' ');
 | 
			
		||||
	count = stoi(ts);
 | 
			
		||||
 | 
			
		||||
	std::getline(is, from_inv, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, from_list, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, ts, ' ');
 | 
			
		||||
	from_i = stoi(ts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
 | 
			
		||||
		ServerEnvironment *env)
 | 
			
		||||
{
 | 
			
		||||
	if(c->current_player == NULL){
 | 
			
		||||
		infostream<<"IDropAction::apply(): FAIL: current_player is NULL"<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Do NOT cast directly to ServerActiveObject*, it breaks
 | 
			
		||||
	// because of multiple inheritance.
 | 
			
		||||
	ServerActiveObject *dropper =
 | 
			
		||||
		static_cast<ServerActiveObject*>(
 | 
			
		||||
		static_cast<ServerRemotePlayer*>(
 | 
			
		||||
			c->current_player
 | 
			
		||||
		));
 | 
			
		||||
 | 
			
		||||
	Inventory *inv_from = mgr->getInventory(c, from_inv);
 | 
			
		||||
	
 | 
			
		||||
	if(!inv_from){
 | 
			
		||||
		infostream<<"IDropAction::apply(): FAIL: source inventory not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	InventoryList *list_from = inv_from->getList(from_list);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		If a list doesn't exist or the source item doesn't exist
 | 
			
		||||
	*/
 | 
			
		||||
	if(!list_from){
 | 
			
		||||
		infostream<<"IDropAction::apply(): FAIL: source list not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", from_list=\""<<from_list<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	InventoryItem *item = list_from->getItem(from_i);
 | 
			
		||||
	if(item == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		infostream<<"IDropAction::apply(): FAIL: source item not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", from_list=\""<<from_list<<"\""
 | 
			
		||||
				<<" from_i="<<from_i<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v3f pos = dropper->getBasePosition();
 | 
			
		||||
	pos.Y += 0.5*BS;
 | 
			
		||||
 | 
			
		||||
	s16 count2 = count;
 | 
			
		||||
	if(count2 == 0)
 | 
			
		||||
		count2 = -1;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		Drop the item
 | 
			
		||||
	*/
 | 
			
		||||
	bool remove = item->dropOrPlace(env, dropper, pos, false, count2);
 | 
			
		||||
	if(remove)
 | 
			
		||||
		list_from->deleteItem(from_i);
 | 
			
		||||
 | 
			
		||||
	mgr->inventoryModified(c, from_inv);
 | 
			
		||||
 | 
			
		||||
	infostream<<"IDropAction::apply(): dropped "
 | 
			
		||||
			<<"["<<describeC(c)<<"]"
 | 
			
		||||
			<<" from inv=\""<<from_inv<<"\""
 | 
			
		||||
			<<" list=\""<<from_list<<"\""
 | 
			
		||||
			<<" i="<<from_i
 | 
			
		||||
			<<std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Craft checking system
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
bool ItemSpec::checkItem(const InventoryItem *item) const
 | 
			
		||||
{
 | 
			
		||||
	if(type == ITEM_NONE)
 | 
			
		||||
	{
 | 
			
		||||
		// Has to be no item
 | 
			
		||||
		if(item != NULL)
 | 
			
		||||
			return false;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// There should be an item
 | 
			
		||||
	if(item == NULL)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	std::string itemname = item->getName();
 | 
			
		||||
 | 
			
		||||
	if(type == ITEM_MATERIAL)
 | 
			
		||||
	{
 | 
			
		||||
		if(itemname != "MaterialItem")
 | 
			
		||||
			return false;
 | 
			
		||||
		MaterialItem *mitem = (MaterialItem*)item;
 | 
			
		||||
		if(num != 65535){
 | 
			
		||||
			if(mitem->getMaterial() != num)
 | 
			
		||||
				return false;
 | 
			
		||||
		} else {
 | 
			
		||||
			if(mitem->getNodeName() != name)
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if(type == ITEM_CRAFT)
 | 
			
		||||
	{
 | 
			
		||||
		if(itemname != "CraftItem")
 | 
			
		||||
			return false;
 | 
			
		||||
		CraftItem *mitem = (CraftItem*)item;
 | 
			
		||||
		if(mitem->getSubName() != name)
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
	else if(type == ITEM_TOOL)
 | 
			
		||||
	{
 | 
			
		||||
		// Not supported yet
 | 
			
		||||
		assert(0);
 | 
			
		||||
	}
 | 
			
		||||
	else if(type == ITEM_MBO)
 | 
			
		||||
	{
 | 
			
		||||
		// Not supported yet
 | 
			
		||||
		assert(0);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		// Not supported yet
 | 
			
		||||
		assert(0);
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *specs)
 | 
			
		||||
{
 | 
			
		||||
	u16 items_min_x = 100;
 | 
			
		||||
	u16 items_max_x = 100;
 | 
			
		||||
	u16 items_min_y = 100;
 | 
			
		||||
	u16 items_max_y = 100;
 | 
			
		||||
	for(u16 y=0; y<3; y++)
 | 
			
		||||
	for(u16 x=0; x<3; x++)
 | 
			
		||||
	{
 | 
			
		||||
		if(items[y*3 + x] == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		if(items_min_x == 100 || x < items_min_x)
 | 
			
		||||
			items_min_x = x;
 | 
			
		||||
		if(items_min_y == 100 || y < items_min_y)
 | 
			
		||||
			items_min_y = y;
 | 
			
		||||
		if(items_max_x == 100 || x > items_max_x)
 | 
			
		||||
			items_max_x = x;
 | 
			
		||||
		if(items_max_y == 100 || y > items_max_y)
 | 
			
		||||
			items_max_y = y;
 | 
			
		||||
	}
 | 
			
		||||
	// No items at all, just return false
 | 
			
		||||
	if(items_min_x == 100)
 | 
			
		||||
		return false;
 | 
			
		||||
	
 | 
			
		||||
	u16 items_w = items_max_x - items_min_x + 1;
 | 
			
		||||
	u16 items_h = items_max_y - items_min_y + 1;
 | 
			
		||||
 | 
			
		||||
	u16 specs_min_x = 100;
 | 
			
		||||
	u16 specs_max_x = 100;
 | 
			
		||||
	u16 specs_min_y = 100;
 | 
			
		||||
	u16 specs_max_y = 100;
 | 
			
		||||
	for(u16 y=0; y<3; y++)
 | 
			
		||||
	for(u16 x=0; x<3; x++)
 | 
			
		||||
	{
 | 
			
		||||
		if(specs[y*3 + x].type == ITEM_NONE)
 | 
			
		||||
			continue;
 | 
			
		||||
		if(specs_min_x == 100 || x < specs_min_x)
 | 
			
		||||
			specs_min_x = x;
 | 
			
		||||
		if(specs_min_y == 100 || y < specs_min_y)
 | 
			
		||||
			specs_min_y = y;
 | 
			
		||||
		if(specs_max_x == 100 || x > specs_max_x)
 | 
			
		||||
			specs_max_x = x;
 | 
			
		||||
		if(specs_max_y == 100 || y > specs_max_y)
 | 
			
		||||
			specs_max_y = y;
 | 
			
		||||
	}
 | 
			
		||||
	// No specs at all, just return false
 | 
			
		||||
	if(specs_min_x == 100)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	u16 specs_w = specs_max_x - specs_min_x + 1;
 | 
			
		||||
	u16 specs_h = specs_max_y - specs_min_y + 1;
 | 
			
		||||
 | 
			
		||||
	// Different sizes
 | 
			
		||||
	if(items_w != specs_w || items_h != specs_h)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	for(u16 y=0; y<specs_h; y++)
 | 
			
		||||
	for(u16 x=0; x<specs_w; x++)
 | 
			
		||||
	{
 | 
			
		||||
		u16 items_x = items_min_x + x;
 | 
			
		||||
		u16 items_y = items_min_y + y;
 | 
			
		||||
		u16 specs_x = specs_min_x + x;
 | 
			
		||||
		u16 specs_y = specs_min_y + y;
 | 
			
		||||
		const InventoryItem *item = items[items_y * 3 + items_x];
 | 
			
		||||
		const ItemSpec &spec = specs[specs_y * 3 + specs_x];
 | 
			
		||||
 | 
			
		||||
		if(spec.checkItem(item) == false)
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool checkItemCombination(const InventoryItem * const * items,
 | 
			
		||||
		const InventoryItem * const * specs)
 | 
			
		||||
{
 | 
			
		||||
	u16 items_min_x = 100;
 | 
			
		||||
	u16 items_max_x = 100;
 | 
			
		||||
	u16 items_min_y = 100;
 | 
			
		||||
	u16 items_max_y = 100;
 | 
			
		||||
	for(u16 y=0; y<3; y++)
 | 
			
		||||
	for(u16 x=0; x<3; x++)
 | 
			
		||||
	{
 | 
			
		||||
		if(items[y*3 + x] == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		if(items_min_x == 100 || x < items_min_x)
 | 
			
		||||
			items_min_x = x;
 | 
			
		||||
		if(items_min_y == 100 || y < items_min_y)
 | 
			
		||||
			items_min_y = y;
 | 
			
		||||
		if(items_max_x == 100 || x > items_max_x)
 | 
			
		||||
			items_max_x = x;
 | 
			
		||||
		if(items_max_y == 100 || y > items_max_y)
 | 
			
		||||
			items_max_y = y;
 | 
			
		||||
	}
 | 
			
		||||
	// No items at all, just return false
 | 
			
		||||
	if(items_min_x == 100)
 | 
			
		||||
		return false;
 | 
			
		||||
	
 | 
			
		||||
	u16 items_w = items_max_x - items_min_x + 1;
 | 
			
		||||
	u16 items_h = items_max_y - items_min_y + 1;
 | 
			
		||||
 | 
			
		||||
	u16 specs_min_x = 100;
 | 
			
		||||
	u16 specs_max_x = 100;
 | 
			
		||||
	u16 specs_min_y = 100;
 | 
			
		||||
	u16 specs_max_y = 100;
 | 
			
		||||
	for(u16 y=0; y<3; y++)
 | 
			
		||||
	for(u16 x=0; x<3; x++)
 | 
			
		||||
	{
 | 
			
		||||
		if(specs[y*3 + x] == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		if(specs_min_x == 100 || x < specs_min_x)
 | 
			
		||||
			specs_min_x = x;
 | 
			
		||||
		if(specs_min_y == 100 || y < specs_min_y)
 | 
			
		||||
			specs_min_y = y;
 | 
			
		||||
		if(specs_max_x == 100 || x > specs_max_x)
 | 
			
		||||
			specs_max_x = x;
 | 
			
		||||
		if(specs_max_y == 100 || y > specs_max_y)
 | 
			
		||||
			specs_max_y = y;
 | 
			
		||||
	}
 | 
			
		||||
	// No specs at all, just return false
 | 
			
		||||
	if(specs_min_x == 100)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	u16 specs_w = specs_max_x - specs_min_x + 1;
 | 
			
		||||
	u16 specs_h = specs_max_y - specs_min_y + 1;
 | 
			
		||||
 | 
			
		||||
	// Different sizes
 | 
			
		||||
	if(items_w != specs_w || items_h != specs_h)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	for(u16 y=0; y<specs_h; y++)
 | 
			
		||||
	for(u16 x=0; x<specs_w; x++)
 | 
			
		||||
	{
 | 
			
		||||
		u16 items_x = items_min_x + x;
 | 
			
		||||
		u16 items_y = items_min_y + y;
 | 
			
		||||
		u16 specs_x = specs_min_x + x;
 | 
			
		||||
		u16 specs_y = specs_min_y + y;
 | 
			
		||||
		const InventoryItem *item = items[items_y * 3 + items_x];
 | 
			
		||||
		const InventoryItem *spec = specs[specs_y * 3 + specs_x];
 | 
			
		||||
		
 | 
			
		||||
		if(item == NULL && spec == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		if(item == NULL && spec != NULL)
 | 
			
		||||
			return false;
 | 
			
		||||
		if(item != NULL && spec == NULL)
 | 
			
		||||
			return false;
 | 
			
		||||
		if(!spec->isSubsetOf(item))
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//END
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										178
									
								
								src/inventory.h
									
									
									
									
									
								
							
							
						
						
									
										178
									
								
								src/inventory.h
									
									
									
									
									
								
							@@ -419,6 +419,7 @@ public:
 | 
			
		||||
	InventoryList(std::string name, u32 size);
 | 
			
		||||
	~InventoryList();
 | 
			
		||||
	void clearItems();
 | 
			
		||||
	void setSize(u32 newsize);
 | 
			
		||||
	void serialize(std::ostream &os) const;
 | 
			
		||||
	void deSerialize(std::istream &is, IGameDef *gamedef);
 | 
			
		||||
 | 
			
		||||
@@ -513,182 +514,5 @@ private:
 | 
			
		||||
	core::array<InventoryList*> m_lists;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Player;
 | 
			
		||||
 | 
			
		||||
struct InventoryContext
 | 
			
		||||
{
 | 
			
		||||
	Player *current_player;
 | 
			
		||||
	
 | 
			
		||||
	InventoryContext():
 | 
			
		||||
		current_player(NULL)
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct InventoryAction;
 | 
			
		||||
 | 
			
		||||
class InventoryManager
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	InventoryManager(){}
 | 
			
		||||
	virtual ~InventoryManager(){}
 | 
			
		||||
	
 | 
			
		||||
	/*
 | 
			
		||||
		Get a pointer to an inventory specified by id.
 | 
			
		||||
		id can be:
 | 
			
		||||
		- "current_player"
 | 
			
		||||
		- "nodemeta:X,Y,Z"
 | 
			
		||||
	*/
 | 
			
		||||
	virtual Inventory* getInventory(InventoryContext *c, std::string id)
 | 
			
		||||
		{return NULL;}
 | 
			
		||||
	// Used on the server by InventoryAction::apply and other stuff
 | 
			
		||||
	virtual void inventoryModified(InventoryContext *c, std::string id)
 | 
			
		||||
		{}
 | 
			
		||||
	// Used on the client
 | 
			
		||||
	virtual void inventoryAction(InventoryAction *a)
 | 
			
		||||
		{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define IACTION_MOVE 0
 | 
			
		||||
#define IACTION_DROP 1
 | 
			
		||||
 | 
			
		||||
struct InventoryAction
 | 
			
		||||
{
 | 
			
		||||
	static InventoryAction * deSerialize(std::istream &is);
 | 
			
		||||
 | 
			
		||||
	virtual u16 getType() const = 0;
 | 
			
		||||
	virtual void serialize(std::ostream &os) const = 0;
 | 
			
		||||
	virtual void apply(InventoryContext *c, InventoryManager *mgr,
 | 
			
		||||
			ServerEnvironment *env) = 0;
 | 
			
		||||
	virtual ~InventoryAction() {};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct IMoveAction : public InventoryAction
 | 
			
		||||
{
 | 
			
		||||
	// count=0 means "everything"
 | 
			
		||||
	u16 count;
 | 
			
		||||
	std::string from_inv;
 | 
			
		||||
	std::string from_list;
 | 
			
		||||
	s16 from_i;
 | 
			
		||||
	std::string to_inv;
 | 
			
		||||
	std::string to_list;
 | 
			
		||||
	s16 to_i;
 | 
			
		||||
	
 | 
			
		||||
	IMoveAction()
 | 
			
		||||
	{
 | 
			
		||||
		count = 0;
 | 
			
		||||
		from_i = -1;
 | 
			
		||||
		to_i = -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	IMoveAction(std::istream &is);
 | 
			
		||||
 | 
			
		||||
	u16 getType() const
 | 
			
		||||
	{
 | 
			
		||||
		return IACTION_MOVE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void serialize(std::ostream &os) const
 | 
			
		||||
	{
 | 
			
		||||
		os<<"Move ";
 | 
			
		||||
		os<<count<<" ";
 | 
			
		||||
		os<<from_inv<<" ";
 | 
			
		||||
		os<<from_list<<" ";
 | 
			
		||||
		os<<from_i<<" ";
 | 
			
		||||
		os<<to_inv<<" ";
 | 
			
		||||
		os<<to_list<<" ";
 | 
			
		||||
		os<<to_i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void apply(InventoryContext *c, InventoryManager *mgr,
 | 
			
		||||
			ServerEnvironment *env);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct IDropAction : public InventoryAction
 | 
			
		||||
{
 | 
			
		||||
	// count=0 means "everything"
 | 
			
		||||
	u16 count;
 | 
			
		||||
	std::string from_inv;
 | 
			
		||||
	std::string from_list;
 | 
			
		||||
	s16 from_i;
 | 
			
		||||
	
 | 
			
		||||
	IDropAction()
 | 
			
		||||
	{
 | 
			
		||||
		count = 0;
 | 
			
		||||
		from_i = -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	IDropAction(std::istream &is);
 | 
			
		||||
 | 
			
		||||
	u16 getType() const
 | 
			
		||||
	{
 | 
			
		||||
		return IACTION_DROP;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void serialize(std::ostream &os) const
 | 
			
		||||
	{
 | 
			
		||||
		os<<"Drop ";
 | 
			
		||||
		os<<count<<" ";
 | 
			
		||||
		os<<from_inv<<" ";
 | 
			
		||||
		os<<from_list<<" ";
 | 
			
		||||
		os<<from_i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void apply(InventoryContext *c, InventoryManager *mgr,
 | 
			
		||||
			ServerEnvironment *env);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Craft checking system
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
enum ItemSpecType
 | 
			
		||||
{
 | 
			
		||||
	ITEM_NONE,
 | 
			
		||||
	ITEM_MATERIAL,
 | 
			
		||||
	ITEM_CRAFT,
 | 
			
		||||
	ITEM_TOOL,
 | 
			
		||||
	ITEM_MBO
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ItemSpec
 | 
			
		||||
{
 | 
			
		||||
	enum ItemSpecType type;
 | 
			
		||||
	// Only other one of these is used
 | 
			
		||||
	std::string name;
 | 
			
		||||
	u16 num;
 | 
			
		||||
 | 
			
		||||
	ItemSpec():
 | 
			
		||||
		type(ITEM_NONE)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	ItemSpec(enum ItemSpecType a_type, std::string a_name):
 | 
			
		||||
		type(a_type),
 | 
			
		||||
		name(a_name),
 | 
			
		||||
		num(65535)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	ItemSpec(enum ItemSpecType a_type, u16 a_num):
 | 
			
		||||
		type(a_type),
 | 
			
		||||
		name(""),
 | 
			
		||||
		num(a_num)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool checkItem(const InventoryItem *item) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	items: a pointer to an array of 9 pointers to items
 | 
			
		||||
	specs: a pointer to an array of 9 ItemSpecs
 | 
			
		||||
*/
 | 
			
		||||
bool checkItemCombination(const InventoryItem * const*items, const ItemSpec *specs);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	items: a pointer to an array of 9 pointers to items
 | 
			
		||||
	specs: a pointer to an array of 9 pointers to items
 | 
			
		||||
*/
 | 
			
		||||
bool checkItemCombination(const InventoryItem * const * items,
 | 
			
		||||
		const InventoryItem * const * specs);
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										544
									
								
								src/inventorymanager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										544
									
								
								src/inventorymanager.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,544 @@
 | 
			
		||||
/*
 | 
			
		||||
Minetest-c55
 | 
			
		||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
 | 
			
		||||
 | 
			
		||||
This program is free software; you can redistribute it and/or modify
 | 
			
		||||
it under the terms of the GNU General Public License as published by
 | 
			
		||||
the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
(at your option) any later version.
 | 
			
		||||
 | 
			
		||||
This program is distributed in the hope that it will be useful,
 | 
			
		||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
You should have received a copy of the GNU General Public License along
 | 
			
		||||
with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "inventorymanager.h"
 | 
			
		||||
#include "serverremoteplayer.h"
 | 
			
		||||
#include "log.h"
 | 
			
		||||
#include "mapblock.h" // getNodeBlockPos
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	InventoryManager
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// Wrapper for old code
 | 
			
		||||
Inventory* InventoryManager::getInventory(InventoryContext *c, std::string id)
 | 
			
		||||
{
 | 
			
		||||
	if(id == "current_player")
 | 
			
		||||
	{
 | 
			
		||||
		assert(c->current_player);
 | 
			
		||||
		InventoryLocation loc;
 | 
			
		||||
		loc.setPlayer(c->current_player->getName());
 | 
			
		||||
		return getInventory(loc);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	Strfnd fn(id);
 | 
			
		||||
	std::string id0 = fn.next(":");
 | 
			
		||||
 | 
			
		||||
	if(id0 == "nodemeta")
 | 
			
		||||
	{
 | 
			
		||||
		v3s16 p;
 | 
			
		||||
		p.X = stoi(fn.next(","));
 | 
			
		||||
		p.Y = stoi(fn.next(","));
 | 
			
		||||
		p.Z = stoi(fn.next(","));
 | 
			
		||||
 | 
			
		||||
		InventoryLocation loc;
 | 
			
		||||
		loc.setNodeMeta(p);
 | 
			
		||||
		return getInventory(loc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
// Wrapper for old code
 | 
			
		||||
void InventoryManager::inventoryModified(InventoryContext *c, std::string id)
 | 
			
		||||
{
 | 
			
		||||
	if(id == "current_player")
 | 
			
		||||
	{
 | 
			
		||||
		assert(c->current_player);
 | 
			
		||||
		InventoryLocation loc;
 | 
			
		||||
		loc.setPlayer(c->current_player->getName());
 | 
			
		||||
		setInventoryModified(loc);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	Strfnd fn(id);
 | 
			
		||||
	std::string id0 = fn.next(":");
 | 
			
		||||
 | 
			
		||||
	if(id0 == "nodemeta")
 | 
			
		||||
	{
 | 
			
		||||
		v3s16 p;
 | 
			
		||||
		p.X = stoi(fn.next(","));
 | 
			
		||||
		p.Y = stoi(fn.next(","));
 | 
			
		||||
		p.Z = stoi(fn.next(","));
 | 
			
		||||
		v3s16 blockpos = getNodeBlockPos(p);
 | 
			
		||||
 | 
			
		||||
		InventoryLocation loc;
 | 
			
		||||
		loc.setNodeMeta(p);
 | 
			
		||||
		setInventoryModified(loc);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	errorstream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	InventoryAction
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
InventoryAction * InventoryAction::deSerialize(std::istream &is)
 | 
			
		||||
{
 | 
			
		||||
	std::string type;
 | 
			
		||||
	std::getline(is, type, ' ');
 | 
			
		||||
 | 
			
		||||
	InventoryAction *a = NULL;
 | 
			
		||||
 | 
			
		||||
	if(type == "Move")
 | 
			
		||||
	{
 | 
			
		||||
		a = new IMoveAction(is);
 | 
			
		||||
	}
 | 
			
		||||
	else if(type == "Drop")
 | 
			
		||||
	{
 | 
			
		||||
		a = new IDropAction(is);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return a;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static std::string describeC(const struct InventoryContext *c)
 | 
			
		||||
{
 | 
			
		||||
	if(c->current_player == NULL)
 | 
			
		||||
		return "current_player=NULL";
 | 
			
		||||
	else
 | 
			
		||||
		return std::string("current_player=") + c->current_player->getName();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IMoveAction::IMoveAction(std::istream &is)
 | 
			
		||||
{
 | 
			
		||||
	std::string ts;
 | 
			
		||||
 | 
			
		||||
	std::getline(is, ts, ' ');
 | 
			
		||||
	count = stoi(ts);
 | 
			
		||||
 | 
			
		||||
	std::getline(is, from_inv, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, from_list, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, ts, ' ');
 | 
			
		||||
	from_i = stoi(ts);
 | 
			
		||||
 | 
			
		||||
	std::getline(is, to_inv, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, to_list, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, ts, ' ');
 | 
			
		||||
	to_i = stoi(ts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IMoveAction::apply(InventoryContext *c, InventoryManager *mgr,
 | 
			
		||||
		ServerEnvironment *env)
 | 
			
		||||
{
 | 
			
		||||
	Inventory *inv_from = mgr->getInventory(c, from_inv);
 | 
			
		||||
	Inventory *inv_to = mgr->getInventory(c, to_inv);
 | 
			
		||||
	
 | 
			
		||||
	if(!inv_from){
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: source inventory not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", to_inv=\""<<to_inv<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if(!inv_to){
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: destination inventory not found: "
 | 
			
		||||
				"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", to_inv=\""<<to_inv<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	InventoryList *list_from = inv_from->getList(from_list);
 | 
			
		||||
	InventoryList *list_to = inv_to->getList(to_list);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		If a list doesn't exist or the source item doesn't exist
 | 
			
		||||
	*/
 | 
			
		||||
	if(!list_from){
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: source list not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", from_list=\""<<from_list<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if(!list_to){
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: destination list not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], to_inv=\""<<to_inv<<"\""
 | 
			
		||||
				<<", to_list=\""<<to_list<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	if(list_from->getItem(from_i) == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: source item not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", from_list=\""<<from_list<<"\""
 | 
			
		||||
				<<" from_i="<<from_i<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	/*
 | 
			
		||||
		If the source and the destination slots are the same
 | 
			
		||||
	*/
 | 
			
		||||
	if(inv_from == inv_to && list_from == list_to && from_i == to_i)
 | 
			
		||||
	{
 | 
			
		||||
		infostream<<"IMoveAction::apply(): FAIL: source and destination slots "
 | 
			
		||||
				<<"are the same: inv=\""<<from_inv<<"\" list=\""<<from_list
 | 
			
		||||
				<<"\" i="<<from_i<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Take item from source list
 | 
			
		||||
	InventoryItem *item1 = NULL;
 | 
			
		||||
	if(count == 0)
 | 
			
		||||
		item1 = list_from->changeItem(from_i, NULL);
 | 
			
		||||
	else
 | 
			
		||||
		item1 = list_from->takeItem(from_i, count);
 | 
			
		||||
 | 
			
		||||
	// Try to add the item to destination list
 | 
			
		||||
	InventoryItem *olditem = item1;
 | 
			
		||||
	item1 = list_to->addItem(to_i, item1);
 | 
			
		||||
 | 
			
		||||
	// If something is returned, the item was not fully added
 | 
			
		||||
	if(item1 != NULL)
 | 
			
		||||
	{
 | 
			
		||||
		// If olditem is returned, nothing was added.
 | 
			
		||||
		bool nothing_added = (item1 == olditem);
 | 
			
		||||
		
 | 
			
		||||
		// If something else is returned, part of the item was left unadded.
 | 
			
		||||
		// Add the other part back to the source item
 | 
			
		||||
		list_from->addItem(from_i, item1);
 | 
			
		||||
 | 
			
		||||
		// If olditem is returned, nothing was added.
 | 
			
		||||
		// Swap the items
 | 
			
		||||
		if(nothing_added)
 | 
			
		||||
		{
 | 
			
		||||
			// Take item from source list
 | 
			
		||||
			item1 = list_from->changeItem(from_i, NULL);
 | 
			
		||||
			// Adding was not possible, swap the items.
 | 
			
		||||
			InventoryItem *item2 = list_to->changeItem(to_i, item1);
 | 
			
		||||
			// Put item from destination list to the source list
 | 
			
		||||
			list_from->changeItem(from_i, item2);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mgr->inventoryModified(c, from_inv);
 | 
			
		||||
	if(from_inv != to_inv)
 | 
			
		||||
		mgr->inventoryModified(c, to_inv);
 | 
			
		||||
	
 | 
			
		||||
	infostream<<"IMoveAction::apply(): moved at "
 | 
			
		||||
			<<"["<<describeC(c)<<"]"
 | 
			
		||||
			<<" from inv=\""<<from_inv<<"\""
 | 
			
		||||
			<<" list=\""<<from_list<<"\""
 | 
			
		||||
			<<" i="<<from_i
 | 
			
		||||
			<<" to inv=\""<<to_inv<<"\""
 | 
			
		||||
			<<" list=\""<<to_list<<"\""
 | 
			
		||||
			<<" i="<<to_i
 | 
			
		||||
			<<std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
IDropAction::IDropAction(std::istream &is)
 | 
			
		||||
{
 | 
			
		||||
	std::string ts;
 | 
			
		||||
 | 
			
		||||
	std::getline(is, ts, ' ');
 | 
			
		||||
	count = stoi(ts);
 | 
			
		||||
 | 
			
		||||
	std::getline(is, from_inv, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, from_list, ' ');
 | 
			
		||||
 | 
			
		||||
	std::getline(is, ts, ' ');
 | 
			
		||||
	from_i = stoi(ts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void IDropAction::apply(InventoryContext *c, InventoryManager *mgr,
 | 
			
		||||
		ServerEnvironment *env)
 | 
			
		||||
{
 | 
			
		||||
	if(c->current_player == NULL){
 | 
			
		||||
		infostream<<"IDropAction::apply(): FAIL: current_player is NULL"<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Do NOT cast directly to ServerActiveObject*, it breaks
 | 
			
		||||
	// because of multiple inheritance.
 | 
			
		||||
	ServerActiveObject *dropper =
 | 
			
		||||
		static_cast<ServerActiveObject*>(
 | 
			
		||||
		static_cast<ServerRemotePlayer*>(
 | 
			
		||||
			c->current_player
 | 
			
		||||
		));
 | 
			
		||||
 | 
			
		||||
	Inventory *inv_from = mgr->getInventory(c, from_inv);
 | 
			
		||||
	
 | 
			
		||||
	if(!inv_from){
 | 
			
		||||
		infostream<<"IDropAction::apply(): FAIL: source inventory not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	InventoryList *list_from = inv_from->getList(from_list);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		If a list doesn't exist or the source item doesn't exist
 | 
			
		||||
	*/
 | 
			
		||||
	if(!list_from){
 | 
			
		||||
		infostream<<"IDropAction::apply(): FAIL: source list not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", from_list=\""<<from_list<<"\""<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	InventoryItem *item = list_from->getItem(from_i);
 | 
			
		||||
	if(item == NULL)
 | 
			
		||||
	{
 | 
			
		||||
		infostream<<"IDropAction::apply(): FAIL: source item not found: "
 | 
			
		||||
				<<"context=["<<describeC(c)<<"], from_inv=\""<<from_inv<<"\""
 | 
			
		||||
				<<", from_list=\""<<from_list<<"\""
 | 
			
		||||
				<<" from_i="<<from_i<<std::endl;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	v3f pos = dropper->getBasePosition();
 | 
			
		||||
	pos.Y += 0.5*BS;
 | 
			
		||||
 | 
			
		||||
	s16 count2 = count;
 | 
			
		||||
	if(count2 == 0)
 | 
			
		||||
		count2 = -1;
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
		Drop the item
 | 
			
		||||
	*/
 | 
			
		||||
	bool remove = item->dropOrPlace(env, dropper, pos, false, count2);
 | 
			
		||||
	if(remove)
 | 
			
		||||
		list_from->deleteItem(from_i);
 | 
			
		||||
 | 
			
		||||
	mgr->inventoryModified(c, from_inv);
 | 
			
		||||
 | 
			
		||||
	infostream<<"IDropAction::apply(): dropped "
 | 
			
		||||
			<<"["<<describeC(c)<<"]"
 | 
			
		||||
			<<" from inv=\""<<from_inv<<"\""
 | 
			
		||||
			<<" list=\""<<from_list<<"\""
 | 
			
		||||
			<<" i="<<from_i
 | 
			
		||||
			<<std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Craft checking system
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
bool ItemSpec::checkItem(const InventoryItem *item) const
 | 
			
		||||
{
 | 
			
		||||
	if(type == ITEM_NONE)
 | 
			
		||||
	{
 | 
			
		||||
		// Has to be no item
 | 
			
		||||
		if(item != NULL)
 | 
			
		||||
			return false;
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// There should be an item
 | 
			
		||||
	if(item == NULL)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	std::string itemname = item->getName();
 | 
			
		||||
 | 
			
		||||
	if(type == ITEM_MATERIAL)
 | 
			
		||||
	{
 | 
			
		||||
		if(itemname != "MaterialItem")
 | 
			
		||||
			return false;
 | 
			
		||||
		MaterialItem *mitem = (MaterialItem*)item;
 | 
			
		||||
		if(num != 65535){
 | 
			
		||||
			if(mitem->getMaterial() != num)
 | 
			
		||||
				return false;
 | 
			
		||||
		} else {
 | 
			
		||||
			if(mitem->getNodeName() != name)
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else if(type == ITEM_CRAFT)
 | 
			
		||||
	{
 | 
			
		||||
		if(itemname != "CraftItem")
 | 
			
		||||
			return false;
 | 
			
		||||
		CraftItem *mitem = (CraftItem*)item;
 | 
			
		||||
		if(mitem->getSubName() != name)
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
	else if(type == ITEM_TOOL)
 | 
			
		||||
	{
 | 
			
		||||
		// Not supported yet
 | 
			
		||||
		assert(0);
 | 
			
		||||
	}
 | 
			
		||||
	else if(type == ITEM_MBO)
 | 
			
		||||
	{
 | 
			
		||||
		// Not supported yet
 | 
			
		||||
		assert(0);
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		// Not supported yet
 | 
			
		||||
		assert(0);
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool checkItemCombination(InventoryItem const * const *items, const ItemSpec *specs)
 | 
			
		||||
{
 | 
			
		||||
	u16 items_min_x = 100;
 | 
			
		||||
	u16 items_max_x = 100;
 | 
			
		||||
	u16 items_min_y = 100;
 | 
			
		||||
	u16 items_max_y = 100;
 | 
			
		||||
	for(u16 y=0; y<3; y++)
 | 
			
		||||
	for(u16 x=0; x<3; x++)
 | 
			
		||||
	{
 | 
			
		||||
		if(items[y*3 + x] == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		if(items_min_x == 100 || x < items_min_x)
 | 
			
		||||
			items_min_x = x;
 | 
			
		||||
		if(items_min_y == 100 || y < items_min_y)
 | 
			
		||||
			items_min_y = y;
 | 
			
		||||
		if(items_max_x == 100 || x > items_max_x)
 | 
			
		||||
			items_max_x = x;
 | 
			
		||||
		if(items_max_y == 100 || y > items_max_y)
 | 
			
		||||
			items_max_y = y;
 | 
			
		||||
	}
 | 
			
		||||
	// No items at all, just return false
 | 
			
		||||
	if(items_min_x == 100)
 | 
			
		||||
		return false;
 | 
			
		||||
	
 | 
			
		||||
	u16 items_w = items_max_x - items_min_x + 1;
 | 
			
		||||
	u16 items_h = items_max_y - items_min_y + 1;
 | 
			
		||||
 | 
			
		||||
	u16 specs_min_x = 100;
 | 
			
		||||
	u16 specs_max_x = 100;
 | 
			
		||||
	u16 specs_min_y = 100;
 | 
			
		||||
	u16 specs_max_y = 100;
 | 
			
		||||
	for(u16 y=0; y<3; y++)
 | 
			
		||||
	for(u16 x=0; x<3; x++)
 | 
			
		||||
	{
 | 
			
		||||
		if(specs[y*3 + x].type == ITEM_NONE)
 | 
			
		||||
			continue;
 | 
			
		||||
		if(specs_min_x == 100 || x < specs_min_x)
 | 
			
		||||
			specs_min_x = x;
 | 
			
		||||
		if(specs_min_y == 100 || y < specs_min_y)
 | 
			
		||||
			specs_min_y = y;
 | 
			
		||||
		if(specs_max_x == 100 || x > specs_max_x)
 | 
			
		||||
			specs_max_x = x;
 | 
			
		||||
		if(specs_max_y == 100 || y > specs_max_y)
 | 
			
		||||
			specs_max_y = y;
 | 
			
		||||
	}
 | 
			
		||||
	// No specs at all, just return false
 | 
			
		||||
	if(specs_min_x == 100)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	u16 specs_w = specs_max_x - specs_min_x + 1;
 | 
			
		||||
	u16 specs_h = specs_max_y - specs_min_y + 1;
 | 
			
		||||
 | 
			
		||||
	// Different sizes
 | 
			
		||||
	if(items_w != specs_w || items_h != specs_h)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	for(u16 y=0; y<specs_h; y++)
 | 
			
		||||
	for(u16 x=0; x<specs_w; x++)
 | 
			
		||||
	{
 | 
			
		||||
		u16 items_x = items_min_x + x;
 | 
			
		||||
		u16 items_y = items_min_y + y;
 | 
			
		||||
		u16 specs_x = specs_min_x + x;
 | 
			
		||||
		u16 specs_y = specs_min_y + y;
 | 
			
		||||
		const InventoryItem *item = items[items_y * 3 + items_x];
 | 
			
		||||
		const ItemSpec &spec = specs[specs_y * 3 + specs_x];
 | 
			
		||||
 | 
			
		||||
		if(spec.checkItem(item) == false)
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool checkItemCombination(const InventoryItem * const * items,
 | 
			
		||||
		const InventoryItem * const * specs)
 | 
			
		||||
{
 | 
			
		||||
	u16 items_min_x = 100;
 | 
			
		||||
	u16 items_max_x = 100;
 | 
			
		||||
	u16 items_min_y = 100;
 | 
			
		||||
	u16 items_max_y = 100;
 | 
			
		||||
	for(u16 y=0; y<3; y++)
 | 
			
		||||
	for(u16 x=0; x<3; x++)
 | 
			
		||||
	{
 | 
			
		||||
		if(items[y*3 + x] == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		if(items_min_x == 100 || x < items_min_x)
 | 
			
		||||
			items_min_x = x;
 | 
			
		||||
		if(items_min_y == 100 || y < items_min_y)
 | 
			
		||||
			items_min_y = y;
 | 
			
		||||
		if(items_max_x == 100 || x > items_max_x)
 | 
			
		||||
			items_max_x = x;
 | 
			
		||||
		if(items_max_y == 100 || y > items_max_y)
 | 
			
		||||
			items_max_y = y;
 | 
			
		||||
	}
 | 
			
		||||
	// No items at all, just return false
 | 
			
		||||
	if(items_min_x == 100)
 | 
			
		||||
		return false;
 | 
			
		||||
	
 | 
			
		||||
	u16 items_w = items_max_x - items_min_x + 1;
 | 
			
		||||
	u16 items_h = items_max_y - items_min_y + 1;
 | 
			
		||||
 | 
			
		||||
	u16 specs_min_x = 100;
 | 
			
		||||
	u16 specs_max_x = 100;
 | 
			
		||||
	u16 specs_min_y = 100;
 | 
			
		||||
	u16 specs_max_y = 100;
 | 
			
		||||
	for(u16 y=0; y<3; y++)
 | 
			
		||||
	for(u16 x=0; x<3; x++)
 | 
			
		||||
	{
 | 
			
		||||
		if(specs[y*3 + x] == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		if(specs_min_x == 100 || x < specs_min_x)
 | 
			
		||||
			specs_min_x = x;
 | 
			
		||||
		if(specs_min_y == 100 || y < specs_min_y)
 | 
			
		||||
			specs_min_y = y;
 | 
			
		||||
		if(specs_max_x == 100 || x > specs_max_x)
 | 
			
		||||
			specs_max_x = x;
 | 
			
		||||
		if(specs_max_y == 100 || y > specs_max_y)
 | 
			
		||||
			specs_max_y = y;
 | 
			
		||||
	}
 | 
			
		||||
	// No specs at all, just return false
 | 
			
		||||
	if(specs_min_x == 100)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	u16 specs_w = specs_max_x - specs_min_x + 1;
 | 
			
		||||
	u16 specs_h = specs_max_y - specs_min_y + 1;
 | 
			
		||||
 | 
			
		||||
	// Different sizes
 | 
			
		||||
	if(items_w != specs_w || items_h != specs_h)
 | 
			
		||||
		return false;
 | 
			
		||||
 | 
			
		||||
	for(u16 y=0; y<specs_h; y++)
 | 
			
		||||
	for(u16 x=0; x<specs_w; x++)
 | 
			
		||||
	{
 | 
			
		||||
		u16 items_x = items_min_x + x;
 | 
			
		||||
		u16 items_y = items_min_y + y;
 | 
			
		||||
		u16 specs_x = specs_min_x + x;
 | 
			
		||||
		u16 specs_y = specs_min_y + y;
 | 
			
		||||
		const InventoryItem *item = items[items_y * 3 + items_x];
 | 
			
		||||
		const InventoryItem *spec = specs[specs_y * 3 + specs_x];
 | 
			
		||||
		
 | 
			
		||||
		if(item == NULL && spec == NULL)
 | 
			
		||||
			continue;
 | 
			
		||||
		if(item == NULL && spec != NULL)
 | 
			
		||||
			return false;
 | 
			
		||||
		if(item != NULL && spec == NULL)
 | 
			
		||||
			return false;
 | 
			
		||||
		if(!spec->isSubsetOf(item))
 | 
			
		||||
			return false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										228
									
								
								src/inventorymanager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										228
									
								
								src/inventorymanager.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,228 @@
 | 
			
		||||
/*
 | 
			
		||||
Minetest-c55
 | 
			
		||||
Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
 | 
			
		||||
 | 
			
		||||
This program is free software; you can redistribute it and/or modify
 | 
			
		||||
it under the terms of the GNU General Public License as published by
 | 
			
		||||
the Free Software Foundation; either version 2 of the License, or
 | 
			
		||||
(at your option) any later version.
 | 
			
		||||
 | 
			
		||||
This program is distributed in the hope that it will be useful,
 | 
			
		||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
GNU General Public License for more details.
 | 
			
		||||
 | 
			
		||||
You should have received a copy of the GNU General Public License along
 | 
			
		||||
with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifndef INVENTORYMANAGER_HEADER
 | 
			
		||||
#define INVENTORYMANAGER_HEADER
 | 
			
		||||
 | 
			
		||||
#include "inventory.h"
 | 
			
		||||
 | 
			
		||||
// Should probably somehow replace InventoryContext over time
 | 
			
		||||
struct InventoryLocation
 | 
			
		||||
{
 | 
			
		||||
	enum Type{
 | 
			
		||||
		UNDEFINED,
 | 
			
		||||
		PLAYER,
 | 
			
		||||
		NODEMETA
 | 
			
		||||
	} type;
 | 
			
		||||
 | 
			
		||||
	std::string name; // PLAYER
 | 
			
		||||
	v3s16 p; // NODEMETA
 | 
			
		||||
 | 
			
		||||
	void setPlayer(const std::string &name_)
 | 
			
		||||
	{
 | 
			
		||||
		type = PLAYER;
 | 
			
		||||
		name = name_;
 | 
			
		||||
	}
 | 
			
		||||
	void setNodeMeta(v3s16 p_)
 | 
			
		||||
	{
 | 
			
		||||
		type = NODEMETA;
 | 
			
		||||
		p = p_;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class Player;
 | 
			
		||||
 | 
			
		||||
struct InventoryContext
 | 
			
		||||
{
 | 
			
		||||
	Player *current_player;
 | 
			
		||||
	
 | 
			
		||||
	InventoryContext():
 | 
			
		||||
		current_player(NULL)
 | 
			
		||||
	{}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct InventoryAction;
 | 
			
		||||
 | 
			
		||||
class InventoryManager
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
	InventoryManager(){}
 | 
			
		||||
	virtual ~InventoryManager(){}
 | 
			
		||||
	
 | 
			
		||||
	// Get an inventory or set it modified (so it will be updated over
 | 
			
		||||
	// network or so)
 | 
			
		||||
	virtual Inventory* getInventory(const InventoryLocation &loc){return NULL;}
 | 
			
		||||
	virtual void setInventoryModified(const InventoryLocation &loc){}
 | 
			
		||||
 | 
			
		||||
	// Used on the client to send an action to the server
 | 
			
		||||
	virtual void inventoryAction(InventoryAction *a){}
 | 
			
		||||
 | 
			
		||||
	// (Deprecated; these wrap to the latter ones)
 | 
			
		||||
	// Get a pointer to an inventory specified by id. id can be:
 | 
			
		||||
	// - "current_player"
 | 
			
		||||
	// - "nodemeta:X,Y,Z"
 | 
			
		||||
	Inventory* getInventory(InventoryContext *c, std::string id);
 | 
			
		||||
	// Used on the server by InventoryAction::apply and other stuff
 | 
			
		||||
	void inventoryModified(InventoryContext *c, std::string id);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#define IACTION_MOVE 0
 | 
			
		||||
#define IACTION_DROP 1
 | 
			
		||||
 | 
			
		||||
struct InventoryAction
 | 
			
		||||
{
 | 
			
		||||
	static InventoryAction * deSerialize(std::istream &is);
 | 
			
		||||
	
 | 
			
		||||
	virtual u16 getType() const = 0;
 | 
			
		||||
	virtual void serialize(std::ostream &os) const = 0;
 | 
			
		||||
	virtual void apply(InventoryContext *c, InventoryManager *mgr,
 | 
			
		||||
			ServerEnvironment *env) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct IMoveAction : public InventoryAction
 | 
			
		||||
{
 | 
			
		||||
	// count=0 means "everything"
 | 
			
		||||
	u16 count;
 | 
			
		||||
	std::string from_inv;
 | 
			
		||||
	std::string from_list;
 | 
			
		||||
	s16 from_i;
 | 
			
		||||
	std::string to_inv;
 | 
			
		||||
	std::string to_list;
 | 
			
		||||
	s16 to_i;
 | 
			
		||||
	
 | 
			
		||||
	IMoveAction()
 | 
			
		||||
	{
 | 
			
		||||
		count = 0;
 | 
			
		||||
		from_i = -1;
 | 
			
		||||
		to_i = -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	IMoveAction(std::istream &is);
 | 
			
		||||
 | 
			
		||||
	u16 getType() const
 | 
			
		||||
	{
 | 
			
		||||
		return IACTION_MOVE;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void serialize(std::ostream &os) const
 | 
			
		||||
	{
 | 
			
		||||
		os<<"Move ";
 | 
			
		||||
		os<<count<<" ";
 | 
			
		||||
		os<<from_inv<<" ";
 | 
			
		||||
		os<<from_list<<" ";
 | 
			
		||||
		os<<from_i<<" ";
 | 
			
		||||
		os<<to_inv<<" ";
 | 
			
		||||
		os<<to_list<<" ";
 | 
			
		||||
		os<<to_i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void apply(InventoryContext *c, InventoryManager *mgr,
 | 
			
		||||
			ServerEnvironment *env);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct IDropAction : public InventoryAction
 | 
			
		||||
{
 | 
			
		||||
	// count=0 means "everything"
 | 
			
		||||
	u16 count;
 | 
			
		||||
	std::string from_inv;
 | 
			
		||||
	std::string from_list;
 | 
			
		||||
	s16 from_i;
 | 
			
		||||
	
 | 
			
		||||
	IDropAction()
 | 
			
		||||
	{
 | 
			
		||||
		count = 0;
 | 
			
		||||
		from_i = -1;
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	IDropAction(std::istream &is);
 | 
			
		||||
 | 
			
		||||
	u16 getType() const
 | 
			
		||||
	{
 | 
			
		||||
		return IACTION_DROP;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void serialize(std::ostream &os) const
 | 
			
		||||
	{
 | 
			
		||||
		os<<"Drop ";
 | 
			
		||||
		os<<count<<" ";
 | 
			
		||||
		os<<from_inv<<" ";
 | 
			
		||||
		os<<from_list<<" ";
 | 
			
		||||
		os<<from_i;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	void apply(InventoryContext *c, InventoryManager *mgr,
 | 
			
		||||
			ServerEnvironment *env);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Craft checking system
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
enum ItemSpecType
 | 
			
		||||
{
 | 
			
		||||
	ITEM_NONE,
 | 
			
		||||
	ITEM_MATERIAL,
 | 
			
		||||
	ITEM_CRAFT,
 | 
			
		||||
	ITEM_TOOL,
 | 
			
		||||
	ITEM_MBO
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ItemSpec
 | 
			
		||||
{
 | 
			
		||||
	enum ItemSpecType type;
 | 
			
		||||
	// Only other one of these is used
 | 
			
		||||
	std::string name;
 | 
			
		||||
	u16 num;
 | 
			
		||||
 | 
			
		||||
	ItemSpec():
 | 
			
		||||
		type(ITEM_NONE)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	ItemSpec(enum ItemSpecType a_type, std::string a_name):
 | 
			
		||||
		type(a_type),
 | 
			
		||||
		name(a_name),
 | 
			
		||||
		num(65535)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
	ItemSpec(enum ItemSpecType a_type, u16 a_num):
 | 
			
		||||
		type(a_type),
 | 
			
		||||
		name(""),
 | 
			
		||||
		num(a_num)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	bool checkItem(const InventoryItem *item) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	items: a pointer to an array of 9 pointers to items
 | 
			
		||||
	specs: a pointer to an array of 9 ItemSpecs
 | 
			
		||||
*/
 | 
			
		||||
bool checkItemCombination(const InventoryItem * const*items, const ItemSpec *specs);
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	items: a pointer to an array of 9 pointers to items
 | 
			
		||||
	specs: a pointer to an array of 9 pointers to items
 | 
			
		||||
*/
 | 
			
		||||
bool checkItemCombination(const InventoryItem * const * items,
 | 
			
		||||
		const InventoryItem * const * specs);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@@ -204,6 +204,20 @@ static v2f read_v2f(lua_State *L, int index)
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static Server* get_server(lua_State *L)
 | 
			
		||||
{
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	return (Server*)lua_touserdata(L, -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ServerEnvironment* get_env(lua_State *L)
 | 
			
		||||
{
 | 
			
		||||
	// Get environment from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_env");
 | 
			
		||||
	return (ServerEnvironment*)lua_touserdata(L, -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static v3f readFloatPos(lua_State *L, int index)
 | 
			
		||||
{
 | 
			
		||||
	v3f pos;
 | 
			
		||||
@@ -551,6 +565,68 @@ static void inventory_get_list_to_lua(Inventory *inv, const char *name,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void push_stack_item(lua_State *L, InventoryItem *item0)
 | 
			
		||||
{
 | 
			
		||||
	if(item0 == NULL){
 | 
			
		||||
		lua_pushnil(L);
 | 
			
		||||
	}
 | 
			
		||||
	if(std::string("MaterialItem") == item0->getName()){
 | 
			
		||||
		MaterialItem *item = (MaterialItem*)item0;
 | 
			
		||||
		lua_newtable(L);
 | 
			
		||||
		lua_pushstring(L, "NodeItem");
 | 
			
		||||
		lua_setfield(L, -2, "type");
 | 
			
		||||
		lua_pushstring(L, item->getNodeName().c_str());
 | 
			
		||||
		lua_setfield(L, -2, "name");
 | 
			
		||||
	}
 | 
			
		||||
	else if(std::string("CraftItem") == item0->getName()){
 | 
			
		||||
		CraftItem *item = (CraftItem*)item0;
 | 
			
		||||
		lua_newtable(L);
 | 
			
		||||
		lua_pushstring(L, "CraftItem");
 | 
			
		||||
		lua_setfield(L, -2, "type");
 | 
			
		||||
		lua_pushstring(L, item->getSubName().c_str());
 | 
			
		||||
		lua_setfield(L, -2, "name");
 | 
			
		||||
	}
 | 
			
		||||
	else if(std::string("ToolItem") == item0->getName()){
 | 
			
		||||
		ToolItem *item = (ToolItem*)item0;
 | 
			
		||||
		lua_newtable(L);
 | 
			
		||||
		lua_pushstring(L, "ToolItem");
 | 
			
		||||
		lua_setfield(L, -2, "type");
 | 
			
		||||
		lua_pushstring(L, item->getToolName().c_str());
 | 
			
		||||
		lua_setfield(L, -2, "name");
 | 
			
		||||
		lua_pushstring(L, itos(item->getWear()).c_str());
 | 
			
		||||
		lua_setfield(L, -2, "wear");
 | 
			
		||||
	}
 | 
			
		||||
	else{
 | 
			
		||||
		errorstream<<"push_stack_item: Unknown item name: \""
 | 
			
		||||
				<<item0->getName()<<"\""<<std::endl;
 | 
			
		||||
		lua_pushnil(L);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static InventoryItem* check_stack_item(lua_State *L, int index)
 | 
			
		||||
{
 | 
			
		||||
	if(index < 0)
 | 
			
		||||
		index = lua_gettop(L) + 1 + index;
 | 
			
		||||
	if(lua_isnil(L, index))
 | 
			
		||||
		return NULL;
 | 
			
		||||
	if(!lua_istable(L, index))
 | 
			
		||||
		throw LuaError(L, "check_stack_item: Item not nil or table");
 | 
			
		||||
	// A very crappy implementation for now
 | 
			
		||||
	// Will be replaced when unified namespace for items is made
 | 
			
		||||
	std::string type = getstringfield_default(L, index, "type", "");
 | 
			
		||||
	std::string name = getstringfield_default(L, index, "name", "");
 | 
			
		||||
	std::string num = getstringfield_default(L, index, "wear", "_");
 | 
			
		||||
	if(num == "_")
 | 
			
		||||
		num = 1;
 | 
			
		||||
	std::string itemstring = type + " \"" + name + "\" " + num;
 | 
			
		||||
	try{
 | 
			
		||||
		return InventoryItem::deSerialize(itemstring, get_server(L));
 | 
			
		||||
	}catch(SerializationError &e){
 | 
			
		||||
		throw LuaError(L, std::string("check_stack_item: "
 | 
			
		||||
				"internal error (itemstring=\"")+itemstring+"\")");
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	ToolDiggingProperties
 | 
			
		||||
*/
 | 
			
		||||
@@ -835,12 +911,9 @@ static int l_register_tool(lua_State *L)
 | 
			
		||||
	luaL_checktype(L, 2, LUA_TTABLE);
 | 
			
		||||
	int table = 2;
 | 
			
		||||
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	// And get the writable tool definition manager from the server
 | 
			
		||||
	// Get the writable tool definition manager from the server
 | 
			
		||||
	IWritableToolDefManager *tooldef =
 | 
			
		||||
			server->getWritableToolDefManager();
 | 
			
		||||
			get_server(L)->getWritableToolDefManager();
 | 
			
		||||
	
 | 
			
		||||
	ToolDefinition def = read_tool_definition(L, table);
 | 
			
		||||
 | 
			
		||||
@@ -857,12 +930,9 @@ static int l_register_craftitem(lua_State *L)
 | 
			
		||||
	luaL_checktype(L, 2, LUA_TTABLE);
 | 
			
		||||
	int table = 2;
 | 
			
		||||
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	// And get the writable CraftItem definition manager from the server
 | 
			
		||||
	// Get the writable CraftItem definition manager from the server
 | 
			
		||||
	IWritableCraftItemDefManager *craftitemdef =
 | 
			
		||||
			server->getWritableCraftItemDefManager();
 | 
			
		||||
			get_server(L)->getWritableCraftItemDefManager();
 | 
			
		||||
	
 | 
			
		||||
	// Check if on_drop is defined
 | 
			
		||||
	lua_getfield(L, table, "on_drop");
 | 
			
		||||
@@ -907,12 +977,9 @@ static int l_register_node(lua_State *L)
 | 
			
		||||
	luaL_checktype(L, 2, LUA_TTABLE);
 | 
			
		||||
	int nodedef_table = 2;
 | 
			
		||||
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	// And get the writable node definition manager from the server
 | 
			
		||||
	// Get the writable node definition manager from the server
 | 
			
		||||
	IWritableNodeDefManager *nodedef =
 | 
			
		||||
			server->getWritableNodeDefManager();
 | 
			
		||||
			get_server(L)->getWritableNodeDefManager();
 | 
			
		||||
	
 | 
			
		||||
	// Get default node definition from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_nodedef_default");
 | 
			
		||||
@@ -1147,12 +1214,9 @@ static int l_alias_node(lua_State *L)
 | 
			
		||||
	std::string name = luaL_checkstring(L, 1);
 | 
			
		||||
	std::string convert_to = luaL_checkstring(L, 2);
 | 
			
		||||
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	// And get the writable node definition manager from the server
 | 
			
		||||
	// Get the writable node definition manager from the server
 | 
			
		||||
	IWritableNodeDefManager *nodedef =
 | 
			
		||||
			server->getWritableNodeDefManager();
 | 
			
		||||
			get_server(L)->getWritableNodeDefManager();
 | 
			
		||||
	
 | 
			
		||||
	nodedef->setAlias(name, convert_to);
 | 
			
		||||
	
 | 
			
		||||
@@ -1165,12 +1229,9 @@ static int l_alias_tool(lua_State *L)
 | 
			
		||||
	std::string name = luaL_checkstring(L, 1);
 | 
			
		||||
	std::string convert_to = luaL_checkstring(L, 2);
 | 
			
		||||
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	// And get the writable tool definition manager from the server
 | 
			
		||||
	// Get the writable tool definition manager from the server
 | 
			
		||||
	IWritableToolDefManager *tooldef =
 | 
			
		||||
			server->getWritableToolDefManager();
 | 
			
		||||
			get_server(L)->getWritableToolDefManager();
 | 
			
		||||
	
 | 
			
		||||
	tooldef->setAlias(name, convert_to);
 | 
			
		||||
 | 
			
		||||
@@ -1183,12 +1244,9 @@ static int l_alias_craftitem(lua_State *L)
 | 
			
		||||
	std::string name = luaL_checkstring(L, 1);
 | 
			
		||||
	std::string convert_to = luaL_checkstring(L, 2);
 | 
			
		||||
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	// And get the writable CraftItem definition manager from the server
 | 
			
		||||
	// Get the writable CraftItem definition manager from the server
 | 
			
		||||
	IWritableCraftItemDefManager *craftitemdef =
 | 
			
		||||
			server->getWritableCraftItemDefManager();
 | 
			
		||||
			get_server(L)->getWritableCraftItemDefManager();
 | 
			
		||||
	
 | 
			
		||||
	craftitemdef->setAlias(name, convert_to);
 | 
			
		||||
 | 
			
		||||
@@ -1202,12 +1260,9 @@ static int l_register_craft(lua_State *L)
 | 
			
		||||
	luaL_checktype(L, 1, LUA_TTABLE);
 | 
			
		||||
	int table0 = 1;
 | 
			
		||||
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	// And get the writable craft definition manager from the server
 | 
			
		||||
	// Get the writable craft definition manager from the server
 | 
			
		||||
	IWritableCraftDefManager *craftdef =
 | 
			
		||||
			server->getWritableCraftDefManager();
 | 
			
		||||
			get_server(L)->getWritableCraftDefManager();
 | 
			
		||||
	
 | 
			
		||||
	std::string output;
 | 
			
		||||
	int width = 0;
 | 
			
		||||
@@ -1295,8 +1350,7 @@ static int l_chat_send_all(lua_State *L)
 | 
			
		||||
{
 | 
			
		||||
	const char *text = luaL_checkstring(L, 1);
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	Server *server = get_server(L);
 | 
			
		||||
	// Send
 | 
			
		||||
	server->notifyPlayers(narrow_to_wide(text));
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -1308,8 +1362,7 @@ static int l_chat_send_player(lua_State *L)
 | 
			
		||||
	const char *name = luaL_checkstring(L, 1);
 | 
			
		||||
	const char *text = luaL_checkstring(L, 2);
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	Server *server = get_server(L);
 | 
			
		||||
	// Send
 | 
			
		||||
	server->notifyPlayer(name, narrow_to_wide(text));
 | 
			
		||||
	return 0;
 | 
			
		||||
@@ -1320,8 +1373,7 @@ static int l_get_player_privs(lua_State *L)
 | 
			
		||||
{
 | 
			
		||||
	const char *name = luaL_checkstring(L, 1);
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	Server *server = get_server(L);
 | 
			
		||||
	// Do it
 | 
			
		||||
	lua_newtable(L);
 | 
			
		||||
	int table = lua_gettop(L);
 | 
			
		||||
@@ -1413,11 +1465,337 @@ static void luaentity_get(lua_State *L, u16 id)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	Reference wrappers
 | 
			
		||||
	Object wrappers
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#define method(class, name) {#name, class::l_##name}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	InvStack
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
class InvStack
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	InventoryItem *m_stack;
 | 
			
		||||
 | 
			
		||||
	static const char className[];
 | 
			
		||||
	static const luaL_reg methods[];
 | 
			
		||||
 | 
			
		||||
	// Exported functions
 | 
			
		||||
	
 | 
			
		||||
	// garbage collector
 | 
			
		||||
	static int gc_object(lua_State *L) {
 | 
			
		||||
		InvStack *o = *(InvStack **)(lua_touserdata(L, 1));
 | 
			
		||||
		delete o;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// take_item(self)
 | 
			
		||||
	static int l_take_item(lua_State *L)
 | 
			
		||||
	{
 | 
			
		||||
		InvStack *o = checkobject(L, 1);
 | 
			
		||||
		push_stack_item(L, o->m_stack);
 | 
			
		||||
		if(o->m_stack->getCount() == 1){
 | 
			
		||||
			delete o->m_stack;
 | 
			
		||||
			o->m_stack = NULL;
 | 
			
		||||
		} else {
 | 
			
		||||
			o->m_stack->remove(1);
 | 
			
		||||
		}
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// put_item(self, item) -> true/false
 | 
			
		||||
	static int l_put_item(lua_State *L)
 | 
			
		||||
	{
 | 
			
		||||
		InvStack *o = checkobject(L, 1);
 | 
			
		||||
		InventoryItem *item = check_stack_item(L, 2);
 | 
			
		||||
		if(!item){ // nil can always be inserted
 | 
			
		||||
			lua_pushboolean(L, true);
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		if(!item->addableTo(o->m_stack)){
 | 
			
		||||
			lua_pushboolean(L, false);
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		o->m_stack->add(1);
 | 
			
		||||
		delete item;
 | 
			
		||||
		lua_pushboolean(L, true);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	InvStack(InventoryItem *item=NULL):
 | 
			
		||||
		m_stack(item)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~InvStack()
 | 
			
		||||
	{
 | 
			
		||||
		delete m_stack;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static InvStack* checkobject(lua_State *L, int narg)
 | 
			
		||||
	{
 | 
			
		||||
		luaL_checktype(L, narg, LUA_TUSERDATA);
 | 
			
		||||
		void *ud = luaL_checkudata(L, narg, className);
 | 
			
		||||
		if(!ud) luaL_typerror(L, narg, className);
 | 
			
		||||
		return *(InvStack**)ud;  // unbox pointer
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	InventoryItem* getItemCopy()
 | 
			
		||||
	{
 | 
			
		||||
		if(!m_stack)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return m_stack->clone();
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Creates an InvStack and leaves it on top of stack
 | 
			
		||||
	static int create_object(lua_State *L)
 | 
			
		||||
	{
 | 
			
		||||
		InventoryItem *item = NULL;
 | 
			
		||||
		if(lua_isstring(L, 1)){
 | 
			
		||||
			std::string itemstring = lua_tostring(L, 1);
 | 
			
		||||
			if(itemstring != ""){
 | 
			
		||||
				try{
 | 
			
		||||
					IGameDef *gdef = get_server(L);
 | 
			
		||||
					item = InventoryItem::deSerialize(itemstring, gdef);
 | 
			
		||||
				}catch(SerializationError &e){
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		InvStack *o = new InvStack(item);
 | 
			
		||||
		*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
 | 
			
		||||
		luaL_getmetatable(L, className);
 | 
			
		||||
		lua_setmetatable(L, -2);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
	// Not callable from Lua
 | 
			
		||||
	static int create(lua_State *L, InventoryItem *item)
 | 
			
		||||
	{
 | 
			
		||||
		InvStack *o = new InvStack(item);
 | 
			
		||||
		*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
 | 
			
		||||
		luaL_getmetatable(L, className);
 | 
			
		||||
		lua_setmetatable(L, -2);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void Register(lua_State *L)
 | 
			
		||||
	{
 | 
			
		||||
		lua_newtable(L);
 | 
			
		||||
		int methodtable = lua_gettop(L);
 | 
			
		||||
		luaL_newmetatable(L, className);
 | 
			
		||||
		int metatable = lua_gettop(L);
 | 
			
		||||
 | 
			
		||||
		lua_pushliteral(L, "__metatable");
 | 
			
		||||
		lua_pushvalue(L, methodtable);
 | 
			
		||||
		lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
 | 
			
		||||
 | 
			
		||||
		lua_pushliteral(L, "__index");
 | 
			
		||||
		lua_pushvalue(L, methodtable);
 | 
			
		||||
		lua_settable(L, metatable);
 | 
			
		||||
 | 
			
		||||
		lua_pushliteral(L, "__gc");
 | 
			
		||||
		lua_pushcfunction(L, gc_object);
 | 
			
		||||
		lua_settable(L, metatable);
 | 
			
		||||
 | 
			
		||||
		lua_pop(L, 1);  // drop metatable
 | 
			
		||||
 | 
			
		||||
		luaL_openlib(L, 0, methods, 0);  // fill methodtable
 | 
			
		||||
		lua_pop(L, 1);  // drop methodtable
 | 
			
		||||
 | 
			
		||||
		// Can be created from Lua (InvStack::create(itemstring))
 | 
			
		||||
		lua_register(L, className, create_object);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
const char InvStack::className[] = "InvStack";
 | 
			
		||||
const luaL_reg InvStack::methods[] = {
 | 
			
		||||
	method(InvStack, take_item),
 | 
			
		||||
	method(InvStack, put_item),
 | 
			
		||||
	{0,0}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	InvRef
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
class InvRef
 | 
			
		||||
{
 | 
			
		||||
private:
 | 
			
		||||
	InventoryLocation m_loc;
 | 
			
		||||
 | 
			
		||||
	static const char className[];
 | 
			
		||||
	static const luaL_reg methods[];
 | 
			
		||||
 | 
			
		||||
	static InvRef *checkobject(lua_State *L, int narg)
 | 
			
		||||
	{
 | 
			
		||||
		luaL_checktype(L, narg, LUA_TUSERDATA);
 | 
			
		||||
		void *ud = luaL_checkudata(L, narg, className);
 | 
			
		||||
		if(!ud) luaL_typerror(L, narg, className);
 | 
			
		||||
		return *(InvRef**)ud;  // unbox pointer
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	static Inventory* getinv(lua_State *L, InvRef *ref)
 | 
			
		||||
	{
 | 
			
		||||
		return get_server(L)->getInventory(ref->m_loc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static InventoryList* getlist(lua_State *L, InvRef *ref,
 | 
			
		||||
			const char *listname)
 | 
			
		||||
	{
 | 
			
		||||
		Inventory *inv = getinv(L, ref);
 | 
			
		||||
		if(!inv)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return inv->getList(listname);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static InventoryItem* getitem(lua_State *L, InvRef *ref,
 | 
			
		||||
			const char *listname, int i)
 | 
			
		||||
	{
 | 
			
		||||
		InventoryList *list = getlist(L, ref, listname);
 | 
			
		||||
		if(!list)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return list->getItem(i);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void reportInventoryChange(lua_State *L, InvRef *ref)
 | 
			
		||||
	{
 | 
			
		||||
		// Inform other things that the inventory has changed
 | 
			
		||||
		get_server(L)->setInventoryModified(ref->m_loc);
 | 
			
		||||
	}
 | 
			
		||||
	
 | 
			
		||||
	// Exported functions
 | 
			
		||||
	
 | 
			
		||||
	// garbage collector
 | 
			
		||||
	static int gc_object(lua_State *L) {
 | 
			
		||||
		InvRef *o = *(InvRef **)(lua_touserdata(L, 1));
 | 
			
		||||
		delete o;
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// set_size(self, listname, size)
 | 
			
		||||
	static int l_set_size(lua_State *L)
 | 
			
		||||
	{
 | 
			
		||||
		InvRef *ref = checkobject(L, 1);
 | 
			
		||||
		const char *listname = luaL_checkstring(L, 2);
 | 
			
		||||
		int newsize = luaL_checknumber(L, 3);
 | 
			
		||||
		Inventory *inv = getinv(L, ref);
 | 
			
		||||
		if(newsize == 0){
 | 
			
		||||
			inv->deleteList(listname);
 | 
			
		||||
			return 0;
 | 
			
		||||
		}
 | 
			
		||||
		InventoryList *list = inv->getList(listname);
 | 
			
		||||
		if(list){
 | 
			
		||||
			list->setSize(newsize);
 | 
			
		||||
		} else {
 | 
			
		||||
			list = inv->addList(listname, newsize);
 | 
			
		||||
		}
 | 
			
		||||
		return 0;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// get_stack(self, listname, i)
 | 
			
		||||
	static int l_get_stack(lua_State *L)
 | 
			
		||||
	{
 | 
			
		||||
		InvRef *ref = checkobject(L, 1);
 | 
			
		||||
		const char *listname = luaL_checkstring(L, 2);
 | 
			
		||||
		int i = luaL_checknumber(L, 3);
 | 
			
		||||
		InventoryItem *item = getitem(L, ref, listname, i);
 | 
			
		||||
		if(!item){
 | 
			
		||||
			InvStack::create(L, NULL);
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		InvStack::create(L, item->clone());
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// set_stack(self, listname, i, stack)
 | 
			
		||||
	static int l_set_stack(lua_State *L)
 | 
			
		||||
	{
 | 
			
		||||
		InvRef *ref = checkobject(L, 1);
 | 
			
		||||
		const char *listname = luaL_checkstring(L, 2);
 | 
			
		||||
		int i = luaL_checknumber(L, 3);
 | 
			
		||||
		InvStack *stack = InvStack::checkobject(L, 4);
 | 
			
		||||
		InventoryList *list = getlist(L, ref, listname);
 | 
			
		||||
		if(!list){
 | 
			
		||||
			lua_pushboolean(L, false);
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		InventoryItem *newitem = stack->getItemCopy();
 | 
			
		||||
		InventoryItem *olditem = list->changeItem(i, newitem);
 | 
			
		||||
		bool success = (olditem != newitem);
 | 
			
		||||
		delete olditem;
 | 
			
		||||
		lua_pushboolean(L, success);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
	InvRef(const InventoryLocation &loc):
 | 
			
		||||
		m_loc(loc)
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	~InvRef()
 | 
			
		||||
	{
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Creates an InvRef and leaves it on top of stack
 | 
			
		||||
	// Not callable from Lua; all references are created on the C side.
 | 
			
		||||
	static void create(lua_State *L, const InventoryLocation &loc)
 | 
			
		||||
	{
 | 
			
		||||
		InvRef *o = new InvRef(loc);
 | 
			
		||||
		*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
 | 
			
		||||
		luaL_getmetatable(L, className);
 | 
			
		||||
		lua_setmetatable(L, -2);
 | 
			
		||||
	}
 | 
			
		||||
	static void createPlayer(lua_State *L, Player *player)
 | 
			
		||||
	{
 | 
			
		||||
		InventoryLocation loc;
 | 
			
		||||
		loc.setPlayer(player->getName());
 | 
			
		||||
		create(L, loc);
 | 
			
		||||
	}
 | 
			
		||||
	static void createNodeMeta(lua_State *L, v3s16 p)
 | 
			
		||||
	{
 | 
			
		||||
		InventoryLocation loc;
 | 
			
		||||
		loc.setNodeMeta(p);
 | 
			
		||||
		create(L, loc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static void Register(lua_State *L)
 | 
			
		||||
	{
 | 
			
		||||
		lua_newtable(L);
 | 
			
		||||
		int methodtable = lua_gettop(L);
 | 
			
		||||
		luaL_newmetatable(L, className);
 | 
			
		||||
		int metatable = lua_gettop(L);
 | 
			
		||||
 | 
			
		||||
		lua_pushliteral(L, "__metatable");
 | 
			
		||||
		lua_pushvalue(L, methodtable);
 | 
			
		||||
		lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
 | 
			
		||||
 | 
			
		||||
		lua_pushliteral(L, "__index");
 | 
			
		||||
		lua_pushvalue(L, methodtable);
 | 
			
		||||
		lua_settable(L, metatable);
 | 
			
		||||
 | 
			
		||||
		lua_pushliteral(L, "__gc");
 | 
			
		||||
		lua_pushcfunction(L, gc_object);
 | 
			
		||||
		lua_settable(L, metatable);
 | 
			
		||||
 | 
			
		||||
		lua_pop(L, 1);  // drop metatable
 | 
			
		||||
 | 
			
		||||
		luaL_openlib(L, 0, methods, 0);  // fill methodtable
 | 
			
		||||
		lua_pop(L, 1);  // drop methodtable
 | 
			
		||||
 | 
			
		||||
		// Cannot be created from Lua
 | 
			
		||||
		//lua_register(L, className, create_object);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
const char InvRef::className[] = "InvRef";
 | 
			
		||||
const luaL_reg InvRef::methods[] = {
 | 
			
		||||
	method(InvRef, set_size),
 | 
			
		||||
	method(InvRef, get_stack),
 | 
			
		||||
	method(InvRef, set_stack),
 | 
			
		||||
	{0,0}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
	NodeMetaRef
 | 
			
		||||
*/
 | 
			
		||||
@@ -2189,41 +2567,7 @@ private:
 | 
			
		||||
		if(player == NULL) return 0;
 | 
			
		||||
		// Do it
 | 
			
		||||
		InventoryItem *item0 = player->getWieldedItem();
 | 
			
		||||
		if(item0 == NULL){
 | 
			
		||||
			lua_pushnil(L);
 | 
			
		||||
			return 1;
 | 
			
		||||
		}
 | 
			
		||||
		if(std::string("MaterialItem") == item0->getName()){
 | 
			
		||||
			MaterialItem *item = (MaterialItem*)item0;
 | 
			
		||||
			lua_newtable(L);
 | 
			
		||||
			lua_pushstring(L, "NodeItem");
 | 
			
		||||
			lua_setfield(L, -2, "type");
 | 
			
		||||
			lua_pushstring(L, item->getNodeName().c_str());
 | 
			
		||||
			lua_setfield(L, -2, "name");
 | 
			
		||||
		}
 | 
			
		||||
		else if(std::string("CraftItem") == item0->getName()){
 | 
			
		||||
			CraftItem *item = (CraftItem*)item0;
 | 
			
		||||
			lua_newtable(L);
 | 
			
		||||
			lua_pushstring(L, "CraftItem");
 | 
			
		||||
			lua_setfield(L, -2, "type");
 | 
			
		||||
			lua_pushstring(L, item->getSubName().c_str());
 | 
			
		||||
			lua_setfield(L, -2, "name");
 | 
			
		||||
		}
 | 
			
		||||
		else if(std::string("ToolItem") == item0->getName()){
 | 
			
		||||
			ToolItem *item = (ToolItem*)item0;
 | 
			
		||||
			lua_newtable(L);
 | 
			
		||||
			lua_pushstring(L, "ToolItem");
 | 
			
		||||
			lua_setfield(L, -2, "type");
 | 
			
		||||
			lua_pushstring(L, item->getToolName().c_str());
 | 
			
		||||
			lua_setfield(L, -2, "name");
 | 
			
		||||
			lua_pushstring(L, itos(item->getWear()).c_str());
 | 
			
		||||
			lua_setfield(L, -2, "wear");
 | 
			
		||||
		}
 | 
			
		||||
		else{
 | 
			
		||||
			errorstream<<"l_get_wielded_item: Unknown item name: \""
 | 
			
		||||
					<<item0->getName()<<"\""<<std::endl;
 | 
			
		||||
			lua_pushnil(L);
 | 
			
		||||
		}
 | 
			
		||||
		push_stack_item(L, item0);
 | 
			
		||||
		return 1;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -3236,12 +3580,9 @@ void scriptapi_environment_on_placenode(lua_State *L, v3s16 p, MapNode newnode,
 | 
			
		||||
	//infostream<<"scriptapi_environment_on_placenode"<<std::endl;
 | 
			
		||||
	StackUnroller stack_unroller(L);
 | 
			
		||||
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	// And get the writable node definition manager from the server
 | 
			
		||||
	// Get the writable node definition manager from the server
 | 
			
		||||
	IWritableNodeDefManager *ndef =
 | 
			
		||||
			server->getWritableNodeDefManager();
 | 
			
		||||
			get_server(L)->getWritableNodeDefManager();
 | 
			
		||||
	
 | 
			
		||||
	// Get minetest.registered_on_placenodes
 | 
			
		||||
	lua_getglobal(L, "minetest");
 | 
			
		||||
@@ -3271,12 +3612,9 @@ void scriptapi_environment_on_dignode(lua_State *L, v3s16 p, MapNode oldnode,
 | 
			
		||||
	//infostream<<"scriptapi_environment_on_dignode"<<std::endl;
 | 
			
		||||
	StackUnroller stack_unroller(L);
 | 
			
		||||
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	// And get the writable node definition manager from the server
 | 
			
		||||
	// Get the writable node definition manager from the server
 | 
			
		||||
	IWritableNodeDefManager *ndef =
 | 
			
		||||
			server->getWritableNodeDefManager();
 | 
			
		||||
			get_server(L)->getWritableNodeDefManager();
 | 
			
		||||
	
 | 
			
		||||
	// Get minetest.registered_on_dignodes
 | 
			
		||||
	lua_getglobal(L, "minetest");
 | 
			
		||||
@@ -3306,12 +3644,9 @@ void scriptapi_environment_on_punchnode(lua_State *L, v3s16 p, MapNode node,
 | 
			
		||||
	//infostream<<"scriptapi_environment_on_punchnode"<<std::endl;
 | 
			
		||||
	StackUnroller stack_unroller(L);
 | 
			
		||||
 | 
			
		||||
	// Get server from registry
 | 
			
		||||
	lua_getfield(L, LUA_REGISTRYINDEX, "minetest_server");
 | 
			
		||||
	Server *server = (Server*)lua_touserdata(L, -1);
 | 
			
		||||
	// And get the writable node definition manager from the server
 | 
			
		||||
	// Get the writable node definition manager from the server
 | 
			
		||||
	IWritableNodeDefManager *ndef =
 | 
			
		||||
			server->getWritableNodeDefManager();
 | 
			
		||||
			get_server(L)->getWritableNodeDefManager();
 | 
			
		||||
	
 | 
			
		||||
	// Get minetest.registered_on_punchnodes
 | 
			
		||||
	lua_getglobal(L, "minetest");
 | 
			
		||||
 
 | 
			
		||||
@@ -2458,7 +2458,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 | 
			
		||||
					craftresult and immediately moved to the free slot.
 | 
			
		||||
				*/
 | 
			
		||||
				do{
 | 
			
		||||
					Inventory *inv_to = getInventory(&c, ma->to_inv);
 | 
			
		||||
					Inventory *inv_to = InventoryManager::getInventory(&c, ma->to_inv);
 | 
			
		||||
					if(!inv_to) break;
 | 
			
		||||
					InventoryList *list_to = inv_to->getList(ma->to_list);
 | 
			
		||||
					if(!list_to) break;
 | 
			
		||||
@@ -3517,6 +3517,68 @@ void Server::onMapEditEvent(MapEditEvent *event)
 | 
			
		||||
	m_unsent_map_edit_queue.push_back(e);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Inventory* Server::getInventory(const InventoryLocation &loc)
 | 
			
		||||
{
 | 
			
		||||
	switch(loc.type){
 | 
			
		||||
	case InventoryLocation::UNDEFINED:
 | 
			
		||||
	{}
 | 
			
		||||
	break;
 | 
			
		||||
	case InventoryLocation::PLAYER:
 | 
			
		||||
	{
 | 
			
		||||
		Player *player = m_env->getPlayer(loc.name.c_str());
 | 
			
		||||
		if(!player)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return &player->inventory;
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
	case InventoryLocation::NODEMETA:
 | 
			
		||||
	{
 | 
			
		||||
		NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
 | 
			
		||||
		if(!meta)
 | 
			
		||||
			return NULL;
 | 
			
		||||
		return meta->getInventory();
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
	default:
 | 
			
		||||
		assert(0);
 | 
			
		||||
	}
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
void Server::setInventoryModified(const InventoryLocation &loc)
 | 
			
		||||
{
 | 
			
		||||
	switch(loc.type){
 | 
			
		||||
	case InventoryLocation::UNDEFINED:
 | 
			
		||||
	{}
 | 
			
		||||
	break;
 | 
			
		||||
	case InventoryLocation::PLAYER:
 | 
			
		||||
	{
 | 
			
		||||
		ServerRemotePlayer *srp = static_cast<ServerRemotePlayer*>
 | 
			
		||||
				(m_env->getPlayer(loc.name.c_str()));
 | 
			
		||||
		if(!srp)
 | 
			
		||||
			return;
 | 
			
		||||
		srp->m_inventory_not_sent = true;
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
	case InventoryLocation::NODEMETA:
 | 
			
		||||
	{
 | 
			
		||||
		v3s16 blockpos = getNodeBlockPos(loc.p);
 | 
			
		||||
 | 
			
		||||
		NodeMetadata *meta = m_env->getMap().getNodeMetadata(loc.p);
 | 
			
		||||
		if(meta)
 | 
			
		||||
			meta->inventoryModified();
 | 
			
		||||
		
 | 
			
		||||
		MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
 | 
			
		||||
		if(block)
 | 
			
		||||
			block->raiseModified(MOD_STATE_WRITE_NEEDED);
 | 
			
		||||
		
 | 
			
		||||
		setBlockNotSent(blockpos);
 | 
			
		||||
	}
 | 
			
		||||
	break;
 | 
			
		||||
	default:
 | 
			
		||||
		assert(0);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
#if 0
 | 
			
		||||
Inventory* Server::getInventory(InventoryContext *c, std::string id)
 | 
			
		||||
{
 | 
			
		||||
	if(id == "current_player")
 | 
			
		||||
@@ -3534,12 +3596,10 @@ Inventory* Server::getInventory(InventoryContext *c, std::string id)
 | 
			
		||||
		p.X = stoi(fn.next(","));
 | 
			
		||||
		p.Y = stoi(fn.next(","));
 | 
			
		||||
		p.Z = stoi(fn.next(","));
 | 
			
		||||
		NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
 | 
			
		||||
		if(meta)
 | 
			
		||||
			return meta->getInventory();
 | 
			
		||||
		infostream<<"nodemeta at ("<<p.X<<","<<p.Y<<","<<p.Z<<"): "
 | 
			
		||||
				<<"no metadata found"<<std::endl;
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
		InventoryLocation loc;
 | 
			
		||||
		loc.setNodeMeta(p);
 | 
			
		||||
		return getInventory(loc);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
 | 
			
		||||
@@ -3567,21 +3627,15 @@ void Server::inventoryModified(InventoryContext *c, std::string id)
 | 
			
		||||
		p.Z = stoi(fn.next(","));
 | 
			
		||||
		v3s16 blockpos = getNodeBlockPos(p);
 | 
			
		||||
 | 
			
		||||
		NodeMetadata *meta = m_env->getMap().getNodeMetadata(p);
 | 
			
		||||
		if(meta)
 | 
			
		||||
			meta->inventoryModified();
 | 
			
		||||
		
 | 
			
		||||
		MapBlock *block = m_env->getMap().getBlockNoCreateNoEx(blockpos);
 | 
			
		||||
		if(block)
 | 
			
		||||
			block->raiseModified(MOD_STATE_WRITE_NEEDED);
 | 
			
		||||
		
 | 
			
		||||
		setBlockNotSent(blockpos);
 | 
			
		||||
 | 
			
		||||
		InventoryLocation loc;
 | 
			
		||||
		loc.setNodeMeta(p);
 | 
			
		||||
		setInventoryModified(loc);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	infostream<<__FUNCTION_NAME<<": unknown id "<<id<<std::endl;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
core::list<PlayerInfo> Server::getPlayerInfo()
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 | 
			
		||||
#include "serialization.h" // For SER_FMT_VER_INVALID
 | 
			
		||||
#include "serverremoteplayer.h"
 | 
			
		||||
#include "mods.h"
 | 
			
		||||
#include "inventorymanager.h"
 | 
			
		||||
struct LuaState;
 | 
			
		||||
typedef struct lua_State lua_State;
 | 
			
		||||
class IWritableToolDefManager;
 | 
			
		||||
@@ -413,8 +414,8 @@ public:
 | 
			
		||||
	/*
 | 
			
		||||
		Shall be called with the environment and the connection locked.
 | 
			
		||||
	*/
 | 
			
		||||
	Inventory* getInventory(InventoryContext *c, std::string id);
 | 
			
		||||
	void inventoryModified(InventoryContext *c, std::string id);
 | 
			
		||||
	Inventory* getInventory(const InventoryLocation &loc);
 | 
			
		||||
	void setInventoryModified(const InventoryLocation &loc);
 | 
			
		||||
 | 
			
		||||
	// Connection must be locked when called
 | 
			
		||||
	std::wstring getStatusString();
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user