Flandre923
881 words
4 minutes
35 LevelSaveData

参考#

https://boson.v2mcdev.com/worldsaveddata/example.html https://docs.neoforged.net/docs/datastorage/saveddata

SaveData#

阅读前,请先自己大概阅读下https://docs.neoforged.net/docs/datastorage/saveddata 内容,大概了解下。

好了,我们正式开始,SaveData类是我的世界提供的一种维度级别的数据保存的方式,这种存储数据可以共享,并且可以跨纬度保存和获取到的,并且数据不存在存档文件夹中,而是在世界文件夹下面。

./<level_folder>/DIM-1/data/example.dat

这次我们介绍怎么使用这个类,我们创建一个存储物品和取出物品的方块,这个方块是谁的都可以存取和取出的(共享)。

/**
 * ModLevelSaveData类用于管理和持久化游戏中的物品堆栈数据。
 * 它继承自SavedData类,用于将数据保存到硬盘并在需要时加载。
 */
public class ModLevelSaveData extends SavedData {
    /**
     * 保存数据的名称常量。
     * 注意这个NAME应该保持是唯一的,不要重复。
     */
    public static final String NAME = "mod_level_save_data";
        /**
     * 用于存储物品堆栈的栈结构。
     */
    private final Stack<ItemStack> itemStacks = new Stack<>();
    /**
     * 创建一个新的ModLevelSaveData实例。
     *
     * @return 新创建的ModLevelSaveData实例。
     */
    public static ModLevelSaveData create() {
        return new ModLevelSaveData();
    }
    /**
     * 将物品堆栈放入栈中。
     *
     * @param item 要放入栈中的物品堆栈。
     */
    public void putItem(ItemStack item) {
        itemStacks.push(item);
        setDirty();
    }
    /**
     * 从栈中获取物品堆栈。
     *
     * @return 如果栈为空,则返回空气物品堆栈;否则返回栈顶的物品堆栈。
     */
    public ItemStack getItem() {
        if (itemStacks.isEmpty()) {
            return new ItemStack(Items.AIR);
        }
        setDirty();
        return itemStacks.pop();
    }
    /**
     * 将ModLevelSaveData的数据保存到CompoundTag中。
     *
     * @param pCompoundTag 要保存数据的CompoundTag。
     * @return 保存了数据的CompoundTag。
     */
    @Override
    public CompoundTag save(CompoundTag pCompoundTag) {
        ListTag listTag = new ListTag();
        itemStacks.forEach((stack) -> {
            CompoundTag compoundTag = new CompoundTag();
            compoundTag.put("itemstack", stack.getTag());
            listTag.add(compoundTag);
        });
        pCompoundTag.put("list", listTag);
        return pCompoundTag;
    }
  /**
     * 从CompoundTag中加载ModLevelSaveData的数据。
     *
     * @param nbt 包含数据的CompoundTag。
     * @return 加载了数据的ModLevelSaveData实例。
     */
    public ModLevelSaveData load(CompoundTag nbt) {
        ModLevelSaveData data = this.create();
        ListTag listNBT = (ListTag) nbt.get("list");
        if (listNBT != null) {
            for (Tag value : listNBT) {
                CompoundTag tag = (CompoundTag) value;
                ItemStack itemStack = ItemStack.of(tag.getCompound("itemstack"));
                itemStacks.push(itemStack);
            }
        }
        return data;
    }
/**
     * 从CompoundTag中解码ModLevelSaveData的数据。
     *
     * @param tag 包含数据的CompoundTag。
     * @return 解码后的ModLevelSaveData实例。
     */
    public static ModLevelSaveData decode(CompoundTag tag){
        ModLevelSaveData modLevelSaveData = ModLevelSaveData.create();
        modLevelSaveData.load(tag);
        return modLevelSaveData;
    }
/**
     * 获取指定世界的ModLevelSaveData实例。通过这个方法获得对应的data
     *
     * @param worldIn 要获取数据的世界。
     * @return 与指定世界关联的ModLevelSaveData实例。
* @throws RuntimeException 如果尝试从客户端世界获取数据,则抛出运行时异常。
     * **/
    public static ModLevelSaveData get(Level worldIn) {
        if (!(worldIn instanceof ServerLevel)) {
            throw new RuntimeException("Attempted to get the data from a client world. This is wrong.");
        }
        ServerLevel world = worldIn.getServer().getLevel(ServerLevel.OVERWORLD);
        DimensionDataStorage dataStorage = world.getDataStorage();
        return dataStorage.computeIfAbsent(new Factory<ModLevelSaveData>(ModLevelSaveData::create, ModLevelSaveData::decode), ModLevelSaveData.NAME);
    }
}

对应的方块的内容。

/**
 * DataSaveBlock是一个自定义的方块类,用于与玩家进行交互并保存和读取物品数据。
 * 它继承自Block类,具有与石头方块相同的属性。
 */
public class DataSaveBlock extends Block {
    public DataSaveBlock() {
        super(BlockBehaviour.Properties.ofFullCopy(Blocks.STONE));
    }
  /**
     * 当玩家使用该方块时触发的交互逻辑。这里如果是空手就从DATA中获得物品,如果手持物品就放入到DATA中去。
     *
     * @param pState 方块的状态。
     * @param pLevel 方块所在的世界。
     * @param pPos 方块的位置。
     * @param pPlayer 与方块交互的玩家。
     * @param pHand 玩家使用的手(主手或副手)。
     * @param pHit 玩家点击方块的碰撞结果。
     * @return 交互的结果,表示交互是否成功。
     */
    @Override
    public InteractionResult use(BlockState pState, Level pLevel, BlockPos pPos, Player pPlayer, InteractionHand pHand, BlockHitResult pHit) {
        if(!pLevel.isClientSide){
            ModLevelSaveData data  = ModLevelSaveData.get(pLevel);
            ItemStack mainHandItem = pPlayer.getMainHandItem();
            if(mainHandItem.isEmpty()){
                ItemStack itemStack = data.getItem();
                pPlayer.setItemInHand(InteractionHand.MAIN_HAND,itemStack);
            }else{
                ItemStack itemStack =mainHandItem.copy();
                mainHandItem.shrink(mainHandItem.getCount());
                data.putItem(itemStack);
            }
        }
        return InteractionResult.SUCCESS;
    }
}
35 LevelSaveData
https://fuwari.vercel.app/posts/minecraft1_20_4/out_35-levelsavedata/
Author
Flandre923
Published at
2024-04-14