inventory should only be updated when digging/placing, don't send the whole thing

This commit is contained in:
darkrose 2015-03-15 21:25:09 +10:00
parent e780ed8cd7
commit d34f87b459
6 changed files with 282 additions and 57 deletions

View File

@ -1102,6 +1102,36 @@ void Client::ProcessData(u8 *data, u32 datasize, u16 sender_peer_id)
m_inventory_updated = true;
}
}
break;
case TOCLIENT_INVENTORY_UPDATE:
{
if (datasize < 3)
return;
{
std::string datastring((char*)&data[2], datasize-2);
std::istringstream is(datastring, std::ios_base::binary);
Player *player = m_env.getLocalPlayer();
assert(player != NULL);
u16 list_count = readU16(is);
for (int i=0; i<list_count; i++) {
std::string name = deSerializeString(is);
u16 slots = readU16(is);
InventoryList *l = player->inventory.getList(name);
if (!l)
return;
for (int k=0; k<slots; k++) {
u16 index = readU16(is);
u16 type = readU16(is);
u16 count = readU16(is);
l->updateItem(index,type,count);
}
}
m_inventory_updated = true;
}
}
//DEBUG
break;
case TOCLIENT_OBJECTDATA:

View File

@ -29,7 +29,7 @@
#include "utility.h"
#define PROTOCOL_VERSION 8
#define PROTOCOL_VERSION 9
/* the last protocol version used by 0.3.x minetest-c55 clients */
#define PROTOCOL_DOTTHREE 3
/* this is the oldest protocol that we will allow to connect
@ -221,11 +221,12 @@ enum ToClientCommand
[0] u16 command
[2] u16 player count
[4] u16 field count
for each player:
for each player {
u16 peer_id
char[20] name
u16 length of serialized chardef
string serialized character definition
}
*/
TOCLIENT_ENV_EVENT = 0x41,
@ -236,6 +237,22 @@ enum ToClientCommand
u16 length of serialised event data
string serialised event data
*/
TOCLIENT_INVENTORY_UPDATE = 0x42,
/*
u16 command
u16 list count
for each list {
u16 length of serialised list name
string serialised list name
u16 slot count
for each slot {
u16 slot index
u16 content type
u16 count/wear
}
}
*/
};
enum ToServerCommand

View File

