mirror of
https://github.com/minetest/minetest.git
synced 2024-12-24 15:12:23 +01:00
Add MoveSomewhere inventory action
Improve shift+click experience
This commit is contained in:
parent
bc55ef337c
commit
2c1fd29884
@ -493,6 +493,9 @@ public:
|
|||||||
bool mediaReceived()
|
bool mediaReceived()
|
||||||
{ return m_media_downloader == NULL; }
|
{ return m_media_downloader == NULL; }
|
||||||
|
|
||||||
|
u8 getProtoVersion()
|
||||||
|
{ return m_proto_ver; }
|
||||||
|
|
||||||
float mediaReceiveProgress();
|
float mediaReceiveProgress();
|
||||||
|
|
||||||
void afterContentReceived(IrrlichtDevice *device);
|
void afterContentReceived(IrrlichtDevice *device);
|
||||||
|
@ -3384,31 +3384,42 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
|||||||
break;
|
break;
|
||||||
ItemStack stack_from = list_from->getItem(s.i);
|
ItemStack stack_from = list_from->getItem(s.i);
|
||||||
assert(shift_move_amount <= stack_from.count);
|
assert(shift_move_amount <= stack_from.count);
|
||||||
|
if (m_client->getProtoVersion() >= 25) {
|
||||||
// find a place (or more than one) to add the new item
|
infostream << "Handing IACTION_MOVE to manager" << std::endl;
|
||||||
u32 ilt_size = list_to->getSize();
|
IMoveAction *a = new IMoveAction();
|
||||||
ItemStack leftover;
|
a->count = shift_move_amount;
|
||||||
for (u32 slot_to = 0; slot_to < ilt_size
|
a->from_inv = s.inventoryloc;
|
||||||
&& shift_move_amount > 0; slot_to++) {
|
a->from_list = s.listname;
|
||||||
list_to->itemFits(slot_to, stack_from, &leftover);
|
a->from_i = s.i;
|
||||||
if (leftover.count < stack_from.count) {
|
a->to_inv = to_inv_sp.inventoryloc;
|
||||||
infostream << "Handing IACTION_MOVE to manager" << std::endl;
|
a->to_list = to_inv_sp.listname;
|
||||||
IMoveAction *a = new IMoveAction();
|
a->move_somewhere = true;
|
||||||
a->count = MYMIN(shift_move_amount,
|
m_invmgr->inventoryAction(a);
|
||||||
(u32) (stack_from.count - leftover.count));
|
} else {
|
||||||
shift_move_amount -= a->count;
|
// find a place (or more than one) to add the new item
|
||||||
a->from_inv = s.inventoryloc;
|
u32 ilt_size = list_to->getSize();
|
||||||
a->from_list = s.listname;
|
ItemStack leftover;
|
||||||
a->from_i = s.i;
|
for (u32 slot_to = 0; slot_to < ilt_size
|
||||||
a->to_inv = to_inv_sp.inventoryloc;
|
&& shift_move_amount > 0; slot_to++) {
|
||||||
a->to_list = to_inv_sp.listname;
|
list_to->itemFits(slot_to, stack_from, &leftover);
|
||||||
a->to_i = slot_to;
|
if (leftover.count < stack_from.count) {
|
||||||
m_invmgr->inventoryAction(a);
|
infostream << "Handing IACTION_MOVE to manager" << std::endl;
|
||||||
stack_from = leftover;
|
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);
|
} while (0);
|
||||||
|
|
||||||
} else if (drop_amount > 0) {
|
} else if (drop_amount > 0) {
|
||||||
m_selected_content_guess = ItemStack(); // Clear
|
m_selected_content_guess = ItemStack(); // Clear
|
||||||
|
|
||||||
|
@ -782,10 +782,47 @@ ItemStack InventoryList::peekItem(u32 i, u32 peekcount) const
|
|||||||
return m_items[i].peekItem(peekcount);
|
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)
|
if(this == dest && i == dest_i)
|
||||||
return;
|
return count;
|
||||||
|
|
||||||
// Take item from source list
|
// Take item from source list
|
||||||
ItemStack item1;
|
ItemStack item1;
|
||||||
@ -795,7 +832,7 @@ void InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i, u32 count)
|
|||||||
item1 = takeItem(i, count);
|
item1 = takeItem(i, count);
|
||||||
|
|
||||||
if(item1.empty())
|
if(item1.empty())
|
||||||
return;
|
return 0;
|
||||||
|
|
||||||
// Try to add the item to destination list
|
// Try to add the item to destination list
|
||||||
u32 oldcount = item1.count;
|
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.
|
// If olditem is returned, nothing was added.
|
||||||
// Swap the items
|
// Swap the items
|
||||||
if(nothing_added)
|
if (nothing_added && swap_if_needed) {
|
||||||
{
|
|
||||||
// Take item from source list
|
// Take item from source list
|
||||||
item1 = changeItem(i, ItemStack());
|
item1 = changeItem(i, ItemStack());
|
||||||
// Adding was not possible, swap the items.
|
// 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);
|
changeItem(i, item2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return (oldcount - item1.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -244,7 +244,13 @@ public:
|
|||||||
|
|
||||||
// Move an item to a different list (or a different stack in the same list)
|
// 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)
|
// 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:
|
private:
|
||||||
std::vector<ItemStack> m_items;
|
std::vector<ItemStack> m_items;
|
||||||
|
@ -121,16 +121,13 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
|
|||||||
|
|
||||||
InventoryAction *a = NULL;
|
InventoryAction *a = NULL;
|
||||||
|
|
||||||
if(type == "Move")
|
if (type == "Move") {
|
||||||
{
|
a = new IMoveAction(is, false);
|
||||||
a = new IMoveAction(is);
|
} else if (type == "MoveSomewhere") {
|
||||||
}
|
a = new IMoveAction(is, true);
|
||||||
else if(type == "Drop")
|
} else if (type == "Drop") {
|
||||||
{
|
|
||||||
a = new IDropAction(is);
|
a = new IDropAction(is);
|
||||||
}
|
} else if(type == "Craft") {
|
||||||
else if(type == "Craft")
|
|
||||||
{
|
|
||||||
a = new ICraftAction(is);
|
a = new ICraftAction(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,9 +138,12 @@ InventoryAction * InventoryAction::deSerialize(std::istream &is)
|
|||||||
IMoveAction
|
IMoveAction
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IMoveAction::IMoveAction(std::istream &is)
|
IMoveAction::IMoveAction(std::istream &is, bool somewhere)
|
||||||
{
|
{
|
||||||
std::string ts;
|
std::string ts;
|
||||||
|
move_somewhere = somewhere;
|
||||||
|
caused_by_move_somewhere = false;
|
||||||
|
move_count = 0;
|
||||||
|
|
||||||
std::getline(is, ts, ' ');
|
std::getline(is, ts, ' ');
|
||||||
count = stoi(ts);
|
count = stoi(ts);
|
||||||
@ -161,8 +161,10 @@ IMoveAction::IMoveAction(std::istream &is)
|
|||||||
|
|
||||||
std::getline(is, to_list, ' ');
|
std::getline(is, to_list, ' ');
|
||||||
|
|
||||||
std::getline(is, ts, ' ');
|
if (!somewhere) {
|
||||||
to_i = stoi(ts);
|
std::getline(is, ts, ' ');
|
||||||
|
to_i = stoi(ts);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
|
void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef)
|
||||||
@ -202,6 +204,48 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
|||||||
return;
|
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
|
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
|
If something is wrong (source item is empty, destination is the
|
||||||
same as source), nothing happens
|
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 source is infinite, reset it's stack
|
||||||
if(src_can_take_count == -1){
|
if(src_can_take_count == -1){
|
||||||
@ -352,15 +397,17 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
|||||||
list_from->takeItem(from_i, count);
|
list_from->takeItem(from_i, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
infostream<<"IMoveAction::apply(): moved"
|
infostream << "IMoveAction::apply(): moved"
|
||||||
<<" count="<<count
|
<< " msom=" << move_somewhere
|
||||||
<<" from inv=\""<<from_inv.dump()<<"\""
|
<< " caused=" << caused_by_move_somewhere
|
||||||
<<" list=\""<<from_list<<"\""
|
<< " count=" << count
|
||||||
<<" i="<<from_i
|
<< " from inv=\"" << from_inv.dump() << "\""
|
||||||
<<" to inv=\""<<to_inv.dump()<<"\""
|
<< " list=\"" << from_list << "\""
|
||||||
<<" list=\""<<to_list<<"\""
|
<< " i=" << from_i
|
||||||
<<" i="<<to_i
|
<< " to inv=\"" << to_inv.dump() << "\""
|
||||||
<<std::endl;
|
<< " list=\"" << to_list << "\""
|
||||||
|
<< " i=" << to_i
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Record rollback information
|
Record rollback information
|
||||||
@ -480,7 +527,10 @@ void IMoveAction::clientApply(InventoryManager *mgr, IGameDef *gamedef)
|
|||||||
if(!list_from || !list_to)
|
if(!list_from || !list_to)
|
||||||
return;
|
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);
|
mgr->setInventoryModified(from_inv);
|
||||||
if(inv_from != inv_to)
|
if(inv_from != inv_to)
|
||||||
|
@ -143,15 +143,24 @@ struct IMoveAction : public InventoryAction
|
|||||||
InventoryLocation to_inv;
|
InventoryLocation to_inv;
|
||||||
std::string to_list;
|
std::string to_list;
|
||||||
s16 to_i;
|
s16 to_i;
|
||||||
|
bool move_somewhere;
|
||||||
|
|
||||||
|
// treat these as private
|
||||||
|
// related to movement to somewhere
|
||||||
|
bool caused_by_move_somewhere;
|
||||||
|
u32 move_count;
|
||||||
|
|
||||||
IMoveAction()
|
IMoveAction()
|
||||||
{
|
{
|
||||||
count = 0;
|
count = 0;
|
||||||
from_i = -1;
|
from_i = -1;
|
||||||
to_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
|
u16 getType() const
|
||||||
{
|
{
|
||||||
@ -160,14 +169,18 @@ struct IMoveAction : public InventoryAction
|
|||||||
|
|
||||||
void serialize(std::ostream &os) const
|
void serialize(std::ostream &os) const
|
||||||
{
|
{
|
||||||
os<<"Move ";
|
if (!move_somewhere)
|
||||||
os<<count<<" ";
|
os << "Move ";
|
||||||
os<<from_inv.dump()<<" ";
|
else
|
||||||
os<<from_list<<" ";
|
os << "MoveSomewhere ";
|
||||||
os<<from_i<<" ";
|
os << count << " ";
|
||||||
os<<to_inv.dump()<<" ";
|
os << from_inv.dump() << " ";
|
||||||
os<<to_list<<" ";
|
os << from_list << " ";
|
||||||
os<<to_i;
|
os << from_i << " ";
|
||||||
|
os << to_inv.dump() << " ";
|
||||||
|
os << to_list;
|
||||||
|
if (!move_somewhere)
|
||||||
|
os << " " << to_i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef);
|
void apply(InventoryManager *mgr, ServerActiveObject *player, IGameDef *gamedef);
|
||||||
|
Loading…
Reference in New Issue
Block a user