diff options
author | Perttu Ahola <celeron55@gmail.com> | 2012-09-02 22:51:38 +0300 |
---|---|---|
committer | Perttu Ahola <celeron55@gmail.com> | 2012-09-02 22:51:38 +0300 |
commit | e1a495ee306290b3bec2de9aa298aac1528e9243 (patch) | |
tree | 352db0aedb58fa4a26790227c388d0773f05279f | |
parent | 6495007924d8907ddfff14be09d38a4b1745b95a (diff) | |
download | minetest-e1a495ee306290b3bec2de9aa298aac1528e9243.tar.gz minetest-e1a495ee306290b3bec2de9aa298aac1528e9243.tar.bz2 minetest-e1a495ee306290b3bec2de9aa298aac1528e9243.zip |
Make inventory GUI do sane things when server-side inventory acts unusually
-rw-r--r-- | src/guiFormSpecMenu.cpp | 68 | ||||
-rw-r--r-- | src/guiFormSpecMenu.h | 6 | ||||
-rw-r--r-- | src/inventorymanager.cpp | 12 | ||||
-rw-r--r-- | src/inventorymanager.h | 23 |
4 files changed, 105 insertions, 4 deletions
diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index 41ec0f3da..ed44e441b 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -733,6 +733,54 @@ void GUIFormSpecMenu::drawMenu() void GUIFormSpecMenu::updateSelectedItem() { + // WARNING: BLACK MAGIC + // See if there is a stack suited for our current guess. + // If such stack does not exist, clear the guess. + if(m_selected_content_guess.name != "") + { + bool found = false; + for(u32 i=0; i<m_inventorylists.size() && !found; i++){ + const ListDrawSpec &s = m_inventorylists[i]; + Inventory *inv = m_invmgr->getInventory(s.inventoryloc); + if(!inv) + continue; + InventoryList *list = inv->getList(s.listname); + if(!list) + continue; + for(s32 i=0; i<s.geom.X*s.geom.Y && !found; i++){ + u32 item_i = i + s.start_item_i; + if(item_i >= list->getSize()) + continue; + ItemStack stack = list->getItem(item_i); + if(stack.name == m_selected_content_guess.name && + stack.count == m_selected_content_guess.count){ + found = true; + if(m_selected_item){ + // If guessed stack is already selected, all is fine + if(m_selected_item->inventoryloc == s.inventoryloc && + m_selected_item->listname == s.listname && + m_selected_item->i == (s32)item_i && + m_selected_amount == stack.count){ + break; + } + delete m_selected_item; + m_selected_item = NULL; + } + infostream<<"Client: Changing selected content guess to " + <<s.inventoryloc.dump()<<" "<<s.listname + <<" "<<item_i<<std::endl; + m_selected_item = new ItemSpec(s.inventoryloc, s.listname, item_i); + m_selected_amount = stack.count; + break; + } + } + } + if(!found){ + infostream<<"Client: Discarding selected content guess: " + <<m_selected_content_guess.getItemString()<<std::endl; + m_selected_content_guess.name = ""; + } + } // If the selected stack has become empty for some reason, deselect it. // If the selected stack has become smaller, adjust m_selected_amount. if(m_selected_item) @@ -1054,21 +1102,28 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) // Check how many items can be moved move_amount = stack_from.count = MYMIN(move_amount, stack_from.count); ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef()); - if(leftover.count == stack_from.count) + // If source stack cannot be added to destination stack at all, + // they are swapped + if(leftover.count == stack_from.count && leftover.name == stack_from.name) { - // Swap the stacks m_selected_amount = stack_to.count; + // In case the server doesn't directly swap them but instead + // moves stack_to somewhere else, set this + m_selected_content_guess = stack_to; + m_selected_content_guess_inventory = s.inventoryloc; } + // Source stack goes fully into destination stack else if(leftover.empty()) { - // Item fits m_selected_amount -= move_amount; + m_selected_content_guess = ItemStack(); // Clear } + // Source stack goes partly into destination stack else { - // Item only fits partially move_amount -= leftover.count; m_selected_amount -= move_amount; + m_selected_content_guess = ItemStack(); // Clear } infostream<<"Handing IACTION_MOVE to manager"<<std::endl; @@ -1084,6 +1139,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) } else if(drop_amount > 0) { + m_selected_content_guess = ItemStack(); // Clear + // Send IACTION_DROP assert(m_selected_item && m_selected_item->isValid()); @@ -1107,6 +1164,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) } else if(craft_amount > 0) { + m_selected_content_guess = ItemStack(); // Clear + // Send IACTION_CRAFT assert(s.isValid()); @@ -1126,6 +1185,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) m_selected_item = NULL; m_selected_amount = 0; m_selected_dragging = false; + m_selected_content_guess = ItemStack(); } } if(event.EventType==EET_GUI_EVENT) diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index f0a5988e9..5c01bdcd2 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -212,6 +212,12 @@ protected: ItemSpec *m_selected_item; u32 m_selected_amount; bool m_selected_dragging; + + // WARNING: BLACK MAGIC + // Used to guess and keep up with some special things the server can do. + // If name is "", no guess exists. + ItemStack m_selected_content_guess; + InventoryLocation m_selected_content_guess_inventory; v2s32 m_pointer; gui::IGUIStaticText *m_tooltip_element; diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp index e2e537838..1a7f56f31 100644 --- a/src/inventorymanager.cpp +++ b/src/inventorymanager.cpp @@ -332,6 +332,18 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame // If source is infinite, reset it's stack if(src_can_take_count == -1){ + // If destination stack is of different type and there are leftover + // items, attempt to put the leftover items to a different place in the + // destination inventory. + // The client-side GUI will try to guess if this happens. + if(from_stack_was.name != to_stack_was.name){ + for(u32 i=0; i<list_to->getSize(); i++){ + if(list_to->getItem(i).empty()){ + list_to->changeItem(i, to_stack_was); + break; + } + } + } list_from->deleteItem(from_i); list_from->addItem(from_i, from_stack_was); } diff --git a/src/inventorymanager.h b/src/inventorymanager.h index dae14f1a6..f81f5b972 100644 --- a/src/inventorymanager.h +++ b/src/inventorymanager.h @@ -66,6 +66,29 @@ struct InventoryLocation name = name_; } + bool operator==(const InventoryLocation &other) const + { + if(type != other.type) + return false; + switch(type){ + case UNDEFINED: + return false; + case CURRENT_PLAYER: + return true; + case PLAYER: + return (name == other.name); + case NODEMETA: + return (p == other.p); + case DETACHED: + return (name == other.name); + } + return false; + } + bool operator!=(const InventoryLocation &other) const + { + return !(*this == other); + } + void applyCurrentPlayer(const std::string &name_) { if(type == CURRENT_PLAYER) |