forked from Mirrorlandia_minetest/minetest
Release invlist resizelock while doing the recursive callback in move_somewhere mode (#13470)
Fixes a crash in popular creative inventory mods that set the list when you put something into trash.
This commit is contained in:
parent
b35aa10579
commit
bec9c68bf3
@ -260,12 +260,18 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InventoryList *list_from = inv_from->getList(from_list);
|
auto get_borrow_checked_invlist = [](Inventory *inv, const std::string &listname)
|
||||||
InventoryList *list_to = inv_to->getList(to_list);
|
-> InventoryList::ResizeLocked
|
||||||
|
{
|
||||||
|
InventoryList *list = inv->getList(listname);
|
||||||
|
if (!list)
|
||||||
|
return nullptr;
|
||||||
|
return list->resizeLock();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto list_from = get_borrow_checked_invlist(inv_from, from_list);
|
||||||
|
auto list_to = get_borrow_checked_invlist(inv_to, to_list);
|
||||||
|
|
||||||
/*
|
|
||||||
If a list doesn't exist or the source item doesn't exist
|
|
||||||
*/
|
|
||||||
if (!list_from) {
|
if (!list_from) {
|
||||||
infostream << "IMoveAction::apply(): FAIL: source list not found: "
|
infostream << "IMoveAction::apply(): FAIL: source list not found: "
|
||||||
<< "from_inv=\"" << from_inv.dump() << "\""
|
<< "from_inv=\"" << from_inv.dump() << "\""
|
||||||
@ -279,10 +285,9 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto list_from_lock = list_from->resizeLock();
|
|
||||||
auto list_to_lock = list_to->resizeLock();
|
|
||||||
|
|
||||||
if (move_somewhere) {
|
if (move_somewhere) {
|
||||||
|
list_from.reset();
|
||||||
|
|
||||||
s16 old_to_i = to_i;
|
s16 old_to_i = to_i;
|
||||||
u16 old_count = count;
|
u16 old_count = count;
|
||||||
caused_by_move_somewhere = true;
|
caused_by_move_somewhere = true;
|
||||||
@ -300,23 +305,32 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
|||||||
|
|
||||||
// Try to add the item to destination list
|
// Try to add the item to destination list
|
||||||
s16 dest_size = list_to->getSize();
|
s16 dest_size = list_to->getSize();
|
||||||
// First try all the non-empty slots
|
auto add_to = [&](s16 dest_i) {
|
||||||
for (s16 dest_i = 0; dest_i < dest_size && count > 0; dest_i++) {
|
// release resize lock while the callbacks are happening
|
||||||
if (!list_to->getItem(dest_i).empty()) {
|
list_to.reset();
|
||||||
|
|
||||||
to_i = dest_i;
|
to_i = dest_i;
|
||||||
apply(mgr, player, gamedef);
|
apply(mgr, player, gamedef);
|
||||||
assert(move_count <= count);
|
assert(move_count <= count);
|
||||||
count -= move_count;
|
count -= move_count;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
list_to = get_borrow_checked_invlist(inv_to, to_list);
|
||||||
|
if (!list_to) {
|
||||||
|
// list_to was removed. simulate an empty list
|
||||||
|
dest_size = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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())
|
||||||
|
add_to(dest_i);
|
||||||
|
}
|
||||||
// Then try all the empty ones
|
// Then try all the empty ones
|
||||||
for (s16 dest_i = 0; dest_i < dest_size && count > 0; dest_i++) {
|
for (s16 dest_i = 0; dest_i < dest_size && count > 0; dest_i++) {
|
||||||
if (list_to->getItem(dest_i).empty()) {
|
if (list_to->getItem(dest_i).empty())
|
||||||
to_i = dest_i;
|
add_to(dest_i);
|
||||||
apply(mgr, player, gamedef);
|
|
||||||
count -= move_count;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
to_i = old_to_i;
|
to_i = old_to_i;
|
||||||
@ -482,7 +496,7 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
|||||||
*/
|
*/
|
||||||
bool did_swap = false;
|
bool did_swap = false;
|
||||||
move_count = list_from->moveItem(from_i,
|
move_count = list_from->moveItem(from_i,
|
||||||
list_to, to_i, count, allow_swap, &did_swap);
|
list_to.get(), to_i, count, allow_swap, &did_swap);
|
||||||
if (caused_by_move_somewhere)
|
if (caused_by_move_somewhere)
|
||||||
count = old_count;
|
count = old_count;
|
||||||
assert(allow_swap == did_swap);
|
assert(allow_swap == did_swap);
|
||||||
@ -574,7 +588,7 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
|||||||
/*
|
/*
|
||||||
Report move to endpoints
|
Report move to endpoints
|
||||||
*/
|
*/
|
||||||
list_to_lock.reset();
|
list_to.reset();
|
||||||
|
|
||||||
// Source = destination => move
|
// Source = destination => move
|
||||||
if (from_inv == to_inv) {
|
if (from_inv == to_inv) {
|
||||||
|
Loading…
Reference in New Issue
Block a user