zh_cn:tutorial:propertydelegates
This is an old revision of the document!
−Table of Contents
使用 PropertyDelegates 同步整形数据
PropertyDelegates:PropertyDelegates
是一种可以包含多个可以被读写的整型值的容器。
在这章教程中,我们将会同步客户端和服务器之间的整型值,比如熔炉熔炼进度。
为了理解这篇教程,你需要先阅读 ScreenHandler 教程,这里不会再次显示已经在那里被提到的代码。
为了减小复杂性,在这章教程中不会再次使用 扩展的 ScreenHandler。
BlockEntity
由于 Block 类完全不需要更改,所以我们把它放在这里。
我们的 BlockEntity
现在实现了 Tickable
,这将提供 tick()
方法,每个 tick 都会调用该方法。我们用它来增加想要同步的整型。
- BoxBlockEnity.java
- public class BoxBlockEntity extends BlockEntity implements NamedScreenHandlerFactory, ImplementedInventory, Tickable {
- private final DefaultedList<ItemStack> inventory = DefaultedList.ofSize(9, ItemStack.EMPTY);
- // 这是我们希望同步的整型,它每 tick 会增加 1。
- private int syncedInt;
- // PropertyDelegate 是一个接口(Ingterface),我们将在这里使用内联(Inline)实现。
- // 它通常可以包含多个整型作为索引标志的数据,但是在本例中只有一个整型
- private final PropertyDelegate propertyDelegate = new PropertyDelegate() {
- @Override
- public int get(int index) {
- return syncedInt;
- }
- @Override
- public void set(int index, int value) {
- syncedInt = value;
- }
- // 这里应该返回你的 delegate 中整型的数量,在本例中只有一个
- @Override
- public int size() {
- return 1;
- }
- };
- public BoxBlockEntity() {
- super(Test.BOX_BLOCK_ENTITY);
- }
- // 返回 ImplementedInventory 接口(Interface)
- @Override
- public DefaultedList<ItemStack> getItems() {
- return inventory;
- }
- //这些方法来自 NamedScreenHandlerFactory 接口(Interface)
- @Override
- public @Nullable ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) {
- // 当我们的类执行完物品栏时,我们将此提供给 screenHandler
- // 只有服务器在开始时拥有物品栏,这将会在 ScreenHandler 中同步到客户端
- // 类似于物品栏:服务器获得 PropertyDelegate 并将其直接给 screen handler 的服务器实例
- return new BoxScreenHandler(syncId, playerInventory, this,propertyDelegate);
- }
- @Override
- public Text getDisplayName() {
- // 对于 1.18.2 或更低版本,请使用 return new TranslatableText(getCachedState().getBlock().getTranslationKey());
- return Text.translatable(getCachedState().getBlock().getTranslationKey());
- }
- // 每个 tick 增加一个同步的整型,我们只是处于演示目的在服务器上这么做。
- @Override
- public void tick() {
- if(!world.isClient)
- syncedInt++;
- }
- }
我们的新的 ScreenHandler
- BoxScreenHandler.java
- public class BoxScreenHandler extends ScreenHandler {
- private final Inventory inventory;
- PropertyDelegate propertyDelegate;
- // 当服务器想要打开 screenHandler 时,这个构造函数将会在客户端被调用
- // 客户端将调用一个带有空的物品栏的父级构造函数和 screenHandler 将自动同步这个空的物品栏到服务器上
- // 就像是于物品栏,客户端将分配一个空的 propertyDelegate 并且它将自动与服务器同步
- public BoxScreenHandler(int syncId, PlayerInventory playerInventory) {
- this(syncId, playerInventory, new SimpleInventory(9),new ArrayPropertyDelegate(1));
- }
- // 该构造函数从服务器上的 BlockEntity 调用,服务器知道容器(Container)中的物品栏,因此可以直接将其作为参数提供。这个物品栏以及 propertyDelegate 将被同步到客户端
- public BoxScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory, PropertyDelegate propertyDelegate) {
- super(Test.BOX_SCREEN_HANDLER, syncId);
- checkSize(inventory, 9);
- this.inventory = inventory;
- this.propertyDelegate = propertyDelegate;
- // 有些物品栏会在玩家打开时作自定义逻辑操作(Custom Logic)
- inventory.onOpen(playerInventory.player);
- // 我们需要告诉 screenHandler 关于 propertyDelegate 里的数据,否则它不会同步这里面的数据
- this.addProperties(propertyDelegate);
- // 这将会把物品槽(Slot)放在 3x3 网格中正确的位置,物品槽(Slot)在服务端和客户端都存在!
- [...]
- }
- // 我们为已同步的整型提供了 getter, 所以 Screen 可以访问它并且在屏幕上显示它。
- public int getSyncedNumber(){
- return propertyDelegate.get(0);
- }
- @Override
- public boolean canUse(PlayerEntity player) {
- return this.inventory.canPlayerUse(player);
- }
- @Override
- public ItemStack transferSlot(PlayerEntity player, int invSlot) {[...]}
- }
使用 Screen 显示信息
当屏幕在其构造函数中获得 ScreenHandler 时,我们可以从上面访问 property delegates ,并可以在屏幕上显示整型。
public class BoxScreen extends HandledScreen<ScreenHandler> { private static final Identifier TEXTURE = new Identifier("minecraft", "textures/gui/container/dispenser.png"); BoxScreenHandler screenHandler; public BoxScreen(ScreenHandler handler, PlayerInventory inventory, Text title) { super(handler, inventory, title); // 我们保存了对 screenhandler 的引用,这样我们就可以在屏幕上呈现 propertyDelegate 中的数字 screenHandler = (BoxScreenHandler) handler; } @Override protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) {[...]} @Override public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { // 我们只是在容器的某个地方渲染我们同步的数字,这毕竟是一个演示 // 最后一个参数是一个颜色代码,使字体亮绿色 renderBackground(matrices); super.render(matrices, mouseX, mouseY, delta); drawMouseoverTooltip(matrices, mouseX, mouseY); } @Override protected void init() { super.init(); // 居中标题 titleX = (backgroundWidth - textRenderer.getWidth(title)) / 2; } }
最后
由于 ScreenHandler
的注册与第一个教程相同,我们已经可以看到结果了!当 BlockEntity
被放置时,它将每 tick
增加一个 syncedInt
;当我们查看容器内部时,整型将自动同步到客户端并呈现在左上角。
如果您想要一个更现实的例子,您可以去看看 Minecraft
代码中的 AbstractFurnaceEntity
和 AbstractFurnaceScreenHandler
。
zh_cn/tutorial/propertydelegates.1675392438.txt.gz · Last modified: 2023/02/03 02:47 by hanatomizu