aboutsummaryrefslogtreecommitdiff
path: root/src/inventory.cpp
diff options
context:
space:
mode:
authorSmallJoker <SmallJoker@users.noreply.github.com>2019-08-24 19:07:38 +0200
committerGitHub <noreply@github.com>2019-08-24 19:07:38 +0200
commit0b4f424f414380b7a46270e1389e8aa0524d8fba (patch)
tree5731cbe72bb3178d697b3cda43b838f26ba34f7d /src/inventory.cpp
parent008b80fe1ca9d46610b8971e2ac92fb56da8e69f (diff)
downloadhax-minetest-server-0b4f424f414380b7a46270e1389e8aa0524d8fba.tar.gz
hax-minetest-server-0b4f424f414380b7a46270e1389e8aa0524d8fba.zip
Inventory: Send dirty lists where appropriate (#8742)
This change reduces the amount of sent data towards clients. Inventory lists that are already known to the player are skipped, saving quite some data over time. Raises protocol version to 38 to ensure correct backwards-compatible code.
Diffstat (limited to 'src/inventory.cpp')
-rw-r--r--src/inventory.cpp114
1 files changed, 73 insertions, 41 deletions
diff --git a/src/inventory.cpp b/src/inventory.cpp
index f2cc2ede3..375f0f147 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "inventory.h"
#include "serialization.h"
#include "debug.h"
+#include <algorithm>
#include <sstream>
#include "log.h"
#include "itemdef.h"
@@ -382,27 +383,32 @@ void InventoryList::clearItems()
m_items.emplace_back();
}
- //setDirty(true);
+ setModified();
}
void InventoryList::setSize(u32 newsize)
{
- if(newsize != m_items.size())
- m_items.resize(newsize);
+ if (newsize == m_items.size())
+ return;
+
+ m_items.resize(newsize);
m_size = newsize;
+ setModified();
}
void InventoryList::setWidth(u32 newwidth)
{
m_width = newwidth;
+ setModified();
}
void InventoryList::setName(const std::string &name)
{
m_name = name;
+ setModified();
}
-void InventoryList::serialize(std::ostream &os) const
+void InventoryList::serialize(std::ostream &os, bool incremental) const
{
//os.imbue(std::locale("C"));
@@ -415,6 +421,9 @@ void InventoryList::serialize(std::ostream &os) const
os<<"Item ";
item.serialize(os);
}
+ // TODO: Implement this:
+ // if (!incremental || item.checkModified())
+ // os << "Keep";
os<<"\n";
}
@@ -424,8 +433,8 @@ void InventoryList::serialize(std::ostream &os) const
void InventoryList::deSerialize(std::istream &is)
{
//is.imbue(std::locale("C"));
+ setModified();
- clearItems();
u32 item_i = 0;
m_width = 0;
@@ -439,12 +448,12 @@ void InventoryList::deSerialize(std::istream &is)
std::string name;
std::getline(iss, name, ' ');
- if (name == "EndInventoryList")
- return;
-
- // This is a temporary backwards compatibility fix
- if (name == "end")
+ if (name == "EndInventoryList" || name == "end") {
+ // If partial incremental: Clear leftover items (should not happen!)
+ for (size_t i = item_i; i < m_items.size(); ++i)
+ m_items[i].clear();
return;
+ }
if (name == "Width") {
iss >> m_width;
@@ -464,6 +473,8 @@ void InventoryList::deSerialize(std::istream &is)
if(item_i > getSize() - 1)
throw SerializationError("too many items");
m_items[item_i++].clear();
+ } else if (name == "Keep") {
+ ++item_i; // Unmodified item
}
}
@@ -557,7 +568,7 @@ ItemStack InventoryList::changeItem(u32 i, const ItemStack &newitem)
ItemStack olditem = m_items[i];
m_items[i] = newitem;
- //setDirty(true);
+ setModified();
return olditem;
}
@@ -565,6 +576,7 @@ void InventoryList::deleteItem(u32 i)
{
assert(i < m_items.size()); // Pre-condition
m_items[i].clear();
+ setModified();
}
ItemStack InventoryList::addItem(const ItemStack &newitem_)
@@ -612,8 +624,8 @@ ItemStack InventoryList::addItem(u32 i, const ItemStack &newitem)
return newitem;
ItemStack leftover = m_items[i].addItem(newitem, m_itemdef);
- //if(leftover != newitem)
- // setDirty(true);
+ if (leftover != newitem)
+ setModified();
return leftover;
}
@@ -682,8 +694,8 @@ ItemStack InventoryList::takeItem(u32 i, u32 takecount)
return ItemStack();
ItemStack taken = m_items[i].takeItem(takecount);
- //if(!taken.empty())
- // setDirty(true);
+ if (!taken.empty())
+ setModified();
return taken;
}
@@ -788,16 +800,6 @@ void Inventory::clear()
m_lists.clear();
}
-void Inventory::clearContents()
-{
- m_dirty = true;
- for (InventoryList *list : m_lists) {
- for (u32 j=0; j<list->getSize(); j++) {
- list->deleteItem(j);
- }
- }
-}
-
Inventory::Inventory(IItemDefManager *itemdef)
{
m_dirty = false;
@@ -807,7 +809,6 @@ Inventory::Inventory(IItemDefManager *itemdef)
Inventory::Inventory(const Inventory &other)
{
*this = other;
- m_dirty = false;
}
Inventory & Inventory::operator = (const Inventory &other)
@@ -838,11 +839,15 @@ bool Inventory::operator == (const Inventory &other) const
return true;
}
-void Inventory::serialize(std::ostream &os) const
+void Inventory::serialize(std::ostream &os, bool incremental) const
{
- for (InventoryList *list : m_lists) {
- os<<"List "<<list->getName()<<" "<<list->getSize()<<"\n";
- list->serialize(os);
+ for (const InventoryList *list : m_lists) {
+ if (!incremental || list->checkModified()) {
+ os << "List " << list->getName() << " " << list->getSize() << "\n";
+ list->serialize(os, incremental);
+ } else {
+ os << "KeepList " << list->getName() << "\n";
+ }
}
os<<"EndInventory\n";
@@ -850,7 +855,8 @@ void Inventory::serialize(std::ostream &os) const
void Inventory::deSerialize(std::istream &is)
{
- clear();
+ std::vector<InventoryList *> new_lists;
+ new_lists.reserve(m_lists.size());
while (is.good()) {
std::string line;
@@ -861,12 +867,20 @@ void Inventory::deSerialize(std::istream &is)
std::string name;
std::getline(iss, name, ' ');
- if (name == "EndInventory")
- return;
+ if (name == "EndInventory" || name == "end") {
+ // Remove all lists that were not sent
+ for (auto &list : m_lists) {
+ if (std::find(new_lists.begin(), new_lists.end(), list) != new_lists.end())
+ continue;
- // This is a temporary backwards compatibility fix
- if (name == "end")
+ delete list;
+ list = nullptr;
+ m_dirty = true;
+ }
+ m_lists.erase(std::remove(m_lists.begin(), m_lists.end(),
+ nullptr), m_lists.end());
return;
+ }
if (name == "List") {
std::string listname;
@@ -875,15 +889,33 @@ void Inventory::deSerialize(std::istream &is)
std::getline(iss, listname, ' ');
iss>>listsize;
- InventoryList *list = new InventoryList(listname, listsize, m_itemdef);
+ InventoryList *list = getList(listname);
+ bool create_new = !list;
+ if (create_new)
+ list = new InventoryList(listname, listsize, m_itemdef);
+ else
+ list->setSize(listsize);
list->deSerialize(is);
- m_lists.push_back(list);
- }
- else
- {
- throw SerializationError("invalid inventory specifier: " + name);
+ new_lists.push_back(list);
+ if (create_new)
+ m_lists.push_back(list);
+
+ } else if (name == "KeepList") {
+ // Incrementally sent list
+ std::string listname;
+ std::getline(iss, listname, ' ');
+
+ InventoryList *list = getList(listname);
+ if (list) {
+ new_lists.push_back(list);
+ } else {
+ errorstream << "Inventory::deSerialize(): Tried to keep list '" <<
+ listname << "' which is non-existent." << std::endl;
+ }
}
+ // Any additional fields will throw errors when received by a client
+ // older than PROTOCOL_VERSION 38
}
// Contents given to deSerialize() were not terminated properly: throw error.