Unknown 6 éve
szülő
commit
2d16d5bc8c

+ 3 - 0
CHANGELOG.md

@@ -1,3 +1,6 @@
+## v2.7.0.82
+- Updated to Fabric 0.4.0
+- Now bundle with Fabric API, Cloth Events API, Cloth Config API
 ## v2.6.2.81
 - Fix [#53](https://github.com/shedaniel/RoughlyEnoughItems/issues/53): Crash on keyPressed
 ## v2.6.2.80

+ 8 - 3
build.gradle

@@ -1,7 +1,7 @@
 import net.fabricmc.loom.task.RemapJar
 
 plugins {
-    id 'fabric-loom' version '0.2.0-SNAPSHOT'
+    id 'fabric-loom' version '0.2.1-SNAPSHOT'
     id "com.github.johnrengelman.shadow" version "4.0.3"
 }
 
@@ -17,7 +17,6 @@ minecraft {
 repositories {
     maven { url "https://tehnut.info/maven/" }
     maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
-    maven { url "https://maven.jamieswhiteshirt.com/libs-release/" }
     maven { url "https://minecraft.curseforge.com/api/maven" }
 }
 
@@ -35,6 +34,7 @@ configurations {
 }
 
 shadowJar {
+    version = project.mod_version.replaceAll('\\+build.', '.')
     classifier = null
     configurations = [project.configurations.included]
 }
@@ -48,10 +48,15 @@ dependencies {
     minecraft "com.mojang:minecraft:${project.minecraft_version}"
     mappings "net.fabricmc:yarn:${project.yarn_version}"
     modCompile "net.fabricmc:fabric-loader:${project.fabricloader_version}"
-    modCompile "info.tehnut.pluginloader:plugin-loader:${project.pluginloader_version}"
     modCompile "net.fabricmc:fabric:${project.fabric_version}"
+    include "net.fabricmc:fabric:${project.fabric_version}"
     modCompile "cloth:Cloth:${cloth_version}"
+    include "cloth:Cloth:${cloth_version}"
+    modCompile "cloth-config:ClothConfig:${cloth_config_version}"
+    include "cloth-config:ClothConfig:${cloth_config_version}"
 
     compile "blue.endless:jankson:${project.jankson_version}"
     included "blue.endless:jankson:${project.jankson_version}"
+
+    modCompile "io.github.prospector.modmenu:ModMenu:${modmenu_version}"
 }

+ 6 - 5
gradle.properties

@@ -1,8 +1,9 @@
-mod_version=2.6.2.81
+mod_version=2.7.0+build.83
 minecraft_version=19w14b
 yarn_version=19w14b.1
-fabric_version=0.2.6.119
-fabricloader_version=0.3.7.109
-pluginloader_version=1.14-1.0.6-8
+fabric_version=0.2.6.121
+fabricloader_version=0.4.0+build.116
 jankson_version=1.1.0
-cloth_version=0.2.1.21
+cloth_version=0.3.0.22
+cloth_config_version=0.1.0.4
+modmenu_version=1.2.1-45

+ 123 - 48
src/main/java/me/shedaniel/rei/RoughlyEnoughItemsCore.java

@@ -1,42 +1,43 @@
 package me.shedaniel.rei;
 
+import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import me.shedaniel.cloth.api.ClientUtils;
+import me.shedaniel.cloth.hooks.ClothClientHooks;
 import me.shedaniel.rei.api.ItemRegistry;
 import me.shedaniel.rei.api.PluginDisabler;
 import me.shedaniel.rei.api.REIPlugin;
 import me.shedaniel.rei.api.RecipeHelper;
-import me.shedaniel.rei.client.ConfigManager;
-import me.shedaniel.rei.client.ItemRegistryImpl;
-import me.shedaniel.rei.client.PluginDisablerImpl;
-import me.shedaniel.rei.client.RecipeHelperImpl;
-import me.shedaniel.rei.gui.widget.ItemListOverlay;
-import me.shedaniel.rei.plugin.DefaultPlugin;
+import me.shedaniel.rei.client.*;
+import me.shedaniel.rei.gui.ContainerScreenOverlay;
 import net.fabricmc.api.ClientModInitializer;
-import net.fabricmc.api.ModInitializer;
-import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
 import net.fabricmc.loader.api.FabricLoader;
+import net.fabricmc.loader.api.ModContainer;
+import net.fabricmc.loader.api.metadata.ModMetadata;
 import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.resource.language.I18n;
-import net.minecraft.item.ItemStack;
-import net.minecraft.server.network.ServerPlayerEntity;
-import net.minecraft.text.StringTextComponent;
-import net.minecraft.text.TranslatableTextComponent;
+import net.minecraft.client.gui.ContainerScreen;
+import net.minecraft.client.gui.Element;
+import net.minecraft.client.gui.ingame.CreativePlayerInventoryScreen;
+import net.minecraft.client.gui.ingame.PlayerInventoryScreen;
+import net.minecraft.client.gui.widget.RecipeBookButtonWidget;
+import net.minecraft.util.ActionResult;
 import net.minecraft.util.Identifier;
+import net.minecraft.util.Pair;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.stream.Collectors;
 
-public class RoughlyEnoughItemsCore implements ClientModInitializer, ModInitializer {
+public class RoughlyEnoughItemsCore implements ClientModInitializer {
     
     public static final Logger LOGGER;
-    public static final Identifier DELETE_ITEMS_PACKET = new Identifier("roughlyenoughitems", "delete_item");
-    public static final Identifier CREATE_ITEMS_PACKET = new Identifier("roughlyenoughitems", "create_item");
     private static final RecipeHelper RECIPE_HELPER = new RecipeHelperImpl();
     private static final PluginDisabler PLUGIN_DISABLER = new PluginDisablerImpl();
     private static final ItemRegistry ITEM_REGISTRY = new ItemRegistryImpl();
@@ -85,22 +86,7 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer, ModInitiali
     public void onInitializeClient() {
         configManager = new ConfigManager();
         
-        // If pluginloader is not installed, base functionality should still remain
-        if (!FabricLoader.getInstance().isModLoaded("pluginloader")) {
-            RoughlyEnoughItemsCore.LOGGER.warn("[REI] Plugin Loader is not loaded! Please consider installing https://minecraft.curseforge.com/projects/pluginloader for REI plugin compatibility!");
-            registerPlugin(new Identifier("roughlyenoughitems", "default_plugin"), new DefaultPlugin());
-        }
-        
-        if (FabricLoader.getInstance().isModLoaded("cloth")) {
-            try {
-                Class.forName("me.shedaniel.rei.utils.ClothRegistry").getDeclaredMethod("register").invoke(null);
-            } catch (IllegalAccessException | InvocationTargetException | ClassNotFoundException | NoSuchMethodException e) {
-                e.printStackTrace();
-            }
-        } else {
-            RoughlyEnoughItemsCore.LOGGER.fatal("[REI] Cloth NOT found! It is a dependency of REI: https://minecraft.curseforge.com/projects/cloth");
-            System.exit(0);
-        }
+        registerClothEvents();
         
         if (FabricLoader.getInstance().isModLoaded("modmenu")) {
             try {
@@ -111,26 +97,115 @@ public class RoughlyEnoughItemsCore implements ClientModInitializer, ModInitiali
                 RoughlyEnoughItemsCore.LOGGER.error("[REI] Failed to add config override for ModMenu!", e);
             }
         }
+        
+        discoverPlugins();
     }
     
-    @Override
-    public void onInitialize() {
-        registerFabricPackets();
+    private void discoverPlugins() {
+        List<Pair<Identifier, String>> list = Lists.newArrayList();
+        for(ModMetadata metadata : FabricLoader.getInstance().getAllMods().stream().map(ModContainer::getMetadata).filter(metadata -> metadata.containsCustomElement("roughlyenoughitems:plugins")).collect(Collectors.toList())) {
+            try {
+                JsonElement pluginsElement = metadata.getCustomElement("roughlyenoughitems:plugins");
+                if (pluginsElement.isJsonArray()) {
+                    for(JsonElement element : pluginsElement.getAsJsonArray())
+                        if (element.isJsonObject())
+                            loadPluginFromJsonObject(list, metadata, element.getAsJsonObject());
+                        else
+                            throw new IllegalStateException("Custom Element in an array is not an object.");
+                } else if (pluginsElement.isJsonObject()) {
+                    loadPluginFromJsonObject(list, metadata, pluginsElement.getAsJsonObject());
+                } else
+                    throw new IllegalStateException("Custom Element not an array or an object.");
+            } catch (Exception e) {
+                e.printStackTrace();
+                RoughlyEnoughItemsCore.LOGGER.error("[REI] Can't load REI plugins from %s: %s", metadata.getId(), e.getLocalizedMessage());
+            }
+        }
+        for(Pair<Identifier, String> pair : list) {
+            String s = pair.getRight();
+            try {
+                Class<?> aClass = Class.forName(s);
+                if (!REIPlugin.class.isAssignableFrom(aClass)) {
+                    RoughlyEnoughItemsCore.LOGGER.error("[REI] Plugin class from %s is not implementing REIPlugin!", s);
+                    break;
+                }
+                REIPlugin o = REIPlugin.class.cast(aClass.newInstance());
+                registerPlugin(pair.getLeft(), o);
+            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+                RoughlyEnoughItemsCore.LOGGER.error("[REI] Can't load REI plugin class from %s!", s);
+            } catch (ClassCastException e) {
+                RoughlyEnoughItemsCore.LOGGER.error("[REI] Failed to cast plugin class from %s to REIPlugin!", s);
+            }
+        }
     }
     
-    private void registerFabricPackets() {
-        ServerSidePacketRegistry.INSTANCE.register(DELETE_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
-            ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
-            if (!player.inventory.getCursorStack().isEmpty())
-                player.inventory.setCursorStack(ItemStack.EMPTY);
+    private void loadPluginFromJsonObject(List<Pair<Identifier, String>> list, ModMetadata modMetadata, JsonObject object) {
+        String namespace = modMetadata.getId();
+        if (object.has("namespace"))
+            namespace = object.get("namespace").getAsString();
+        String id = object.get("id").getAsString();
+        String className = object.get("class").getAsString();
+        list.add(new Pair<>(new Identifier(namespace, id), className));
+    }
+    
+    private void registerClothEvents() {
+        ClothClientHooks.SYNC_RECIPES.register((minecraftClient, recipeManager, synchronizeRecipesS2CPacket) -> {
+            ((RecipeHelperImpl) RoughlyEnoughItemsCore.getRecipeHelper()).recipesLoaded(recipeManager);
+        });
+        ClothClientHooks.SCREEN_ADD_BUTTON.register((minecraftClient, screen, abstractButtonWidget) -> {
+            if (RoughlyEnoughItemsCore.getConfigManager().getConfig().disableRecipeBook && screen instanceof ContainerScreen && abstractButtonWidget instanceof RecipeBookButtonWidget)
+                return ActionResult.FAIL;
+            return ActionResult.PASS;
+        });
+        ClothClientHooks.SCREEN_INIT_POST.register((minecraftClient, screen, screenHooks) -> {
+            if (screen instanceof ContainerScreen) {
+                if (screen instanceof PlayerInventoryScreen && minecraftClient.interactionManager.hasCreativeInventory())
+                    return;
+                ScreenHelper.setLastContainerScreen((ContainerScreen) screen);
+                boolean alreadyAdded = false;
+                for(Element element : Lists.newArrayList(screenHooks.cloth_getInputListeners()))
+                    if (ContainerScreenOverlay.class.isAssignableFrom(element.getClass()))
+                        if (alreadyAdded)
+                            screenHooks.cloth_getInputListeners().remove(element);
+                        else
+                            alreadyAdded = true;
+                if (!alreadyAdded)
+                    screenHooks.cloth_getInputListeners().add(ScreenHelper.getLastOverlay(true, false));
+            }
+        });
+        ClothClientHooks.SCREEN_RENDER_POST.register((minecraftClient, screen, i, i1, v) -> {
+            if (screen instanceof ContainerScreen)
+                ScreenHelper.getLastOverlay().render(i, i1, v);
+        });
+        ClothClientHooks.SCREEN_MOUSE_CLICKED.register((minecraftClient, screen, v, v1, i) -> {
+            if (screen instanceof CreativePlayerInventoryScreen)
+                if (ScreenHelper.isOverlayVisible() && ScreenHelper.getLastOverlay().mouseClicked(v, v1, i))
+                    return ActionResult.SUCCESS;
+            return ActionResult.PASS;
+        });
+        ClothClientHooks.SCREEN_MOUSE_SCROLLED.register((minecraftClient, screen, v, v1, v2) -> {
+            if (screen instanceof ContainerScreen)
+                if (ScreenHelper.isOverlayVisible() && ScreenHelper.getLastOverlay().getRectangle().contains(ClientUtils.getMouseLocation()) && ScreenHelper.getLastOverlay().mouseScrolled(v, v1, v2))
+                    return ActionResult.SUCCESS;
+            return ActionResult.PASS;
+        });
+        ClothClientHooks.SCREEN_CHAR_TYPED.register((minecraftClient, screen, character, keyCode) -> {
+            if (screen instanceof ContainerScreen)
+                if (ScreenHelper.getLastOverlay().charTyped(character, keyCode))
+                    return ActionResult.SUCCESS;
+            return ActionResult.PASS;
+        });
+        ClothClientHooks.SCREEN_LATE_RENDER.register((minecraftClient, screen, i, i1, v) -> {
+            if (!ScreenHelper.isOverlayVisible())
+                return;
+            if (screen instanceof ContainerScreen)
+                ScreenHelper.getLastOverlay().lateRender(i, i1, v);
         });
-        ServerSidePacketRegistry.INSTANCE.register(CREATE_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
-            ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
-            ItemStack stack = packetByteBuf.readItemStack();
-            if (player.inventory.insertStack(stack.copy()))
-                player.addChatMessage(new StringTextComponent(I18n.translate("text.rei.cheat_items").replaceAll("\\{item_name}", ItemListOverlay.tryGetItemStackName(stack.copy())).replaceAll("\\{item_count}", stack.copy().getAmount() + "").replaceAll("\\{player_name}", player.getEntityName())), false);
-            else
-                player.addChatMessage(new TranslatableTextComponent("text.rei.failed_cheat_items"), false);
+        ClothClientHooks.SCREEN_KEY_PRESSED.register((minecraftClient, screen, i, i1, i2) -> {
+            if (screen instanceof ContainerScreen)
+                if (ScreenHelper.getLastOverlay().keyPressed(i, i1, i2))
+                    return ActionResult.SUCCESS;
+            return ActionResult.PASS;
         });
     }
     

+ 35 - 0
src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java

@@ -0,0 +1,35 @@
+package me.shedaniel.rei;
+
+import me.shedaniel.rei.gui.widget.ItemListOverlay;
+import net.fabricmc.api.ModInitializer;
+import net.fabricmc.fabric.api.network.ServerSidePacketRegistry;
+import net.minecraft.client.resource.language.I18n;
+import net.minecraft.item.ItemStack;
+import net.minecraft.server.network.ServerPlayerEntity;
+import net.minecraft.text.StringTextComponent;
+import net.minecraft.text.TranslatableTextComponent;
+import net.minecraft.util.Identifier;
+
+public class RoughlyEnoughItemsNetwork implements ModInitializer {
+    
+    public static final Identifier DELETE_ITEMS_PACKET = new Identifier("roughlyenoughitems", "delete_item");
+    public static final Identifier CREATE_ITEMS_PACKET = new Identifier("roughlyenoughitems", "create_item");
+    
+    @Override
+    public void onInitialize() {
+        ServerSidePacketRegistry.INSTANCE.register(DELETE_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
+            ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
+            if (!player.inventory.getCursorStack().isEmpty())
+                player.inventory.setCursorStack(ItemStack.EMPTY);
+        });
+        ServerSidePacketRegistry.INSTANCE.register(CREATE_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
+            ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
+            ItemStack stack = packetByteBuf.readItemStack();
+            if (player.inventory.insertStack(stack.copy()))
+                player.addChatMessage(new StringTextComponent(I18n.translate("text.rei.cheat_items").replaceAll("\\{item_name}", ItemListOverlay.tryGetItemStackName(stack.copy())).replaceAll("\\{item_count}", stack.copy().getAmount() + "").replaceAll("\\{player_name}", player.getEntityName())), false);
+            else
+                player.addChatMessage(new TranslatableTextComponent("text.rei.failed_cheat_items"), false);
+        });
+    }
+    
+}

+ 0 - 27
src/main/java/me/shedaniel/rei/RoughlyEnoughItemsPlugins.java

@@ -1,27 +0,0 @@
-package me.shedaniel.rei;
-
-import info.tehnut.pluginloader.LoaderCreator;
-import info.tehnut.pluginloader.PluginLoaderBuilder;
-import info.tehnut.pluginloader.ValidationStrategy;
-import me.shedaniel.rei.api.REIPlugin;
-import net.fabricmc.loader.language.LanguageAdapter;
-import net.fabricmc.loader.language.LanguageAdapterException;
-import net.minecraft.util.Identifier;
-
-public class RoughlyEnoughItemsPlugins implements LoaderCreator {
-    
-    @Override
-    public void createLoaders() {
-        LanguageAdapter.Options instantiationOptions = new LanguageAdapter.Options();
-        
-        new PluginLoaderBuilder("roughlyenoughitems").withValidator(ValidationStrategy.hasInterface(REIPlugin.class)).withInitializer((aClass, container) -> {
-            Identifier id = new Identifier(container.getOwner().getInfo().getId(), container.getInfo().getId());
-            try {
-                REIPlugin plugin = (REIPlugin) container.getOwner().getAdapter().createInstance(aClass, instantiationOptions);
-                RoughlyEnoughItemsCore.registerPlugin(id, plugin);
-            } catch (LanguageAdapterException e) {
-                RoughlyEnoughItemsCore.LOGGER.error("[REI] Error loading plugin %s", id, e);
-            }
-        }).build();
-    }
-}

+ 3 - 4
src/main/java/me/shedaniel/rei/client/ClientHelper.java

@@ -3,6 +3,7 @@ package me.shedaniel.rei.client;
 import com.google.common.collect.ImmutableList;
 import io.netty.buffer.Unpooled;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
+import me.shedaniel.rei.RoughlyEnoughItemsNetwork;
 import me.shedaniel.rei.api.RecipeCategory;
 import me.shedaniel.rei.api.RecipeDisplay;
 import me.shedaniel.rei.api.RecipeHelper;
@@ -43,7 +44,6 @@ public class ClientHelper implements ClientModInitializer {
             String modid = location.getNamespace();
             if (modid.equalsIgnoreCase("minecraft"))
                 return "Minecraft";
-            //            return FabricLoader.getInstance().getAllMods().stream().map(ModContainer::getMetadata).filter(metadata -> metadata.getId().equals(modid)).findFirst().map(ModMetadata::getName).orElse(modid);
             return FabricLoader.getInstance().getModContainer(modid).map(ModContainer::getMetadata).map(ModMetadata::getName).orElse(modid);
         }
         return "";
@@ -67,13 +67,13 @@ public class ClientHelper implements ClientModInitializer {
             MinecraftClient.getInstance().player.inventory.setCursorStack(ItemStack.EMPTY);
             return;
         }
-        ClientSidePacketRegistry.INSTANCE.sendToServer(RoughlyEnoughItemsCore.DELETE_ITEMS_PACKET, new PacketByteBuf(Unpooled.buffer()));
+        ClientSidePacketRegistry.INSTANCE.sendToServer(RoughlyEnoughItemsNetwork.DELETE_ITEMS_PACKET, new PacketByteBuf(Unpooled.buffer()));
     }
     
     public static boolean tryCheatingStack(ItemStack cheatedStack) {
         if (MinecraftClient.getInstance().isInSingleplayer()) {
             try {
-                ClientSidePacketRegistry.INSTANCE.sendToServer(RoughlyEnoughItemsCore.CREATE_ITEMS_PACKET, new PacketByteBuf(Unpooled.buffer()).writeItemStack(cheatedStack.copy()));
+                ClientSidePacketRegistry.INSTANCE.sendToServer(RoughlyEnoughItemsNetwork.CREATE_ITEMS_PACKET, new PacketByteBuf(Unpooled.buffer()).writeItemStack(cheatedStack.copy()));
                 return true;
             } catch (Exception e) {
                 return false;
@@ -87,7 +87,6 @@ public class ClientHelper implements ClientModInitializer {
                 madeUpCommand = og.replaceAll("\\{player_name}", MinecraftClient.getInstance().player.getEntityName()).replaceAll("\\{item_identifier}", identifier.toString()).replaceAll("\\{nbt}", "").replaceAll("\\{count}", String.valueOf(cheatedStack.getAmount()));
                 MinecraftClient.getInstance().player.addChatMessage(new TranslatableTextComponent("text.rei.too_long_nbt"), false);
             }
-            System.out.println(madeUpCommand);
             MinecraftClient.getInstance().player.sendChatMessage(madeUpCommand);
             return true;
         }

+ 42 - 4
src/main/java/me/shedaniel/rei/client/ConfigManager.java

@@ -6,7 +6,10 @@ import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 import net.fabricmc.loader.api.FabricLoader;
+import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.Screen;
+import net.minecraft.client.resource.language.I18n;
+import net.minecraft.text.StringTextComponent;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -14,6 +17,7 @@ import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.nio.file.Files;
 import java.nio.file.StandardCopyOption;
+import java.util.List;
 
 public class ConfigManager implements me.shedaniel.rei.api.ConfigManager {
     
@@ -122,10 +126,44 @@ public class ConfigManager implements me.shedaniel.rei.api.ConfigManager {
     
     @Override
     public void openConfigScreen(Screen parent) {
-        try {
-            Class.forName("me.shedaniel.rei.utils.ClothRegistry").getDeclaredMethod("openConfigScreen", Screen.class).invoke(null, parent);
-        } catch (IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {
-            e.printStackTrace();
+        if (FabricLoader.getInstance().isModLoaded("cloth-config")) {
+            try {
+                Class.forName("me.shedaniel.rei.utils.ClothScreenRegistry").getDeclaredMethod("openConfigScreen", Screen.class).invoke(null, parent);
+            } catch (IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {
+                e.printStackTrace();
+            }
+        } else {
+            MinecraftClient.getInstance().openScreen(new Screen(new StringTextComponent("")) {
+                @Override
+                public void render(int int_1, int int_2, float float_1) {
+                    renderDirtBackground(0);
+                    List<String> list = minecraft.textRenderer.wrapStringToWidthAsList(I18n.translate("text.rei.no_config_api"), width - 100);
+                    int y = (int) (height / 2 - minecraft.textRenderer.fontHeight * 1.3f / 2 * list.size());
+                    for(int i = 0; i < list.size(); i++) {
+                        String s = list.get(i);
+                        drawCenteredString(minecraft.textRenderer, s, width / 2, y, -1);
+                        y += minecraft.textRenderer.fontHeight;
+                    }
+                    super.render(int_1, int_2, float_1);
+                }
+                
+                @Override
+                protected void init() {
+                    super.init();
+                    addButton(new net.minecraft.client.gui.widget.ButtonWidget(width / 2 - 100, height - 26, 200, 20, I18n.translate("gui.done"), buttonWidget -> {
+                        this.minecraft.openScreen(parent);
+                    }));
+                }
+                
+                @Override
+                public boolean keyPressed(int int_1, int int_2, int int_3) {
+                    if (int_1 == 256 && this.shouldCloseOnEsc()) {
+                        this.minecraft.openScreen(parent);
+                        return true;
+                    }
+                    return super.keyPressed(int_1, int_2, int_3);
+                }
+            });
         }
     }
     

+ 7 - 7
src/main/java/me/shedaniel/rei/gui/config/ItemListOrderingEntry.java

@@ -1,7 +1,6 @@
 package me.shedaniel.rei.gui.config;
 
 import com.google.common.collect.Lists;
-import javafx.util.Pair;
 import me.shedaniel.cloth.gui.ClothConfigScreen.ListEntry;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 import me.shedaniel.rei.client.ItemListOrdering;
@@ -10,6 +9,7 @@ import net.minecraft.client.gui.Element;
 import net.minecraft.client.gui.widget.ButtonWidget;
 import net.minecraft.client.resource.language.I18n;
 import net.minecraft.client.util.Window;
+import net.minecraft.util.Pair;
 
 import java.util.Arrays;
 import java.util.List;
@@ -26,8 +26,8 @@ public class ItemListOrderingEntry extends ListEntry {
         super(fieldName);
         this.value = new AtomicReference(val);
         this.buttonWidget = new ButtonWidget(0, 0, 150, 20, "", widget -> {
-            int index = Arrays.asList(ItemListOrdering.values()).indexOf(value.get().getKey()) + 1;
-            boolean currentAscending = value.get().getValue();
+            int index = Arrays.asList(ItemListOrdering.values()).indexOf(value.get().getLeft()) + 1;
+            boolean currentAscending = value.get().getRight();
             if (index >= ItemListOrdering.values().length) {
                 index = 0;
                 currentAscending = !currentAscending;
@@ -54,10 +54,10 @@ public class ItemListOrderingEntry extends ListEntry {
     @Override
     public void render(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
         Window window = MinecraftClient.getInstance().window;
-        this.resetButton.active = this.getDefaultValue().isPresent() && (((Pair<ItemListOrdering, Boolean>) this.getDefaultValue().get()).getKey() != this.value.get().getKey() || ((Pair<ItemListOrdering, Boolean>) this.getDefaultValue().get()).getValue().booleanValue() != this.value.get().getValue().booleanValue());
+        this.resetButton.active = this.getDefaultValue().isPresent() && (((Pair<ItemListOrdering, Boolean>) this.getDefaultValue().get()).getLeft() != this.value.get().getLeft() || ((Pair<ItemListOrdering, Boolean>) this.getDefaultValue().get()).getRight().booleanValue() != this.value.get().getRight().booleanValue());
         this.resetButton.y = y;
         this.buttonWidget.y = y;
-        this.buttonWidget.setMessage(I18n.translate("text.rei.config.list_ordering_button", I18n.translate(value.get().getKey().getNameTranslationKey()), I18n.translate(value.get().getValue() ? "ordering.rei.ascending" : "ordering.rei.descending")));
+        this.buttonWidget.setMessage(I18n.translate("text.rei.config.list_ordering_button", I18n.translate(value.get().getLeft().getNameTranslationKey()), I18n.translate(value.get().getRight() ? "ordering.rei.ascending" : "ordering.rei.descending")));
         if (MinecraftClient.getInstance().textRenderer.isRightToLeft()) {
             MinecraftClient.getInstance().textRenderer.drawWithShadow(I18n.translate(this.getFieldName(), new Object[0]), (float) (window.getScaledWidth() - x - MinecraftClient.getInstance().textRenderer.getStringWidth(I18n.translate(this.getFieldName(), new Object[0]))), (float) (y + 5), 16777215);
             this.resetButton.x = x;
@@ -84,7 +84,7 @@ public class ItemListOrderingEntry extends ListEntry {
     
     @Override
     public void save() {
-        RoughlyEnoughItemsCore.getConfigManager().getConfig().itemListOrdering = value.get().getKey();
-        RoughlyEnoughItemsCore.getConfigManager().getConfig().isAscending = value.get().getValue();
+        RoughlyEnoughItemsCore.getConfigManager().getConfig().itemListOrdering = value.get().getLeft();
+        RoughlyEnoughItemsCore.getConfigManager().getConfig().isAscending = value.get().getRight();
     }
 }

+ 2 - 1
src/main/java/me/shedaniel/rei/gui/credits/CreditsScreen.java

@@ -40,7 +40,8 @@ public class CreditsScreen extends Screen {
             @Override
             public void onPressed() {
                 CreditsScreen.this.minecraft.openScreen(parent);
-                ScreenHelper.getLastOverlay().init();
+                if (parent instanceof ContainerScreen)
+                    ScreenHelper.getLastOverlay().init();
             }
         });
     }

+ 0 - 9
src/main/java/me/shedaniel/rei/listeners/CreativePlayerInventoryScreenHooks.java

@@ -1,9 +0,0 @@
-package me.shedaniel.rei.listeners;
-
-public interface CreativePlayerInventoryScreenHooks {
-    int rei_getSelectedTab();
-    
-    boolean rei_doRenderScrollBar();
-    
-    boolean rei_getField2888();
-}

+ 0 - 36
src/main/java/me/shedaniel/rei/mixin/MixinCreativePlayerInventoryScreen.java

@@ -1,36 +0,0 @@
-package me.shedaniel.rei.mixin;
-
-import me.shedaniel.rei.listeners.CreativePlayerInventoryScreenHooks;
-import net.minecraft.client.gui.ingame.CreativePlayerInventoryScreen;
-import net.minecraft.entity.player.PlayerInventory;
-import net.minecraft.text.TextComponent;
-import org.spongepowered.asm.mixin.Mixin;
-import org.spongepowered.asm.mixin.Shadow;
-
-@Mixin(CreativePlayerInventoryScreen.class)
-public abstract class MixinCreativePlayerInventoryScreen implements CreativePlayerInventoryScreenHooks {
-    
-    @Shadow
-    private static int selectedTab;
-    @Shadow
-    private boolean field_2888;
-    
-    @Shadow
-    protected abstract boolean doRenderScrollBar();
-    
-    @Override
-    public int rei_getSelectedTab() {
-        return selectedTab;
-    }
-    
-    @Override
-    public boolean rei_doRenderScrollBar() {
-        return doRenderScrollBar();
-    }
-    
-    @Override
-    public boolean rei_getField2888() {
-        return field_2888;
-    }
-    
-}

+ 0 - 152
src/main/java/me/shedaniel/rei/utils/ClothRegistry.java

@@ -1,152 +0,0 @@
-package me.shedaniel.rei.utils;
-
-import com.google.common.collect.Lists;
-import javafx.util.Pair;
-import me.shedaniel.cloth.api.ClientUtils;
-import me.shedaniel.cloth.api.ConfigScreenBuilder;
-import me.shedaniel.cloth.gui.ClothConfigScreen;
-import me.shedaniel.cloth.gui.entries.BooleanListEntry;
-import me.shedaniel.cloth.gui.entries.IntegerListEntry;
-import me.shedaniel.cloth.gui.entries.StringListEntry;
-import me.shedaniel.cloth.hooks.ClothClientHooks;
-import me.shedaniel.rei.RoughlyEnoughItemsCore;
-import me.shedaniel.rei.client.RecipeHelperImpl;
-import me.shedaniel.rei.client.ScreenHelper;
-import me.shedaniel.rei.gui.ContainerScreenOverlay;
-import me.shedaniel.rei.gui.config.ItemListOrderingEntry;
-import me.shedaniel.rei.listeners.CreativePlayerInventoryScreenHooks;
-import net.minecraft.client.MinecraftClient;
-import net.minecraft.client.gui.ContainerScreen;
-import net.minecraft.client.gui.Element;
-import net.minecraft.client.gui.Screen;
-import net.minecraft.client.gui.ingame.CreativePlayerInventoryScreen;
-import net.minecraft.client.gui.ingame.PlayerInventoryScreen;
-import net.minecraft.client.gui.widget.RecipeBookButtonWidget;
-import net.minecraft.item.ItemGroup;
-import net.minecraft.util.ActionResult;
-
-import java.io.IOException;
-
-public class ClothRegistry {
-    
-    public static void register() {
-        ClothClientHooks.SYNC_RECIPES.register((minecraftClient, recipeManager, synchronizeRecipesS2CPacket) -> {
-            ((RecipeHelperImpl) RoughlyEnoughItemsCore.getRecipeHelper()).recipesLoaded(recipeManager);
-        });
-        ClothClientHooks.SCREEN_ADD_BUTTON.register((minecraftClient, screen, abstractButtonWidget) -> {
-            if (RoughlyEnoughItemsCore.getConfigManager().getConfig().disableRecipeBook && screen instanceof ContainerScreen && abstractButtonWidget instanceof RecipeBookButtonWidget)
-                return ActionResult.FAIL;
-            return ActionResult.PASS;
-        });
-        ClothClientHooks.SCREEN_INIT_POST.register((minecraftClient, screen, screenHooks) -> {
-            if (screen instanceof ContainerScreen) {
-                if (screen instanceof CreativePlayerInventoryScreen)
-                    if (((CreativePlayerInventoryScreenHooks) screen).rei_getSelectedTab() != ItemGroup.INVENTORY.getIndex())
-                        return;
-                if (screen instanceof PlayerInventoryScreen && minecraftClient.interactionManager.hasCreativeInventory())
-                    return;
-                ScreenHelper.setLastContainerScreen((ContainerScreen) screen);
-                boolean alreadyAdded = false;
-                for(Element element : Lists.newArrayList(screenHooks.cloth_getInputListeners()))
-                    if (ContainerScreenOverlay.class.isAssignableFrom(element.getClass()))
-                        if (alreadyAdded)
-                            screenHooks.cloth_getInputListeners().remove(element);
-                        else
-                            alreadyAdded = true;
-                if (!alreadyAdded)
-                    screenHooks.cloth_getInputListeners().add(ScreenHelper.getLastOverlay(true, false));
-            }
-        });
-        ClothClientHooks.SCREEN_RENDER_POST.register((minecraftClient, screen, i, i1, v) -> {
-            if (screen instanceof ContainerScreen) {
-                if (screen instanceof CreativePlayerInventoryScreen) {
-                    CreativePlayerInventoryScreenHooks creativePlayerInventoryScreenHooks = (CreativePlayerInventoryScreenHooks) screen;
-                    if (creativePlayerInventoryScreenHooks.rei_getSelectedTab() != ItemGroup.INVENTORY.getIndex())
-                        return;
-                }
-                ScreenHelper.getLastOverlay().render(i, i1, v);
-            }
-        });
-        ClothClientHooks.SCREEN_MOUSE_CLICKED.register((minecraftClient, screen, v, v1, i) -> {
-            if (screen instanceof CreativePlayerInventoryScreen)
-                if (((CreativePlayerInventoryScreenHooks) screen).rei_getSelectedTab() == ItemGroup.INVENTORY.getIndex())
-                    if (ScreenHelper.isOverlayVisible() && ScreenHelper.getLastOverlay().mouseClicked(v, v1, i))
-                        return ActionResult.SUCCESS;
-            return ActionResult.PASS;
-        });
-        ClothClientHooks.SCREEN_MOUSE_SCROLLED.register((minecraftClient, screen, v, v1, v2) -> {
-            if (screen instanceof ContainerScreen)
-                if (screen instanceof CreativePlayerInventoryScreen) {
-                    if (((CreativePlayerInventoryScreenHooks) screen).rei_doRenderScrollBar())
-                        return ActionResult.PASS;
-                    if (ScreenHelper.isOverlayVisible() && ScreenHelper.getLastOverlay().getRectangle().contains(ClientUtils.getMouseLocation()) && ScreenHelper.getLastOverlay().mouseScrolled(v, v1, v2))
-                        return ActionResult.SUCCESS;
-                } else {
-                    ContainerScreenOverlay overlay = ScreenHelper.getLastOverlay();
-                    if (ScreenHelper.isOverlayVisible() && ContainerScreenOverlay.getItemListOverlay().getListArea().contains(ClientUtils.getMouseLocation()))
-                        if (overlay.mouseScrolled(v, v1, v2))
-                            return ActionResult.SUCCESS;
-                }
-            return ActionResult.PASS;
-        });
-        ClothClientHooks.SCREEN_CHAR_TYPED.register((minecraftClient, screen, character, keyCode) -> {
-            if (screen instanceof ContainerScreen)
-                if (screen instanceof CreativePlayerInventoryScreen) {
-                    if (((CreativePlayerInventoryScreenHooks) screen).rei_getField2888() || ((CreativePlayerInventoryScreenHooks) screen).rei_getSelectedTab() != ItemGroup.INVENTORY.getIndex())
-                        return ActionResult.PASS;
-                    if (ScreenHelper.getLastOverlay().charTyped(character, keyCode))
-                        return ActionResult.SUCCESS;
-                } else if (ScreenHelper.getLastOverlay().charTyped(character, keyCode))
-                    return ActionResult.SUCCESS;
-            return ActionResult.PASS;
-        });
-        ClothClientHooks.SCREEN_LATE_RENDER.register((minecraftClient, screen, i, i1, v) -> {
-            if (!ScreenHelper.isOverlayVisible())
-                return;
-            if (screen instanceof CreativePlayerInventoryScreen)
-                if (((CreativePlayerInventoryScreenHooks) screen).rei_getSelectedTab() != ItemGroup.INVENTORY.getIndex())
-                    return;
-            if (screen instanceof ContainerScreen)
-                ScreenHelper.getLastOverlay().lateRender(i, i1, v);
-        });
-        ClothClientHooks.SCREEN_KEY_PRESSED.register((minecraftClient, screen, i, i1, i2) -> {
-            if (screen instanceof CreativePlayerInventoryScreen)
-                if (((CreativePlayerInventoryScreenHooks) screen).rei_getSelectedTab() != ItemGroup.INVENTORY.getIndex())
-                    return ActionResult.PASS;
-            if (screen instanceof ContainerScreen)
-                if (ScreenHelper.getLastOverlay().keyPressed(i, i1, i2))
-                    return ActionResult.SUCCESS;
-            return ActionResult.PASS;
-        });
-    }
-    
-    public static void openConfigScreen(Screen parent) {
-        ConfigScreenBuilder builder = new ClothConfigScreen.Builder(parent, "text.rei.config.title", savedConfig -> {
-            try {
-                RoughlyEnoughItemsCore.getConfigManager().saveConfig();
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        });
-        builder.addCategory("text.rei.config.general").addOption(new BooleanListEntry("text.rei.config.cheating", RoughlyEnoughItemsCore.getConfigManager().getConfig().cheating, "text.cloth.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().cheating = bool));
-        ConfigScreenBuilder.CategoryBuilder appearance = builder.addCategory("text.rei.config.appearance");
-        appearance.addOption(new BooleanListEntry("text.rei.config.side_search_box", RoughlyEnoughItemsCore.getConfigManager().getConfig().sideSearchField, "text.cloth.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().sideSearchField = bool));
-        appearance.addOption(new ItemListOrderingEntry("text.rei.config.list_ordering", new Pair<>(RoughlyEnoughItemsCore.getConfigManager().getConfig().itemListOrdering, RoughlyEnoughItemsCore.getConfigManager().getConfig().isAscending)));
-        appearance.addOption(new BooleanListEntry("text.rei.config.mirror_rei", RoughlyEnoughItemsCore.getConfigManager().getConfig().mirrorItemPanel, "text.cloth.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().mirrorItemPanel = bool));
-        appearance.addOption(new IntegerListEntry("text.rei.config.max_recipes_per_page", RoughlyEnoughItemsCore.getConfigManager().getConfig().maxRecipePerPage, "text.cloth.reset_value", () -> 3, i -> RoughlyEnoughItemsCore.getConfigManager().getConfig().maxRecipePerPage = i).setMinimum(2).setMaximum(99));
-        ConfigScreenBuilder.CategoryBuilder modules = builder.addCategory("text.rei.config.modules");
-        modules.addOption(new BooleanListEntry("text.rei.config.enable_craftable_only", RoughlyEnoughItemsCore.getConfigManager().getConfig().enableCraftableOnlyButton, "text.cloth.reset_value", () -> true, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().enableCraftableOnlyButton = bool));
-        modules.addOption(new BooleanListEntry("text.rei.config.enable_util_buttons", RoughlyEnoughItemsCore.getConfigManager().getConfig().showUtilsButtons, "text.cloth.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().showUtilsButtons = bool));
-        modules.addOption(new BooleanListEntry("text.rei.config.disable_recipe_book", RoughlyEnoughItemsCore.getConfigManager().getConfig().disableRecipeBook, "text.cloth.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().disableRecipeBook = bool));
-        ConfigScreenBuilder.CategoryBuilder advanced = builder.addCategory("text.rei.config.advanced");
-        advanced.addOption(new StringListEntry("text.rei.give_command", RoughlyEnoughItemsCore.getConfigManager().getConfig().giveCommand, "text.cloth.reset_value", () -> "/give {player_name} {item_identifier}{nbt} {count}", s -> RoughlyEnoughItemsCore.getConfigManager().getConfig().giveCommand = s));
-        advanced.addOption(new StringListEntry("text.rei.gamemode_command", RoughlyEnoughItemsCore.getConfigManager().getConfig().gamemodeCommand, "text.cloth.reset_value", () -> "/gamemode {gamemode}", s -> RoughlyEnoughItemsCore.getConfigManager().getConfig().gamemodeCommand = s));
-        advanced.addOption(new StringListEntry("text.rei.weather_command", RoughlyEnoughItemsCore.getConfigManager().getConfig().weatherCommand, "text.cloth.reset_value", () -> "/weather {weather}", s -> RoughlyEnoughItemsCore.getConfigManager().getConfig().weatherCommand = s));
-        advanced.addOption(new BooleanListEntry("text.rei.config.prefer_visible_recipes", RoughlyEnoughItemsCore.getConfigManager().getConfig().preferVisibleRecipes, "text.cloth.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().preferVisibleRecipes = bool));
-        advanced.addOption(new BooleanListEntry("text.rei.config.enable_legacy_speedcraft_support", RoughlyEnoughItemsCore.getConfigManager().getConfig().enableLegacySpeedCraftSupport, "text.cloth.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().enableLegacySpeedCraftSupport = bool));
-        ConfigScreenBuilder.CategoryBuilder aprilFools = builder.addCategory("text.rei.config.april_fools");
-        aprilFools.addOption(new BooleanListEntry("text.rei.config.april_fools.2019", RoughlyEnoughItemsCore.getConfigManager().getConfig().aprilFoolsFish2019, "text.cloth.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().aprilFoolsFish2019 = bool));
-        MinecraftClient.getInstance().openScreen(builder.build());
-    }
-    
-}

+ 46 - 0
src/main/java/me/shedaniel/rei/utils/ClothScreenRegistry.java

@@ -0,0 +1,46 @@
+package me.shedaniel.rei.utils;
+
+import me.shedaniel.cloth.api.ConfigScreenBuilder;
+import me.shedaniel.cloth.gui.entries.BooleanListEntry;
+import me.shedaniel.cloth.gui.entries.IntegerListEntry;
+import me.shedaniel.cloth.gui.entries.StringListEntry;
+import me.shedaniel.rei.RoughlyEnoughItemsCore;
+import me.shedaniel.rei.gui.config.ItemListOrderingEntry;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.Screen;
+import net.minecraft.util.Pair;
+
+import java.io.IOException;
+
+public class ClothScreenRegistry {
+    
+    public static void openConfigScreen(Screen parent) {
+        ConfigScreenBuilder builder = ConfigScreenBuilder.create(parent, "text.rei.config.title", savedConfig -> {
+            try {
+                RoughlyEnoughItemsCore.getConfigManager().saveConfig();
+            } catch (IOException e) {
+                e.printStackTrace();
+            }
+        });
+        builder.addCategory("text.rei.config.general").addOption(new BooleanListEntry("text.rei.config.cheating", RoughlyEnoughItemsCore.getConfigManager().getConfig().cheating, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().cheating = bool));
+        ConfigScreenBuilder.CategoryBuilder appearance = builder.addCategory("text.rei.config.appearance");
+        appearance.addOption(new BooleanListEntry("text.rei.config.side_search_box", RoughlyEnoughItemsCore.getConfigManager().getConfig().sideSearchField, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().sideSearchField = bool));
+        appearance.addOption(new ItemListOrderingEntry("text.rei.config.list_ordering", new Pair<>(RoughlyEnoughItemsCore.getConfigManager().getConfig().itemListOrdering, RoughlyEnoughItemsCore.getConfigManager().getConfig().isAscending)));
+        appearance.addOption(new BooleanListEntry("text.rei.config.mirror_rei", RoughlyEnoughItemsCore.getConfigManager().getConfig().mirrorItemPanel, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().mirrorItemPanel = bool));
+        appearance.addOption(new IntegerListEntry("text.rei.config.max_recipes_per_page", RoughlyEnoughItemsCore.getConfigManager().getConfig().maxRecipePerPage, "text.cloth-config.reset_value", () -> 3, i -> RoughlyEnoughItemsCore.getConfigManager().getConfig().maxRecipePerPage = i).setMinimum(2).setMaximum(99));
+        ConfigScreenBuilder.CategoryBuilder modules = builder.addCategory("text.rei.config.modules");
+        modules.addOption(new BooleanListEntry("text.rei.config.enable_craftable_only", RoughlyEnoughItemsCore.getConfigManager().getConfig().enableCraftableOnlyButton, "text.cloth-config.reset_value", () -> true, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().enableCraftableOnlyButton = bool));
+        modules.addOption(new BooleanListEntry("text.rei.config.enable_util_buttons", RoughlyEnoughItemsCore.getConfigManager().getConfig().showUtilsButtons, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().showUtilsButtons = bool));
+        modules.addOption(new BooleanListEntry("text.rei.config.disable_recipe_book", RoughlyEnoughItemsCore.getConfigManager().getConfig().disableRecipeBook, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().disableRecipeBook = bool));
+        ConfigScreenBuilder.CategoryBuilder advanced = builder.addCategory("text.rei.config.advanced");
+        advanced.addOption(new StringListEntry("text.rei.give_command", RoughlyEnoughItemsCore.getConfigManager().getConfig().giveCommand, "text.cloth-config.reset_value", () -> "/give {player_name} {item_identifier}{nbt} {count}", s -> RoughlyEnoughItemsCore.getConfigManager().getConfig().giveCommand = s));
+        advanced.addOption(new StringListEntry("text.rei.gamemode_command", RoughlyEnoughItemsCore.getConfigManager().getConfig().gamemodeCommand, "text.cloth-config.reset_value", () -> "/gamemode {gamemode}", s -> RoughlyEnoughItemsCore.getConfigManager().getConfig().gamemodeCommand = s));
+        advanced.addOption(new StringListEntry("text.rei.weather_command", RoughlyEnoughItemsCore.getConfigManager().getConfig().weatherCommand, "text.cloth-config.reset_value", () -> "/weather {weather}", s -> RoughlyEnoughItemsCore.getConfigManager().getConfig().weatherCommand = s));
+        advanced.addOption(new BooleanListEntry("text.rei.config.prefer_visible_recipes", RoughlyEnoughItemsCore.getConfigManager().getConfig().preferVisibleRecipes, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().preferVisibleRecipes = bool));
+        advanced.addOption(new BooleanListEntry("text.rei.config.enable_legacy_speedcraft_support", RoughlyEnoughItemsCore.getConfigManager().getConfig().enableLegacySpeedCraftSupport, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().enableLegacySpeedCraftSupport = bool));
+        ConfigScreenBuilder.CategoryBuilder aprilFools = builder.addCategory("text.rei.config.april_fools");
+        aprilFools.addOption(new BooleanListEntry("text.rei.config.april_fools.2019", RoughlyEnoughItemsCore.getConfigManager().getConfig().aprilFoolsFish2019, "text.cloth-config.reset_value", () -> false, bool -> RoughlyEnoughItemsCore.getConfigManager().getConfig().aprilFoolsFish2019 = bool));
+        MinecraftClient.getInstance().openScreen(builder.build());
+    }
+    
+}

BIN
src/main/resources/assets/roughlyenoughitems/icon.png


+ 1 - 0
src/main/resources/assets/roughlyenoughitems/lang/en_us.json

@@ -77,6 +77,7 @@
   "text.rei.config.enable_legacy_speedcraft_support": "Enable Legacy Plugin Support: ",
   "text.rei.config.april_fools": "April Fools",
   "text.rei.config.april_fools.2019": "Force 2019 REI April Fools' joke: ",
+  "text.rei.no_config_api": "Cloth Config API does not exist!\nPlease install it in order to show an in-game config screen!",
   "_comment": "Don't change / translate the credit down below if you are doing it :)",
   "text.rei.credit.text": "§lRoughly Enough Items\n§7Originally a fork for Almost Enough Items.\n\n§lDevelopers\n  - Originally by ZenDarva\n  - Created by Danielshe\n  - Plugin Support by TehNut\n\n§lLanguage Translation\n  English - Danielshe\n  Simplified Chinese - Danielshe\n  Traditional Chinese - hugoalh & Danielshe\n  French - Yanis48\n  German - MelanX\n  Estonian - Madis0\n  Portuguese - thiagokenis\n  LOLCAT - Danielshe\n  Upside Down - Danielshe\n\n§lLicense\n§7Roughly Enough Items is using MIT."
 }

+ 36 - 12
src/main/resources/fabric.mod.json

@@ -1,24 +1,48 @@
 {
+  "schemaVersion": 1,
   "id": "roughlyenoughitems",
   "name": "RoughlyEnoughItems",
   "description": "To allow players to view items and recipes. Version: ${version}",
-  "version": "2.6",
-  "side": "client",
+  "version": "${version}",
   "authors": [
     "Danielshe"
   ],
-  "initializers": [
-    "me.shedaniel.rei.RoughlyEnoughItemsCore",
-    "me.shedaniel.rei.client.ClientHelper",
-    "me.shedaniel.rei.client.ScreenHelper"
-  ],
+  "contact": {
+    "homepage": "https://minecraft.curseforge.com/projects/roughly-enough-items",
+    "sources": "https://github.com/shedaniel/RoughlyEnoughItems",
+    "issues": "https://github.com/shedaniel/RoughlyEnoughItems/issues"
+  },
+  "license": "MIT",
+  "icon": "pack.png",
+  "environment": "client",
+  "entrypoints": {
+    "client": [
+      "me.shedaniel.rei.RoughlyEnoughItemsCore",
+      "me.shedaniel.rei.client.ClientHelper",
+      "me.shedaniel.rei.client.ScreenHelper"
+    ],
+    "main": [
+      "me.shedaniel.rei.RoughlyEnoughItemsNetwork"
+    ]
+  },
   "requires": {
-    "fabric": "^0.2.3"
+    "fabricloader": ">=0.4.0",
+    "fabric": "^0.2.6",
+    "cloth": "*"
   },
-  "recommended": {
-    "pluginloader": "^1.0.6"
+  "recommends": {
+    "cloth-config": ">=0.1.0"
   },
-  "mixins": {
-    "client": "roughlyenoughitems.client.json"
+  "mixins": [
+    "roughlyenoughitems.mixins.json"
+  ],
+  "custom": {
+    "modmenu:clientsideOnly": true,
+    "roughlyenoughitems:plugins": [
+      {
+        "id": "default_plugin",
+        "class": "me.shedaniel.rei.plugin.DefaultPlugin"
+      }
+    ]
   }
 }

+ 0 - 7
src/main/resources/pluginloader.json

@@ -1,7 +0,0 @@
-{
-  "id": "roughlyenoughitems",
-  "initializer": "me.shedaniel.rei.RoughlyEnoughItemsPlugins",
-  "data": {
-    "side": "CLIENT"
-  }
-}

+ 0 - 6
src/main/resources/plugins/roughlyenoughitems.plugin.json

@@ -1,6 +0,0 @@
-[
-  {
-    "id": "default_plugin",
-    "initializer": "me.shedaniel.rei.plugin.DefaultPlugin"
-  }
-]

+ 2 - 2
src/main/resources/roughlyenoughitems.client.json → src/main/resources/roughlyenoughitems.mixins.json

@@ -3,9 +3,9 @@
   "package": "me.shedaniel.rei.mixin",
   "minVersion": "0.7.11",
   "compatibilityLevel": "JAVA_8",
-  "mixins": [
+  "mixins": [],
+  "client": [
     "MixinContainerScreen",
-    "MixinCreativePlayerInventoryScreen",
     "MixinBrewingRecipeRegistry",
     "MixinRecipeBookGui"
   ],