跳到主要内容
版本:1.21 - 1.21.1

存档数据(Saved Data)

存档数据(Saved Data,简称 SD)系统可用于在世界(Level)上保存额外数据。

如果数据只与某些方块实体、区块或实体相关,请考虑改用数据附加

声明

每个 SD 实现都必须继承 SavedData 类。有两个重要方法需要留意:

  • save:允许实现将 NBT 数据写入世界。
  • setDirty:在修改数据后必须调用该方法,以通知游戏存在需要写入的更改。如果不调用,#save 将不会被调用,原有数据也将保持不变。

附加到世界

任何 SavedData 都是动态加载和/或附加到世界的。因此,如果某个世界从未创建过它,它就不会存在。

SavedDataDimensionDataStorage 创建和加载,后者可通过调用 ServerChunkCache#getDataStorageServerLevel#getDataStorage 获取。随后,你可以调用 DimensionDataStorage#computeIfAbsent 来获取或创建你的 SD 实例。该方法会尝试获取当前存在的 SD 实例,若不存在则创建一个新实例并加载所有可用数据。

DimensionDataStorage#computeIfAbsent 接收两个参数。第一个是 SavedData.Factory 的实例,它由一个用于构造 SD 新实例的 Supplier 和一个用于将 NBT 数据加载进 SD 并返回该 SD 的函数组成。第二个参数是存储在对应世界 data 文件夹中的 .dat 文件名。该名称必须是合法的文件名,且不能包含 /\

例如,若在下界(Nether)中有一个名为 "example" 的 SD,则会在 ./<level_folder>/DIM-1/data/example.dat 处创建文件,其实现方式如下:

// In some saved data implementation
public class ExampleSavedData extends SavedData {

// Create new instance of saved data
public static ExampleSavedData create() {
return new ExampleSavedData();
}

// Load existing instance of saved data
public static ExampleSavedData load(CompoundTag tag, HolderLookup.Provider lookupProvider) {
ExampleSavedData data = ExampleSavedData.create();
// Load saved data
return data;
}

@Override
public CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) {
// Write data to tag
return tag;
}

public void foo() {
// Change data in saved data
// Call set dirty if data changes
this.setDirty();
}
}

// In some method within the class
netherDataStorage.computeIfAbsent(new Factory<>(ExampleSavedData::create, ExampleSavedData::load), "example");

如果某个 SD 并非特定于某个世界,则应将其附加到主世界(Overworld),主世界可通过 MinecraftServer#overworld 获取。主世界是唯一永远不会被完全卸载的维度,因此非常适合用来存储跨世界数据。