summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client.h3
-rw-r--r--src/guiFormSpecMenu.cpp55
-rw-r--r--src/inventory.cpp47
-rw-r--r--src/inventory.h8
-rw-r--r--src/inventorymanager.cpp96
-rw-r--r--src/inventorymanager.h31
6 files changed, 180 insertions, 60 deletions
diff --git a/src/client.h b/src/client.h
index 56f040909..daeef3985 100644
--- a/src/client.h
+++ b/src/client.h
@@ -493,6 +493,9 @@ public:
bool mediaReceived()
{ return m_media_downloader == NULL; }
+ u8 getProtoVersion()
+ { return m_proto_ver; }
+
float mediaReceiveProgress();
void afterContentReceived(IrrlichtDevice *device);
diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp
index c11fc303a..f16830619 100644
--- a/src/guiFormSpecMenu.cpp
+++ b/src/guiFormSpecMenu.cpp
@@ -3384,31 +3384,42 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
break;
ItemStack stack_from = list_from->getItem(s.i);
assert(shift_move_amount <= stack_from.count);
-
- // find a place (or more than one) to add the new item
- u32 ilt_size = list_to->getSize();
- ItemStack leftover;
- for (u32 slot_to = 0; slot_to < ilt_size
- && shift_move_amount > 0; slot_to++) {
- list_to->itemFits(slot_to, stack_from, &leftover);
- if (leftover.count < stack_from.count) {
- infostream << "Handing IACTION_MOVE to manager" << std::endl;
- IMoveAction *a = new IMoveAction();
- a->count = MYMIN(shift_move_amount,
- (u32) (stack_from.count - leftover.count));
- shift_move_amount -= a->count;
- a->from_inv = s.inventoryloc;
- a->from_list = s.listname;
- a->from_i = s.i;
- a->to_inv = to_inv_sp.inventoryloc;
- a->to_list = to_inv_sp.listname;
- a->to_i = slot_to;
- m_invmgr->inventoryAction(a);
- stack_from = leftover;
+ if (m_client->getProtoVersion() >= 25) {
+ infostream << "Handing IACTION_MOVE to manager" << std::endl;
+ IMoveAction *a = new IMoveAction();
+ a->count = shift_move_amount;
+ a->from_inv = s.inventoryloc;
+ a->from_list = s.listname;
+ a->from_i = s.i;
+ a->to_inv = to_inv_sp.inventoryloc;
+ a->to_list = to_inv_sp.listname;
+ a->move_somewhere = true;
+ m_invmgr->inventoryAction(a);
+ } else {
+ // find a place (or more than one) to add the new item
+ u32 ilt_size = list_to->getSize();
+ ItemStack leftover;
+ for (u32 slot_to = 0; slot_to < ilt_size
+ && shift_move_amount > 0; slot_to++) {
+ list_to->itemFits(slot_to, stack_from, &leftover);
+ if (leftover.count < stack_from.count) {
+ infostream << "Handing IACTION_MOVE to manager" << std::endl;
+ IMoveAction *a = new IMoveAction();
+ a->count = MYMIN(shift_move_amount,
+ (u32) (stack_from.count - leftover.count));
+ shift_move_amount -= a->count;
+ a->from_inv = s.inventoryloc;
+ a->from_list = s.listname;
+ a->from_i = s.i;
+ a->to_inv = to_inv_sp.inventoryloc;
+ a->to_list = to_inv_sp.listname;
+ a->to_i = slot_to;
+ m_invmgr->inventoryAction(a);
+ stack_from = leftover;
+ }
}
}
} while (0);
-
} else if (drop_amount > 0) {
m_selected_content_guess = ItemStack(); // Clear
diff --git a/src/inventory.cpp b/src/inventory.cpp
index 7941b3a2a..ff2c15b65 100644
--- a/src/inventory.cpp
+++ b/src/inventory.cpp
@@ -782,11 +782,48 @@ ItemStack InventoryList::peekItem(u32 i, u32 peekcount) const
return m_items[i].peekItem(peekcount);
}
-void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
+void InventoryList::moveItemSomewhere(u32 i, InventoryList *dest, u32 count)
{
- if(this == dest && i == dest_i)
+ // Take item from source list
+ ItemStack item1;
+ if (count == 0)
+ item1 = changeItem(i, ItemStack());
+ else
+ item1 = takeItem(i, count);
+
+ if (item1.empty())
return;
+ // Try to add the item to destination list
+ u32 oldcount = item1.count;
+ u32 dest_size = dest->getSize();
+ // First try all the non-empty slots
+ for (u32 dest_i = 0; dest_i < dest_size; dest_i++) {
+ if (!m_items[dest_i].empty()) {
+ item1 = dest->addItem(dest_i, item1);
+ if (item1.empty()) return;
+ }
+ }
+
+ // Then try all the empty ones
+ for (u32 dest_i = 0; dest_i < dest_size; dest_i++) {
+ if (m_items[dest_i].empty()) {
+ item1 = dest->addItem(dest_i, item1);
+ if (item1.empty()) return;
+ }
+ }
+
+ // If we reach this, the item was not fully added
+ // Add the remaining part back to the source item
+ addItem(i, item1);
+}
+
+u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i,
+ u32 count, bool swap_if_needed)
+{
+ if(this == dest && i == dest_i)
+ return count;
+
// Take item from source list
ItemStack item1;
if(count == 0)
@@ -795,7 +832,7 @@ void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
item1 = takeItem(i, count);
if(item1.empty())
- return;
+ return 0;
// Try to add the item to destination list
u32 oldcount = item1.count;
@@ -813,8 +850,7 @@ void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
// If olditem is returned, nothing was added.
// Swap the items
- if(nothing_added)
- {
+ if (nothing_added && swap_if_needed) {
// Take item from source list
item1 = changeItem(i, ItemStack());
// Adding was not possible, swap the items.
@@ -823,6 +859,7 @@ void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
changeItem(i, item2);
}
}
+ return (oldcount - item1.count);
}
/*
diff --git a/src/inventory.h b/src/inventory.h
index faaa5ef95..e3c994fc3 100644
--- a/src/inventory.h
+++ b/src/inventory.h
@@ -244,7 +244,13 @@ public:
// Move an item to a different list (or a different stack in the same list)
// count is the maximum number of items to move (0 for everything)
- void moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count = 0);
+ // returns number of moved items
+ u32 moveItem(u32 i, InventoryList *dest, u32 dest_i,
+ u32 count = 0, bool swap_if_needed = true);
+
+ // like moveItem, but without a fixed destination index
+ // also with optional rollback recording
+ void moveItemSomewhere(u32 i, InventoryList *dest, u32 count);
private:
std::vector<ItemStack> m_items;
diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp
index 640e3395b..96ce48086 100644
--- a/src/inventorymanager.cpp
+++ b/src/inventorymanager.cpp
@@ -121,16 +121,13 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
InventoryAction *a = NULL;
- if(type == "Move")
- {
- a = new IMoveAction(is);
- }
- else if(type == "Drop")
- {
+ if (type == "Move") {
+ a = new IMoveAction(is, false);
+ } else if (type == "MoveSomewhere") {
+ a = new IMoveAction(is, true);
+ } else if (type == "Drop") {
a = new IDropAction(is);
- }
- else if(type == "Craft")
- {
+ } else if(type == "Craft") {
a = new ICraftAction(is);
}
@@ -141,9 +138,12 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
IMoveAction
*/
-IMoveAction::IMoveAction(std::istream &is)
+IMoveAction::IMoveAction(std::istream &is, bool somewhere)
{
std::string ts;
+ move_somewhere = somewhere;
+ caused_by_move_somewhere = false;
+ move_count = 0;
std::getline(is, ts, ' ');
count = stoi(ts);
@@ -161,8 +161,10 @@ IMoveAction::IMoveAction(std::istream &is)
std::getline(is, to_list, ' ');
- std::getline(is, ts, ' ');
- to_i = stoi(ts);
+ if (!somewhere) {
+ std::getline(is, ts, ' ');
+ to_i = stoi(ts);
+ }
}
void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
@@ -202,6 +204,48 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
return;
}
+ if (move_somewhere) {
+ s16 old_to_i = to_i;
+ u16 old_count = count;
+ caused_by_move_somewhere = true;
+ move_somewhere = false;
+
+ infostream << "IMoveAction::apply(): moving item somewhere"
+ << " msom=" << move_somewhere
+ << " count=" << count
+ << " from inv=\"" << from_inv.dump() << "\""
+ << " list=\"" << from_list << "\""
+ << " i=" << from_i
+ << " to inv=\"" << to_inv.dump() << "\""
+ << " list=\"" << to_list << "\""
+ << std::endl;
+
+ // Try to add the item to destination list
+ s16 dest_size = list_to->getSize();
+ // First try all the non-empty slots
+ for (s16 dest_i = 0; dest_i < dest_size && count > 0; dest_i++) {
+ if (!list_to->getItem(dest_i).empty()) {
+ to_i = dest_i;
+ apply(mgr, player, gamedef);
+ count -= move_count;
+ }
+ }
+
+ // Then try all the empty ones
+ for (s16 dest_i = 0; dest_i < dest_size && count > 0; dest_i++) {
+ if (list_to->getItem(dest_i).empty()) {
+ to_i = dest_i;
+ apply(mgr, player, gamedef);
+ count -= move_count;
+ }
+ }
+
+ to_i = old_to_i;
+ count = old_count;
+ caused_by_move_somewhere = false;
+ move_somewhere = true;
+ return;
+ }
/*
Do not handle rollback if both inventories are that of the same player
*/
@@ -324,7 +368,8 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
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);
+ move_count = list_from->moveItem(from_i,
+ list_to, to_i, count, !caused_by_move_somewhere);
// If source is infinite, reset it's stack
if(src_can_take_count == -1){
@@ -352,15 +397,17 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
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;
+ infostream << "IMoveAction::apply(): moved"
+ << " msom=" << move_somewhere
+ << " caused=" << caused_by_move_somewhere
+ << " 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;
/*
Record rollback information
@@ -480,7 +527,10 @@ void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
if(!list_from || !list_to)
return;
- list_from->moveItem(from_i, list_to, to_i, count);
+ if (!move_somewhere)
+ list_from->moveItem(from_i, list_to, to_i, count);
+ else
+ list_from->moveItemSomewhere(from_i, list_to, count);
mgr->setInventoryModified(from_inv);
if(inv_from != inv_to)
diff --git a/src/inventorymanager.h b/src/inventorymanager.h
index a255e979a..bbeb5117c 100644
--- a/src/inventorymanager.h
+++ b/src/inventorymanager.h
@@ -143,15 +143,24 @@ struct IMoveAction : public InventoryAction
InventoryLocation to_inv;
std::string to_list;
s16 to_i;
+ bool move_somewhere;
+
+ // treat these as private
+ // related to movement to somewhere
+ bool caused_by_move_somewhere;
+ u32 move_count;
IMoveAction()
{
count = 0;
from_i = -1;
to_i = -1;
+ move_somewhere = false;
+ caused_by_move_somewhere = false;
+ move_count = 0;
}
- IMoveAction(std::istream &is);
+ IMoveAction(std::istream &is, bool somewhere);
u16 getType() const
{
@@ -160,14 +169,18 @@ struct IMoveAction : public InventoryAction
void serialize(std::ostream &os) const
{
- os<<"Move ";
- os<<count<<" ";
- os<<from_inv.dump()<<" ";
- os<<from_list<<" ";
- os<<from_i<<" ";
- os<<to_inv.dump()<<" ";
- os<<to_list<<" ";
- os<<to_i;
+ if (!move_somewhere)
+ os << "Move ";
+ else
+ os << "MoveSomewhere ";
+ os << count << " ";
+ os << from_inv.dump() << " ";
+ os << from_list << " ";
+ os << from_i << " ";
+ os << to_inv.dump() << " ";
+ os << to_list;
+ if (!move_somewhere)
+ os << " " << to_i;
}
void apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef);