User Tools

Site Tools


zh_cn:tutorial:screenhandler

Differences

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

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
zh_cn:tutorial:screenhandler [2022/12/19 08:28] solidblockzh_cn:tutorial:screenhandler [2024/08/27 04:50] (current) – update translations solidblock
Line 1: Line 1:
-====== 创建一个容器方块 ======+====== 创建容器方块 ======
 这篇教程会创建一个类似发射器的简单存储方块,并解释如何使用 Fabric 和原版 Minecraft 中的 ScreenHandler API 构建用户界面。 这篇教程会创建一个类似发射器的简单存储方块,并解释如何使用 Fabric 和原版 Minecraft 中的 ScreenHandler API 构建用户界面。
  
 先解释一些词汇: 先解释一些词汇:
  
-**Screenhandler:**+**Screenhandler**
 ''ScreenHandler'' 是负责在客户端和服务器之间同步物品栏内容的类。它也可以同步额外的数值,比如熔炉烧炼进度,这将在下一个教程中展示。我们的子类会有以下两个构造器:一个将在服务器端使用,并将储存真正的 ''Inventory'',另外一个将会在客户端运行,用于储存 ''ItemStack'' 并且让他们能和服务端同步。 ''ScreenHandler'' 是负责在客户端和服务器之间同步物品栏内容的类。它也可以同步额外的数值,比如熔炉烧炼进度,这将在下一个教程中展示。我们的子类会有以下两个构造器:一个将在服务器端使用,并将储存真正的 ''Inventory'',另外一个将会在客户端运行,用于储存 ''ItemStack'' 并且让他们能和服务端同步。
  
-**Screen:**+**Screen**
 ''Screen'' 类仅存在于客户端,将为您的 ''ScreenHandler'' 呈现背景和其他装饰。 ''Screen'' 类仅存在于客户端,将为您的 ''ScreenHandler'' 呈现背景和其他装饰。
  
Line 18: Line 18:
     protected BoxBlock(Settings settings) {     protected BoxBlock(Settings settings) {
         super(settings);         super(settings);
 +    }
 +    
 +    // 从 1.20.5 开始需要有这个方法。
 +    @Override
 +    protected MapCodec<? extends BoxBlock> getCodec() {
 +        return createCodec(BoxBlock::new);
     }     }
  
Line 106: Line 112:
     public Text getDisplayName() {     public Text getDisplayName() {
         return Text.translatable(getCachedState().getBlock().getTranslationKey());         return Text.translatable(getCachedState().getBlock().getTranslationKey());
-        // 对于1.19之前的版本,请使用:+        // 对于 1.19 之前的版本,请使用:
         // return new TranslatableText(getCachedState().getBlock().getTranslationKey());         // return new TranslatableText(getCachedState().getBlock().getTranslationKey());
     }     }
          
 +    // 以下两个方法,旧版本请移除参数 `registryLookup`。
     @Override     @Override
-    public void readNbt(NbtCompound nbt) { +    public void readNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { 
-        super.readNbt(nbt); +        super.readNbt(nbt, registryLookup); 
-        Inventories.readNbt(nbt, this.inventory);+        Inventories.readNbt(nbt, this.inventory, registryLookup);
     }     }
  
     @Override     @Override
-    public NbtCompound writeNbt(NbtCompound nbt) { +    public NbtCompound writeNbt(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup) { 
-        super.writeNbt(nbt); +        super.writeNbt(nbt, registryLookup); 
-        Inventories.writeNbt(nbt, this.inventory);+        Inventories.writeNbt(nbt, this.inventory, registryLookup);
         return nbt;         return nbt;
     }     }
