Gespeicherte Daten sind die integrierte Lösung von Minecraft, um Daten über mehrere Sitzungen hinweg zu speichern.
Die Daten werden auf dem Datenträger gespeichert und beim Schließen und erneuten Öffnen des Spiels wieder geladen. Diese Daten sind in der Regel auf einen Geltungsbereich begrenzt (z. B. auf das Level). Die Daten werden als NBT auf den Datenträger geschrieben, und Codecs werden verwendet, um diese Daten zu serialisieren/deserialisieren.
Betrachten wir ein einfaches Szenario, in dem wir die Anzahl der vom Spieler abgebauten Blöcke speichern müssen. Wir können diese Anzahl auf dem logischen Server speichern.
Wir können das Event PlayerBlockBreakEvents.AFTER mit einem einfachen statischen Integer-Feld verwenden, um diesen Wert zu speichern und als Chat-Nachricht zu versenden.
java
private static int blocksBroken = 0; // keeps track of the number of blocks broken
PlayerBlockBreakEvents.AFTER.register((level, player, pos, state, blockEntity) -> {
blocksBroken++; // increment the counter each time a block is broken
player.displayClientMessage(Component.literal("Blocks broken: " + blocksBroken), false);
});1
2
3
4
5
6
2
3
4
5
6
Wenn du jetzt einen Block abbaust, wird eine Nachricht mit der Anzahl angezeigt.

Wenn du Minecraft neu startest, die Welt lädst und anfängst, Blöcke abzubauen, wirst du feststellen, dass der Zähler zurückgesetzt wurde. Hier benötigen wir gespeicherte Daten. Wir können diese Anzahl dann speichern, sodass wir beim nächsten Laden der Welt die gespeicherte Anzahl abrufen und ab diesem Punkt weiterzählen können.
Daten speichern
SavedData ist die Hauptklasse, die für das Speichern und Laden von Daten zuständig ist. Da es sich um eine abstrakte Klasse handelt, wird von dir erwartet, dass du eine Implementierung bereitstellst.
Eine Datenklasse einrichten
Nennen wir unsere Datenklasse SavedBlockData und lassen wir sie SavedData erweitern.
Diese Klasse enthält ein Feld, um die Anzahl der abgebauten Blöcke zu verfolgen, sowie eine Methode zum Abrufen und eine Methode zum Erhöhen dieser Anzahl.
java
public class SavedBlockData extends SavedData {
private int blocksBroken = 0;
public SavedBlockData() {
}
public int getBlocksBroken() {
return blocksBroken;
}
// :::set_dirty
public void incrementBlocksBroken() {
blocksBroken++;
// If saved data is not marked dirty, nothing will be saved when Minecraft closes.
setDirty();
}
// :::set_dirty
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Um diese Daten zu serialisieren und zu deserialisieren, müssen wir einen Codec definieren. Wir können einen Codec aus verschiedenen primitiven Codecs zusammenstellen, die von Minecraft bereitgestellt werden.
Du benötigst einen Konstruktor mit einem int-Argument, um die Klasse zu initialisieren.
java
public SavedBlockData(int count) {
blocksBroken = count;
}1
2
3
2
3
Dann können wir einen Codec bauen.
java
private static final Codec<SavedBlockData> CODEC = Codec.INT.xmap(
SavedBlockData::new, // Create a new 'SavedBlockData' from the stored number.
SavedBlockData::getBlocksBroken // Return the number from the 'SavedBlockData' to be saved/
);1
2
3
4
2
3
4
Wir sollten setDirty() aufrufen, wenn Daten tatsächlich geändert werden, damit Minecraft weiß, dass sie auf der Festplatte gespeichert werden müssen.
java
public void incrementBlocksBroken() {
blocksBroken++;
// If saved data is not marked dirty, nothing will be saved when Minecraft closes.
setDirty();
}1
2
3
4
5
6
2
3
4
5
6
Schließlich benötigen wir einen SavedDataType, der unsere gespeicherten Daten beschreibt. Das erste Argument entspricht dem Namen der Datei, die im Verzeichnis data der Welt erstellt wird.
java
private static final SavedDataType<SavedBlockData> TYPE = new SavedDataType<>(
"saved_block_data", // The unique name for this saved data.
SavedBlockData::new, // If there's no 'SavedBlockData', yet create one and refresh fields.
CODEC, // The codec used for serialization/deserialization.
null // A data fixer, which is not needed here.
);1
2
3
4
5
6
2
3
4
5
6
Auf gespeicherte Daten zugreifen
Wie bereits erwähnt, können gespeicherte Daten mit einem Geltungsbereich wie dem aktuellen Level verknüpft werden. In diesem Fall sind unsere Daten Teil der Level-Daten. Wir können die DimensionDataStorage des Level abrufen, um unsere Daten hinzuzufügen und zu ändern.
Wir werden diese Logik in eine Hilfsmethode einbauen.
java
public static SavedBlockData getSavedBlockData(MinecraftServer server) {
// This could be either the overworld or another dimension.
ServerLevel level = server.getLevel(ServerLevel.OVERWORLD);
if (level == null) {
return new SavedBlockData(); // Return a new instance if the level is null.
}
// The first time the following 'computeIfAbsent' function is called, it creates a new 'SavedBlockData'
// instance and stores it inside the 'DimensionDataStorage'.
// Subsequent calls to 'computeIfAbsent' returns the saved 'SavedBlockData' NBT on disk to the Codec in our type,
// using the Codec to decode the NBT into our saved data.
return level.getDataStorage().computeIfAbsent(TYPE);
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
Gespeicherte Daten verwenden
Nachdem wir jetzt alles eingerichtet haben, speichern wir einige Daten.
Wir können das erste Szenario wiederverwenden und anstatt das Feld zu erhöhen, können wir unsere Funktion incrementBlocksBroken aus unseren SavedBlockData aufrufen.
java
PlayerBlockBreakEvents.AFTER.register((level, player, pos, state, blockEntity) -> {
MinecraftServer server = level.getServer();
if (server == null) {
return;
}
// Retrieve the saved block data from the server.
SavedBlockData savedData = SavedBlockData.getSavedBlockData(server);
savedData.incrementBlocksBroken(); // Increment the counter each time a block is broken.
player.displayClientMessage(Component.literal("Blocks broken: " + savedData.getBlocksBroken()), false);
});1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
Dies sollte den Wert erhöhen und ihn auf dem Datenträger speichern.
Wenn du Minecraft neu startest, die Welt lädst und einen Block abbaust, wirst du sehen, dass die zuvor gespeicherte Anzahl jetzt erhöht ist.
Wenn du in das Verzeichnis data der Welt gehst, siehst du eine .dat -Datei mit dem Namen saved_block_data.dat . Wenn du diese Datei in einem NBT-Reader öffnest, siehst du, wie unsere Daten darin gespeichert sind.