@ -338,8 +338,10 @@ InventoryList::~InventoryList()
void InventoryList::clearItems()
{
for (u32 i=0; i<m_items.size(); i++) {
if (m_items[i])
if (m_items[i]) {
delete m_items[i];
m_diff.add(m_name,i,NULL);
}
}
m_items.clear();
@ -537,6 +539,7 @@ InventoryItem * InventoryList::changeItem(u32 i, InventoryItem *newitem)
InventoryItem *olditem = m_items[i];
m_items[i] = newitem;
m_diff.add(m_name,i,m_items[i]);
return olditem;
}
@ -546,6 +549,7 @@ void InventoryList::deleteItem(u32 i)
InventoryItem *item = changeItem(i, NULL);
if (item)
delete item;
m_diff.add(m_name,i,m_items[i]);
}
InventoryItem * InventoryList::addItem(InventoryItem *newitem)
@ -605,15 +609,18 @@ InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
newitem->remove(1);
m_items[i] = newitem->clone();
m_items[i]->setCount(1);
m_diff.add(m_name,i,m_items[i]);
return newitem;
}
m_items[i] = newitem;
m_diff.add(m_name,i,m_items[i]);
return to_item;
}
// If it is an empty position, it's an easy job.
if (to_item == NULL) {
m_items[i] = newitem;
m_diff.add(m_name,i,m_items[i]);
return NULL;
}
@ -624,6 +631,7 @@ InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
// If the item fits fully in the slot, add counter and delete it
if (newitem->getCount() <= to_item->freeSpace()) {
to_item->add(newitem->getCount());
m_diff.add(m_name,i,m_items[i]);
delete newitem;
return NULL;
}
@ -634,11 +642,37 @@ InventoryItem * InventoryList::addItem(u32 i, InventoryItem *newitem)
if (!freespace)
return newitem;
to_item->add(freespace);
m_diff.add(m_name,i,m_items[i]);
newitem->remove(freespace);
return newitem;
}
}
void InventoryList::updateItem(u32 i, content_t type, u16 wear_count)
{
if (type == CONTENT_IGNORE) {
if (m_items[i] != NULL)
delete m_items[i];
m_items[i] = NULL;
return;
}
if (m_items[i] != NULL) {
if (m_items[i]->getContent() == type) {
if (
(type&CONTENT_TOOLITEM_MASK) == CONTENT_TOOLITEM_MASK
|| (type&CONTENT_CLOTHESITEM_MASK) == CONTENT_CLOTHESITEM_MASK
) {
m_items[i]->setWear(wear_count);
}else{
m_items[i]->setCount(wear_count);
}
return;
}
delete m_items[i];
}
m_items[i] = InventoryItem::create(type,wear_count,wear_count);
}
bool InventoryList::itemFits(const u32 i, const InventoryItem *newitem)
{
// If it is an empty position, it's an easy job.
@ -659,18 +693,19 @@ bool InventoryList::itemFits(const u32 i, const InventoryItem *newitem)
bool InventoryList::roomForItem(const InventoryItem *item)
{
for(u32 i=0; i<m_items.size(); i++)
if(itemFits(i, item))
for (u32 i=0; i<m_items.size(); i++) {
if (itemFits(i, item))
return true;
}
return false;
}
bool InventoryList::roomForCookedItem(const InventoryItem *item)
{
if(!item)
if (!item)
return false;
const InventoryItem *cook = item->createCookResult();
if(!cook)
if (!cook)
return false;
bool room = roomForItem(cook);
delete cook;
@ -689,11 +724,14 @@ InventoryItem * InventoryList::takeItem(u32 i, u32 count)
if (count >= item->getCount()) {
// Get the item by swapping NULL to its place
return changeItem(i, NULL);
InventoryItem *item = changeItem(i, NULL);
m_diff.add(m_name,i,m_items[i]);
return item;
}else{
InventoryItem *item2 = item->clone();
item->remove(count);
item2->setCount(count);
m_diff.add(m_name,i,m_items[i]);
return item2;
}
@ -719,6 +757,7 @@ void InventoryList::decrementMaterials(u16 count)
InventoryItem *item = takeItem(i, count);
if (item)
delete item;
m_diff.add(m_name,i,m_items[i]);
}
}

View File

@ -519,6 +519,74 @@ private:
u16 m_wear;
};
class InventoryDiffData
{
public:
InventoryDiffData(u32 i, content_t t, u16 c):
index(i),
type(t),
wear_count(c)
{
}
InventoryDiffData():
index(0),
type(CONTENT_IGNORE),
wear_count(0)
{
}
u32 index;
content_t type;
u16 wear_count;
};
class InventoryDiff
{
public:
InventoryDiff()
{
clear();
}
~InventoryDiff()
{
clear();
}
void clear()
{
m_data.clear();
}
void add(std::string list, u32 index, content_t type, u16 count_wear)
{
m_data[list][index] = InventoryDiffData(index,type,count_wear);
}
void add(std::string list, u32 index, InventoryItem *item)
{
if (item == NULL) {
add(list,index,CONTENT_IGNORE,0);
}else if (
(item->getContent()&CONTENT_TOOLITEM_MASK) == CONTENT_TOOLITEM_MASK
|| (item->getContent()&CONTENT_CLOTHESITEM_MASK) == CONTENT_CLOTHESITEM_MASK
) {
add(list,index,item->getContent(),item->getWear());
}else{
add(list,index,item->getContent(),item->getCount());
}
}
void merge(InventoryDiff &other)
{
for (std::map<std::string,std::map<u32,InventoryDiffData> >::iterator i = other.m_data.begin(); i != other.m_data.end(); i++) {
m_data[i->first].swap(i->second);
i->second.clear();
}
}
std::map<std::string,std::map<u32,InventoryDiffData> > m_data;
};
class InventoryList
{
public:
@ -579,6 +647,9 @@ public:
// If can be added fully, NULL is returned.
InventoryItem * addItem(u32 i, InventoryItem *newitem);
// Updates item type/count/wear
void updateItem(u32 i, content_t type, u16 wear_count);
// Checks whether the item could be added to the given slot
bool itemFits(const u32 i, const InventoryItem *newitem);
@ -601,6 +672,9 @@ public:
void print(std::ostream &o);
void addDiff(u32 index, InventoryItem *item) {m_diff.add(m_name,index,item);}
InventoryDiff &getDiff() {return m_diff;}
private:
core::array<InventoryItem*> m_items;
u32 m_size;
@ -608,7 +682,7 @@ private:
std::map<content_t,bool> m_allowed;
std::map<content_t,bool> m_denied;
bool m_stackable;
//bool m_dirty;
InventoryDiff m_diff;
};
class Inventory
@ -634,16 +708,26 @@ public:
InventoryItem * addItem(const std::string &listname, InventoryItem *newitem)
{
InventoryList *list = getList(listname);
if(list == NULL)
if (list == NULL)
return newitem;
return list->addItem(newitem);
}
InventoryDiff &getDiff()
{
m_diff.clear();
for (u32 i=0; i<m_lists.size(); i++) {
InventoryDiff &diff = m_lists[i]->getDiff();
m_diff.merge(diff);
}
return m_diff;
}
private:
// -1 if not found
const s32 getListIndex(const std::string &name) const;
core::array<InventoryList*> m_lists;
InventoryDiff m_diff;
};
class Player;

