# Minecraft Fabric Modding - REI API
## REI 簡介
全名 Roughly Enough Items,乃是 Fabric 平台上如 JEI 的模組,其功用可以讓使用者更加容易的得知物品取得途徑。

## 引入
首先,在檔案 `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`