Line 127: Line 134:
  
 ===== 注册方块、物品和方块实体 ===== ===== 注册方块、物品和方块实体 =====
 +在这个例子中,方块、方块物品。方块实体直接注册在 ''ExampleMod'' 类中,实际开发模组时可能也需要考虑放到单独的类里面(参见 [[blocks]] 和 [[blockentity]])。
  
 <code java [enable_line_numbers="true"] ExampleMod.java> <code java [enable_line_numbers="true"] ExampleMod.java>
 public class ExampleMod implements ModInitializer { public class ExampleMod implements ModInitializer {
  
-    public static final Block BOX_BLOCK; +    // 对于 1.21 之前版本,将 `Identifier.of` 替换为 `new Identifier`。 
-    public static final BlockItem BOX_BLOCK_ITEM; +    public static final Block BOX_BLOCK = Registry.register(Registries.BLOCK, Identifier.of("tutorial""box_block"), 
-    public static final BlockEntityType<BoxBlockEntity> BOX_BLOCK_ENTITY; +        new BoxBlock(AbstractBlock.Settings.copyOf(Blocks.CHEST))); 
- +         
-    public static final String MOD_ID = "testmod"; +    public static final BlockItem BOX_BLOCK_ITEM = Registry.register(Registries.ITEM, Identifier.of("tutorial""block"), 
-    // 我们大型箱子中不同部分的公共id +        new BlockItem(BOX_BLOCK, new Item.Settings())); 
-    public static final Identifier BOX = new Identifier(MOD_ID, "box_block"); +         
- +    public static final BlockEntityType<BoxBlockEntity> BOX_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, Identifier.of("tutorial""box_block"),  
-    static +        BlockEntityType.Builder.create(BoxBlockEntity::new, BOX_BLOCK).build()); 
-        BOX_BLOCK = Registry.register(Registries.BLOCK, BOX, new BoxBlock(FabricBlockSettings.copyOf(Blocks.CHEST))); +    // 在 1.17 使用 FabricBlockEntityTypeBuilder 而不是 BlockEntityType.Builder 
-        BOX_BLOCK_ITEM = Registry.register(Registries.ITEM, BOX, new BlockItem(BOX_BLOCK, new Item.Settings().group(ItemGroup.MISC))); +    // public static final BlockEntityType<BoxBlockEntity> BOX_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, new Identifier("tutorial""box_block"), 
- +    //     FabricBlockEntityTypeBuilder.create(BoxBlockEntity::new, BOX_BLOCK).build(null));;
-        //The parameter of build at the very end is always null, do not worry about it +
-        // 1.17 之前 +
-        BOX_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, BOX, BlockEntityType.Builder.create(BoxBlockEntity::new, BOX_BLOCK).build(null)); +
-        // 在 1.17 使用 FabricBlockEntityTypeBuilder 而不是 BlockEntityType.Builder +
-        BOX_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, BOX, FabricBlockEntityTypeBuilder.create(BoxBlockEntity::new, BOX_BLOCK).build(null)); +
-    }+
  
     @Override     @Override
     public void onInitialize() {     public void onInitialize() {
- 
     }     }
 } }
- 
- 
 </code> </code>
  
Line 174: Line 173:
     }     }
  
