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;
|
||||
}
|
||||
|
||||
InventoryList *list_from = inv_from->getList(from_list);
|
||||
InventoryList *list_to = inv_to->getList(to_list);
|
||||
auto get_borrow_checked_invlist = [](Inventory *inv, const std::string &listname)
|
||||
-> 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) {
|
||||
infostream << "IMoveAction::apply(): FAIL: source list not found: "
|
||||
<< "from_inv=\"" << from_inv.dump() << "\""
|
||||
@ -279,10 +285,9 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||
return;
|
||||
}
|
||||
|
||||
auto list_from_lock = list_from->resizeLock();
|
||||
auto list_to_lock = list_to->resizeLock();
|
||||
|
||||
if (move_somewhere) {
|
||||
list_from.reset();
|
||||
|
||||
s16 old_to_i = to_i;
|
||||
u16 old_count = count;
|
||||
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
|
||||
s16 dest_size = list_to->getSize();
|
||||
auto add_to = [&](s16 dest_i) {
|
||||
// release resize lock while the callbacks are happening
|
||||
list_to.reset();
|
||||
|
||||
to_i = dest_i;
|
||||
apply(mgr, player, gamedef);
|
||||
assert(move_count <= 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()) {
|
||||
to_i = dest_i;
|
||||
apply(mgr, player, gamedef);
|
||||
assert(move_count <= count);
|
||||
count -= move_count;
|
||||
}
|
||||
if (!list_to->getItem(dest_i).empty())
|
||||
add_to(dest_i);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
if (list_to->getItem(dest_i).empty())
|
||||
add_to(dest_i);
|
||||
}
|
||||
|
||||
to_i = old_to_i;
|
||||
@ -482,7 +496,7 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||
*/
|
||||
bool did_swap = false;
|
||||
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)
|
||||
count = old_count;
|
||||
assert(allow_swap == did_swap);
|
||||
@ -574,7 +588,7 @@ void IMoveAction::apply(InventoryManager *mgr, ServerActiveObject *player, IGame
|
||||
/*
|
||||
Report move to endpoints
|
||||
*/
|
||||
list_to_lock.reset();
|
||||
list_to.reset();
|
||||
|
||||
// Source = destination => move
|
||||
if (from_inv == to_inv) {
|
||||
|
Loading…
Reference in New Issue
Block a user