存储数据(Saved Data)
存储数据(Saved Data,简称 SD)系统可以用来在关卡(level)上保存额外的数据。
如果你的数据是特定于某些方块实体、区块或实体的,请考虑使用 数据附加。
声明(Declaration)
每一个 SD 实现都必须继承自 SavedData 类。需要注意两个重要的方法:
save:允许你的实现将 NBT 数据写入到关卡中。setDirty:在你修改了数据之后,必须调用此方法,以通知游戏有数据需要写入。如果不调用,#save方法将不会被调用,原始数据也不会被更改。
绑定到关卡(Attaching to a Level)
任何 SavedData 都是动态加载或绑定到关卡的。因此,如果你从未在某个关卡上创建过它,那么它就不会存在。
SavedData 的创建和加载都依赖于 DimensionDataStorage,你可以通过调用 ServerChunkCache#getDataStorage 或 ServerLevel#getDataStorage 来访问它。之后,你可以通过调用 DimensionDataStorage#computeIfAbsent 获取或创建你的 SD 实例。这个方法会尝试获取当前已有的 SD 实例,如果不存在,则会创建一个新的实例并加载所有可用的数据。
DimensionDataStorage#computeIfAbsent 需要两个参数。第一个参数是 SavedData.Factory 的一个实例,它由一个用于构造新 SD 实例的 supplier 和一个用于将 NBT 数据加载到 SD 并返回的函数组成。第二个参数是存储在已实现关卡的 data 文件夹下 .dat 文件的名称。该名称必须是合法的文件名,且不能包含 / 或 \。
例如,如果一个 SD 在下界(Nether)中名为 "example",那么会在 ./<level_folder>/DIM-1/data/example.dat 路径下创建一个文件,实现方式如下:
// 在某个存储数据实现类中
public class ExampleSavedData extends SavedData {
// 创建新的存储数据实例
public static ExampleSavedData create() {
return new ExampleSavedData();
}
// 加载已存在的存储数据实例
public static ExampleSavedData load(CompoundTag tag, HolderLookup.Provider lookupProvider) {
ExampleSavedData data = ExampleSavedData.create();
// 加载已保存的数据
return data;
}
@Override
public CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) {
// 将数据 写入 tag
return tag;
}
public void foo() {
// 修改存储数据中的内容
// 如果数据发生变化,必须调用 setDirty
this.setDirty();
}
}
// 在某个类的方法中
netherDataStorage.computeIfAbsent(new Factory<>(ExampleSavedData::create, ExampleSavedData::load), "example");
如果一个 SD 并不是特定于某个关卡的,应该将其绑定到主世界(Overworld),可以通过 MinecraftServer#overworld 获取主世界。主世界是唯一永远不会被完全卸载的维度,因此非常适合用来存储跨多个关卡的数据。