Blockcontainer
Es empfiehlt sich, bei der Erstellung von Blöcken, die Items speichern können, wie Truhen und Öfen, Container zu implementieren. Dadurch ist es beispielsweise möglich, mit dem Block mithilfe von Trichtern zu interagieren.
In diesem Tutorial erstellen wir einen Block, der seinen Container verwendet, um alle darin platzierten Items zu duplizieren.
Erstellen des Blocks
Dies sollte dem Leser bekannt sein, wenn er die Leitfäden Erstellen deines ersten Blocks und Block-Entitäten befolgt hat. Wir werden einen DuplicatorBlock erstellen, der von BaseEntityBlock erbt und EntityBlock implementiert.
java
No lines matched.1
Dann müssen wir eine DuplicatorBlockEntity erstellen, welche das Interface Container implementieren muss. Da die meisten Container in der Regel auf die gleiche Weise funktionieren, kannst du einen Helfer namens ImplementedContainer kopieren und einfügen, der den Großteil der Arbeit übernimmt, sodass wir nur noch wenige Methoden implementieren müssen.
Zeige ImplementedContainer
java
package com.example.docs.container;
import net.minecraft.core.NonNullList;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
/**
* A simple {@link Container} implementation with only default methods + an item list getter.
*
* @author Juuz
*/
public interface ImplementedContainer extends Container {
/**
* Retrieves the item list of this container.
* Must return the same instance every time it's called.
*/
NonNullList<ItemStack> getItems();
/**
* Creates a container from the item list.
*/
static ImplementedContainer of(NonNullList<ItemStack> items) {
return () -> items;
}
/**
* Creates a new container with the specified size.
*/
static ImplementedContainer ofSize(int size) {
return of(NonNullList.withSize(size, ItemStack.EMPTY));
}
/**
* Returns the container size.
*/
@Override
default int getContainerSize() {
return getItems().size();
}
/**
* Checks if the container is empty.
* @return true if this container has only empty stacks, false otherwise.
*/
@Override
default boolean isEmpty() {
for (int i = 0; i < getContainerSize(); i++) {
ItemStack stack = getItem(i);
if (!stack.isEmpty()) {
return false;
}
}
return true;
}
/**
* Retrieves the item in the slot.
*/
@Override
default ItemStack getItem(int slot) {
return getItems().get(slot);
}
/**
* Removes items from a container slot.
* @param slot The slot to remove from.
* @param count How many items to remove. If there are fewer items in the slot than what are requested,
* takes all items in that slot.
*/
@Override
default ItemStack removeItem(int slot, int count) {
ItemStack result = ContainerHelper.removeItem(getItems(), slot, count);
if (!result.isEmpty()) {
setChanged();
}
return result;
}
/**
* Removes all items from a container slot.
* @param slot The slot to remove from.
*/
@Override
default ItemStack removeItemNoUpdate(int slot) {
return ContainerHelper.takeItem(getItems(), slot);
}
/**
* Replaces the current stack in an container slot with the provided stack.
* @param slot The container slot of which to replace the item stack.
* @param stack The replacing item stack. If the stack is too big for
* this container ({@link Container#getMaxStackSize()}),
* it gets resized to this container's maximum amount.
*/
@Override
default void setItem(int slot, ItemStack stack) {
getItems().set(slot, stack);
if (stack.getCount() > stack.getMaxStackSize()) {
stack.setCount(stack.getMaxStackSize());
}
}
/**
* Clears the container.
*/
@Override
default void clearContent() {
getItems().clear();
}
/**
* Marks that the state has changed.
* Must be called after changes in the container, so that the game can properly save
* the container contents and notify neighboring blocks of container changes.
*/
@Override
default void setChanged() {
// Override if you want behavior.
}
/**
* @return true if the player can use the container, false otherwise.
*/
@Override
default boolean stillValid(Player player) {
return true;
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
java
No lines matched.1
In der Liste items wird der Inhalt des Containers gespeichert. Für diesen Block haben wir eine Größe von 1 Slot für die Eingabe festgelegt.
Vergiss nicht den Block und die Blockentität in deren jeweiligen Klasse zu registrieren!
Speichern & Laden
Wenn wir möchten, dass die Inhalte zwischen den Spielneustarts wie bei einer Vanilla BlockEntity erhalten bleiben, müssen wir sie als NBT speichern. Dankenswerterweise stellt Mojang eine Hilfsklasse namens ContainerHelper mit der gesamten erforderlichen Logik zur Verfügung.
java
No lines matched.1
Mit dem Container interagieren
Technisch gesehen, funktioniert der Container bereits. Um jedoch Items einzufügen, müssen wir derzeit Trichter verwenden. Lasst uns es so einrichten, dass wir Items durch einen Rechtsklick auf den Block einfügen können.
Um dies zu tun, müssen wir die Methode useItemOn in DuplicatorBlock überschreiben:
java
No lines matched.1
Wenn der Spieler ein Item hält und ein Platz frei ist, verschieben wir das Item aus der Hand des Spielers in den Container des Blocks und geben InteractionResult.SUCCESS zurück.
Wenn du jetzt mit der rechten Maustaste auf den Block mit einem Item klickst, wirst du es nicht mehr haben! Wenn du /data get block auf dem Block ausführst, wirst du das Item in dem Feld items des NBT sehen.

Items duplizieren
Lasst uns jetzt dafür sorgen, dass der Block den Stack, den du hineingeworfen hast, dupliziert, jedoch nur jeweils zwei Items auf einmal. Und lassen wir es jedes Mal eine Sekunde warten, um den Spieler nicht mit Items zuzuspammen!
Dazu fügen wir eine Funktion tick zur DuplicatorBlockEntity hinzu und ein Feld, um zu speichern, wie lange wir gewartet haben:
java
No lines matched.1
Der DuplicatorBlock sollte nun über eine Methode getTicker verfügen, die eine Referenz auf DuplicatorBlockEntity::tick zurückgibt.
Weltbasierte Container
Standardmäßig kannst du Items von jeder Seite aus in den Container einfügen und aus ihm entnehmen. Dies ist jedoch unter Umständen nicht immer erwünscht: Beispielsweise nimmt ein Ofen Brennstoff nur von der Seite und Items nur von oben auf.
Um dieses Verhalten zu erzeugen, müssen wir das Interface WorldlyContainer in BlockEntity implementieren. Das Interface hat drei Methoden:
getSlotsForFace(Direction)lässt dir steuern, mit welchen Slots von einer bestimmten Seite aus interagiert werden kann.canPlaceItemThroughFace(int, ItemStack, Direction)lässt dir steuern, ob ein Item von einer gegebenen Seite in einen Slot eingefügt werden kann.canTakeItemThroughFace(int, ItemStack, Direction)lässt dir steuern, ob ein Item von einer gegebenen Seite entnommen werden kann.
Lasst uns die DuplicatorBlockEntity bearbeiten, um nur Items von der Oberseite zu akzeptieren:
java
No lines matched.1
Die Methode getSlotsForFace gibt ein Array der Slot Indizes zurück, mit denen von der angegebenen Seite aus interagiert werden kann. In diesem Fall haben wir nur einen einzigen Slot (0), daher geben wir ein Array mit genau diesem Index zurück.
Außerdem sollten wir die Methode useItemOn von DuplicatorBlock ändern, um das neue Verhalten tatsächlich zu berücksichtigen:
java
No lines matched.1
Wenn wir nun versuchen, Items von der Seite statt von oben einzufügen, funktioniert das nicht!
Menüs
Um über ein Menü auf den neuen Containerblock zuzugreifen, so wie du es bei einer Truhe tust, lies bitte den Leitfaden Containermenüs.