-    // 这个构造器是在服务器的 BlockEntity 中被调用的,无需线调用其他构造器,服务器知道容器的物品栏+    // 这个构造器是在服务器的 BlockEntity 中被调用的,无需调用其他构造器,服务器知道容器的物品栏
     // 并直接将其作为参数传入。然后物品栏在客户端完成同步。     // 并直接将其作为参数传入。然后物品栏在客户端完成同步。
     public BoxScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) {     public BoxScreenHandler(int syncId, PlayerInventory playerInventory, Inventory inventory) {
Line 184: Line 183:
  
         // 这会将槽位放置在 3×3 网格的正确位置中。这些槽位在客户端和服务器中都存在!         // 这会将槽位放置在 3×3 网格的正确位置中。这些槽位在客户端和服务器中都存在!
-        // 但是这不会渲染槽位的背景,这是 Screens job+        // 但是这不会渲染槽位的背景,这是 Screens 类的工作
         int m;         int m;
         int l;         int l;
Line 243: Line 242:
 public class BoxScreen extends HandledScreen<ScreenHandler> { public class BoxScreen extends HandledScreen<ScreenHandler> {
     // GUI 纹理的路径,本例中使用发射器中的纹理     // GUI 纹理的路径,本例中使用发射器中的纹理
-    private static final Identifier TEXTURE = new Identifier("minecraft", "textures/gui/container/dispenser.png");+    private static final Identifier TEXTURE = Identifier.ofVanilla("minecraft", "textures/gui/container/dispenser.png");
  
     public BoxScreen(ScreenHandler handler, PlayerInventory inventory, Text title) {     public BoxScreen(ScreenHandler handler, PlayerInventory inventory, Text title) {
Line 250: Line 249:
  
     @Override     @Override
-    protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) { +    protected void drawBackground(DrawContext context, float delta, int mouseX, int mouseY) { 
-        RenderSystem.setShader(GameRenderer::getPositionTexShader);+        RenderSystem.setShader(GameRenderer::getPositionTexProgram);
         RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);         RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
         RenderSystem.setShaderTexture(0, TEXTURE);         RenderSystem.setShaderTexture(0, TEXTURE);
         int x = (width - backgroundWidth) / 2;         int x = (width - backgroundWidth) / 2;
         int y = (height - backgroundHeight) / 2;         int y = (height - backgroundHeight) / 2;
-        drawTexture(matrices, x, y, 0, 0, backgroundWidth, backgroundHeight);+        context.drawTexture(TEXTURE, x, y, 0, 0, backgroundWidth, backgroundHeight);
     }     }
  
     @Override     @Override
-    public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { +    public void render(DrawContext context, int mouseX, int mouseY, float delta) { 
-        renderBackground(matrices); +        renderBackground(context, mouseX, mouseY, delta); 
-        super.render(matrices, mouseX, mouseY, delta); +        super.render(context, mouseX, mouseY, delta); 
-        drawMouseoverTooltip(matrices, mouseX, mouseY);+        drawMouseoverTooltip(context, mouseX, mouseY);
     }     }
  
Line 280: Line 279:
  
 <code java [enable_line_numbers="true"] ExampleModClient.java> <code java [enable_line_numbers="true"] ExampleModClient.java>
- 
 @Environment(EnvType.CLIENT) @Environment(EnvType.CLIENT)
 public class ExampleClientMod implements ClientModInitializer { public class ExampleClientMod implements ClientModInitializer {
     @Override     @Override
     public void onInitializeClient() {     public void onInitializeClient() {
-        ScreenRegistry.register(ExampleMod.BOX_SCREEN_HANDLER, BoxScreen::new);+        HandledScreens.register(ExampleMod.BOX_SCREEN_HANDLER, BoxScreen::new);
     }     }
 } }
Line 292: Line 290:
  
 别忘了在 ''fabric.mod.json'' 中注册这个入口点,如果还没有完成的话: 别忘了在 ''fabric.mod.json'' 中注册这个入口点,如果还没有完成的话:
-<code json> +<code javascript src/main/resources/fabric.mod.json> 
-/* ... */+
 +   /* ... */
   "entrypoints": {   "entrypoints": {
     /* ... */     /* ... */
     "client": [     "client": [
-      "(到这个 ExampleModClient 的路径)"+      "net.fabricmc.example.ExampleModClient"
     ]     ]
   },   },
 +  /* ... */
 +}
 </code> </code>
  
Line 307: Line 308:
 public class ExampleMod implements ModInitializer { public class ExampleMod implements ModInitializer {
     [...]     [...]
-    public static final ScreenHandlerType<BoxScreenHandler> BOX_SCREEN_HANDLER+    public static final ScreenHandlerType<BoxScreenHandler> BOX_SCREEN_HANDLER = Registry.register(Registries.SCREEN_HANDLER, Identifier.of("tutorial""box_block"), new ScreenHandlerType<>(BoxScreenHandler::new, FeatureSet.empty())); 
-    [...+    
-    static { +
-        [...] +
-        // 我们在这里使用 registerSimple 因为实体不是 ExtendedScreenHandlerFactory +
-        // 而是 NamedScreenHandlerFactory. +
-        // 后面的教程中,你将会看到 ExtendedScreenHandlerFactory 能做什么! +
-        BOX_SCREEN_HANDLER = ScreenHandlerRegistry.registerSimple(BOX, BoxScreenHandler::new); +
-    +
     @Override     @Override
     public void onInitialize() {     public void onInitialize() {
 +        [...]
     }     }
 } }
Line 330: Line 323:
  
 ===== 延伸阅读 ===== ===== 延伸阅读 =====
-[[extendedscreenhandler|屏幕开启时,使用 Extended ScreenHandlers 同步自定义的数据]] +  * [[extendedscreenhandler|屏幕开启时,使用 Extended ScreenHandlers 同步自定义的数据]] 
- +  [[propertydelegates|使用 PropertyDelegates 持续同步整数]]
-[[propertydelegates|使用 PropertyDelegates 持续同步整数]]+
  
-使用 ''ScreenHandler'' 的示例模组:[[https://github.com/FabricMC/fabric/tree/1.16/fabric-screen-handler-api-v1/src/testmod|Github 上的示例模组]]。+使用 ''ScreenHandler'' 的示例模组:[[https://github.com/FabricMC/fabric/tree/1.16/fabric-screen-handler-api-v1/src/testmod|Github 上的示例模组]]。
  
zh_cn/tutorial/screenhandler.1671438503.txt.gz · Last modified: 2022/12/19 08:28 by solidblock