User Tools

Site Tools


zh_cn:tutorial:extendedscreenhandler

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Next revision
Previous revision
zh_cn:tutorial:extendedscreenhandler [2022/02/10 12:50] – created timothy_starmanzh_cn:tutorial:extendedscreenhandler [2022/02/10 13:32] (current) – Result timothy_starman
Line 1: Line 1:
-====== 使用扩展的 ScreenHandler 同步数据 ====== +====== 使用扩展的 ScreenHandler 同步数据 ====== 
-在本教程中,我们将使用 ExtendedScreenHandler 在 ScreenHandler 打开时将任意数据从服务器传输到客户端 ScreenHandler。 +在本教程中,我们将使用 ExtendedScreenHandler 在 ScreenHandler 打开时将任意数据从服务器传输到客户端 ScreenHandler。 
 + 
 在我们的示例中,我们将用方块的位置作为容器的标题。 在我们的示例中,我们将用方块的位置作为容器的标题。
  
-要理解教程,需要阅读第一个[[tutorial:screenhandler|Screenhandler]] 教程。  +====== 方块实体 ====== 
-此处代码方法已在该教程示。+由于 Block 类根本不需更改,我们将其留在这里。 
 + 
 +我们的方块实体现在实现了 ''ExtendedScreenHandlerFactory'',这个接口为我们提供了 ''writeScreenOpeningData'' 方法,当它请求客户端(client)打开一个 ''ScreenHandler'' 时,将在服务器(server)上调用该方法。 您写入 ''PacketByteBuf'' 的数据将通过网络传输到客户端(client)。 
 + 
 +<code java [enable_line_numbers="true"] BoxBlockEntity.java> 
 + 
 +public class BoxBlockEntity extends BlockEntity implements ExtendedScreenHandlerFactory, ImplementedInventory { 
 +    private final DefaultedList<ItemStack> inventory = DefaultedList.ofSize(9, ItemStack.EMPTY); 
 + 
 +    public BoxBlockEntity() { 
 +        super(Test.BOX_BLOCK_ENTITY); 
 +    } 
 + 
 + 
 +    //来自 ImplementedInventory 接口 
 + 
 +    @Override 
 +    public DefaultedList<ItemStack> getItems() { 
 +        return inventory; 
 + 
 +    } 
 + 
 +    //这些方法来自 NamedScreenHandlerFactory 接口 
 + 
 +    @Override 
 +    public @Nullable ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) { 
 +        //我们将它提供给 screenHandler 作为我们的类实现 Inventory 
 +        //一开始只有服务器(Server)有 Inventory ,这将在 ScreenHandler 中同步到客户端(Cilent) 
 +        return new BoxScreenHandler(syncId, playerInventory, this); 
 +    } 
 + 
 +    @Override 
 +    public Text getDisplayName() { 
 +        return new TranslatableText(getCachedState().getBlock().getTranslationKey()); 
 +    } 
 + 
 +    //此方法来自 ExtendedScreenHandlerFactory 
 + 
 +    //当它请求客户端(client)打开 screenHandler 时,在服务器(server)上调用此方法 
 +    //您写入 packetByteBuf 的内容将自动以(数据)包的形式传输到客户端 
 +    //并在客户端(client)调用带有 packetByteBuf 参数的 ScreenHandler 构造函数 
 +    // 
 +    //您在此处插入内容的顺序与您需要提取它们的顺序相同。您不需要颠倒顺序! 
 +    @Override 
 +    public void writeScreenOpeningData(ServerPlayerEntity serverPlayerEntity, PacketByteBuf packetByteBuf) { 
 +        //pos 字段是 BlockEntity 的公共字段 
 +        packetByteBuf.writeBlockPos(pos); 
 +    } 
 +
 + 
 +</code> 
 + 
 +====== 新的 ExtendedScreenHandler (实例) ====== 
 + 
 +<code java [enable_line_numbers="true"] BoxScreenHandler.java> 
 +public class BoxScreenHandler extends ScreenHandler { 
 +    //我们保存从服务器获得的 blockPos 并为其提供一个 getter,以便 BoxScreen 可以读取该信息 
 +    private BlockPos pos; 
 +    private final Inventory inventory; 
 + 
 +    //当服务器(Server)希望它打开 screenHandler 时,在客户端(Cilent)上调用此构造函数, 
 +    //客户端将使用一个空的 Inventory 调用超级构造函数,并且 screenHandler 将自动将此空库存与服务器上的库存同步。 
 + 
 +    //新:客户端的构造函数现在获取我们在 BlockEntity 中填充的 PacketByteBuf 
 +    public BoxScreenHandler(int syncId, PlayerInventory playerInventory, PacketByteBuf buf) { 
 +        this(syncId, playerInventory, new SimpleInventory(9)); 
 +        pos = buf.readBlockPos(); 
 +    } 
 + 
 +    //此构造函数从服务器上的 BlockEntity 调用,服务器知道容器的库存(你可以将它理解为物品栏),因此可以直接将其作为参数提供。 然后,此库存(物品栏)将同步到客户端。 
 +    public BoxScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) { 
 +        //[...] 
 +        //有关其余代码,请参阅第一个 Screenhandler 教程 
 +         
 +        //想一想为什么我们在这里使用 BlockPos.ORIGIN? 
 +        //This is because the packetByteBuf with our blockPosition is only availible on the Client, so we need a placeholder 
 +        //value here. This is not a problem however, as the Server version of the ScreenHandler does not really need this 
 +        //information. 
 +        //(机翻警告)这是因为带有我们 blockPosition 的 packetByteBuf 仅在 Client 上可用,所以我们这里需要一个占位符值。 然而,这不是问题, 
 +        //因为 ScreenHandler 的服务器版本并不真正需要此信息。 
 +        pos = BlockPos.ORIGIN; 
 + 
 +        [...] 
 +    } 
 + 
 +    //这个 getter 将被我们的 Screen 类使用 
 +    public BlockPos getPos() { 
 +        return pos; 
 +    } 
 + 
 +    @Override 
 +    public boolean canUse(PlayerEntity player) { 
 +        return this.inventory.canPlayerUse(player); 
 +    } 
 + 
 +    // 参阅 Screenhandler 教程 
 +    // Shift + Player Inv Slot 
 +    @Override 
 +    public ItemStack transferSlot(PlayerEntity player, int invSlot); 
 +
 +</code> 
 + 
 +====== 在 Screen 中使用 ExtendedScreenHandler 信息 ====== 
 + 
 +<code java [enable_line_numbers="true"] BoxScreen.java> 
 + 
 +public class BoxScreen extends HandledScreen<ScreenHandler>
 +    private static final Identifier TEXTURE = new Identifier("minecraft", "textures/gui/container/dispenser.png"); 
 + 
 +    public BoxScreen(ScreenHandler handler, PlayerInventory inventory, Text title) { 
 +        super(handler, inventory, getPositionText(handler).orElse(title)); 
 +        //我们尝试获取方块位置以将其用作我们的标题,如果由于某种原因失败,我们将使用默认标题 
 +    } 
 + 
 +    //此方法将尝试从 ScreenHandler 获取位置,因为 ScreenRendering 仅发生在客户端上, 
 +    //我们在此处获取具正确 BlockPos 的 ScreenHandler 实例! 
 +    private static Optional<Text> getPositionText(ScreenHandler handler) { 
 +        if (handler instanceof BoxScreenHandler) { 
 +            BlockPos pos = ((BoxScreenHandler) handler).getPos(); 
 +            return pos != null ? Optional.of(new LiteralText("(" + pos.toShortString() + ")")) : Optional.empty(); 
 +        } else { 
 +            return Optional.empty(); 
 +        } 
 +    } 
 + 
 + 
 +    @Override 
 +    protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) { [...] } 
 + 
 +    @Override 
 +    public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { [...] } 
 + 
 +    @Override 
 +    protected void init() { [...] } 
 +
 + 
 +</code> 
 + 
 +====== 注册我们的 ScreenHandler ====== 
 + 
 +<code java [enable_line_numbers="true"] ExampleMod.java> 
 +public class ExampleMod implements ModInitializer { 
 + 
 +    [...] 
 +    public static final ScreenHandlerType<BoxScreenHandler> BOX_SCREEN_HANDLER; 
 + 
 +    static { 
 +        [...] 
 +        
 +        //我们现在使用 registerExtended 作为我们的 screenHandler 现在在其构造函数中接受一个 packetByteBuf 
 +        BOX_SCREEN_HANDLER = ScreenHandlerRegistry.registerExtended(BOX, BoxScreenHandler::new); 
 +    } 
 + 
 +    @Override 
 +    public void onInitialize() { 
 + 
 +    } 
 +
 +</code> 
 + 
 +====== 结果 ====== 
 +您现在经了解了如何在 ScreenHandler 打开时传输数据。 在图像您可以看到结果:方块的标题现在是它的位置。 
 +请注意,这只是一个演,还有更简单的方法可以将位置设置为标题 
 + 
 +您可能想知道://即使在屏幕打开后,我可以再次传输这些数据吗?// 
 +这可以通过在屏幕打开后发送自定义数据包来实现。 (see: [[tutorial:networking|Networking Tutorial]]) \\ 
 +您可能还想看看''BlockEntityClientSerializable'', 来自Fabric API 的界面. 
 + 
 +如果您只想同步整数值,您可以使用''PropertyDelegate'': [[tutorial:propertydelegates]]. 
 + 
 +{{:tutorial:bildschirmfoto_vom_2020-08-14_18-37-51.png?nolink&400|}} 
 + 
zh_cn/tutorial/extendedscreenhandler.1644497430.txt.gz · Last modified: 2022/02/10 12:50 by timothy_starman