函数
介绍 Rebar 函数系统的基础知识。
最后更新时间
物品构造函数
你可能会以为每次创建物品时(比如每次物品被合成时)都会调构造函数。但事实并非如此。
关键的一点是:构造函数可以被任意调用,不只是在物品"被创建"的时候。
等等……为什么构造函数可以被任意调用?
(叹气) 说来话长……简单讲:
Rebar 没法时刻跟踪每一个物品。如果能改服务端核心代码的话倒是可以。但事实上,Rebar 只能临时跟踪 Rebar 物品。
比如,当我们用一个实现了 RebarItemEntityInteractor 的物品右键实体时,Rebar 会监听 PlayerInteractEntityEvent,发现有个实体被某个物品右键了。为了搞清楚这是什么物品——以及它到底是不是 Rebar 物品——Rebar 得查看存储在物品里的键。但即使 Rebar 知道了键,它对这个物品的了解也有限。这个物品实现了 RebarItemEntityInteractor 吗?如果实现了,Rebar 就需要调它的 onUsedToRightClickEntity。
这时候就要靠构造函数了。我们可以查到该物品对应的类,创建一个新实例,然后调用 onUsedToRightClickEntity 方法。
总结一下:这个类可以在任何时候被创建或销毁。字段里存的数据都是临时的。
但假设我们想存便携电池的电量。既然字段存不了电量,那到底能存哪呢?
持久化数据容器 (PDCs)
PDC 是 Paper 加的,不是 Pylon 的。之所以在这里介绍,是因为 Pylon 里几乎所有持久化数据存储(包括方块和实体)都用到了它。
PersistentDataContainer(PDC)是一种简单直接的持久化数据存储方式。结构上类似 JSON——嵌套的键值对存储。每个值用 NamespacedKey 标识。PDC 可以互相嵌套。物品自带一个 PDC,所以要持久保存数据,就得在修改时写入物品的 PDC。
PDC 更多信息看 Paper 文档。
举个例子:记录便携电池的电量。把电量存到物品 PDC 里,键名叫 charge_level。不管物品放进箱子还是服务器重启,数据都还在。
听着有点晕的话别急,看个例子就明白了。
计数法棍
想法
做一个能存数字的"计数法棍"。右键时,法棍把存的数字发到你聊天框,然后数字 +1。
创建物品
先做一个还不能计数的法棍。
public class MyAddonKeys {
public static final NamespacedKey countingBaguetteKey = new NamespacedKey(this, "counting_baguette");
}public final class ExampleAddonItems {
// ...
public static final ItemStack countingBaguette = ItemStackBuilder.rebar(Material.BREAD, countingBaguetteKey)
.build();
// ...
public static void initialize() {
// ...
RebarItem.register(CountingBaguette.class, countingBaguette);
PylonPages.FOOD.addItem(countingBaguette);
}
}public class CountingBaguette extends RebarItem {
public CountingBaguette(@NotNull ItemStack stack) {
super(stack);
}
}item:
counting_baguette:
name: "Counting Baguette"
lore: |-
<arrow> Mathematics is improved tenfold when combined with baguettes添加计数逻辑
先检测玩家右键操作:
public class CountingBaguette extends RebarItem implements RebarInteractor {
public CountingBaguette(@NotNull ItemStack stack) {
super(stack);
}
@Override
public void onUsedToClick(@NotNull PlayerInteractEvent event, @NotNull EventPriority priority) {
// TODO 发送存储的值给玩家
// TODO 增加存储的值
}
}在方法里,读取存的值,发给玩家,再存回 +1 后的值。
往 PDC 存数据还需要两样东西:标识这条数据的 NamespacedKey,以及数据的类型(PersistentDataType)。
PylonSerializers
方便起见,Pylon 在 PylonSerializers 里提供了很多类型。包括 Paper 默认的所有类型,还额外加了一些(如 UUID、Vector、BlockPosition、ItemStack 等)。
public class CountingBaguette extends RebarItem implements RebarInteractor {
public static final NamespacedKey COUNT_KEY = new NamespacedKey(MyAddon.getInstance(), "count");
public CountingBaguette(@NotNull ItemStack stack) {
super(stack);
}
@Override
public void onUsedToClick(@NotNull PlayerInteractEvent event, @NotNull EventPriority priority) {
int count = getStack().getPersistentDataContainer().get(COUNT_KEY, PylonSerializers.INTEGER);
event.getPlayer().sendMessage(String.valueOf(count));
getStack().editPersistentDataContainer(pdc -> pdc.set(COUNT_KEY, PylonSerializers.INTEGER, count + 1));
}
}设置默认值
你可能注意到还没设初始值。来加上:
NamespacedKey countingBaguetteKey = new NamespacedKey(this, "counting_baguette");
ItemStack countingBaguette = ItemStackBuilder.rebar(Material.BREAD, countingBaguetteKey)
.editPdc(pdc -> pdc.set(CountingBaguette.COUNT_KEY, PylonSerializers.INTEGER, 0))
.build();
RebarItem.register(CountingBaguette.class, countingBaguette);
PylonPages.FOOD.addItem(countingBaguette);搞定!只要物品还在,存的数据就一直在。