2018-09-23 15:02:18 +03:00
|
|
|
---
|
|
|
|
title: ItemStacks and Inventories
|
|
|
|
layout: default
|
|
|
|
root: ../..
|
|
|
|
idx: 2.4
|
|
|
|
description: Manipulate InvRefs and ItemStacks
|
|
|
|
redirect_from:
|
|
|
|
- /en/chapters/inventories.html
|
|
|
|
- /en/chapters/itemstacks.html
|
|
|
|
- /en/inventories/inventories.html
|
|
|
|
- /en/inventories/itemstacks.html
|
|
|
|
---
|
|
|
|
|
2019-05-31 20:32:40 +03:00
|
|
|
## Introduction <!-- omit in toc -->
|
2018-09-23 15:02:18 +03:00
|
|
|
|
2019-05-31 20:32:40 +03:00
|
|
|
In this chapter, you will learn how to use and manipulate inventories, whether
|
2018-10-20 03:37:41 +03:00
|
|
|
that be a player inventory, a node inventory, or a detached inventory.
|
2018-09-23 15:02:18 +03:00
|
|
|
|
2019-05-31 20:32:40 +03:00
|
|
|
- [What are ItemStacks and Inventories?](#what-are-itemstacks-and-inventories)
|
|
|
|
- [ItemStacks](#itemstacks)
|
|
|
|
- [Inventory Locations](#inventory-locations)
|
|
|
|
- [Lists](#lists)
|
|
|
|
- [Size and Width](#size-and-width)
|
|
|
|
- [Checking Contents](#checking-contents)
|
|
|
|
- [Modifying Inventories and ItemStacks](#modifying-inventories-and-itemstacks)
|
|
|
|
- [Adding to a List](#adding-to-a-list)
|
|
|
|
- [Taking Items](#taking-items)
|
|
|
|
- [Manipulating Stacks](#manipulating-stacks)
|
|
|
|
- [Wear](#wear)
|
|
|
|
- [Lua Tables](#lua-tables)
|
2018-09-23 15:02:18 +03:00
|
|
|
|
|
|
|
## What are ItemStacks and Inventories?
|
|
|
|
|
|
|
|
An ItemStack is the data behind a single cell in an inventory.
|
|
|
|
|
|
|
|
An *inventory* is a collection of *inventory lists*, each of which
|
|
|
|
is a 2D grid of ItemStacks.
|
|
|
|
Inventory lists are simply called *lists* in the context
|
|
|
|
of inventories.
|
|
|
|
The point of an inventory is to allow multiple grids when Players
|
|
|
|
and Nodes only have at most one inventory in them.
|
|
|
|
|
|
|
|
## ItemStacks
|
|
|
|
|
2020-07-06 02:26:25 +03:00
|
|
|
ItemStacks have four components to them: name, count, wear and metadata.
|
2018-09-23 15:02:18 +03:00
|
|
|
|
|
|
|
The item name may be the item name of a registered item, an alias, or an unknown
|
|
|
|
item name.
|
|
|
|
Unknown items are common when users uninstall mods, or when mods remove items without
|
2018-10-20 03:37:41 +03:00
|
|
|
precautions, such as registering aliases.
|
2018-09-23 15:02:18 +03:00
|
|
|
|
|
|
|
```lua
|
|
|
|
print(stack:get_name())
|
|
|
|
stack:set_name("default:dirt")
|
|
|
|
|
|
|
|
if not stack:is_known() then
|
|
|
|
print("Is an unknown item!")
|
|
|
|
end
|
|
|
|
```
|
|
|
|
|
|
|
|
The count will always be 0 or greater.
|
|
|
|
Through normal gameplay, the count should be no more than the maximum stack size
|
|
|
|
of the item - `stack_max`.
|
|
|
|
However, admin commands and buggy mods may result in stacks exceeding the maximum
|
|
|
|
size.
|
|
|
|
|
|
|
|
```lua
|
|
|
|
print(stack:get_stack_max())
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
An ItemStack can be empty, in which case the count will be 0.
|
|
|
|
|
|
|
|
```lua
|
|
|
|
print(stack:get_count())
|
|
|
|
stack:set_count(10)
|
|
|
|
```
|
|
|
|
|
|
|
|
ItemStacks can be constructed in multiple ways using the ItemStack function.
|
|
|
|
|
|
|
|
```lua
|
|
|
|
ItemStack() -- name="", count=0
|
|
|
|
ItemStack("default:pick_stone") -- count=1
|
|
|
|
ItemStack("default:stone 30")
|
|
|
|
ItemStack({ name = "default:wood", count = 10 })
|
|
|
|
```
|
|
|
|
|
|
|
|
Item metadata is an unlimited key-value store for data about the item.
|
|
|
|
Key-value means that you use a name (called the key) to access the data (called the value).
|
|
|
|
Some keys have special meaning, such as `description` which is used to have a per-stack
|
|
|
|
item description.
|
|
|
|
This will be covered in more detail in the Metadata and Storage chapter.
|
|
|
|
|
|
|
|
## Inventory Locations
|
|
|
|
|
|
|
|
An Inventory Location is where and how the inventory is stored.
|
|
|
|
There are three types of inventory location: player, node, and detached.
|
|
|
|
An inventory is directly tied to one and only one location - updating the inventory
|
|
|
|
will cause it to update immediately.
|
|
|
|
|
|
|
|
Node inventories are related to the position of a specific node, such as a chest.
|
2019-07-01 23:47:52 +03:00
|
|
|
The node must be loaded because it is stored in [node metadata](../map/storage.html#metadata).
|
2018-09-23 15:02:18 +03:00
|
|
|
|
|
|
|
```lua
|
|
|
|
local inv = minetest.get_inventory({ type="node", pos={x=1, y=2, z=3} })
|
|
|
|
```
|
|
|
|
|
|
|
|
The above obtains an *inventory reference*, commonly referred to as *InvRef*.
|
|
|
|
Inventory references are used to manipulate an inventory.
|
|
|
|
*Reference* means that the data isn't actually stored inside that object,
|
|
|
|
but the object instead directly updates the data in-place.
|
|
|
|
|
2019-07-01 23:47:52 +03:00
|
|
|
The location of an inventory reference can be found like so:
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local location = inv:get_location()
|
|
|
|
```
|
|
|
|
|
2018-09-23 15:02:18 +03:00
|
|
|
Player inventories can be obtained similarly or using a player reference.
|
|
|
|
The player must be online to access their inventory.
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local inv = minetest.get_inventory({ type="player", name="player1" })
|
|
|
|
-- or
|
|
|
|
local inv = player:get_inventory()
|
|
|
|
```
|
|
|
|
|
|
|
|
A detached inventory is one which is independent of players or nodes.
|
|
|
|
Detached inventories also don't save over a restart.
|
|
|
|
|
|
|
|
```lua
|
2018-09-24 19:16:00 +03:00
|
|
|
local inv = minetest.get_inventory({
|
|
|
|
type="detached", name="inventory_name" })
|
2018-09-23 15:02:18 +03:00
|
|
|
```
|
|
|
|
|
2020-07-06 02:26:25 +03:00
|
|
|
Unlike the other types of inventory, you must first create a detached inventory
|
|
|
|
before accessing it:
|
2018-09-23 15:02:18 +03:00
|
|
|
|
|
|
|
```lua
|
2019-07-01 23:47:52 +03:00
|
|
|
minetest.create_detached_inventory("inventory_name")
|
2018-09-23 15:02:18 +03:00
|
|
|
```
|
|
|
|
|
2021-02-21 07:23:48 +03:00
|
|
|
The create_detached_inventory function accepts 3 arguments, where only the first - the inventory name -
|
2020-07-06 02:26:25 +03:00
|
|
|
is required.
|
2019-07-01 23:47:52 +03:00
|
|
|
The second argument takes a table of callbacks, which can be used to control how
|
|
|
|
players interact with the inventory:
|
|
|
|
|
|
|
|
```lua
|
|
|
|
-- Input only detached inventory
|
|
|
|
minetest.create_detached_inventory("inventory_name", {
|
|
|
|
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
|
|
|
|
return count -- allow moving
|
|
|
|
end,
|
|
|
|
|
|
|
|
allow_put = function(inv, listname, index, stack, player)
|
|
|
|
return stack:get_count() -- allow putting
|
|
|
|
end,
|
|
|
|
|
|
|
|
allow_take = function(inv, listname, index, stack, player)
|
2021-02-21 07:23:48 +03:00
|
|
|
return 0 -- don't allow taking
|
2019-07-01 23:47:52 +03:00
|
|
|
end,
|
|
|
|
|
|
|
|
on_put = function(inv, listname, index, stack, player)
|
|
|
|
minetest.chat_send_all(player:get_player_name() ..
|
|
|
|
" gave " .. stack:to_string() ..
|
2020-07-06 02:26:25 +03:00
|
|
|
" to the donation chest from " .. minetest.pos_to_string(player:get_pos()))
|
2019-07-01 23:47:52 +03:00
|
|
|
end,
|
|
|
|
})
|
|
|
|
```
|
|
|
|
|
2020-07-06 02:26:25 +03:00
|
|
|
Permission callbacks - ie: those starting with `allow_` - return the number
|
2021-02-21 07:23:48 +03:00
|
|
|
of items to transfer, with 0 being used to prevent transfer completely.
|
2019-07-01 23:47:52 +03:00
|
|
|
|
2020-07-06 02:26:25 +03:00
|
|
|
On the contrary, action callbacks - starting with `on_` - don't have a return value.
|
2019-07-01 23:47:52 +03:00
|
|
|
|
2018-09-23 15:02:18 +03:00
|
|
|
## Lists
|
|
|
|
|
|
|
|
Inventory Lists are a concept used to allow multiple grids to be stored inside a single location.
|
|
|
|
This is especially useful for the player as there are a number of common lists
|
|
|
|
which all games have, such as the *main* inventory and *craft* slots.
|
|
|
|
|
|
|
|
### Size and Width
|
|
|
|
|
2018-10-20 03:37:41 +03:00
|
|
|
Lists have a size, which is the total number of cells in the grid, and a width,
|
|
|
|
which is only used within the engine.
|
2019-05-31 20:32:40 +03:00
|
|
|
The width of the list is not used when drawing the inventory in a window,
|
2018-10-20 03:37:41 +03:00
|
|
|
because the code behind the window determines the width to use.
|
2018-09-23 15:02:18 +03:00
|
|
|
|
|
|
|
```lua
|
|
|
|
if inv:set_size("main", 32) then
|
|
|
|
inv:set_width("main", 8)
|
2020-08-09 01:56:50 +03:00
|
|
|
print("size: " .. inv:get_size("main"))
|
2018-09-23 15:02:18 +03:00
|
|
|
print("width: " .. inv:get_width("main"))
|
|
|
|
else
|
|
|
|
print("Error! Invalid itemname or size to set_size()")
|
|
|
|
end
|
|
|
|
```
|
|
|
|
|
|
|
|
`set_size` will fail and return false if the listname or size is invalid.
|
|
|
|
For example, the new size may be too small to fit all the current items
|
|
|
|
in the inventory.
|
|
|
|
|
|
|
|
### Checking Contents
|
|
|
|
|
|
|
|
`is_empty` can be used to see if a list contains any items:
|
|
|
|
|
|
|
|
```lua
|
|
|
|
if inv:is_empty("main") then
|
|
|
|
print("The list is empty!")
|
|
|
|
end
|
|
|
|
```
|
|
|
|
|
2020-07-06 02:26:25 +03:00
|
|
|
`contains_item` can be used to see if a list contains a specific item:
|
|
|
|
|
|
|
|
```lua
|
|
|
|
if inv:contains_item("main", "default:stone") then
|
|
|
|
print("I've found some stone!")
|
|
|
|
end
|
|
|
|
```
|
2018-09-23 15:02:18 +03:00
|
|
|
|
|
|
|
## Modifying Inventories and ItemStacks
|
|
|
|
|
|
|
|
### Adding to a List
|
|
|
|
|
2020-07-06 02:26:25 +03:00
|
|
|
`add_item` adds items to a list (in this case `"main"`). In the example below,
|
|
|
|
the maximum stack size is also respected:
|
2018-09-23 15:02:18 +03:00
|
|
|
|
|
|
|
```lua
|
|
|
|
local stack = ItemStack("default:stone 99")
|
|
|
|
local leftover = inv:add_item("main", stack)
|
|
|
|
if leftover:get_count() > 0 then
|
2018-09-24 19:16:00 +03:00
|
|
|
print("Inventory is full! " ..
|
|
|
|
leftover:get_count() .. " items weren't added")
|
2018-09-23 15:02:18 +03:00
|
|
|
end
|
|
|
|
```
|
|
|
|
|
|
|
|
### Taking Items
|
|
|
|
|
|
|
|
To remove items from a list:
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local taken = inv:remove_item("main", stack)
|
|
|
|
print("Took " .. taken:get_count())
|
|
|
|
```
|
|
|
|
|
|
|
|
### Manipulating Stacks
|
|
|
|
|
|
|
|
You can modify individual stacks by first getting them:
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local stack = inv:get_stack(listname, 0)
|
|
|
|
```
|
|
|
|
|
|
|
|
Then modifying them by setting properties or by using the methods which
|
|
|
|
respect `stack_size`:
|
|
|
|
|
|
|
|
|
|
|
|
```lua
|
|
|
|
local stack = ItemStack("default:stone 50")
|
|
|
|
local to_add = ItemStack("default:stone 100")
|
|
|
|
local leftover = stack:add_item(to_add)
|
|
|
|
local taken = stack:take_item(19)
|
|
|
|
|
|
|
|
print("Could not add" .. leftover:get_count() .. " of the items.")
|
|
|
|
-- ^ will be 51
|
|
|
|
|
|
|
|
print("Have " .. stack:get_count() .. " items")
|
2019-05-31 20:32:40 +03:00
|
|
|
-- ^ will be 80
|
2018-09-23 15:02:18 +03:00
|
|
|
-- min(50+100, stack_max) - 19 = 80
|
|
|
|
-- where stack_max = 99
|
|
|
|
```
|
|
|
|
|
|
|
|
`add_item` will add items to an ItemStack and return any that could not be added.
|
|
|
|
`take_item` will take up to the number of items but may take less, and returns the stack taken.
|
|
|
|
|
|
|
|
Finally, set the item stack:
|
|
|
|
|
|
|
|
```lua
|
|
|
|
inv:set_stack(listname, 0, stack)
|
|
|
|
```
|
|
|
|
|
|
|
|
## Wear
|
|
|
|
|
|
|
|
Tools can have wear; wear shows a progress bar and makes the tool break when completely worn.
|
2018-10-20 03:37:41 +03:00
|
|
|
Wear is a number out of 65535; the higher it is, the more worn the tool is.
|
2018-09-23 15:02:18 +03:00
|
|
|
|
2018-10-20 03:37:41 +03:00
|
|
|
Wear can be manipulated using `add_wear()`, `get_wear()`, and `set_wear(wear)`.
|
2018-09-23 15:02:18 +03:00
|
|
|
|
|
|
|
```lua
|
|
|
|
local stack = ItemStack("default:pick_mese")
|
|
|
|
local max_uses = 10
|
|
|
|
|
|
|
|
-- This is done automatically when you use a tool that digs things
|
|
|
|
-- It increases the wear of an item by one use.
|
|
|
|
stack:add_wear(65535 / (max_uses - 1))
|
|
|
|
```
|
|
|
|
|
2019-05-31 20:32:40 +03:00
|
|
|
When digging a node, the amount of wear a tool gets may depend on the node
|
2018-09-23 15:02:18 +03:00
|
|
|
being dug. So max_uses varies depending on what is being dug.
|
|
|
|
|
|
|
|
## Lua Tables
|
|
|
|
|
|
|
|
ItemStacks and Inventories can be converted to and from tables.
|
|
|
|
This is useful for copying and bulk operations.
|
|
|
|
|
|
|
|
```lua
|
|
|
|
-- Entire inventory
|
|
|
|
local data = inv1:get_lists()
|
|
|
|
inv2:set_lists(data)
|
|
|
|
|
|
|
|
-- One list
|
|
|
|
local listdata = inv1:get_list("main")
|
|
|
|
inv2:set_list("main", listdata)
|
|
|
|
```
|
|
|
|
|
|
|
|
The table of lists returned by `get_lists()` will be in this form:
|
|
|
|
|
|
|
|
```lua
|
|
|
|
{
|
|
|
|
list_one = {
|
|
|
|
ItemStack,
|
|
|
|
ItemStack,
|
|
|
|
ItemStack,
|
|
|
|
ItemStack,
|
|
|
|
-- inv:get_size("list_one") elements
|
|
|
|
},
|
|
|
|
list_two = {
|
|
|
|
ItemStack,
|
|
|
|
ItemStack,
|
|
|
|
ItemStack,
|
|
|
|
ItemStack,
|
|
|
|
-- inv:get_size("list_two") elements
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
`get_list()` will return a single list as just a list of ItemStacks.
|
|
|
|
|
|
|
|
One important thing to note is that the set methods above don't change the size
|
|
|
|
of the lists.
|
|
|
|
This means that you can clear a list by setting it to an empty table and it won't
|
|
|
|
decrease in size:
|
|
|
|
|
|
|
|
```lua
|
|
|
|
inv:set_list("main", {})
|
|
|
|
```
|