mirror of
https://github.com/luanti-org/luanti.git
synced 2025-11-09 19:45:21 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
@@ -304,6 +304,15 @@ Client::~Client()
|
||||
sleep_ms(100);
|
||||
|
||||
delete m_inventory_from_server;
|
||||
|
||||
// Delete detached inventories
|
||||
{
|
||||
for(std::map<std::string, Inventory*>::iterator
|
||||
i = m_detached_inventories.begin();
|
||||
i != m_detached_inventories.end(); i++){
|
||||
delete i->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Client::connect(Address address)
|
||||
@@ -1698,6 +1707,24 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
|
||||
assert(player != NULL);
|
||||
player->inventory_formspec = deSerializeLongString(is);
|
||||
}
|
||||
else if(command == TOCLIENT_DETACHED_INVENTORY)
|
||||
{
|
||||
std::string datastring((char*)&data[2], datasize-2);
|
||||
std::istringstream is(datastring, std::ios_base::binary);
|
||||
|
||||
std::string name = deSerializeString(is);
|
||||
|
||||
infostream<<"Client: Detached inventory update: \""<<name<<"\""<<std::endl;
|
||||
|
||||
Inventory *inv = NULL;
|
||||
if(m_detached_inventories.count(name) > 0)
|
||||
inv = m_detached_inventories[name];
|
||||
else{
|
||||
inv = new Inventory(m_itemdef);
|
||||
m_detached_inventories[name] = inv;
|
||||
}
|
||||
inv->deSerialize(is);
|
||||
}
|
||||
else
|
||||
{
|
||||
infostream<<"Client: Ignoring unknown command "
|
||||
@@ -2090,6 +2117,13 @@ Inventory* Client::getInventory(const InventoryLocation &loc)
|
||||
return meta->getInventory();
|
||||
}
|
||||
break;
|
||||
case InventoryLocation::DETACHED:
|
||||
{
|
||||
if(m_detached_inventories.count(loc.name) == 0)
|
||||
return NULL;
|
||||
return m_detached_inventories[loc.name];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
@@ -393,6 +393,10 @@ private:
|
||||
|
||||
// Privileges
|
||||
std::set<std::string> m_privileges;
|
||||
|
||||
// Detached inventories
|
||||
// key = name
|
||||
std::map<std::string, Inventory*> m_detached_inventories;
|
||||
};
|
||||
|
||||
#endif // !CLIENT_HEADER
|
||||
|
||||
@@ -64,6 +64,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
PROTOCOL_VERSION 12:
|
||||
TOSERVER_INVENTORY_FIELDS
|
||||
16-bit node ids
|
||||
TOCLIENT_DETACHED_INVENTORY
|
||||
*/
|
||||
|
||||
#define PROTOCOL_VERSION 12
|
||||
@@ -321,6 +322,14 @@ enum ToClientCommand
|
||||
u32 len
|
||||
u8[len] formspec
|
||||
*/
|
||||
|
||||
TOCLIENT_DETACHED_INVENTORY = 0x43,
|
||||
/*
|
||||
[0] u16 command
|
||||
u16 len
|
||||
u8[len] name
|
||||
[2] serialized inventory
|
||||
*/
|
||||
};
|
||||
|
||||
enum ToServerCommand
|
||||
|
||||
@@ -292,13 +292,6 @@ public:
|
||||
ServerActiveObject *puncher,
|
||||
float time_from_last_punch)
|
||||
{
|
||||
// Directly delete item in creative mode
|
||||
if(g_settings->getBool("creative_mode") == true)
|
||||
{
|
||||
m_removed = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Take item into inventory
|
||||
ItemStack item = createItemStack();
|
||||
Inventory *inv = puncher->getInventory();
|
||||
@@ -1143,16 +1136,6 @@ void PlayerSAO::disconnected()
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerSAO::createCreativeInventory()
|
||||
{
|
||||
if(m_inventory != &m_player->inventory)
|
||||
delete m_inventory;
|
||||
|
||||
m_inventory = new Inventory(m_player->inventory);
|
||||
m_inventory->clearContents();
|
||||
scriptapi_get_creative_inventory(m_env->getLua(), this);
|
||||
}
|
||||
|
||||
std::string PlayerSAO::getPropertyPacket()
|
||||
{
|
||||
m_prop.is_visible = (getHP() != 0);
|
||||
|
||||
@@ -163,8 +163,6 @@ public:
|
||||
|
||||
void disconnected();
|
||||
|
||||
void createCreativeInventory();
|
||||
|
||||
Player* getPlayer()
|
||||
{
|
||||
return m_player;
|
||||
|
||||
@@ -2304,6 +2304,13 @@ void the_game(
|
||||
<<playeritem.name<<" is "
|
||||
<<def.node_placement_prediction<<std::endl;
|
||||
v3s16 p = neighbourpos;
|
||||
// Place inside node itself if buildable_to
|
||||
try{
|
||||
MapNode n_under = map.getNode(nodepos);
|
||||
if(nodedef->get(n_under).buildable_to)
|
||||
p = nodepos;
|
||||
}catch(InvalidPositionException &e){}
|
||||
// Find id of predicted node
|
||||
content_t id;
|
||||
bool found =
|
||||
nodedef->getId(def.node_placement_prediction, id);
|
||||
|
||||
@@ -215,10 +215,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
}
|
||||
else{
|
||||
invsize.Y = stof(f.next(";"));
|
||||
errorstream<<"WARNING: invsize is deprecated, use size"<<std::endl;
|
||||
f.next("]");
|
||||
}
|
||||
infostream<<"size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
|
||||
infostream<<"Form size ("<<invsize.X<<","<<invsize.Y<<")"<<std::endl;
|
||||
|
||||
padding = v2s32(screensize.Y/40, screensize.Y/40);
|
||||
spacing = v2s32(screensize.Y/12, screensize.Y/13);
|
||||
@@ -257,10 +256,13 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
<<", pos=("<<pos.X<<","<<pos.Y<<")"
|
||||
<<", geom=("<<geom.X<<","<<geom.Y<<")"
|
||||
<<std::endl;
|
||||
f.next("]");
|
||||
std::string start_i_s = f.next("]");
|
||||
s32 start_i = 0;
|
||||
if(start_i_s != "")
|
||||
start_i = stoi(start_i_s);
|
||||
if(bp_set != 2)
|
||||
errorstream<<"WARNING: invalid use of button without a size[] element"<<std::endl;
|
||||
m_inventorylists.push_back(ListDrawSpec(loc, listname, pos, geom));
|
||||
errorstream<<"WARNING: invalid use of list without a size[] element"<<std::endl;
|
||||
m_inventorylists.push_back(ListDrawSpec(loc, listname, pos, geom, start_i));
|
||||
}
|
||||
else if(type == "image")
|
||||
{
|
||||
@@ -380,9 +382,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
}
|
||||
else if(type == "label")
|
||||
{
|
||||
v2s32 pos;
|
||||
pos.X = stof(f.next(",")) * (float)spacing.X;
|
||||
pos.Y = stof(f.next(";")) * (float)spacing.Y;
|
||||
v2s32 pos = padding;
|
||||
pos.X += stof(f.next(",")) * (float)spacing.X;
|
||||
pos.Y += stof(f.next(";")) * (float)spacing.Y;
|
||||
|
||||
rect = core::rect<s32>(pos.X, pos.Y+((imgsize.Y/2)-15), pos.X+300, pos.Y+((imgsize.Y/2)+15));
|
||||
|
||||
@@ -401,9 +403,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
}
|
||||
else if(type == "button" || type == "button_exit")
|
||||
{
|
||||
v2s32 pos;
|
||||
pos.X = stof(f.next(",")) * (float)spacing.X;
|
||||
pos.Y = stof(f.next(";")) * (float)spacing.Y;
|
||||
v2s32 pos = padding;
|
||||
pos.X += stof(f.next(",")) * (float)spacing.X;
|
||||
pos.Y += stof(f.next(";")) * (float)spacing.Y;
|
||||
v2s32 geom;
|
||||
geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
|
||||
pos.Y += (stof(f.next(";")) * (float)imgsize.Y)/2;
|
||||
@@ -429,9 +431,9 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize)
|
||||
}
|
||||
else if(type == "image_button" || type == "image_button_exit")
|
||||
{
|
||||
v2s32 pos;
|
||||
pos.X = stof(f.next(",")) * (float)spacing.X;
|
||||
pos.Y = stof(f.next(";")) * (float)spacing.Y;
|
||||
v2s32 pos = padding;
|
||||
pos.X += stof(f.next(",")) * (float)spacing.X;
|
||||
pos.Y += stof(f.next(";")) * (float)spacing.Y;
|
||||
v2s32 geom;
|
||||
geom.X = (stof(f.next(",")) * (float)spacing.X)-(spacing.X-imgsize.X);
|
||||
geom.Y = (stof(f.next(";")) * (float)spacing.Y)-(spacing.Y-imgsize.Y);
|
||||
@@ -531,13 +533,14 @@ GUIFormSpecMenu::ItemSpec GUIFormSpecMenu::getItemAtPos(v2s32 p) const
|
||||
|
||||
for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
|
||||
{
|
||||
s32 item_i = i + s.start_item_i;
|
||||
s32 x = (i%s.geom.X) * spacing.X;
|
||||
s32 y = (i/s.geom.X) * spacing.Y;
|
||||
v2s32 p0(x,y);
|
||||
core::rect<s32> rect = imgrect + s.pos + p0;
|
||||
if(rect.isPointInside(p))
|
||||
{
|
||||
return ItemSpec(s.inventoryloc, s.listname, i);
|
||||
return ItemSpec(s.inventoryloc, s.listname, item_i);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -576,13 +579,16 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase)
|
||||
|
||||
for(s32 i=0; i<s.geom.X*s.geom.Y; i++)
|
||||
{
|
||||
u32 item_i = i + s.start_item_i;
|
||||
if(item_i >= ilist->getSize())
|
||||
break;
|
||||
s32 x = (i%s.geom.X) * spacing.X;
|
||||
s32 y = (i/s.geom.X) * spacing.Y;
|
||||
v2s32 p(x,y);
|
||||
core::rect<s32> rect = imgrect + s.pos + p;
|
||||
ItemStack item;
|
||||
if(ilist)
|
||||
item = ilist->getItem(i);
|
||||
item = ilist->getItem(item_i);
|
||||
|
||||
bool selected = m_selected_item
|
||||
&& m_invmgr->getInventory(m_selected_item->inventoryloc) == inv
|
||||
@@ -884,14 +890,14 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||
|
||||
InventoryList *list = inv_s->getList(s.listname);
|
||||
if(list == NULL){
|
||||
errorstream<<"InventoryMenu: The selected inventory list \""
|
||||
verbosestream<<"InventoryMenu: The selected inventory list \""
|
||||
<<s.listname<<"\" does not exist"<<std::endl;
|
||||
s.i = -1; // make it invalid again
|
||||
break;
|
||||
}
|
||||
|
||||
if((u32)s.i >= list->getSize()){
|
||||
errorstream<<"InventoryMenu: The selected inventory list \""
|
||||
infostream<<"InventoryMenu: The selected inventory list \""
|
||||
<<s.listname<<"\" is too small (i="<<s.i<<", size="
|
||||
<<list->getSize()<<")"<<std::endl;
|
||||
s.i = -1; // make it invalid again
|
||||
@@ -1160,6 +1166,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||
return true;
|
||||
}else{
|
||||
s.send = false;
|
||||
// Restore focus to the full form
|
||||
Environment->setFocus(this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,11 +86,12 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
}
|
||||
ListDrawSpec(const InventoryLocation &a_inventoryloc,
|
||||
const std::string &a_listname,
|
||||
v2s32 a_pos, v2s32 a_geom):
|
||||
v2s32 a_pos, v2s32 a_geom, s32 a_start_item_i):
|
||||
inventoryloc(a_inventoryloc),
|
||||
listname(a_listname),
|
||||
pos(a_pos),
|
||||
geom(a_geom)
|
||||
geom(a_geom),
|
||||
start_item_i(a_start_item_i)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -98,6 +99,7 @@ class GUIFormSpecMenu : public GUIModalMenu
|
||||
std::string listname;
|
||||
v2s32 pos;
|
||||
v2s32 geom;
|
||||
s32 start_item_i;
|
||||
};
|
||||
|
||||
struct ImageDrawSpec
|
||||
|
||||
@@ -41,30 +41,25 @@ std::string InventoryLocation::dump() const
|
||||
|
||||
void InventoryLocation::serialize(std::ostream &os) const
|
||||
{
|
||||
switch(type){
|
||||
case InventoryLocation::UNDEFINED:
|
||||
{
|
||||
switch(type){
|
||||
case InventoryLocation::UNDEFINED:
|
||||
os<<"undefined";
|
||||
}
|
||||
break;
|
||||
case InventoryLocation::CURRENT_PLAYER:
|
||||
{
|
||||
break;
|
||||
case InventoryLocation::CURRENT_PLAYER:
|
||||
os<<"current_player";
|
||||
}
|
||||
break;
|
||||
case InventoryLocation::PLAYER:
|
||||
{
|
||||
break;
|
||||
case InventoryLocation::PLAYER:
|
||||
os<<"player:"<<name;
|
||||
}
|
||||
break;
|
||||
case InventoryLocation::NODEMETA:
|
||||
{
|
||||
break;
|
||||
case InventoryLocation::NODEMETA:
|
||||
os<<"nodemeta:"<<p.X<<","<<p.Y<<","<<p.Z;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
break;
|
||||
case InventoryLocation::DETACHED:
|
||||
os<<"detached:"<<name;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
void InventoryLocation::deSerialize(std::istream &is)
|
||||
@@ -94,6 +89,11 @@ void InventoryLocation::deSerialize(std::istream &is)
|
||||
p.Y = stoi(fn.next(","));
|
||||
p.Z = stoi(fn.next(","));
|
||||
}
|
||||
else if(tname == "detached")
|
||||
{
|
||||
type = InventoryLocation::DETACHED;
|
||||
std::getline(is, name, '\n');
|
||||
}
|
||||
else
|
||||
{
|
||||
infostream<<"Unknown InventoryLocation type=\""<<tname<<"\""<<std::endl;
|
||||
@@ -198,78 +198,106 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||
<<", to_list=\""<<to_list<<"\""<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Collect information of endpoints
|
||||
*/
|
||||
|
||||
int try_take_count = count;
|
||||
if(try_take_count == 0)
|
||||
try_take_count = list_from->getItem(from_i).count;
|
||||
|
||||
int src_can_take_count = 0xffff;
|
||||
int dst_can_put_count = 0xffff;
|
||||
|
||||
// Handle node metadata move
|
||||
if(from_inv.type == InventoryLocation::NODEMETA &&
|
||||
to_inv.type == InventoryLocation::NODEMETA &&
|
||||
from_inv.p != to_inv.p)
|
||||
/* Query detached inventories */
|
||||
|
||||
// Move occurs in the same detached inventory
|
||||
if(from_inv.type == InventoryLocation::DETACHED &&
|
||||
to_inv.type == InventoryLocation::DETACHED &&
|
||||
from_inv.name == to_inv.name)
|
||||
{
|
||||
errorstream<<"Directly moving items between two nodes is "
|
||||
<<"disallowed."<<std::endl;
|
||||
return;
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
src_can_take_count = scriptapi_detached_inventory_allow_move(
|
||||
L, from_inv.name, from_list, from_i,
|
||||
to_list, to_i, try_take_count, player);
|
||||
dst_can_put_count = src_can_take_count;
|
||||
}
|
||||
else if(from_inv.type == InventoryLocation::NODEMETA &&
|
||||
else
|
||||
{
|
||||
// Destination is detached
|
||||
if(to_inv.type == InventoryLocation::DETACHED)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
ItemStack src_item = list_from->getItem(from_i);
|
||||
src_item.count = try_take_count;
|
||||
dst_can_put_count = scriptapi_detached_inventory_allow_put(
|
||||
L, to_inv.name, to_list, to_i, src_item, player);
|
||||
}
|
||||
// Source is detached
|
||||
if(from_inv.type == InventoryLocation::DETACHED)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
ItemStack src_item = list_from->getItem(from_i);
|
||||
src_item.count = try_take_count;
|
||||
src_can_take_count = scriptapi_detached_inventory_allow_take(
|
||||
L, from_inv.name, from_list, from_i, src_item, player);
|
||||
}
|
||||
}
|
||||
|
||||
/* Query node metadata inventories */
|
||||
|
||||
// Both endpoints are nodemeta
|
||||
// Move occurs in the same nodemeta inventory
|
||||
if(from_inv.type == InventoryLocation::NODEMETA &&
|
||||
to_inv.type == InventoryLocation::NODEMETA &&
|
||||
from_inv.p == to_inv.p)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
int count0 = count;
|
||||
if(count0 == 0)
|
||||
count0 = list_from->getItem(from_i).count;
|
||||
infostream<<player->getDescription()<<" moving "<<count0
|
||||
<<" items inside node at "<<PP(from_inv.p)<<std::endl;
|
||||
scriptapi_node_on_metadata_inventory_move(L, from_inv.p,
|
||||
from_list, from_i, to_list, to_i, count0, player);
|
||||
src_can_take_count = scriptapi_nodemeta_inventory_allow_move(
|
||||
L, from_inv.p, from_list, from_i,
|
||||
to_list, to_i, try_take_count, player);
|
||||
dst_can_put_count = src_can_take_count;
|
||||
}
|
||||
// Handle node metadata take
|
||||
else if(from_inv.type == InventoryLocation::NODEMETA)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
int count0 = count;
|
||||
if(count0 == 0)
|
||||
count0 = list_from->getItem(from_i).count;
|
||||
infostream<<player->getDescription()<<" taking "<<count0
|
||||
<<" items from node at "<<PP(from_inv.p)<<std::endl;
|
||||
ItemStack return_stack = scriptapi_node_on_metadata_inventory_take(
|
||||
L, from_inv.p, from_list, from_i, count0, player);
|
||||
if(return_stack.count == 0)
|
||||
infostream<<"Node metadata gave no items"<<std::endl;
|
||||
return_stack = list_to->addItem(to_i, return_stack);
|
||||
list_to->addItem(return_stack); // Force return of everything
|
||||
}
|
||||
// Handle node metadata offer
|
||||
else if(to_inv.type == InventoryLocation::NODEMETA)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
int count0 = count;
|
||||
if(count0 == 0)
|
||||
count0 = list_from->getItem(from_i).count;
|
||||
ItemStack offer_stack = list_from->takeItem(from_i, count0);
|
||||
infostream<<player->getDescription()<<" offering "
|
||||
<<offer_stack.count<<" items to node at "
|
||||
<<PP(to_inv.p)<<std::endl;
|
||||
ItemStack reject_stack = scriptapi_node_on_metadata_inventory_offer(
|
||||
L, to_inv.p, to_list, to_i, offer_stack, player);
|
||||
if(reject_stack.count == offer_stack.count)
|
||||
infostream<<"Node metadata rejected all items"<<std::endl;
|
||||
else if(reject_stack.count != 0)
|
||||
infostream<<"Node metadata rejected some items"<<std::endl;
|
||||
reject_stack = list_from->addItem(from_i, reject_stack);
|
||||
list_from->addItem(reject_stack); // Force return of everything
|
||||
}
|
||||
// Handle regular move
|
||||
else
|
||||
{
|
||||
/*
|
||||
This performs the actual movement
|
||||
// Destination is nodemeta
|
||||
if(to_inv.type == InventoryLocation::NODEMETA)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
ItemStack src_item = list_from->getItem(from_i);
|
||||
src_item.count = try_take_count;
|
||||
dst_can_put_count = scriptapi_nodemeta_inventory_allow_put(
|
||||
L, to_inv.p, to_list, to_i, src_item, player);
|
||||
}
|
||||
// Source is nodemeta
|
||||
if(from_inv.type == InventoryLocation::NODEMETA)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
ItemStack src_item = list_from->getItem(from_i);
|
||||
src_item.count = try_take_count;
|
||||
src_can_take_count = scriptapi_nodemeta_inventory_allow_take(
|
||||
L, from_inv.p, from_list, from_i, src_item, player);
|
||||
}
|
||||
}
|
||||
|
||||
If something is wrong (source item is empty, destination is the
|
||||
same as source), nothing happens
|
||||
*/
|
||||
list_from->moveItem(from_i, list_to, to_i, count);
|
||||
|
||||
infostream<<"IMoveAction::apply(): moved "
|
||||
<<" count="<<count
|
||||
int old_count = count;
|
||||
|
||||
/* Modify count according to collected data */
|
||||
count = try_take_count;
|
||||
if(src_can_take_count != -1 && count > src_can_take_count)
|
||||
count = src_can_take_count;
|
||||
if(dst_can_put_count != -1 && count > dst_can_put_count)
|
||||
count = dst_can_put_count;
|
||||
/* Limit according to source item count */
|
||||
if(count > list_from->getItem(from_i).count)
|
||||
count = list_from->getItem(from_i).count;
|
||||
|
||||
/* If no items will be moved, don't go further */
|
||||
if(count == 0)
|
||||
{
|
||||
infostream<<"IMoveAction::apply(): move was completely disallowed:"
|
||||
<<" count="<<old_count
|
||||
<<" from inv=\""<<from_inv.dump()<<"\""
|
||||
<<" list=\""<<from_list<<"\""
|
||||
<<" i="<<from_i
|
||||
@@ -277,6 +305,105 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||
<<" list=\""<<to_list<<"\""
|
||||
<<" i="<<to_i
|
||||
<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack src_item = list_from->getItem(from_i);
|
||||
src_item.count = count;
|
||||
ItemStack from_stack_was = list_from->getItem(from_i);
|
||||
ItemStack to_stack_was = list_to->getItem(to_i);
|
||||
|
||||
/*
|
||||
Perform actual move
|
||||
|
||||
If something is wrong (source item is empty, destination is the
|
||||
same as source), nothing happens
|
||||
*/
|
||||
list_from->moveItem(from_i, list_to, to_i, count);
|
||||
|
||||
// If source is infinite, reset it's stack
|
||||
if(src_can_take_count == -1){
|
||||
list_from->deleteItem(from_i);
|
||||
list_from->addItem(from_i, from_stack_was);
|
||||
}
|
||||
// If destination is infinite, reset it's stack and take count from source
|
||||
if(dst_can_put_count == -1){
|
||||
list_to->deleteItem(to_i);
|
||||
list_to->addItem(to_i, to_stack_was);
|
||||
list_from->takeItem(from_i, count);
|
||||
}
|
||||
|
||||
infostream<<"IMoveAction::apply(): moved"
|
||||
<<" count="<<count
|
||||
<<" from inv=\""<<from_inv.dump()<<"\""
|
||||
<<" list=\""<<from_list<<"\""
|
||||
<<" i="<<from_i
|
||||
<<" to inv=\""<<to_inv.dump()<<"\""
|
||||
<<" list=\""<<to_list<<"\""
|
||||
<<" i="<<to_i
|
||||
<<std::endl;
|
||||
|
||||
/*
|
||||
Report move to endpoints
|
||||
*/
|
||||
|
||||
/* Detached inventories */
|
||||
|
||||
// Both endpoints are same detached
|
||||
if(from_inv.type == InventoryLocation::DETACHED &&
|
||||
to_inv.type == InventoryLocation::DETACHED &&
|
||||
from_inv.name == to_inv.name)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
scriptapi_detached_inventory_on_move(
|
||||
L, from_inv.name, from_list, from_i,
|
||||
to_list, to_i, count, player);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Destination is detached
|
||||
if(to_inv.type == InventoryLocation::DETACHED)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
scriptapi_detached_inventory_on_put(
|
||||
L, to_inv.name, to_list, to_i, src_item, player);
|
||||
}
|
||||
// Source is detached
|
||||
if(from_inv.type == InventoryLocation::DETACHED)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
scriptapi_detached_inventory_on_take(
|
||||
L, from_inv.name, from_list, from_i, src_item, player);
|
||||
}
|
||||
}
|
||||
|
||||
/* Node metadata inventories */
|
||||
|
||||
// Both endpoints are same nodemeta
|
||||
if(from_inv.type == InventoryLocation::NODEMETA &&
|
||||
to_inv.type == InventoryLocation::NODEMETA &&
|
||||
from_inv.p == to_inv.p)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
scriptapi_nodemeta_inventory_on_move(
|
||||
L, from_inv.p, from_list, from_i,
|
||||
to_list, to_i, count, player);
|
||||
}
|
||||
else{
|
||||
// Destination is nodemeta
|
||||
if(to_inv.type == InventoryLocation::NODEMETA)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
scriptapi_nodemeta_inventory_on_put(
|
||||
L, to_inv.p, to_list, to_i, src_item, player);
|
||||
}
|
||||
// Source is nodemeta
|
||||
else if(from_inv.type == InventoryLocation::NODEMETA)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
scriptapi_nodemeta_inventory_on_take(
|
||||
L, from_inv.p, from_list, from_i, src_item, player);
|
||||
}
|
||||
}
|
||||
|
||||
mgr->setInventoryModified(from_inv);
|
||||
@@ -361,47 +488,64 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||
return;
|
||||
}
|
||||
|
||||
ItemStack item1;
|
||||
/*
|
||||
Collect information of endpoints
|
||||
*/
|
||||
|
||||
// Handle node metadata take
|
||||
int take_count = list_from->getItem(from_i).count;
|
||||
if(count != 0 && count < take_count)
|
||||
take_count = count;
|
||||
int src_can_take_count = take_count;
|
||||
|
||||
// Source is detached
|
||||
if(from_inv.type == InventoryLocation::DETACHED)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
ItemStack src_item = list_from->getItem(from_i);
|
||||
src_item.count = take_count;
|
||||
src_can_take_count = scriptapi_detached_inventory_allow_take(
|
||||
L, from_inv.name, from_list, from_i, src_item, player);
|
||||
}
|
||||
|
||||
// Source is nodemeta
|
||||
if(from_inv.type == InventoryLocation::NODEMETA)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
int count0 = count;
|
||||
if(count0 == 0)
|
||||
count0 = list_from->getItem(from_i).count;
|
||||
infostream<<player->getDescription()<<" dropping "<<count0
|
||||
<<" items from node at "<<PP(from_inv.p)<<std::endl;
|
||||
ItemStack return_stack = scriptapi_node_on_metadata_inventory_take(
|
||||
L, from_inv.p, from_list, from_i, count0, player);
|
||||
if(return_stack.count == 0)
|
||||
infostream<<"Node metadata gave no items"<<std::endl;
|
||||
item1 = return_stack;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Take item from source list
|
||||
if(count == 0)
|
||||
item1 = list_from->changeItem(from_i, ItemStack());
|
||||
else
|
||||
item1 = list_from->takeItem(from_i, count);
|
||||
ItemStack src_item = list_from->getItem(from_i);
|
||||
src_item.count = take_count;
|
||||
src_can_take_count = scriptapi_nodemeta_inventory_allow_take(
|
||||
L, from_inv.p, from_list, from_i, src_item, player);
|
||||
}
|
||||
|
||||
// Drop the item and apply the returned ItemStack
|
||||
ItemStack item2 = item1;
|
||||
if(scriptapi_item_on_drop(player->getEnv()->getLua(), item2, player,
|
||||
if(src_can_take_count != -1 && src_can_take_count < take_count)
|
||||
take_count = src_can_take_count;
|
||||
|
||||
int actually_dropped_count = 0;
|
||||
|
||||
ItemStack src_item = list_from->getItem(from_i);
|
||||
|
||||
// Drop the item
|
||||
ItemStack item1 = list_from->getItem(from_i);
|
||||
if(scriptapi_item_on_drop(player->getEnv()->getLua(), item1, player,
|
||||
player->getBasePosition() + v3f(0,1,0)))
|
||||
{
|
||||
if(g_settings->getBool("creative_mode") == true
|
||||
&& from_inv.type == InventoryLocation::PLAYER)
|
||||
item2 = item1; // creative mode
|
||||
actually_dropped_count = take_count - item1.count;
|
||||
|
||||
list_from->addItem(from_i, item2);
|
||||
if(actually_dropped_count == 0){
|
||||
infostream<<"Actually dropped no items"<<std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// If source isn't infinite
|
||||
if(src_can_take_count != -1){
|
||||
// Take item from source list
|
||||
ItemStack item2 = list_from->takeItem(from_i, actually_dropped_count);
|
||||
|
||||
if(item2.count != actually_dropped_count)
|
||||
errorstream<<"Could not take dropped count of items"<<std::endl;
|
||||
|
||||
// Unless we have put the same amount back as we took in the first place,
|
||||
// set inventory modified flag
|
||||
if(item2.count != item1.count)
|
||||
mgr->setInventoryModified(from_inv);
|
||||
}
|
||||
}
|
||||
|
||||
infostream<<"IDropAction::apply(): dropped "
|
||||
@@ -409,6 +553,28 @@ void IDropAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||
<<" list=\""<<from_list<<"\""
|
||||
<<" i="<<from_i
|
||||
<<std::endl;
|
||||
|
||||
src_item.count = actually_dropped_count;
|
||||
|
||||
/*
|
||||
Report drop to endpoints
|
||||
*/
|
||||
|
||||
// Source is detached
|
||||
if(from_inv.type == InventoryLocation::DETACHED)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
scriptapi_detached_inventory_on_take(
|
||||
L, from_inv.name, from_list, from_i, src_item, player);
|
||||
}
|
||||
|
||||
// Source is nodemeta
|
||||
if(from_inv.type == InventoryLocation::NODEMETA)
|
||||
{
|
||||
lua_State *L = player->getEnv()->getLua();
|
||||
scriptapi_nodemeta_inventory_on_take(
|
||||
L, from_inv.p, from_list, from_i, src_item, player);
|
||||
}
|
||||
}
|
||||
|
||||
void IDropAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
|
||||
|
||||
@@ -32,9 +32,10 @@ struct InventoryLocation
|
||||
CURRENT_PLAYER,
|
||||
PLAYER,
|
||||
NODEMETA,
|
||||
DETACHED,
|
||||
} type;
|
||||
|
||||
std::string name; // PLAYER
|
||||
std::string name; // PLAYER, DETACHED
|
||||
v3s16 p; // NODEMETA
|
||||
|
||||
InventoryLocation()
|
||||
@@ -59,6 +60,11 @@ struct InventoryLocation
|
||||
type = NODEMETA;
|
||||
p = p_;
|
||||
}
|
||||
void setDetached(const std::string &name_)
|
||||
{
|
||||
type = DETACHED;
|
||||
name = name_;
|
||||
}
|
||||
|
||||
void applyCurrentPlayer(const std::string &name_)
|
||||
{
|
||||
@@ -80,13 +86,11 @@ public:
|
||||
InventoryManager(){}
|
||||
virtual ~InventoryManager(){}
|
||||
|
||||
// Get an inventory or set it modified (so it will be updated over
|
||||
// network or so)
|
||||
// Get an inventory (server and client)
|
||||
virtual Inventory* getInventory(const InventoryLocation &loc){return NULL;}
|
||||
virtual std::string getInventoryOwner(const InventoryLocation &loc){return "";}
|
||||
// Set modified (will be saved and sent over network; only on server)
|
||||
virtual void setInventoryModified(const InventoryLocation &loc){}
|
||||
|
||||
// Used on the client to send an action to the server
|
||||
// Send inventory action to server (only on client)
|
||||
virtual void inventoryAction(InventoryAction *a){}
|
||||
};
|
||||
|
||||
|
||||
@@ -612,8 +612,10 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
|
||||
*/
|
||||
if(disk)
|
||||
{
|
||||
// Node timers
|
||||
m_node_timers.serialize(os);
|
||||
if(version <= 24){
|
||||
// Node timers
|
||||
m_node_timers.serialize(os, version);
|
||||
}
|
||||
|
||||
// Static objects
|
||||
m_static_objects.serialize(os);
|
||||
@@ -623,6 +625,11 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk)
|
||||
|
||||
// Write block-specific node definition id mapping
|
||||
nimap.serialize(os);
|
||||
|
||||
if(version >= 25){
|
||||
// Node timers
|
||||
m_node_timers.serialize(os, version);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -696,10 +703,10 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
|
||||
// Read unused zero
|
||||
readU8(is);
|
||||
}
|
||||
else if(version >= 24){
|
||||
if(version == 24){
|
||||
TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
|
||||
<<": Node timers"<<std::endl);
|
||||
m_node_timers.deSerialize(is);
|
||||
<<": Node timers (ver==24)"<<std::endl);
|
||||
m_node_timers.deSerialize(is, version);
|
||||
}
|
||||
|
||||
// Static objects
|
||||
@@ -719,6 +726,12 @@ void MapBlock::deSerialize(std::istream &is, u8 version, bool disk)
|
||||
NameIdMapping nimap;
|
||||
nimap.deSerialize(is);
|
||||
correctBlockNodeIds(&nimap, data, m_gamedef);
|
||||
|
||||
if(version >= 25){
|
||||
TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
|
||||
<<": Node timers (ver>=25)"<<std::endl);
|
||||
m_node_timers.deSerialize(is, version);
|
||||
}
|
||||
}
|
||||
|
||||
TRACESTREAM(<<"MapBlock::deSerialize "<<PP(getPos())
|
||||
|
||||
@@ -234,8 +234,10 @@ u32 MapNode::serializedLength(u8 version)
|
||||
return 1;
|
||||
else if(version <= 9)
|
||||
return 2;
|
||||
else
|
||||
else if(version <= 23)
|
||||
return 3;
|
||||
else
|
||||
return 4;
|
||||
}
|
||||
void MapNode::serialize(u8 *dest, u8 version)
|
||||
{
|
||||
|
||||
@@ -42,19 +42,22 @@ void NodeTimer::deSerialize(std::istream &is)
|
||||
NodeTimerList
|
||||
*/
|
||||
|
||||
void NodeTimerList::serialize(std::ostream &os) const
|
||||
void NodeTimerList::serialize(std::ostream &os, u8 map_format_version) const
|
||||
{
|
||||
/*
|
||||
Version 0 is a placeholder for "nothing to see here; go away."
|
||||
*/
|
||||
|
||||
if(m_data.size() == 0){
|
||||
writeU8(os, 0); // version
|
||||
return;
|
||||
if(map_format_version == 24){
|
||||
// Version 0 is a placeholder for "nothing to see here; go away."
|
||||
if(m_data.size() == 0){
|
||||
writeU8(os, 0); // version
|
||||
return;
|
||||
}
|
||||
writeU8(os, 1); // version
|
||||
writeU16(os, m_data.size());
|
||||
}
|
||||
|
||||
writeU8(os, 1); // version
|
||||
writeU16(os, m_data.size());
|
||||
if(map_format_version >= 25){
|
||||
writeU8(os, 2+4+4);
|
||||
writeU16(os, m_data.size());
|
||||
}
|
||||
|
||||
for(std::map<v3s16, NodeTimer>::const_iterator
|
||||
i = m_data.begin();
|
||||
@@ -68,15 +71,23 @@ void NodeTimerList::serialize(std::ostream &os) const
|
||||
}
|
||||
}
|
||||
|
||||
void NodeTimerList::deSerialize(std::istream &is)
|
||||
void NodeTimerList::deSerialize(std::istream &is, u8 map_format_version)
|
||||
{
|
||||
m_data.clear();
|
||||
|
||||
if(map_format_version == 24){
|
||||
u8 timer_version = readU8(is);
|
||||
if(timer_version == 0)
|
||||
return;
|
||||
if(timer_version != 1)
|
||||
throw SerializationError("unsupported NodeTimerList version");
|
||||
}
|
||||
|
||||
u8 version = readU8(is);
|
||||
if(version == 0)
|
||||
return;
|
||||
if(version != 1)
|
||||
throw SerializationError("unsupported NodeTimerList version");
|
||||
if(map_format_version >= 25){
|
||||
u8 timer_data_len = readU8(is);
|
||||
if(timer_data_len != 2+4+4)
|
||||
throw SerializationError("unsupported NodeTimer data length");
|
||||
}
|
||||
|
||||
u16 count = readU16(is);
|
||||
|
||||
|
||||
@@ -57,8 +57,8 @@ public:
|
||||
NodeTimerList() {}
|
||||
~NodeTimerList() {}
|
||||
|
||||
void serialize(std::ostream &os) const;
|
||||
void deSerialize(std::istream &is);
|
||||
void serialize(std::ostream &os, u8 map_format_version) const;
|
||||
void deSerialize(std::istream &is, u8 map_format_version);
|
||||
|
||||
// Get timer
|
||||
NodeTimer get(v3s16 p){
|
||||
|
||||
@@ -150,7 +150,6 @@ public:
|
||||
|
||||
u8 light;
|
||||
|
||||
// In creative mode, this is the invisible backup inventory
|
||||
Inventory inventory;
|
||||
|
||||
u16 hp;
|
||||
|
||||
@@ -4567,6 +4567,9 @@ static int l_get_inventory(lua_State *L)
|
||||
lua_getfield(L, 1, "pos");
|
||||
v3s16 pos = check_v3s16(L, -1);
|
||||
loc.setNodeMeta(pos);
|
||||
} else if(type == "detached"){
|
||||
std::string name = checkstringfield(L, 1, "name");
|
||||
loc.setDetached(name);
|
||||
}
|
||||
|
||||
if(get_server(L)->getInventory(loc) != NULL)
|
||||
@@ -4576,6 +4579,20 @@ static int l_get_inventory(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
// create_detached_inventory_raw(name)
|
||||
static int l_create_detached_inventory_raw(lua_State *L)
|
||||
{
|
||||
const char *name = luaL_checkstring(L, 1);
|
||||
if(get_server(L)->createDetachedInventory(name) != NULL){
|
||||
InventoryLocation loc;
|
||||
loc.setDetached(name);
|
||||
InvRef::create(L, loc);
|
||||
}else{
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
// get_dig_params(groups, tool_capabilities[, time_from_last_punch])
|
||||
static int l_get_dig_params(lua_State *L)
|
||||
{
|
||||
@@ -4849,6 +4866,7 @@ static const struct luaL_Reg minetest_f [] = {
|
||||
{"chat_send_player", l_chat_send_player},
|
||||
{"get_player_privs", l_get_player_privs},
|
||||
{"get_inventory", l_get_inventory},
|
||||
{"create_detached_inventory_raw", l_create_detached_inventory_raw},
|
||||
{"get_dig_params", l_get_dig_params},
|
||||
{"get_hit_params", l_get_hit_params},
|
||||
{"get_current_modname", l_get_current_modname},
|
||||
@@ -5308,21 +5326,6 @@ void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player)
|
||||
scriptapi_run_callbacks(L, 1, RUN_CALLBACKS_MODE_FIRST);
|
||||
}
|
||||
|
||||
void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
Inventory *inv = player->getInventory();
|
||||
assert(inv);
|
||||
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "creative_inventory");
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
inventory_set_list_from_lua(inv, "main", L, -1, PLAYER_INVENTORY_SIZE);
|
||||
}
|
||||
|
||||
static void get_auth_handler(lua_State *L)
|
||||
{
|
||||
lua_getglobal(L, "minetest");
|
||||
@@ -5716,7 +5719,134 @@ void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
void scriptapi_node_on_metadata_inventory_move(lua_State *L, v3s16 p,
|
||||
/*
|
||||
Node metadata inventory callbacks
|
||||
*/
|
||||
|
||||
// Return number of accepted items to be moved
|
||||
int scriptapi_nodemeta_inventory_allow_move(lua_State *L, v3s16 p,
|
||||
const std::string &from_list, int from_index,
|
||||
const std::string &to_list, int to_index,
|
||||
int count, ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
INodeDefManager *ndef = get_server(L)->ndef();
|
||||
|
||||
// If node doesn't exist, we don't know what callback to call
|
||||
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
|
||||
if(node.getContent() == CONTENT_IGNORE)
|
||||
return 0;
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
||||
"allow_metadata_inventory_move"))
|
||||
return count;
|
||||
|
||||
// function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
// pos
|
||||
push_v3s16(L, p);
|
||||
// from_list
|
||||
lua_pushstring(L, from_list.c_str());
|
||||
// from_index
|
||||
lua_pushinteger(L, from_index + 1);
|
||||
// to_list
|
||||
lua_pushstring(L, to_list.c_str());
|
||||
// to_index
|
||||
lua_pushinteger(L, to_index + 1);
|
||||
// count
|
||||
lua_pushinteger(L, count);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 7, 1, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
if(!lua_isnumber(L, -1))
|
||||
throw LuaError(L, "allow_metadata_inventory_move should return a number");
|
||||
return luaL_checkinteger(L, -1);
|
||||
}
|
||||
|
||||
// Return number of accepted items to be put
|
||||
int scriptapi_nodemeta_inventory_allow_put(lua_State *L, v3s16 p,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
INodeDefManager *ndef = get_server(L)->ndef();
|
||||
|
||||
// If node doesn't exist, we don't know what callback to call
|
||||
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
|
||||
if(node.getContent() == CONTENT_IGNORE)
|
||||
return 0;
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
||||
"allow_metadata_inventory_put"))
|
||||
return stack.count;
|
||||
|
||||
// Call function(pos, listname, index, stack, player)
|
||||
// pos
|
||||
push_v3s16(L, p);
|
||||
// listname
|
||||
lua_pushstring(L, listname.c_str());
|
||||
// index
|
||||
lua_pushinteger(L, index + 1);
|
||||
// stack
|
||||
LuaItemStack::create(L, stack);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 5, 1, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
if(!lua_isnumber(L, -1))
|
||||
throw LuaError(L, "allow_metadata_inventory_put should return a number");
|
||||
return luaL_checkinteger(L, -1);
|
||||
}
|
||||
|
||||
// Return number of accepted items to be taken
|
||||
int scriptapi_nodemeta_inventory_allow_take(lua_State *L, v3s16 p,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
INodeDefManager *ndef = get_server(L)->ndef();
|
||||
|
||||
// If node doesn't exist, we don't know what callback to call
|
||||
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
|
||||
if(node.getContent() == CONTENT_IGNORE)
|
||||
return 0;
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
||||
"allow_metadata_inventory_take"))
|
||||
return stack.count;
|
||||
|
||||
// Call function(pos, listname, index, count, player)
|
||||
// pos
|
||||
push_v3s16(L, p);
|
||||
// listname
|
||||
lua_pushstring(L, listname.c_str());
|
||||
// index
|
||||
lua_pushinteger(L, index + 1);
|
||||
// stack
|
||||
LuaItemStack::create(L, stack);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 5, 1, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
if(!lua_isnumber(L, -1))
|
||||
throw LuaError(L, "allow_metadata_inventory_take should return a number");
|
||||
return luaL_checkinteger(L, -1);
|
||||
}
|
||||
|
||||
// Report moved items
|
||||
void scriptapi_nodemeta_inventory_on_move(lua_State *L, v3s16 p,
|
||||
const std::string &from_list, int from_index,
|
||||
const std::string &to_list, int to_index,
|
||||
int count, ServerActiveObject *player)
|
||||
@@ -5738,18 +5868,26 @@ void scriptapi_node_on_metadata_inventory_move(lua_State *L, v3s16 p,
|
||||
return;
|
||||
|
||||
// function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||
// pos
|
||||
push_v3s16(L, p);
|
||||
// from_list
|
||||
lua_pushstring(L, from_list.c_str());
|
||||
// from_index
|
||||
lua_pushinteger(L, from_index + 1);
|
||||
// to_list
|
||||
lua_pushstring(L, to_list.c_str());
|
||||
// to_index
|
||||
lua_pushinteger(L, to_index + 1);
|
||||
// count
|
||||
lua_pushinteger(L, count);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 7, 0, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p,
|
||||
// Report put items
|
||||
void scriptapi_nodemeta_inventory_on_put(lua_State *L, v3s16 p,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player)
|
||||
{
|
||||
@@ -5762,26 +5900,31 @@ ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p,
|
||||
// If node doesn't exist, we don't know what callback to call
|
||||
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
|
||||
if(node.getContent() == CONTENT_IGNORE)
|
||||
return stack;
|
||||
return;
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
||||
"on_metadata_inventory_offer"))
|
||||
return stack;
|
||||
"on_metadata_inventory_put"))
|
||||
return;
|
||||
|
||||
// Call function(pos, listname, index, stack, player)
|
||||
// pos
|
||||
push_v3s16(L, p);
|
||||
// listname
|
||||
lua_pushstring(L, listname.c_str());
|
||||
// index
|
||||
lua_pushinteger(L, index + 1);
|
||||
// stack
|
||||
LuaItemStack::create(L, stack);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 5, 1, 0))
|
||||
if(lua_pcall(L, 5, 0, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
return read_item(L, -1);
|
||||
}
|
||||
|
||||
ItemStack scriptapi_node_on_metadata_inventory_take(lua_State *L, v3s16 p,
|
||||
const std::string &listname, int index, int count,
|
||||
// Report taken items
|
||||
void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
@@ -5793,22 +5936,276 @@ ItemStack scriptapi_node_on_metadata_inventory_take(lua_State *L, v3s16 p,
|
||||
// If node doesn't exist, we don't know what callback to call
|
||||
MapNode node = get_env(L)->getMap().getNodeNoEx(p);
|
||||
if(node.getContent() == CONTENT_IGNORE)
|
||||
return ItemStack();
|
||||
return;
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_item_callback(L, ndef->get(node).name.c_str(),
|
||||
"on_metadata_inventory_take"))
|
||||
return ItemStack();
|
||||
return;
|
||||
|
||||
// Call function(pos, listname, index, count, player)
|
||||
// Call function(pos, listname, index, stack, player)
|
||||
// pos
|
||||
push_v3s16(L, p);
|
||||
// listname
|
||||
lua_pushstring(L, listname.c_str());
|
||||
// index
|
||||
lua_pushinteger(L, index + 1);
|
||||
// stack
|
||||
LuaItemStack::create(L, stack);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 5, 0, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
/*
|
||||
Detached inventory callbacks
|
||||
*/
|
||||
|
||||
// Retrieves minetest.detached_inventories[name][callbackname]
|
||||
// If that is nil or on error, return false and stack is unchanged
|
||||
// If that is a function, returns true and pushes the
|
||||
// function onto the stack
|
||||
static bool get_detached_inventory_callback(lua_State *L,
|
||||
const std::string &name, const char *callbackname)
|
||||
{
|
||||
lua_getglobal(L, "minetest");
|
||||
lua_getfield(L, -1, "detached_inventories");
|
||||
lua_remove(L, -2);
|
||||
luaL_checktype(L, -1, LUA_TTABLE);
|
||||
lua_getfield(L, -1, name.c_str());
|
||||
lua_remove(L, -2);
|
||||
// Should be a table
|
||||
if(lua_type(L, -1) != LUA_TTABLE)
|
||||
{
|
||||
errorstream<<"Item \""<<name<<"\" not defined"<<std::endl;
|
||||
lua_pop(L, 1);
|
||||
return false;
|
||||
}
|
||||
lua_getfield(L, -1, callbackname);
|
||||
lua_remove(L, -2);
|
||||
// Should be a function or nil
|
||||
if(lua_type(L, -1) == LUA_TFUNCTION)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if(lua_isnil(L, -1))
|
||||
{
|
||||
lua_pop(L, 1);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
errorstream<<"Detached inventory \""<<name<<"\" callback \""
|
||||
<<callbackname<<"\" is not a function"<<std::endl;
|
||||
lua_pop(L, 1);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Return number of accepted items to be moved
|
||||
int scriptapi_detached_inventory_allow_move(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &from_list, int from_index,
|
||||
const std::string &to_list, int to_index,
|
||||
int count, ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_detached_inventory_callback(L, name, "allow_move"))
|
||||
return count;
|
||||
|
||||
// function(inv, from_list, from_index, to_list, to_index, count, player)
|
||||
// inv
|
||||
InventoryLocation loc;
|
||||
loc.setDetached(name);
|
||||
InvRef::create(L, loc);
|
||||
// from_list
|
||||
lua_pushstring(L, from_list.c_str());
|
||||
// from_index
|
||||
lua_pushinteger(L, from_index + 1);
|
||||
// to_list
|
||||
lua_pushstring(L, to_list.c_str());
|
||||
// to_index
|
||||
lua_pushinteger(L, to_index + 1);
|
||||
// count
|
||||
lua_pushinteger(L, count);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 7, 1, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
if(!lua_isnumber(L, -1))
|
||||
throw LuaError(L, "allow_move should return a number");
|
||||
return luaL_checkinteger(L, -1);
|
||||
}
|
||||
|
||||
// Return number of accepted items to be put
|
||||
int scriptapi_detached_inventory_allow_put(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_detached_inventory_callback(L, name, "allow_put"))
|
||||
return stack.count; // All will be accepted
|
||||
|
||||
// Call function(inv, listname, index, stack, player)
|
||||
// inv
|
||||
InventoryLocation loc;
|
||||
loc.setDetached(name);
|
||||
InvRef::create(L, loc);
|
||||
// listname
|
||||
lua_pushstring(L, listname.c_str());
|
||||
// index
|
||||
lua_pushinteger(L, index + 1);
|
||||
// stack
|
||||
LuaItemStack::create(L, stack);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 5, 1, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
return read_item(L, -1);
|
||||
if(!lua_isnumber(L, -1))
|
||||
throw LuaError(L, "allow_put should return a number");
|
||||
return luaL_checkinteger(L, -1);
|
||||
}
|
||||
|
||||
// Return number of accepted items to be taken
|
||||
int scriptapi_detached_inventory_allow_take(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_detached_inventory_callback(L, name, "allow_take"))
|
||||
return stack.count; // All will be accepted
|
||||
|
||||
// Call function(inv, listname, index, stack, player)
|
||||
// inv
|
||||
InventoryLocation loc;
|
||||
loc.setDetached(name);
|
||||
InvRef::create(L, loc);
|
||||
// listname
|
||||
lua_pushstring(L, listname.c_str());
|
||||
// index
|
||||
lua_pushinteger(L, index + 1);
|
||||
// stack
|
||||
LuaItemStack::create(L, stack);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 5, 1, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
if(!lua_isnumber(L, -1))
|
||||
throw LuaError(L, "allow_take should return a number");
|
||||
return luaL_checkinteger(L, -1);
|
||||
}
|
||||
|
||||
// Report moved items
|
||||
void scriptapi_detached_inventory_on_move(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &from_list, int from_index,
|
||||
const std::string &to_list, int to_index,
|
||||
int count, ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_detached_inventory_callback(L, name, "on_move"))
|
||||
return;
|
||||
|
||||
// function(inv, from_list, from_index, to_list, to_index, count, player)
|
||||
// inv
|
||||
InventoryLocation loc;
|
||||
loc.setDetached(name);
|
||||
InvRef::create(L, loc);
|
||||
// from_list
|
||||
lua_pushstring(L, from_list.c_str());
|
||||
// from_index
|
||||
lua_pushinteger(L, from_index + 1);
|
||||
// to_list
|
||||
lua_pushstring(L, to_list.c_str());
|
||||
// to_index
|
||||
lua_pushinteger(L, to_index + 1);
|
||||
// count
|
||||
lua_pushinteger(L, count);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 7, 0, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
// Report put items
|
||||
void scriptapi_detached_inventory_on_put(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_detached_inventory_callback(L, name, "on_put"))
|
||||
return;
|
||||
|
||||
// Call function(inv, listname, index, stack, player)
|
||||
// inv
|
||||
InventoryLocation loc;
|
||||
loc.setDetached(name);
|
||||
InvRef::create(L, loc);
|
||||
// listname
|
||||
lua_pushstring(L, listname.c_str());
|
||||
// index
|
||||
lua_pushinteger(L, index + 1);
|
||||
// stack
|
||||
LuaItemStack::create(L, stack);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 5, 0, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
// Report taken items
|
||||
void scriptapi_detached_inventory_on_take(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player)
|
||||
{
|
||||
realitycheck(L);
|
||||
assert(lua_checkstack(L, 20));
|
||||
StackUnroller stack_unroller(L);
|
||||
|
||||
// Push callback function on stack
|
||||
if(!get_detached_inventory_callback(L, name, "on_take"))
|
||||
return;
|
||||
|
||||
// Call function(inv, listname, index, stack, player)
|
||||
// inv
|
||||
InventoryLocation loc;
|
||||
loc.setDetached(name);
|
||||
InvRef::create(L, loc);
|
||||
// listname
|
||||
lua_pushstring(L, listname.c_str());
|
||||
// index
|
||||
lua_pushinteger(L, index + 1);
|
||||
// stack
|
||||
LuaItemStack::create(L, stack);
|
||||
// player
|
||||
objectref_get_or_create(L, player);
|
||||
if(lua_pcall(L, 5, 0, 0))
|
||||
script_error(L, "error: %s", lua_tostring(L, -1));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -61,7 +61,6 @@ void scriptapi_on_dieplayer(lua_State *L, ServerActiveObject *player);
|
||||
bool scriptapi_on_respawnplayer(lua_State *L, ServerActiveObject *player);
|
||||
void scriptapi_on_joinplayer(lua_State *L, ServerActiveObject *player);
|
||||
void scriptapi_on_leaveplayer(lua_State *L, ServerActiveObject *player);
|
||||
void scriptapi_get_creative_inventory(lua_State *L, ServerActiveObject *player);
|
||||
bool scriptapi_get_auth(lua_State *L, const std::string &playername,
|
||||
std::string *dst_password, std::set<std::string> *dst_privs);
|
||||
void scriptapi_create_auth(lua_State *L, const std::string &playername,
|
||||
@@ -101,18 +100,67 @@ void scriptapi_node_on_receive_fields(lua_State *L, v3s16 p,
|
||||
const std::string &formname,
|
||||
const std::map<std::string, std::string> &fields,
|
||||
ServerActiveObject *sender);
|
||||
// Moves items
|
||||
void scriptapi_node_on_metadata_inventory_move(lua_State *L, v3s16 p,
|
||||
|
||||
/* Node metadata inventory callbacks */
|
||||
// Return number of accepted items to be moved
|
||||
int scriptapi_nodemeta_inventory_allow_move(lua_State *L, v3s16 p,
|
||||
const std::string &from_list, int from_index,
|
||||
const std::string &to_list, int to_index,
|
||||
int count, ServerActiveObject *player);
|
||||
// Inserts items, returns rejected items
|
||||
ItemStack scriptapi_node_on_metadata_inventory_offer(lua_State *L, v3s16 p,
|
||||
// Return number of accepted items to be put
|
||||
int scriptapi_nodemeta_inventory_allow_put(lua_State *L, v3s16 p,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player);
|
||||
// Takes items, returns taken items
|
||||
ItemStack scriptapi_node_on_metadata_inventory_take(lua_State *L, v3s16 p,
|
||||
const std::string &listname, int index, int count,
|
||||
// Return number of accepted items to be taken
|
||||
int scriptapi_nodemeta_inventory_allow_take(lua_State *L, v3s16 p,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player);
|
||||
// Report moved items
|
||||
void scriptapi_nodemeta_inventory_on_move(lua_State *L, v3s16 p,
|
||||
const std::string &from_list, int from_index,
|
||||
const std::string &to_list, int to_index,
|
||||
int count, ServerActiveObject *player);
|
||||
// Report put items
|
||||
void scriptapi_nodemeta_inventory_on_put(lua_State *L, v3s16 p,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player);
|
||||
// Report taken items
|
||||
void scriptapi_nodemeta_inventory_on_take(lua_State *L, v3s16 p,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player);
|
||||
|
||||
/* Detached inventory callbacks */
|
||||
// Return number of accepted items to be moved
|
||||
int scriptapi_detached_inventory_allow_move(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &from_list, int from_index,
|
||||
const std::string &to_list, int to_index,
|
||||
int count, ServerActiveObject *player);
|
||||
// Return number of accepted items to be put
|
||||
int scriptapi_detached_inventory_allow_put(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player);
|
||||
// Return number of accepted items to be taken
|
||||
int scriptapi_detached_inventory_allow_take(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player);
|
||||
// Report moved items
|
||||
void scriptapi_detached_inventory_on_move(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &from_list, int from_index,
|
||||
const std::string &to_list, int to_index,
|
||||
int count, ServerActiveObject *player);
|
||||
// Report put items
|
||||
void scriptapi_detached_inventory_on_put(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player);
|
||||
// Report taken items
|
||||
void scriptapi_detached_inventory_on_take(lua_State *L,
|
||||
const std::string &name,
|
||||
const std::string &listname, int index, ItemStack &stack,
|
||||
ServerActiveObject *player);
|
||||
|
||||
/* luaentity */
|
||||
|
||||
@@ -59,12 +59,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
21: dynamic content type allocation
|
||||
22: minerals removed, facedir & wallmounted changed
|
||||
23: new node metadata format
|
||||
24: 16-bit node ids and node timers
|
||||
24: 16-bit node ids and node timers (never released as stable)
|
||||
25: Improved node timer format
|
||||
*/
|
||||
// This represents an uninitialized or invalid format
|
||||
#define SER_FMT_VER_INVALID 255
|
||||
// Highest supported serialization version
|
||||
#define SER_FMT_VER_HIGHEST 24
|
||||
#define SER_FMT_VER_HIGHEST 25
|
||||
// Lowest supported serialization version
|
||||
#define SER_FMT_VER_LOWEST 0
|
||||
|
||||
|
||||
153
src/server.cpp
153
src/server.cpp
@@ -1160,6 +1160,15 @@ Server::~Server()
|
||||
// Deinitialize scripting
|
||||
infostream<<"Server: Deinitializing scripting"<<std::endl;
|
||||
script_deinit(m_lua);
|
||||
|
||||
// Delete detached inventories
|
||||
{
|
||||
for(std::map<std::string, Inventory*>::iterator
|
||||
i = m_detached_inventories.begin();
|
||||
i != m_detached_inventories.end(); i++){
|
||||
delete i->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Server::start(unsigned short port)
|
||||
@@ -2250,10 +2259,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
// Send inventory
|
||||
UpdateCrafting(peer_id);
|
||||
SendInventory(peer_id);
|
||||
|
||||
|
||||
// Send HP
|
||||
SendPlayerHP(peer_id);
|
||||
|
||||
// Send detached inventories
|
||||
sendDetachedInventories(peer_id);
|
||||
|
||||
// Show death screen if necessary
|
||||
if(player->hp == 0)
|
||||
SendDeathscreen(m_con, peer_id, false, v3f(0,0,0));
|
||||
@@ -2532,30 +2544,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
delete a;
|
||||
return;
|
||||
}
|
||||
|
||||
// If player is not an admin, check for ownership of src and dst
|
||||
/*if(!checkPriv(player->getName(), "server"))
|
||||
{
|
||||
std::string owner_from = getInventoryOwner(ma->from_inv);
|
||||
if(owner_from != "" && owner_from != player->getName())
|
||||
{
|
||||
infostream<<"WARNING: "<<player->getName()
|
||||
<<" tried to access an inventory that"
|
||||
<<" belongs to "<<owner_from<<std::endl;
|
||||
delete a;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string owner_to = getInventoryOwner(ma->to_inv);
|
||||
if(owner_to != "" && owner_to != player->getName())
|
||||
{
|
||||
infostream<<"WARNING: "<<player->getName()
|
||||
<<" tried to access an inventory that"
|
||||
<<" belongs to "<<owner_to<<std::endl;
|
||||
delete a;
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
/*
|
||||
Handle restrictions and special cases of the drop action
|
||||
@@ -2574,19 +2562,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
delete a;
|
||||
return;
|
||||
}
|
||||
// If player is not an admin, check for ownership
|
||||
/*else if(!checkPriv(player->getName(), "server"))
|
||||
{
|
||||
std::string owner_from = getInventoryOwner(da->from_inv);
|
||||
if(owner_from != "" && owner_from != player->getName())
|
||||
{
|
||||
infostream<<"WARNING: "<<player->getName()
|
||||
<<" tried to access an inventory that"
|
||||
<<" belongs to "<<owner_from<<std::endl;
|
||||
delete a;
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
/*
|
||||
Handle restrictions and special cases of the craft action
|
||||
@@ -2611,20 +2586,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
delete a;
|
||||
return;
|
||||
}
|
||||
|
||||
// If player is not an admin, check for ownership of inventory
|
||||
/*if(!checkPriv(player->getName(), "server"))
|
||||
{
|
||||
std::string owner_craft = getInventoryOwner(ca->craft_inv);
|
||||
if(owner_craft != "" && owner_craft != player->getName())
|
||||
{
|
||||
infostream<<"WARNING: "<<player->getName()
|
||||
<<" tried to access an inventory that"
|
||||
<<" belongs to "<<owner_craft<<std::endl;
|
||||
delete a;
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// Do the action
|
||||
@@ -3170,8 +3131,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
// Placement was handled in lua
|
||||
|
||||
// Apply returned ItemStack
|
||||
if(g_settings->getBool("creative_mode") == false)
|
||||
playersao->setWieldedItem(item);
|
||||
playersao->setWieldedItem(item);
|
||||
}
|
||||
|
||||
// If item has node placement prediction, always send the above
|
||||
@@ -3197,8 +3157,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
||||
item, playersao, pointed))
|
||||
{
|
||||
// Apply returned ItemStack
|
||||
if(g_settings->getBool("creative_mode") == false)
|
||||
playersao->setWieldedItem(item);
|
||||
playersao->setWieldedItem(item);
|
||||
}
|
||||
|
||||
} // action == 4
|
||||
@@ -3318,6 +3277,13 @@ Inventory* Server::getInventory(const InventoryLocation &loc)
|
||||
return meta->getInventory();
|
||||
}
|
||||
break;
|
||||
case InventoryLocation::DETACHED:
|
||||
{
|
||||
if(m_detached_inventories.count(loc.name) == 0)
|
||||
return NULL;
|
||||
return m_detached_inventories[loc.name];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
@@ -3352,6 +3318,11 @@ void Server::setInventoryModified(const InventoryLocation &loc)
|
||||
setBlockNotSent(blockpos);
|
||||
}
|
||||
break;
|
||||
case InventoryLocation::DETACHED:
|
||||
{
|
||||
sendDetachedInventoryToAll(loc.name);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
@@ -4016,7 +3987,7 @@ void Server::SendBlocks(float dtime)
|
||||
|
||||
RemoteClient *client = getClient(q.peer_id);
|
||||
|
||||
SendBlockNoLock(q.peer_id, block, 24);//client->serialization_version);
|
||||
SendBlockNoLock(q.peer_id, block, client->serialization_version);
|
||||
|
||||
client->SentBlock(q.pos);
|
||||
|
||||
@@ -4309,6 +4280,51 @@ void Server::sendRequestedMedia(u16 peer_id,
|
||||
}
|
||||
}
|
||||
|
||||
void Server::sendDetachedInventory(const std::string &name, u16 peer_id)
|
||||
{
|
||||
if(m_detached_inventories.count(name) == 0){
|
||||
errorstream<<__FUNCTION_NAME<<": \""<<name<<"\" not found"<<std::endl;
|
||||
return;
|
||||
}
|
||||
Inventory *inv = m_detached_inventories[name];
|
||||
|
||||
std::ostringstream os(std::ios_base::binary);
|
||||
writeU16(os, TOCLIENT_DETACHED_INVENTORY);
|
||||
os<<serializeString(name);
|
||||
inv->serialize(os);
|
||||
|
||||
// Make data buffer
|
||||
std::string s = os.str();
|
||||
SharedBuffer<u8> data((u8*)s.c_str(), s.size());
|
||||
// Send as reliable
|
||||
m_con.Send(peer_id, 0, data, true);
|
||||
}
|
||||
|
||||
void Server::sendDetachedInventoryToAll(const std::string &name)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
for(core::map<u16, RemoteClient*>::Iterator
|
||||
i = m_clients.getIterator();
|
||||
i.atEnd() == false; i++){
|
||||
RemoteClient *client = i.getNode()->getValue();
|
||||
sendDetachedInventory(name, client->peer_id);
|
||||
}
|
||||
}
|
||||
|
||||
void Server::sendDetachedInventories(u16 peer_id)
|
||||
{
|
||||
DSTACK(__FUNCTION_NAME);
|
||||
|
||||
for(std::map<std::string, Inventory*>::iterator
|
||||
i = m_detached_inventories.begin();
|
||||
i != m_detached_inventories.end(); i++){
|
||||
const std::string &name = i->first;
|
||||
//Inventory *inv = i->second;
|
||||
sendDetachedInventory(name, peer_id);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Something random
|
||||
*/
|
||||
@@ -4362,9 +4378,7 @@ void Server::UpdateCrafting(u16 peer_id)
|
||||
|
||||
// Get a preview for crafting
|
||||
ItemStack preview;
|
||||
// No crafting in creative mode
|
||||
if(g_settings->getBool("creative_mode") == false)
|
||||
getCraftingResult(&player->inventory, preview, false, this);
|
||||
getCraftingResult(&player->inventory, preview, false, this);
|
||||
|
||||
// Put the new preview in
|
||||
InventoryList *plist = player->inventory.getList("craftpreview");
|
||||
@@ -4493,6 +4507,21 @@ void Server::queueBlockEmerge(v3s16 blockpos, bool allow_generate)
|
||||
m_emerge_queue.addBlock(PEER_ID_INEXISTENT, blockpos, flags);
|
||||
}
|
||||
|
||||
Inventory* Server::createDetachedInventory(const std::string &name)
|
||||
{
|
||||
if(m_detached_inventories.count(name) > 0){
|
||||
infostream<<"Server clearing detached inventory \""<<name<<"\""<<std::endl;
|
||||
delete m_detached_inventories[name];
|
||||
} else {
|
||||
infostream<<"Server creating detached inventory \""<<name<<"\""<<std::endl;
|
||||
}
|
||||
Inventory *inv = new Inventory(m_itemdef);
|
||||
assert(inv);
|
||||
m_detached_inventories[name] = inv;
|
||||
sendDetachedInventoryToAll(name);
|
||||
return inv;
|
||||
}
|
||||
|
||||
// IGameDef interface
|
||||
// Under envlock
|
||||
IItemDefManager* Server::getItemDefManager()
|
||||
@@ -4684,10 +4713,6 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id)
|
||||
|
||||
scriptapi_on_joinplayer(m_lua, playersao);
|
||||
|
||||
/* Creative mode */
|
||||
if(g_settings->getBool("creative_mode"))
|
||||
playersao->createCreativeInventory();
|
||||
|
||||
return playersao;
|
||||
}
|
||||
|
||||
|
||||
13
src/server.h
13
src/server.h
@@ -538,6 +538,9 @@ public:
|
||||
|
||||
void queueBlockEmerge(v3s16 blockpos, bool allow_generate);
|
||||
|
||||
// Creates or resets inventory
|
||||
Inventory* createDetachedInventory(const std::string &name);
|
||||
|
||||
// Envlock and conlock should be locked when using Lua
|
||||
lua_State *getLua(){ return m_lua; }
|
||||
|
||||
@@ -627,6 +630,10 @@ private:
|
||||
void sendMediaAnnouncement(u16 peer_id);
|
||||
void sendRequestedMedia(u16 peer_id,
|
||||
const core::list<MediaRequest> &tosend);
|
||||
|
||||
void sendDetachedInventory(const std::string &name, u16 peer_id);
|
||||
void sendDetachedInventoryToAll(const std::string &name);
|
||||
void sendDetachedInventories(u16 peer_id);
|
||||
|
||||
/*
|
||||
Something random
|
||||
@@ -828,6 +835,12 @@ private:
|
||||
*/
|
||||
std::map<s32, ServerPlayingSound> m_playing_sounds;
|
||||
s32 m_next_sound_id;
|
||||
|
||||
/*
|
||||
Detached inventories (behind m_env_mutex)
|
||||
*/
|
||||
// key = name
|
||||
std::map<std::string, Inventory*> m_detached_inventories;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user