View File

@ -2024,7 +2024,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Send inventory to player
UpdateCrafting(peer_id);
SendInventory(peer_id);
SendInventory(peer_id,true);
// Send player items to all players
SendPlayerItems();
@ -2151,15 +2151,17 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
thrown = content_craftitem_features(item->getContent()).shot_item;
if (thrown == CONTENT_IGNORE)
return;
item_i = i;
if (g_settings->getBool("tool_wear")) {
bool weared_out = titem->addWear(1000);
if (weared_out) {
InventoryList *mlist = player->inventory.getList("main");
mlist->deleteItem(item_i);
}else{
ilist->addDiff(item_i,titem);
}
SendInventory(player->peer_id);
}
item_i = i;
}
if (g_settings->getBool("droppable_inventory") == false || (getPlayerPrivs(player) & PRIV_BUILD) == 0) {
@ -2403,8 +2405,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
if (titem && g_settings->getBool("tool_wear")) {
if (titem->addWear(wear))
if (titem->addWear(wear)) {
mlist->deleteItem(item_i);
}else{
mlist->addDiff(item_i,titem);
}
SendInventory(player->peer_id);
}
}
@ -2550,9 +2555,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
ToolItem *titem = (ToolItem*)wield;
if ((getPlayerPrivs(player) & PRIV_SERVER) == 0 && g_settings->getBool("tool_wear")) {
bool weared_out = titem->addWear(10000);
InventoryList *mlist = player->inventory.getList("main");
if (weared_out) {
InventoryList *mlist = player->inventory.getList("main");
mlist->deleteItem(item_i);
}else{
mlist->addDiff(item_i,titem);
}
SendInventory(player->peer_id);
}
@ -2792,9 +2799,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
ToolItem *titem = (ToolItem*)wield;
if (g_settings->getBool("tool_wear")) {
bool weared_out = titem->addWear(1000);
InventoryList *mlist = player->inventory.getList("main");
if (weared_out) {
InventoryList *mlist = player->inventory.getList("main");
mlist->deleteItem(item_i);
}else{
mlist->addDiff(item_i,titem);
}
SendInventory(player->peer_id);
}
@ -2826,9 +2835,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
ToolItem *titem = (ToolItem*)wield;
if (g_settings->getBool("tool_wear")) {
bool weared_out = titem->addWear(1000);
InventoryList *mlist = player->inventory.getList("main");
if (weared_out) {
InventoryList *mlist = player->inventory.getList("main");
mlist->deleteItem(item_i);
}else{
mlist->addDiff(item_i,titem);
}
SendInventory(player->peer_id);
}
@ -2943,9 +2954,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
ToolItem *titem = (ToolItem*)wield;
if (g_settings->getBool("tool_wear")) {
bool weared_out = titem->addWear(200);
InventoryList *mlist = player->inventory.getList("main");
if (weared_out) {
InventoryList *mlist = player->inventory.getList("main");
mlist->deleteItem(item_i);
}else{
mlist->addDiff(item_i,titem);
}
SendInventory(player->peer_id);
}
@ -2993,6 +3006,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
ilist->deleteItem(item_i);
}else{
wield->remove(1);
ilist->addDiff(item_i,wield);
}
// Send inventory
UpdateCrafting(peer_id);
@ -3557,7 +3571,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
std::string dug_s = std::string("ToolItem ") + tool->getToolName() + "_water 1";
std::istringstream is(dug_s, std::ios::binary);
item = InventoryItem::deSerialize(is);
mlist->changeItem(item_i,item);
InventoryItem *ritem = mlist->changeItem(item_i,item);
if (ritem)
delete ritem;
item = NULL;
UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
@ -3592,14 +3608,16 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
{
u16 peer_id = *i;
RemoteClient *client = getClient(peer_id);
if(client==NULL)
if (client==NULL)
continue;
client->SetBlocksNotSent(modified_blocks);
}
std::string dug_s = std::string("ToolItem ") + tool->getToolName() + "_water 1";
std::istringstream is(dug_s, std::ios::binary);
item = InventoryItem::deSerialize(is);
mlist->changeItem(item_i,item);
InventoryItem *ritem = mlist->changeItem(item_i,item);
if (ritem)
delete ritem;
item = NULL;
UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
@ -3618,7 +3636,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
std::string dug_s = std::string("ToolItem ") + tool->getToolName() + "_lava 1";
std::istringstream is(dug_s, std::ios::binary);
item = InventoryItem::deSerialize(is);
mlist->changeItem(item_i,item);
InventoryItem *ritem = mlist->changeItem(item_i,item);
if (ritem)
delete ritem;
item = NULL;
}
UpdateCrafting(player->peer_id);
@ -3675,13 +3695,13 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
&& material != CONTENT_WATER
&& material != CONTENT_LAVA
) {
bool dosend = false;
if (item != NULL) {
// Add a item to inventory
player->inventory.addItem("main", item);
// Send inventory
UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
dosend = true;
}
item = NULL;
@ -3704,6 +3724,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
player->inventory.addItem("main", item);
// Send inventory
dosend = true;
}
if (dosend) {
UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
}
@ -4028,10 +4051,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
InventoryList *ilist = player->inventory.getList("main");
if(g_settings->getBool("infinite_inventory") == false && ilist) {
// Remove from inventory and send inventory
if (mitem->getCount() == 1)
if (mitem->getCount() == 1) {
ilist->deleteItem(item_i);
else
}else{
mitem->remove(1);
ilist->addDiff(item_i,mitem);
}
// Send inventory
UpdateCrafting(peer_id);
SendInventory(peer_id);
@ -4233,12 +4258,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if (g_settings->getBool("infinite_inventory") == false) {
// Delete the right amount of items from the slot
u16 dropcount = item->getDropCount();
InventoryList *ilist = player->inventory.getList("main");
// Delete item if all gone
if (item->getCount() <= dropcount) {
if (item->getCount() < dropcount)
infostream<<"WARNING: Server: dropped more items"
<<" than the slot contains"<<std::endl;
InventoryList *ilist = player->inventory.getList("main");
// Remove from inventory and send inventory
if (ilist)
ilist->deleteItem(item_i);
@ -4246,6 +4271,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Else decrement it
else{
item->remove(dropcount);
ilist->addDiff(item_i,item);
}
// Send inventory
UpdateCrafting(peer_id);
@ -4287,6 +4313,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if (g_settings->getBool("infinite_inventory") == false) {
// Delete the right amount of items from the slot
u16 dropcount = item->getDropCount();
InventoryList *ilist = player->inventory.getList("main");
// Delete item if all gone
if (item->getCount() <= dropcount) {
@ -4294,12 +4321,12 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
infostream<<"WARNING: Server: dropped more items"
<<" than the slot contains"<<std::endl;
InventoryList *ilist = player->inventory.getList("main");
if (ilist)
// Remove from inventory and send inventory
ilist->deleteItem(item_i);
}else{
item->remove(dropcount);
ilist->addDiff(item_i,item);
}
// Send inventory
@ -4368,6 +4395,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
if (g_settings->getBool("infinite_inventory") == false) {
// Delete the right amount of items from the slot
u16 dropcount = item->getDropCount();
InventoryList *ilist = player->inventory.getList("main");
// Delete item if all gone
if (item->getCount() <= dropcount) {
@ -4375,7 +4403,6 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
infostream<<"WARNING: Server: dropped more items"
<<" than the slot contains"<<std::endl;
InventoryList *ilist = player->inventory.getList("main");
if(ilist)
// Remove from inventory and send inventory
ilist->deleteItem(item_i);
@ -4383,6 +4410,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
// Else decrement it
else{
item->remove(dropcount);
ilist->addDiff(item_i,item);
}
// Send inventory
@ -4482,8 +4510,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
fw /= bonus;
w = fw;
}
if (i->addWear(w))
if (i->addWear(w)) {
l->deleteItem(0);
}else{
l->addDiff(0,i);
}
}
SendInventory(player->peer_id);
return;
@ -4652,7 +4683,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
dir.rotateXZBy(player->getYaw());
pos += dir;
ServerActiveObject *obj = item->createSAO(&m_env,0,pos);
m_env.addActiveObject(obj);
if (obj)
m_env.addActiveObject(obj);
}
if (g_settings->getBool("infinite_inventory") == false) {
list->deleteItem(0);
@ -4662,9 +4694,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
}
// Eat the action
delete a;
}
else
{
}else{
// Send inventory
UpdateCrafting(player->peer_id);
SendInventory(player->peer_id);
@ -5017,8 +5047,7 @@ void Server::inventoryModified(InventoryContext *c, std::string id)
Strfnd fn(id);
std::string id0 = fn.next(":");
if(id0 == "nodemeta")
{
if (id0 == "nodemeta") {
v3s16 p;
p.X = mystoi(fn.next(","));
p.Y = mystoi(fn.next(","));
@ -5026,15 +5055,14 @@ void Server::inventoryModified(InventoryContext *c, std::string id)
v3s16 blockpos = getNodeBlockPos(p);
NodeMetadata *meta = m_env.getMap().getNodeMetadata(p);
if(meta)
if (meta)
meta->inventoryModified();
MapBlock *block = m_env.getMap().getBlockNoCreateNoEx(blockpos);
if(block)
if (block)
block->raiseModified(MOD_STATE_WRITE_NEEDED);
setBlockNotSent(blockpos);
return;
}
@ -5222,29 +5250,59 @@ void Server::SendPlayerInfos()
m_con.SendToAll(0, data, true);
}
void Server::SendInventory(u16 peer_id)
void Server::SendInventory(u16 peer_id, bool full)
{
DSTACK(__FUNCTION_NAME);
Player* player = m_env.getPlayer(peer_id);
assert(player);
/*
Serialize it
*/
// get also clears, so get diff for full and partial sends
InventoryDiff idiff = player->inventory.getDiff();
std::ostringstream os;
if (full) {
/*
Serialize it
*/
player->inventory.serialize(os);
std::ostringstream os(std::ios_base::binary);
std::string s = os.str();
writeU16(os,TOCLIENT_INVENTORY);
player->inventory.serialize(os);
SharedBuffer<u8> data(s.size()+2);
writeU16(&data[0], TOCLIENT_INVENTORY);
memcpy(&data[2], s.c_str(), s.size());
// 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);
// Send as reliable
m_con.Send(peer_id, 0, data, true);
return;
}
{
if (idiff.m_data.size() == 0)
return;
std::ostringstream os(std::ios_base::binary);
writeU16(os, TOCLIENT_INVENTORY_UPDATE);
writeU16(os, idiff.m_data.size());
for (std::map<std::string,std::map<u32,InventoryDiffData> >::iterator l = idiff.m_data.begin(); l != idiff.m_data.end(); l++) {
os<<serializeString(l->first);
writeU16(os,l->second.size());
for (std::map<u32,InventoryDiffData>::iterator i = l->second.begin(); i != l->second.end(); i++) {
writeU16(os,i->second.index);
writeU16(os,i->second.type);
writeU16(os,i->second.wear_count);
}
}
// 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);
}
}
std::string getWieldedItemString(const Player *player)
@ -5842,15 +5900,12 @@ void Server::UpdateCrafting(u16 peer_id)
if(rlist && rlist->getUsedSlots() == 0)
player->craftresult_is_preview = true;
if(rlist && player->craftresult_is_preview)
{
if (rlist && player->craftresult_is_preview) {
rlist->clearItems();
}
if(clist && rlist && player->craftresult_is_preview)
{
if (clist && rlist && player->craftresult_is_preview) {
InventoryItem *items[9];
for(u16 i=0; i<9; i++)
{
for (u16 i=0; i<9; i++) {
items[i] = clist->getItem(i);
}

View File

@ -533,7 +533,7 @@ private:
// Envlock and conlock should be locked when calling these
void SendObjectData(float dtime);
void SendPlayerInfos();
void SendInventory(u16 peer_id);
void SendInventory(u16 peer_id, bool full=false);
// send animation info about player to all
void SendPlayerAnim(const Player *player, u8 animation_id);
// send wielded item info about all players to all players