Minetest: contains_item is unable to count tools correctly

Created on 3 Sep 2016  Â·  2Comments  Â·  Source: minetest/minetest

I have stumpled upon a really weird bug in the Lua API: If you use contains_item to count tools in an inventory, you can not reliably count the number of tools of the same kind.

I give you an example:
Get yourselves 4 water buckets (which have max. stack size 1) and 4 wooden shovels (also max. stack size 1). Use the luacmd mod to test the contains_item method:

/lua print(me:get_inventory():contains_item("main", "bucket:bucket_water"))
→ true. OK.

/lua print(me:get_inventory():contains_item("main", "bucket:bucket_water 4"))
→ true. OK.

/lua print(me:get_inventory():contains_item("main", "bucket:bucket_water 5"))
→ false. OK.

/lua print(me:get_inventory():contains_item("main", "default:shovel_wood"))
→ true. OK.

/lua print(me:get_inventory():contains_item("main", "default:shovel_wood 4"))
→ true. OK.

/lua print(me:get_inventory():contains_item("main", "default:shovel_wood 5"))
→ true. Unexpected!

/lua print(me:get_inventory():contains_item("main", "default:shovel_wood 5000"))
→ true. Unexpected!

So, contains_item is able to count the water buckets correctly in the inventory, but not the wooden shovels. In otther words, contains_item is broken.

In my example, the difference between water bucket and wooden shovel seems to be related to the fact that the wooden shovel is created with register_tool but the water bucket is created with register_craftitem.

Seen in Minetest 0.4.14 and revision 986d70ccecb09fcbd247758643a4d623c9c4e1b8.

@ Script API @ Server / Client / Env. Bug

Most helpful comment

It was I who originally wrote the ItemStack deserialization, but now I think that the engine (and builtin) should not enforce a stack_max of 1 for tools at all. Instead it should allow mods and subgames to have stackable tools if they want to simply by overriding stack_max.

Stackable tools could work like in e.g. Junk Jack: if a tool with item count greater than 1 wears out, the count is decremented by one and wear is reset to 0, basically the worn out tool is replaced by a full-durability tool from the stack. So, a tool with item count C can be thought of as one currently active tool plus (C-1) full-durability backup tools.

Of course there would have to be other considerations, such as how add_item would deal with such stacks.

All 2 comments

Bug traceback:
inv:contains_item: https://github.com/minetest/minetest/blob/master/src/script/lua_api/l_inventory.cpp#L335
read_item: https://github.com/minetest/minetest/blob/master/src/script/common/c_content.cpp#L797
ItemStack::deSerialize: https://github.com/minetest/minetest/blob/master/src/inventory.cpp#L305

The problem here is quite complex because the deserialize function is also the one that disallows you from having 5 shovels in one slot, where 5000 cobble is no problem (using /giveme ..).

It was I who originally wrote the ItemStack deserialization, but now I think that the engine (and builtin) should not enforce a stack_max of 1 for tools at all. Instead it should allow mods and subgames to have stackable tools if they want to simply by overriding stack_max.

Stackable tools could work like in e.g. Junk Jack: if a tool with item count greater than 1 wears out, the count is decremented by one and wear is reset to 0, basically the worn out tool is replaced by a full-durability tool from the stack. So, a tool with item count C can be thought of as one currently active tool plus (C-1) full-durability backup tools.

Of course there would have to be other considerations, such as how add_item would deal with such stacks.

Was this page helpful?
0 / 5 - 0 ratings