mirror of
https://github.com/minetest/minetest.git
synced 2024-11-05 07:13:46 +01:00
Inventory: prevent item loss when stacking oversized ItemStacks (#14072)
This commit is contained in:
parent
c871b6dd4e
commit
94a54375e2
@ -777,20 +777,18 @@ u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// Try to add the item to destination list
|
// Try to add the item to destination list
|
||||||
u32 oldcount = item1.count;
|
count = item1.count;
|
||||||
item1 = dest->addItem(dest_i, item1);
|
item1 = dest->addItem(dest_i, item1);
|
||||||
|
|
||||||
// If something is returned, the item was not fully added
|
// If something is returned, the item was not fully added
|
||||||
if (!item1.empty()) {
|
if (!item1.empty()) {
|
||||||
// If olditem is returned, nothing was added.
|
bool nothing_added = (item1.count == count);
|
||||||
bool nothing_added = (item1.count == oldcount);
|
|
||||||
|
|
||||||
// If something else is returned, part of the item was left unadded.
|
// Add any leftover stack back to the source stack.
|
||||||
// Add the other part back to the source item
|
item1.add(getItem(i).count); // leftover + source count
|
||||||
addItem(i, item1);
|
changeItem(i, item1); // do NOT use addItem to allow oversized stacks!
|
||||||
|
|
||||||
// If olditem is returned, nothing was added.
|
// Swap if no items could be moved
|
||||||
// Swap the items
|
|
||||||
if (nothing_added && swap_if_needed) {
|
if (nothing_added && swap_if_needed) {
|
||||||
// Tell that we swapped
|
// Tell that we swapped
|
||||||
if (did_swap != NULL) {
|
if (did_swap != NULL) {
|
||||||
@ -802,9 +800,10 @@ u32 InventoryList::moveItem(u32 i, InventoryList *dest, u32 dest_i,
|
|||||||
ItemStack item2 = dest->changeItem(dest_i, item1);
|
ItemStack item2 = dest->changeItem(dest_i, item1);
|
||||||
// Put item from destination list to the source list
|
// Put item from destination list to the source list
|
||||||
changeItem(i, item2);
|
changeItem(i, item2);
|
||||||
|
item1.clear(); // no leftover
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (oldcount - item1.count);
|
return (count - item1.count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InventoryList::checkResizeLock()
|
void InventoryList::checkResizeLock()
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
minetest.register_allow_player_inventory_action(function(player, action, inventory, info)
|
minetest.register_allow_player_inventory_action(function(player, action, inventory, info)
|
||||||
|
if action == "move" then
|
||||||
|
return info.count
|
||||||
|
end
|
||||||
|
|
||||||
if info.stack:get_name() == "default:water" then
|
if info.stack:get_name() == "default:water" then
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
@ -36,6 +36,7 @@ public:
|
|||||||
void runTests(IGameDef *gamedef);
|
void runTests(IGameDef *gamedef);
|
||||||
|
|
||||||
void testMove(ServerActiveObject *obj, IGameDef *gamedef);
|
void testMove(ServerActiveObject *obj, IGameDef *gamedef);
|
||||||
|
void testMoveFillStack(ServerActiveObject *obj, IGameDef *gamedef);
|
||||||
void testMoveSomewhere(ServerActiveObject *obj, IGameDef *gamedef);
|
void testMoveSomewhere(ServerActiveObject *obj, IGameDef *gamedef);
|
||||||
void testMoveUnallowed(ServerActiveObject *obj, IGameDef *gamedef);
|
void testMoveUnallowed(ServerActiveObject *obj, IGameDef *gamedef);
|
||||||
void testMovePartial(ServerActiveObject *obj, IGameDef *gamedef);
|
void testMovePartial(ServerActiveObject *obj, IGameDef *gamedef);
|
||||||
@ -51,14 +52,24 @@ void TestMoveAction::runTests(IGameDef *gamedef)
|
|||||||
MockServer server;
|
MockServer server;
|
||||||
|
|
||||||
ServerScripting server_scripting(&server);
|
ServerScripting server_scripting(&server);
|
||||||
server_scripting.loadMod(Server::getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
|
try {
|
||||||
server_scripting.loadMod(std::string(HELPERS_PATH) + DIR_DELIM "helper_moveaction.lua", BUILTIN_MOD_NAME);
|
server_scripting.loadMod(Server::getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME);
|
||||||
|
server_scripting.loadMod(
|
||||||
|
std::string(HELPERS_PATH) + DIR_DELIM "helper_moveaction.lua", BUILTIN_MOD_NAME
|
||||||
|
);
|
||||||
|
} catch (ModError &e) {
|
||||||
|
// Print backtrace in case of syntax errors
|
||||||
|
rawstream << e.what() << std::endl;
|
||||||
|
num_tests_failed = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MetricsBackend mb;
|
MetricsBackend mb;
|
||||||
ServerEnvironment server_env(nullptr, &server_scripting, &server, "", &mb);
|
ServerEnvironment server_env(nullptr, &server_scripting, &server, "", &mb);
|
||||||
MockServerActiveObject obj(&server_env);
|
MockServerActiveObject obj(&server_env);
|
||||||
|
|
||||||
TEST(testMove, &obj, gamedef);
|
TEST(testMove, &obj, gamedef);
|
||||||
|
TEST(testMoveFillStack, &obj, gamedef);
|
||||||
TEST(testMoveSomewhere, &obj, gamedef);
|
TEST(testMoveSomewhere, &obj, gamedef);
|
||||||
TEST(testMoveUnallowed, &obj, gamedef);
|
TEST(testMoveUnallowed, &obj, gamedef);
|
||||||
TEST(testMovePartial, &obj, gamedef);
|
TEST(testMovePartial, &obj, gamedef);
|
||||||
@ -95,6 +106,26 @@ void TestMoveAction::testMove(ServerActiveObject *obj, IGameDef *gamedef)
|
|||||||
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:stone 20");
|
UASSERT(inv.p2.getList("main")->getItem(0).getItemString() == "default:stone 20");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestMoveAction::testMoveFillStack(ServerActiveObject *obj, IGameDef *gamedef)
|
||||||
|
{
|
||||||
|
MockInventoryManager inv(gamedef);
|
||||||
|
|
||||||
|
auto list = inv.p1.addList("main", 10);
|
||||||
|
list->changeItem(0, parse_itemstack("default:stone 209"));
|
||||||
|
list->changeItem(1, parse_itemstack("default:stone 90")); // 9 free slots
|
||||||
|
|
||||||
|
apply_action("Move 209 player:p1 main 0 player:p1 main 1", &inv, obj, gamedef);
|
||||||
|
|
||||||
|
UASSERT(list->getItem(0).getItemString() == "default:stone 200");
|
||||||
|
UASSERT(list->getItem(1).getItemString() == "default:stone 99");
|
||||||
|
|
||||||
|
// Trigger stack swap
|
||||||
|
apply_action("Move 200 player:p1 main 0 player:p1 main 1", &inv, obj, gamedef);
|
||||||
|
|
||||||
|
UASSERT(list->getItem(0).getItemString() == "default:stone 99");
|
||||||
|
UASSERT(list->getItem(1).getItemString() == "default:stone 200");
|
||||||
|
}
|
||||||
|
|
||||||
void TestMoveAction::testMoveSomewhere(ServerActiveObject *obj, IGameDef *gamedef)
|
void TestMoveAction::testMoveSomewhere(ServerActiveObject *obj, IGameDef *gamedef)
|
||||||
{
|
{
|
||||||
MockInventoryManager inv(gamedef);
|
MockInventoryManager inv(gamedef);
|
||||||
|
Loading…
Reference in New Issue
Block a user