zh_cn:tutorial:screenhandler
Differences
This shows you the differences between two versions of the page.
Next revision | Previous revision | ||
zh_cn:tutorial:screenhandler [2021/11/08 15:45] – created breakice | zh_cn:tutorial:screenhandler [2023/09/14 01:42] (current) – [ScreenHandler 和 Screen] wjz_p | ||
---|---|---|---|
Line 1: | Line 1: | ||
====== 创建一个容器方块 ====== | ====== 创建一个容器方块 ====== | ||
- | 这篇教程会创建一个类似分解器的方块,用于解释如何使用FabricAPI中的 | + | 这篇教程会创建一个类似发射器的简单存储方块,并解释如何使用 |
- | 让我们先做一些词汇练习: | + | 先解释一些词汇: |
**Screenhandler: | **Screenhandler: | ||
- | '' | + | '' |
- | 我们的子类会有以下两个构造器: 一个将在服务器端使用,并将储存真正的 '' | + | |
**Screen:** | **Screen:** | ||
- | '' | + | '' |
===== 方块和方块实体类 ===== | ===== 方块和方块实体类 ===== | ||
- | 首先我们需要创建 '' | + | 首先我们需要创建 '' |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
Line 28: | Line 27: | ||
@Override | @Override | ||
public BlockRenderType getRenderType(BlockState state) { | public BlockRenderType getRenderType(BlockState state) { | ||
- | // 通过从 BlockWithEntity 继承而来的值是默认为 INVISIBLE | + | // 从 BlockWithEntity 继承的默认值为 INVISIBLE,所以这里需要进行改变! |
return BlockRenderType.MODEL; | return BlockRenderType.MODEL; | ||
} | } | ||
Line 35: | Line 34: | ||
public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { | public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { | ||
if (!world.isClient) { | if (!world.isClient) { | ||
- | // 这里会调用 BlockWithEntity 的 createScreenHandlerFactory 方法, 他会转换为 | + | // 这里会调用 BlockWithEntity 的 createScreenHandlerFactory 方法,会将返回的方块实体强转为 |
- | // 一个 namedScreenHandlerFactory。 如果你的方块没有继承 BlockWithEntity,那就需要单独实现 createScreenHandlerFactory. | + | // 一个 namedScreenHandlerFactory。如果你的方块没有继承 BlockWithEntity,那就需要单独实现 createScreenHandlerFactory。 |
NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, | NamedScreenHandlerFactory screenHandlerFactory = state.createScreenHandlerFactory(world, | ||
if (screenHandlerFactory != null) { | if (screenHandlerFactory != null) { | ||
- | //With this call the server will request the client to open the appropriate | + | // 这个调用会让服务器请求客户端开启合适的 |
player.openHandledScreen(screenHandlerFactory); | player.openHandledScreen(screenHandlerFactory); | ||
} | } | ||
Line 48: | Line 47: | ||
| | ||
| | ||
- | // 这个方法能让你储存在他里面的物品在被破坏时洒落一地! | + | // 这个方法能让方块破坏时物品全部掉落 |
@Override | @Override | ||
public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { | public void onStateReplaced(BlockState state, World world, BlockPos pos, BlockState newState, boolean moved) { | ||
Line 74: | Line 73: | ||
</ | </ | ||
- | 我们接下里要创建 '' | + | 我们接下来要创建 '' |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
Line 93: | Line 92: | ||
} | } | ||
- | //These Methods are from the NamedScreenHandlerFactory | + | // 这些方法来自 |
- | // | + | // createMenu |
- | // | + | // getDisplayName |
@Override | @Override | ||
public ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, | public ScreenHandler createMenu(int syncId, PlayerInventory playerInventory, | ||
- | //We provide | + | // 因为我们的类实现 Inventory,所以将*这个*提供给 ScreenHandler |
- | //Only the Server has the Inventory at the start, this will be synced to the client in the ScreenHandler | + | // 一开始只有服务器拥有物品栏,然后在 |
return new BoxScreenHandler(syncId, | return new BoxScreenHandler(syncId, | ||
} | } | ||
Line 106: | Line 105: | ||
@Override | @Override | ||
public Text getDisplayName() { | public Text getDisplayName() { | ||
- | return new TranslatableText(getCachedState().getBlock().getTranslationKey()); | + | |
+ | // 对于1.19之前的版本,请使用: | ||
+ | // return new TranslatableText(getCachedState().getBlock().getTranslationKey()); | ||
} | } | ||
| | ||
Line 125: | Line 126: | ||
</ | </ | ||
- | ===== Registering Block, BlockItem and BlockEntity | + | ===== 注册方块、物品和方块实体 |
- | + | ||
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
Line 137: | Line 136: | ||
public static final String MOD_ID = " | public static final String MOD_ID = " | ||
- | // a public identifier for multiple parts of our bigger chest | + | // 我们的大型箱子中不同部分的公共id |
public static final Identifier BOX = new Identifier(MOD_ID, | public static final Identifier BOX = new Identifier(MOD_ID, | ||
static { | static { | ||
- | BOX_BLOCK = Registry.register(Registry.BLOCK, BOX, new BoxBlock(FabricBlockSettings.copyOf(Blocks.CHEST))); | + | BOX_BLOCK = Registry.register(Registries.BLOCK, BOX, new BoxBlock(FabricBlockSettings.copyOf(Blocks.CHEST))); |
- | BOX_BLOCK_ITEM = Registry.register(Registry.ITEM, BOX, new BlockItem(BOX_BLOCK, | + | BOX_BLOCK_ITEM = Registry.register(Registries.ITEM, BOX, new BlockItem(BOX_BLOCK, |
//The parameter of build at the very end is always null, do not worry about it | //The parameter of build at the very end is always null, do not worry about it | ||
- | // pre-1.17 | + | // 1.17 之前 |
- | BOX_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, | + | BOX_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, |
- | // In 1.17 use FabricBlockEntityTypeBuilder | + | // 在 1.17 使用 |
- | BOX_BLOCK_ENTITY = Registry.register(Registry.BLOCK_ENTITY_TYPE, | + | BOX_BLOCK_ENTITY = Registry.register(Registries.BLOCK_ENTITY_TYPE, |
} | } | ||
Line 160: | Line 159: | ||
</ | </ | ||
- | ===== ScreenHandler | + | ===== ScreenHandler |
- | As explained earlier, we need both a '' | + | 正如前面解释的,我们同时需要 |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
Line 168: | Line 167: | ||
private final Inventory inventory; | private final Inventory inventory; | ||
- | //This constructor gets called on the client when the server wants it to open the screenHandler, | + | // 服务器想要客户端开启 |
- | //The client will call the other constructor with an empty Inventory and the screenHandler | + | // 如有空的物品栏,客户端会调用其他构造器,screenHandler |
- | //sync this empty inventory with the inventory on the server. | + | // 在客户端将空白物品栏同步给物品栏。 |
public BoxScreenHandler(int syncId, PlayerInventory playerInventory) { | public BoxScreenHandler(int syncId, PlayerInventory playerInventory) { | ||
this(syncId, | this(syncId, | ||
} | } | ||
- | //This constructor gets called from the BlockEntity | + | // 这个构造器是在服务器的 |
- | //and can therefore directly provide it as an argument. This inventory will then be synced to the client. | + | // 并直接将其作为参数传入。然后物品栏在客户端完成同步。 |
public BoxScreenHandler(int syncId, PlayerInventory playerInventory, | public BoxScreenHandler(int syncId, PlayerInventory playerInventory, | ||
super(ExampleMod.BOX_SCREEN_HANDLER, | super(ExampleMod.BOX_SCREEN_HANDLER, | ||
checkSize(inventory, | checkSize(inventory, | ||
this.inventory = inventory; | this.inventory = inventory; | ||
- | //some inventories do custom logic when a player opens it. | + | // 玩家开启时,一些物品栏有自定义的逻辑。 |
inventory.onOpen(playerInventory.player); | inventory.onOpen(playerInventory.player); | ||
- | //This will place the slot in the correct locations for a 3x3 Grid. The slots exist on both server and client! | + | // 这会将槽位放置在 3×3 网格的正确位置中。这些槽位在客户端和服务器中都存在! |
- | //This will not render the background of the slots however, this is the Screens | + | // 但是这不会渲染槽位的背景,这是 |
int m; | int m; | ||
int l; | int l; | ||
Line 194: | Line 193: | ||
} | } | ||
} | } | ||
- | //The player inventory | + | // 玩家物品栏 |
for (m = 0; m < 3; ++m) { | for (m = 0; m < 3; ++m) { | ||
for (l = 0; l < 9; ++l) { | for (l = 0; l < 9; ++l) { | ||
Line 200: | Line 199: | ||
} | } | ||
} | } | ||
- | //The player Hotbar | + | // 玩家快捷栏 |
for (m = 0; m < 9; ++m) { | for (m = 0; m < 9; ++m) { | ||
this.addSlot(new Slot(playerInventory, | this.addSlot(new Slot(playerInventory, | ||
Line 212: | Line 211: | ||
} | } | ||
- | // Shift + Player Inv Slot | + | // Shift + 玩家物品栏槽位 |
@Override | @Override | ||
public ItemStack transferSlot(PlayerEntity player, int invSlot) { | public ItemStack transferSlot(PlayerEntity player, int invSlot) { | ||
Line 243: | Line 242: | ||
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
public class BoxScreen extends HandledScreen< | public class BoxScreen extends HandledScreen< | ||
- | //A path to the gui texture. In this example we use the texture from the dispenser | + | // GUI 纹理的路径,本例中使用发射器中的纹理 |
private static final Identifier TEXTURE = new Identifier(" | private static final Identifier TEXTURE = new Identifier(" | ||
Line 252: | Line 251: | ||
@Override | @Override | ||
protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) { | protected void drawBackground(MatrixStack matrices, float delta, int mouseX, int mouseY) { | ||
- | RenderSystem.setShader(GameRenderer:: | + | RenderSystem.setShader(GameRenderer:: |
RenderSystem.setShaderColor(1.0F, | RenderSystem.setShaderColor(1.0F, | ||
RenderSystem.setShaderTexture(0, | RenderSystem.setShaderTexture(0, | ||
Line 258: | Line 257: | ||
int y = (height - backgroundHeight) / 2; | int y = (height - backgroundHeight) / 2; | ||
drawTexture(matrices, | drawTexture(matrices, | ||
+ | // | ||
} | } | ||
Line 270: | Line 270: | ||
protected void init() { | protected void init() { | ||
super.init(); | super.init(); | ||
- | // Center the title | + | // 将标题居中 |
titleX = (backgroundWidth - textRenderer.getWidth(title)) / 2; | titleX = (backgroundWidth - textRenderer.getWidth(title)) / 2; | ||
} | } | ||
Line 276: | Line 276: | ||
</ | </ | ||
- | ===== Registering our Screen | + | ===== 注册 |
- | As screens are a client-only concept, we can only register them on the client. | + | 所有的屏幕都只是仅存于客户端的概念,因此只能在客户端进行注册。 |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
Line 293: | Line 292: | ||
</ | </ | ||
- | Don't forget to register this entrypoint in '' | + | 别忘了在 |
<code json> | <code json> | ||
/* ... */ | /* ... */ | ||
Line 299: | Line 298: | ||
/* ... */ | /* ... */ | ||
" | " | ||
- | "tutorial.path.to.ExampleModClient" | + | "(到这个 |
] | ] | ||
}, | }, | ||
</ | </ | ||
- | '' | + | '' |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
Line 313: | Line 312: | ||
static { | static { | ||
[...] | [...] | ||
- | //We use registerSimple | + | // 我们在这里使用 |
- | //but a NamedScreenHandlerFactory. | + | // 而是 |
- | //In a later Tutorial you will see what ExtendedScreenHandlerFactory | + | // 后面的教程中,你将会看到 |
BOX_SCREEN_HANDLER = ScreenHandlerRegistry.registerSimple(BOX, | BOX_SCREEN_HANDLER = ScreenHandlerRegistry.registerSimple(BOX, | ||
} | } | ||
Line 326: | Line 325: | ||
</ | </ | ||
- | ===== Result | + | ===== 结果 |
- | You have now created your own container Block, you could easily change it to contain a smaller or bigger Inventory. Maybe even apply a texture :-P | + | 您现在应该创建了容器方块,可以轻易地改变它以包含更小或者更大的物品栏。也许还需要应用一个纹理!qwq |
{{: | {{: | ||
- | ===== Further Reading | + | ===== 延伸阅读 |
- | - [[tutorial:extendedscreenhandler|Syncing Custom Data with Extended ScreenHandlers | + | - [[extendedscreenhandler|屏幕开启时,使用 |
- | - [[tutorial:propertydelegates|Syncing Integers continuously with PropertyDelegates]] | + | - [[propertydelegates|使用 |
- | - An example mod using the '' | + | - 使用 |
zh_cn/tutorial/screenhandler.1636386309.txt.gz · Last modified: 2021/11/08 15:45 by breakice