Add MoveSomewhere inventory action

Improve shift+click experience
This commit is contained in:
est31 2015-06-20 12:55:48 +02:00
parent bc55ef337c
commit 2c1fd29884
6 changed files with 180 additions and 60 deletions

View File

@ -493,6 +493,9 @@ class Client : public con::PeerHandler, public InventoryManager, public IGameDef
bool mediaReceived()
{ return m_media_downloader == NULL; }
u8 getProtoVersion()
{ return m_proto_ver; }
float mediaReceiveProgress();
void afterContentReceived(IrrlichtDevice *device);

View File

@ -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

View File

@ -782,10 +782,47 @@ 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)
{
// 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;
return count;
// Take item from source list
ItemStack item1;
@ -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);
}
/*

View File

@ -244,7 +244,13 @@ class InventoryList
// 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;

View File

@ -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)

View File

@ -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);