# Minecraft Fabric Modding - REI API ## REI 簡介 全名 Roughly Enough Items,乃是 Fabric 平台上如 JEI 的模組,其功用可以讓使用者更加容易的得知物品取得途徑。 ![](https://i.imgur.com/6puY3b2.png =500x) ## 引入 首先,在檔案 `gradle.properties` 中加入以下這串: ```java roughly_enough_items_version = 8.2.463 ``` 這個是一個變數名稱,可以任意取名。 後面則是版本,可填入當時最新之版本號。 接著,在 `build.gradle` 中加入兩個物件 ```java repositories { ... maven { url "https://maven.shedaniel.me" } } dependencies { ... modCompileOnly "me.shedaniel:RoughlyEnoughItems-api-fabric:${project.roughly_enough_items_version}" modRuntimeOnly "me.shedaniel:RoughlyEnoughItems-fabric:${project.roughly_enough_items_version}" } ``` 這裡的 `roughly_enough_items_version` 就是我們剛剛取的名子 :::success 都更改完成後就可以重新載入! ::: ## 使用 :::warning 建議新增一個資料夾專門來放關於 REI 的程式碼 以下以 `AlloyManufactory` 做舉例 ::: ### Identifiers ```java= public class ModREICategoryIdentifiers { public static final CategoryIdentifier<AlloyManufactoryREIDisplay> ALLOY_MANUFACTORY = CategoryIdentifier.of(new Identifier(More_Ores.MOD_ID, "alloy_manufacture")); } ``` ### abstract RecipeDisplay ```java= public abstract class ModRecipeDisplay<T extends Recipe<SimpleInventory>> implements Display { protected final T recipe; protected List<EntryIngredient> inputs; protected EntryIngredient outputs; public ModRecipeDisplay(T recipe) { this.recipe = recipe; this.inputs = EntryIngredients.ofIngredients(recipe.getIngredients()); this.outputs = EntryIngredients.of(recipe.getOutput()); } @Override public @Nonnull List<EntryIngredient> getInputEntries() { return this.inputs; } @Override public @Nonnull List<EntryIngredient> getOutputEntries() { return Collections.singletonList(this.outputs); } @Override public @Nonnull Optional<Identifier> getDisplayLocation() { return Optional.ofNullable(this.recipe).map(T::getId); } } ``` input 與 ouput 可依據你的食譜類型作調整 ### Category & Display REI 的合成表主要由兩種 class 組成:`Category` 與 `Display` 建立兩個檔案:`AlloyManufactoryREICategory.java`、`AlloyManufactoryREIDisplay.java` ```java= public class AlloyManufactoryREIDisplay extends ModRecipeDisplay<AlloyManufactoryRecipe> { public AlloyManufactoryREIDisplay(AlloyManufactoryRecipe recipe) { super(recipe); } public int getLava() { return recipe.getLavaAmount(); } @Override public CategoryIdentifier<?> getCategoryIdentifier() { return ModREICategoryIdentifiers.ALLOY_MANUFACTORY; } } ``` `getLava()` 是為了取得 Alloy Manufactory 的 lava,若有更多的 property,皆可再新增更多函數 ```java= public class AlloyManufactoryREICategory implements DisplayCategory<AlloyManufactoryREIDisplay> { private static final Identifier TEXTURE = new Identifier(More_Ores.MOD_ID, "textures/gui/rei/alloy_manufactory_rei_gui.png"); private final EntryStack<ItemStack> icon = EntryStacks.of(ModBlocks.ALLOY_MANUFACTORY); @Override public CategoryIdentifier<? extends AlloyManufactoryREIDisplay> getCategoryIdentifier() { return ModREICategoryIdentifiers.ALLOY_MANUFACTORY; } @Override public Renderer getIcon() { return icon; } @Override public Text getTitle() { return new TranslatableText("rei.more_ores.alloy_manufacture"); } @Override public @NotNull List<Widget> setupDisplay(AlloyManufactoryREIDisplay display, Rectangle bounds) { List<Widget> widgets = new ArrayList<>(); int lava = display.getLava(); List<EntryIngredient> inputs = display.getInputEntries(); EntryStack<?> output = display.getOutputEntries().get(0).get(0); int x = bounds.getMinX(), y = bounds.getMinY(); int w = bounds.getWidth(), h = bounds.getHeight(); widgets.add(Widgets.createRecipeBase(bounds)); // Necessary! widgets.add(Widgets.createDrawableWidget(((helper, matrices, mouseX, mouseY, delta) -> DrawUtil.drawOverlay(helper, matrices,TEXTURE, x, y, 0, 0, w, h)))); widgets.add(Widgets.createLabel(new Point(x + 86, y + 20), new LiteralText(new TranslatableText("block.minecraft.lava").getString() + ": " + lava))); widgets.add(Widgets.createSlot(new Point(x + 18 , y + 24)).entries(inputs.get(0)).disableBackground()); widgets.add(Widgets.createSlot(new Point(x + 42 , y + 24)).entries(inputs.get(1)).disableBackground()); widgets.add(Widgets.createSlot(new Point(x + 116, y + 24)).entry(output).disableBackground()); return widgets; } } ``` #### setupDisplay 這是用來設定顯示的合成表長怎樣,非常之重要! 加入顯示物件: ```java= widget.add(Widgets.create...); ``` `createDrawableWidget` 可以加入背景 `createLabel` 可以加入文字 `createSlot` 可以加入物品格,後可加上 `entry()` 或 `entries` 加入物品 :::warning REI 的預設食譜範圍大小為 **150×65** (即上方的 w=150, h=65) ::: `DrawUtil.drawOverlay()` 這個函數則是自訂義的: ```java= public class DrawUtil { public static void drawOverlay(DrawableHelper helper, MatrixStack matrices, Identifier id, int x, int y, int u, int v, int width, int height) { RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); RenderSystem.setShaderTexture(0, id); helper.drawTexture(matrices, x, y, u, v, width, height); } } ``` ### 主程式 ```java= public class ModREIPlugin implements REIClientPlugin { @Override public void registerCategories(CategoryRegistry registry) { registry.add( new AlloyManufactoryREICategory() ); registry.addWorkstations(ModREICategoryIdentifiers.ALLOY_MANUFACTORY, EntryStacks.of(ModBlocks.ALLOY_MANUFACTORY)); registry.removePlusButton(ModREICategoryIdentifiers.ALLOY_MANUFACTORY); } @Override public void registerDisplays(DisplayRegistry registry) { registry.registerRecipeFiller(AlloyManufactoryRecipe.class, ModRecipes.ALLOY_MANUFACTORY_RECIPE_TYPE, AlloyManufactoryREIDisplay::new); } } ``` `registry.add()` 函數中放入你所有的 Category `registry.addWorkstations()` 中放入所有皆適用某食譜的方塊 `registry.removePlusButton()` 則是移除自動放入按鈕 `registry.registerRecipeFiller()` 一定要加,為顯示食譜的必要函數 ### json 最後,記得在 `fabric.mod.json` 的 `entrypoints` 中加入以下程式碼,並填入路徑: ```json= "rei_plugins_v0": [ "the path of ModREIPlugin" ] ``` ## 參考資料 [shedaniel - Roughly Enough Items](https://github.com/shedaniel/RoughlyEnoughItems) --- ###### tags: `Minecraft Fabric Modding`