Skip to content

Commit

Permalink
Add MoveSomewhere inventory action
Browse files Browse the repository at this point in the history
Improve shift+click experience
  • Loading branch information
est31 committed Jun 23, 2015
1 parent bc55ef3 commit 2c1fd29
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 60 deletions.
3 changes: 3 additions & 0 deletions src/client.h
Expand Up @@ -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);
Expand Down
55 changes: 33 additions & 22 deletions src/guiFormSpecMenu.cpp
Expand Up @@ -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

Expand Down
47 changes: 42 additions & 5 deletions src/inventory.cpp
Expand Up @@ -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;

This comment has been minimized.

Copy link
@TeTpaAka

TeTpaAka Jun 25, 2015

Contributor

warning: unused variable ‘oldcount’ [-Wunused-variable]

This comment has been minimized.

Copy link
@est31

est31 Jun 25, 2015

Author Contributor

thanks for pointing out. I've got it myself multiple times too but forgot to adress it.

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)
Expand All @@ -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;
Expand All @@ -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.
Expand All @@ -823,6 +859,7 @@ void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
changeItem(i, item2);
}
}
return (oldcount - item1.count);
}

/*
Expand Down
8 changes: 7 additions & 1 deletion src/inventory.h
Expand Up @@ -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;
Expand Down
96 changes: 73 additions & 23 deletions src/inventorymanager.cpp
Expand Up @@ -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);
}

Expand All @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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
*/
Expand Down Expand Up @@ -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){
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
31 changes: 22 additions & 9 deletions src/inventorymanager.h
Expand Up @@ -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
{
Expand All @@ -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);
Expand Down

0 comments on commit 2c1fd29

Please sign in to comment.