保存数据

保存数据

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

如果数据属于特定方块实体、区块或实体,可以考虑改用数据附加。

声明

每个 SD 实现都必须继承 SavedData,其中有两个重要方法:

  • save:将 NBT 数据写入世界。
  • setDirty:修改数据后必须调用,用于通知游戏存在需要写入的变更。如果不调用,#save 就不会执行,原有数据也不会改变。

附加到世界

SavedData 会动态加载和/或附加到世界。如果从未在某个世界中创建对应数据,它就不会存在。

SD 由 DimensionDataStorage 创建和加载,可通过 ServerChunkCache#getDataStorage 或 ServerLevel#getDataStorage 获取该存储。然后调用 DimensionDataStorage#computeIfAbsent 来获取或创建 SD 实例:如果现有实例存在则取得它,否则创建新实例并加载所有可用数据。

DimensionDataStorage#computeIfAbsent 接受两个参数。第一个是 SavedData.Factory 实例,包含用于构造新 SD 实例的 supplier,以及将 NBT 载入 SD 并返回它的函数。第二个参数是保存在对应世界 data 文件夹中的 .dat 文件名。名称必须是有效文件名,不能包含 / 或反斜杠。

例如,下界中名为“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 不属于特定维度,应附加到主世界,可通过 MinecraftServer#overworld 获取。主世界是唯一永远不会完全卸载的维度,因此适合存储跨维度数据。


来源: NeoForged/Documentation(1.21.1)。中文翻译依据提交 4a680cdd4d15。