Browse Source

Update to 20w18a and add recipe exporter

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 5 years ago
parent
commit
3733dd4514
54 changed files with 323 additions and 544 deletions
  1. 3 3
      build.gradle
  2. 7 7
      gradle.properties
  3. 4 4
      src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java
  4. 11 11
      src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java
  5. 2 2
      src/main/java/me/shedaniel/rei/gui/OverlaySearchField.java
  6. 1 1
      src/main/java/me/shedaniel/rei/gui/PreRecipeViewingScreen.java
  7. 28 119
      src/main/java/me/shedaniel/rei/gui/RecipeDisplayExporter.java
  8. 3 3
      src/main/java/me/shedaniel/rei/gui/RecipeViewingScreen.java
  9. 3 3
      src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java
  10. 7 7
      src/main/java/me/shedaniel/rei/gui/WarningAndErrorScreen.java
  11. 8 7
      src/main/java/me/shedaniel/rei/gui/config/entry/FilteringEntry.java
  12. 4 4
      src/main/java/me/shedaniel/rei/gui/credits/CreditsEntryListWidget.java
  13. 1 1
      src/main/java/me/shedaniel/rei/gui/credits/CreditsScreen.java
  14. 29 29
      src/main/java/me/shedaniel/rei/gui/modules/Menu.java
  15. 4 4
      src/main/java/me/shedaniel/rei/gui/modules/MenuEntry.java
  16. 12 12
      src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java
  17. 4 4
      src/main/java/me/shedaniel/rei/gui/modules/entries/GameModeMenuEntry.java
  18. 28 28
      src/main/java/me/shedaniel/rei/gui/modules/entries/SubSubsetsMenuEntry.java
  19. 4 4
      src/main/java/me/shedaniel/rei/gui/modules/entries/WeatherMenuEntry.java
  20. 76 0
      src/main/java/me/shedaniel/rei/gui/toast/ExportRecipeIdentifierToast.java
  21. 5 5
      src/main/java/me/shedaniel/rei/gui/widget/ClickableLabelWidget.java
  22. 5 5
      src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java
  23. 3 2
      src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java
  24. 6 6
      src/main/java/me/shedaniel/rei/gui/widget/LabelWidget.java
  25. 3 3
      src/main/java/me/shedaniel/rei/gui/widget/RecipeChoosePageWidget.java
  26. 0 203
      src/main/java/me/shedaniel/rei/gui/widget/ScrollingContainer.java
  27. 1 1
      src/main/java/me/shedaniel/rei/gui/widget/TabWidget.java
  28. 8 8
      src/main/java/me/shedaniel/rei/gui/widget/TextFieldWidget.java
  29. 2 2
      src/main/java/me/shedaniel/rei/impl/ClientHelperImpl.java
  30. 1 1
      src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java
  31. 7 15
      src/main/java/me/shedaniel/rei/impl/ItemEntryStack.java
  32. 2 2
      src/main/java/me/shedaniel/rei/impl/RenderingEntry.java
  33. 8 8
      src/main/java/me/shedaniel/rei/impl/widgets/LabelWidget.java
  34. 3 2
      src/main/java/me/shedaniel/rei/plugin/beacon/DefaultBeaconBaseCategory.java
  35. 3 3
      src/main/java/me/shedaniel/rei/plugin/brewing/DefaultBrewingDisplay.java
  36. 1 1
      src/main/java/me/shedaniel/rei/plugin/composting/DefaultCompostingCategory.java
  37. 1 1
      src/main/java/me/shedaniel/rei/plugin/cooking/DefaultCookingDisplay.java
  38. 1 1
      src/main/java/me/shedaniel/rei/plugin/fuel/DefaultFuelCategory.java
  39. 5 6
      src/main/java/me/shedaniel/rei/plugin/information/DefaultInformationCategory.java
  40. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/bg_bg.json
  41. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/de_de.json
  42. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/en_ud.json
  43. 5 2
      src/main/resources/assets/roughlyenoughitems/lang/en_us.json
  44. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/et_ee.json
  45. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/fr_fr.json
  46. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/ja_jp.json
  47. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/lol_us.json
  48. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/nn_no.json
  49. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/pl_pl.json
  50. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/pt_br.json
  51. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/pt_pt.json
  52. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/ru_ru.json
  53. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/zh_cn.json
  54. 1 1
      src/main/resources/assets/roughlyenoughitems/lang/zh_tw.json

+ 3 - 3
build.gradle

@@ -69,9 +69,9 @@ dependencies {
     modCompileOnly("io.github.prospector:modmenu:${modmenu_version}") {
         transitive = false
     }
-//    modRuntime("io.github.prospector:modmenu:${modmenu_version}") {
-//        transitive = false
-//    }
+    modRuntime("io.github.prospector:modmenu:${modmenu_version}") {
+        transitive = false
+    }
     if (includeDep) {
         afterEvaluate {
             def listAdded = new ArrayList(Arrays.asList((api_exculde as String).split(',')))

+ 7 - 7
gradle.properties

@@ -1,12 +1,12 @@
-mod_version=4.2.2-unstable
-supported_version=20w17a
-minecraft_version=20w17a
-yarn_version=20w17a+build.2
+mod_version=4.3.0-unstable
+supported_version=20w18a
+minecraft_version=20w18a
+yarn_version=20w18a+build.1
 fabricloader_version=0.8.2+build.194
 cloth_events_version=2.2.0-unstable
-cloth_config_version=4.0.0-unstable
-modmenu_version=1.11.0+build.2
-fabric_api=0.6.2+build.327-1.16
+cloth_config_version=4.0.5-unstable
+modmenu_version=1.11.2+build.6
+fabric_api=0.7.1+build.331-1.16
 autoconfig1u=3.0.1-unstable
 api_include=me.shedaniel.cloth:cloth-events,me.shedaniel.cloth:config-2,me.sargunvohra.mcmods:autoconfig1u,org.jetbrains:annotations
 api_exculde=

+ 4 - 4
src/main/java/me/shedaniel/rei/RoughlyEnoughItemsNetwork.java

@@ -65,7 +65,7 @@ public class RoughlyEnoughItemsNetwork implements ModInitializer {
             ServerSidePacketRegistry.INSTANCE.register(DELETE_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
                 ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
                 if (player.getServer().getPermissionLevel(player.getGameProfile()) < player.getServer().getOpPermissionLevel()) {
-                    player.sendMessage(new TranslatableText("text.rei.no_permission_cheat").method_27692(Formatting.RED), false);
+                    player.sendMessage(new TranslatableText("text.rei.no_permission_cheat").formatted(Formatting.RED), false);
                     return;
                 }
                 if (!player.inventory.getCursorStack().isEmpty())
@@ -74,7 +74,7 @@ public class RoughlyEnoughItemsNetwork implements ModInitializer {
             ServerSidePacketRegistry.INSTANCE.register(CREATE_ITEMS_PACKET, (packetContext, packetByteBuf) -> {
                 ServerPlayerEntity player = (ServerPlayerEntity) packetContext.getPlayer();
                 if (player.getServer().getPermissionLevel(player.getGameProfile()) < player.getServer().getOpPermissionLevel()) {
-                    player.sendMessage(new TranslatableText("text.rei.no_permission_cheat").method_27692(Formatting.RED), false);
+                    player.sendMessage(new TranslatableText("text.rei.no_permission_cheat").formatted(Formatting.RED), false);
                     return;
                 }
                 ItemStack stack = packetByteBuf.readItemStack();
@@ -118,9 +118,9 @@ public class RoughlyEnoughItemsNetwork implements ModInitializer {
                             ServerSidePacketRegistry.INSTANCE.sendToPlayer(player, NOT_ENOUGH_ITEMS_PACKET, buf);
                         }
                     } catch (IllegalStateException e) {
-                        player.sendSystemMessage(new TranslatableText(e.getMessage()).method_27692(Formatting.RED));
+                        player.sendSystemMessage(new TranslatableText(e.getMessage()).formatted(Formatting.RED));
                     } catch (Exception e) {
-                        player.sendSystemMessage(new TranslatableText("error.rei.internal.error", e.getMessage()).method_27692(Formatting.RED));
+                        player.sendSystemMessage(new TranslatableText("error.rei.internal.error", e.getMessage()).formatted(Formatting.RED));
                         e.printStackTrace();
                     }
                 } catch (Exception e) {

+ 11 - 11
src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java

@@ -34,9 +34,9 @@ import me.shedaniel.rei.api.widgets.Button;
 import me.shedaniel.rei.api.widgets.Tooltip;
 import me.shedaniel.rei.api.widgets.Widgets;
 import me.shedaniel.rei.gui.config.SearchFieldLocation;
-import me.shedaniel.rei.gui.modules.GameModeMenuEntry;
-import me.shedaniel.rei.gui.modules.WeatherMenuEntry;
-import me.shedaniel.rei.gui.subsets.SubsetsMenu;
+import me.shedaniel.rei.gui.modules.entries.GameModeMenuEntry;
+import me.shedaniel.rei.gui.modules.entries.WeatherMenuEntry;
+import me.shedaniel.rei.gui.modules.Menu;
 import me.shedaniel.rei.gui.widget.*;
 import me.shedaniel.rei.impl.ClientHelperImpl;
 import me.shedaniel.rei.impl.InternalWidgets;
@@ -126,17 +126,17 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
     private Rectangle subsetsButtonBounds;
     @ApiStatus.Experimental
     @Nullable
-    private SubsetsMenu subsetsMenu = null;
+    private Menu subsetsMenu = null;
     private Widget wrappedSubsetsMenu = null;
     
     @Nullable
-    private SubsetsMenu weatherMenu = null;
+    private Menu weatherMenu = null;
     private Widget wrappedWeatherMenu = null;
     private boolean renderWeatherMenu = false;
     private Button weatherButton = null;
     
     @Nullable
-    private SubsetsMenu gameModeMenu = null;
+    private Menu gameModeMenu = null;
     private Widget wrappedGameModeMenu = null;
     private boolean renderGameModeMenu = false;
     private Button gameModeButton = null;
@@ -152,7 +152,7 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
     
     @ApiStatus.Experimental
     @Nullable
-    public SubsetsMenu getSubsetsMenu() {
+    public Menu getSubsetsMenu() {
         return subsetsMenu;
     }
     
@@ -273,7 +273,7 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
                         renderGameModeMenu = !renderWeatherMenu && (button.isFocused() || button.containsMouse(PointHelper.ofMouse()) || (wrappedGameModeMenu != null && wrappedGameModeMenu.containsMouse(PointHelper.ofMouse())));
                         if (tmpRender != renderGameModeMenu) {
                             if (renderGameModeMenu) {
-                                this.gameModeMenu = new SubsetsMenu(new Point(button.getBounds().x, button.getBounds().getMaxY()),
+                                this.gameModeMenu = new Menu(new Point(button.getBounds().x, button.getBounds().getMaxY()),
                                         CollectionUtils.filterAndMap(Arrays.asList(GameMode.values()), mode -> mode != GameMode.NOT_SET, GameModeMenuEntry::new));
                                 if (ConfigObject.getInstance().isLeftHandSidePanel())
                                     this.gameModeMenu.menuStartPoint.x -= this.gameModeMenu.getBounds().width - this.gameModeButton.getBounds().width;
@@ -294,7 +294,7 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
                         renderWeatherMenu = !renderGameModeMenu && (button.isFocused() || button.containsMouse(PointHelper.ofMouse()) || (wrappedWeatherMenu != null && wrappedWeatherMenu.containsMouse(PointHelper.ofMouse())));
                         if (tmpRender != renderWeatherMenu) {
                             if (renderWeatherMenu) {
-                                this.weatherMenu = new SubsetsMenu(new Point(button.getBounds().x, button.getBounds().getMaxY()),
+                                this.weatherMenu = new Menu(new Point(button.getBounds().x, button.getBounds().getMaxY()),
                                         CollectionUtils.map(Weather.values(), WeatherMenuEntry::new));
                                 if (ConfigObject.getInstance().isLeftHandSidePanel())
                                     this.weatherMenu.menuStartPoint.x -= this.weatherMenu.getBounds().width - this.weatherButton.getBounds().width;
@@ -319,7 +319,7 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
             widgets.add(InternalWidgets.wrapLateRenderable(InternalWidgets.wrapTranslate(Widgets.createButton(subsetsButtonBounds, ((ClientHelperImpl) ClientHelper.getInstance()).isAprilFools.get() ? new TranslatableText("text.rei.tiny_potato") : new TranslatableText("text.rei.subsets"))
                     .onClick(button -> {
                         if (subsetsMenu == null) {
-                            wrappedSubsetsMenu = InternalWidgets.wrapTranslate(InternalWidgets.wrapLateRenderable(this.subsetsMenu = SubsetsMenu.createFromRegistry(new Point(this.subsetsButtonBounds.x, this.subsetsButtonBounds.getMaxY()))), 0, 0, 400);
+                            wrappedSubsetsMenu = InternalWidgets.wrapTranslate(InternalWidgets.wrapLateRenderable(this.subsetsMenu = Menu.createSubsetsMenuFromRegistry(new Point(this.subsetsButtonBounds.x, this.subsetsButtonBounds.getMaxY()))), 0, 0, 400);
                             this.widgets.add(this.wrappedSubsetsMenu);
                         } else {
                             this.widgets.remove(this.wrappedSubsetsMenu);
@@ -560,7 +560,7 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
     public void renderTooltip(MatrixStack matrices, List<Text> lines, int mouseX, int mouseY) {
         if (lines.isEmpty())
             return;
-        tooltipWidth = lines.stream().map(font::method_27525).max(Integer::compareTo).get();
+        tooltipWidth = lines.stream().map(font::getWidth).max(Integer::compareTo).get();
         tooltipHeight = lines.size() <= 1 ? 8 : lines.size() * 10;
         tooltipLines = lines;
         ScreenHelper.drawHoveringWidget(matrices, mouseX, mouseY, renderTooltipCallback, tooltipWidth, tooltipHeight, 0);

+ 2 - 2
src/main/java/me/shedaniel/rei/gui/OverlaySearchField.java

@@ -84,9 +84,9 @@ public class OverlaySearchField extends TextFieldWidget {
     @Override
     protected void renderSuggestion(MatrixStack matrices, int x, int y) {
         if (containsMouse(PointHelper.ofMouse()) || isFocused())
-            this.font.drawWithShadow(matrices, this.font.method_27523(this.getSuggestion(), this.getWidth()), x, y, REIHelper.getInstance().isDarkThemeEnabled() ? 0xccddaa3d : 0xddeaeaea);
+            this.font.drawWithShadow(matrices, this.font.trimToWidth(this.getSuggestion(), this.getWidth()), x, y, REIHelper.getInstance().isDarkThemeEnabled() ? 0xccddaa3d : 0xddeaeaea);
         else
-            this.font.drawWithShadow(matrices, this.font.method_27523(this.getSuggestion(), this.getWidth()), x, y, -6250336);
+            this.font.drawWithShadow(matrices, this.font.trimToWidth(this.getSuggestion(), this.getWidth()), x, y, -6250336);
     }
     
     @Override

+ 1 - 1
src/main/java/me/shedaniel/rei/gui/PreRecipeViewingScreen.java

@@ -127,7 +127,7 @@ public class PreRecipeViewingScreen extends Screen {
         this.method_27534(matrices, this.textRenderer, this.title, this.width / 2, 20, 16777215);
         if (showTips) {
             int i = 30;
-            for (Text s : this.textRenderer.wrapStringToWidthAsList(new TranslatableText("text.rei.recipe_screen_type.selection.sub").method_27692(Formatting.GRAY), width - 30)) {
+            for (Text s : this.textRenderer.wrapLines(new TranslatableText("text.rei.recipe_screen_type.selection.sub").formatted(Formatting.GRAY), width - 30)) {
                 this.method_27534(matrices, this.textRenderer, s, width / 2, i, -1);
                 i += 10;
             }

+ 28 - 119
src/main/java/me/shedaniel/rei/gui/RecipeDisplayExporter.java

@@ -23,26 +23,20 @@
 
 package me.shedaniel.rei.gui;
 
-import com.mojang.blaze3d.platform.GlStateManager;
 import com.mojang.blaze3d.systems.RenderSystem;
 import me.shedaniel.math.Rectangle;
+import me.shedaniel.rei.gui.toast.ExportRecipeIdentifierToast;
 import me.shedaniel.rei.gui.widget.Widget;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gl.Framebuffer;
 import net.minecraft.client.gui.Element;
 import net.minecraft.client.render.DiffuseLighting;
-import net.minecraft.client.render.OverlayTexture;
-import net.minecraft.client.render.VertexConsumerProvider;
-import net.minecraft.client.render.model.BakedModel;
-import net.minecraft.client.render.model.json.ModelTransformation;
+import net.minecraft.client.resource.language.I18n;
 import net.minecraft.client.texture.NativeImage;
-import net.minecraft.client.texture.SpriteAtlasTexture;
+import net.minecraft.client.util.Window;
 import net.minecraft.client.util.math.MatrixStack;
-import net.minecraft.item.ItemStack;
-import net.minecraft.item.Items;
 import net.minecraft.resource.ResourceImpl;
 import org.jetbrains.annotations.ApiStatus;
-import org.lwjgl.opengl.GL11;
 
 import java.io.File;
 import java.io.IOException;
@@ -59,6 +53,7 @@ public final class RecipeDisplayExporter extends Widget {
     
     public static void exportRecipeDisplay(Rectangle rectangle, List<Widget> widgets) {
         INSTANCE.exportRecipe(rectangle, widgets);
+        ExportRecipeIdentifierToast.addToast(I18n.translate("msg.rei.exported_recipe"), I18n.translate("msg.rei.exported_recipe.desc"));
     }
     
     private static File getExportFilename(File directory) {
@@ -66,7 +61,7 @@ public final class RecipeDisplayExporter extends Widget {
         int i = 1;
         
         while (true) {
-            File file = new File(directory, "REI_" + string + (i == 1 ? "" : "_" + i) + ".png");
+            File file = new File(directory, string + (i == 1 ? "" : "_" + i) + ".png");
             if (!file.exists()) {
                 return file;
             }
@@ -77,134 +72,48 @@ public final class RecipeDisplayExporter extends Widget {
     
     @SuppressWarnings("deprecation")
     private void exportRecipe(Rectangle rectangle, List<Widget> widgets) {
-        MatrixStack matrices = new MatrixStack();
-        Framebuffer framebuffer = new Framebuffer(rectangle.width * 8, rectangle.height * 8, true, MinecraftClient.IS_SYSTEM_MAC);
-        framebuffer.setClearColor(0, 0, 0, 0);
-        //        int color = REIHelper.getInstance().isDarkThemeEnabled() ? -13750738 : -3750202;
-        //        framebuffer.setClearColor(((color >> 16) & 0xFF) / 255f, ((color >> 8) & 0xFF) / 255f, (color & 0xFF) / 255f, ((color >> 24) & 0xFF) / 255f);
-        framebuffer.clear(MinecraftClient.IS_SYSTEM_MAC);
         RenderSystem.pushMatrix();
-        //        RenderSystem.clear(16640, MinecraftClient.IS_SYSTEM_MAC);
+        MinecraftClient client = MinecraftClient.getInstance();
+        Window window = client.getWindow();
+        Framebuffer framebuffer = new Framebuffer(window.getFramebufferWidth(), window.getFramebufferHeight(), false, false);
         framebuffer.beginWrite(true);
-        
-        // Fresh matrices
-        //        RenderSystem.clear(256, MinecraftClient.IS_SYSTEM_MAC);
-        RenderSystem.matrixMode(GL11.GL_PROJECTION);
-        RenderSystem.pushMatrix();
+        RenderSystem.viewport(0, 0, window.getFramebufferWidth(), window.getFramebufferHeight());
+        RenderSystem.clear(256, MinecraftClient.IS_SYSTEM_MAC);
+        RenderSystem.matrixMode(5889);
         RenderSystem.loadIdentity();
-        //        RenderSystem.ortho(0.0D, rectangle.width * 8, rectangle.height * 8, 0.0D, -1, 1);
-        //        RenderSystem.scalef(1, -1,0);
-        //        RenderSystem.ortho(-1, 1, 1, -1, -1, 1);
-        //        RenderSystem.ortho(-1, 1, 1, -1, -1, 1);
-        RenderSystem.matrixMode(GL11.GL_MODELVIEW);
-        RenderSystem.pushMatrix();
+        RenderSystem.ortho(0.0D, (double) window.getFramebufferWidth() / window.getScaleFactor(), (double) window.getFramebufferHeight() / window.getScaleFactor(), 0.0D, 1000.0D, 3000.0D);
+        RenderSystem.matrixMode(5888);
         RenderSystem.loadIdentity();
-        //        RenderSystem.translatef(0.0F, 0.0F, -2000.0F);
-        //        RenderSystem.rotatef(180, 1, 0, 0);
-        RenderSystem.scalef(2f / rectangle.width, -2f / rectangle.height, 0);
-        //        RenderSystem.scalef(1f / rectangle.width, -1f / rectangle.height, 0);
-        //        RenderSystem.translatef(10,10,0);
-        RenderSystem.translatef(-rectangle.x, -rectangle.y, 0);
-        //        RenderSystem.translatef(rectangle.x, rectangle.y, 0);
-        RenderSystem.translatef(-rectangle.width / 2f, -rectangle.height / 2f, 0);
-        
-        //        RenderSystem.enableAlphaTest();
-        //        RenderSystem.alphaFunc(516, 0.1F);
-        //        RenderSystem.enableBlend();
-        //        RenderSystem.blendFuncSeparate(GlStateManager.SrcFactor.ONE_MINUS_DST_ALPHA, GlStateManager.DstFactor.DST_ALPHA, GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
-        RenderSystem.enableAlphaTest();
-        RenderSystem.defaultAlphaFunc();
-        RenderSystem.enableBlend();
-        RenderSystem.enableDepthTest();
-        RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
-        RenderSystem.depthMask(false);
-        RenderSystem.disableCull();
-        RenderSystem.pushLightingAttributes();
+        RenderSystem.translatef(0.0F, 0.0F, -2000.0F);
+        DiffuseLighting.enableGuiDepthLighting();
+        MatrixStack matrices = new MatrixStack();
         for (Widget widget : widgets) {
-            widget.render(matrices, -1, -1, minecraft.getTickDelta());
-        }
-        {
-            ItemStack stack = new ItemStack(Items.OAK_STAIRS);
-            final BakedModel model = minecraft.getItemRenderer().getHeldItemModel(stack, minecraft.world, minecraft.player);
-            minecraft.getTextureManager().bindTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEX);
-            minecraft.getTextureManager().getTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEX).setFilter(false, false);
-            
-            RenderSystem.enableRescaleNormal();
-            RenderSystem.enableAlphaTest();
-            RenderSystem.defaultAlphaFunc();
-            RenderSystem.enableBlend();
-            RenderSystem.enableDepthTest();
-            RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA);
-            
-            RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
-            matrices.push();
-            
-            matrices.translate(rectangle.x + 8, rectangle.y + 8, 0);
-            matrices.scale(16, -16, 1F);
-            
-            boolean disableGuiLight = !model.isSideLit();
-            if (disableGuiLight) {
-                DiffuseLighting.disableGuiDepthLighting();
-            }
-            
-            VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
-            minecraft.getItemRenderer().renderItem(stack, ModelTransformation.Mode.GUI, false, matrices, immediate, 15728880, OverlayTexture.DEFAULT_UV, model);
-            immediate.draw();
-            matrices.pop();
-            
-            RenderSystem.enableDepthTest();
-            
-            if (disableGuiLight) {
-                DiffuseLighting.enableGuiDepthLighting();
-            }
-            
-            RenderSystem.disableAlphaTest();
-            RenderSystem.disableRescaleNormal();
+            widget.render(matrices, -1, -1, 0);
         }
-        //        fillGradient(0, 0, 10, 10, -1, -1);
-        //        fillGradient(rectangle.x, rectangle.y, rectangle.x + 10, rectangle.y + 10, -16777216, -16777216);
-        RenderSystem.depthMask(true);
-        RenderSystem.disableAlphaTest();
-        RenderSystem.disableRescaleNormal();
-        RenderSystem.disableDepthTest();
-        //        RenderSystem.disableAlphaTest();
-        //        RenderSystem.disableBlend();
-        
-        // Reset matrices
-        RenderSystem.matrixMode(GL11.GL_PROJECTION);
         RenderSystem.popMatrix();
-        RenderSystem.matrixMode(GL11.GL_MODELVIEW);
-        RenderSystem.popMatrix();
-        
-        framebuffer.endWrite();
-        RenderSystem.popMatrix();
-        RenderSystem.viewport(0, 0, minecraft.getWindow().getFramebufferWidth(), minecraft.getWindow().getFramebufferHeight());
         
-        NativeImage nativeImage = new NativeImage(rectangle.width * 8, rectangle.height * 8, false);
+        NativeImage nativeImage = new NativeImage(framebuffer.textureWidth, framebuffer.textureHeight, false);
         RenderSystem.bindTexture(framebuffer.colorAttachment);
         nativeImage.loadFromTextureImage(0, false);
-        {
-            int width = rectangle.width * 8;
-            int height = rectangle.height * 8;
-            for (int y = 0; y < height; ++y) {
-                for (int x = 0; x < width; ++x) {
-                    if (x > 24 && x < width - 24 && y > 24 && y < height - 24)
-                        nativeImage.setPixelRgba(x, y, nativeImage.getPixelRgba(x, y) | 255 << NativeImage.Format.RGBA.getAlphaChannelOffset());
-                }
+        nativeImage.mirrorVertically();
+        int outWidth = (int) (rectangle.width * window.getScaleFactor());
+        int outHeight = (int) (rectangle.height * window.getScaleFactor());
+        NativeImage strippedImage = new NativeImage(outWidth, outHeight, false);
+        for (int y = 0; y < outHeight; ++y) {
+            for (int x = 0; x < outWidth; ++x) {
+                strippedImage.setPixelRgba(x, y, nativeImage.getPixelRgba(x + (int) (rectangle.x * window.getScaleFactor()), y + (int) (rectangle.y * window.getScaleFactor())));
             }
         }
-        
-        nativeImage.mirrorVertically();
         ResourceImpl.RESOURCE_IO_EXECUTOR.execute(() -> {
             try {
-                File export = new File(minecraft.runDirectory, "export");
-                //noinspection ResultOfMethodCallIgnored
+                File export = new File(minecraft.runDirectory, "rei_exports");
                 export.mkdirs();
-                nativeImage.writeFile(getExportFilename(export));
+                strippedImage.writeFile(getExportFilename(export));
             } catch (IOException e) {
                 e.printStackTrace();
             } finally {
                 nativeImage.close();
+                strippedImage.close();
                 RenderSystem.recordRenderCall(framebuffer::delete);
             }
         });

+ 3 - 3
src/main/java/me/shedaniel/rei/gui/RecipeViewingScreen.java

@@ -342,7 +342,7 @@ public class RecipeViewingScreen extends Screen implements RecipeScreen {
             preWidgets.add(workingStationsBaseWidget = Widgets.createCategoryBase(new Rectangle(xx - 5, yy - 5, 15 + innerWidth * 16, 10 + actualHeight * 16)));
             preWidgets.add(Widgets.createSlotBase(new Rectangle(xx - 1, yy - 1, innerWidth * 16 + 2, actualHeight * 16 + 2)));
             int index = 0;
-            List<Text> list = Collections.singletonList(new TranslatableText("text.rei.working_station").method_27692(Formatting.YELLOW));
+            List<Text> list = Collections.singletonList(new TranslatableText("text.rei.working_station").formatted(Formatting.YELLOW));
             xx += (innerWidth - 1) * 16;
             for (List<EntryStack> workingStation : workingStations) {
                 preWidgets.add(new WorkstationSlotWidget(xx, yy, CollectionUtils.map(workingStation, stack -> stack.copy().setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, s -> list))));
@@ -436,12 +436,12 @@ public class RecipeViewingScreen extends Screen implements RecipeScreen {
                     setZOffset(470);
                     if (bounds.contains(mouseX, mouseY)) {
                         fillGradient(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), 1744822402, 1744822402);
-                        Text text = new TranslatableText("text.rei.release_export", export.getLocalizedName());
+                        Text text = new TranslatableText("text.rei.release_export", export.getLocalizedName().copy().getString());
                         VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer());
                         matrices.push();
                         matrices.translate(0.0D, 0.0D, 480);
                         Matrix4f matrix4f = matrices.peek().getModel();
-                        textRenderer.draw(text, bounds.getCenterX() - textRenderer.method_27525(text) / 2f, bounds.getCenterY() - 4.5f, 0xff000000, false, matrix4f, immediate, false, 0, 15728880);
+                        textRenderer.draw(text, bounds.getCenterX() - textRenderer.getWidth(text) / 2f, bounds.getCenterY() - 4.5f, 0xff000000, false, matrix4f, immediate, false, 0, 15728880);
                         immediate.draw();
                         matrices.pop();
                     } else {

+ 3 - 3
src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java

@@ -27,6 +27,7 @@ import com.google.common.collect.Lists;
 import com.mojang.blaze3d.systems.RenderSystem;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.api.ScissorsHandler;
+import me.shedaniel.clothconfig2.api.ScrollingContainer;
 import me.shedaniel.math.Point;
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
@@ -35,7 +36,6 @@ import me.shedaniel.rei.api.widgets.Button;
 import me.shedaniel.rei.api.widgets.Tooltip;
 import me.shedaniel.rei.api.widgets.Widgets;
 import me.shedaniel.rei.gui.entries.RecipeEntry;
-import me.shedaniel.rei.gui.widget.ScrollingContainer;
 import me.shedaniel.rei.gui.widget.TabWidget;
 import me.shedaniel.rei.gui.widget.Widget;
 import me.shedaniel.rei.impl.ClientHelperImpl;
@@ -171,7 +171,7 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen
             widgets.add(Widgets.createCategoryBase(new Rectangle(xx - 5, bounds.y + bounds.height - 5, 10 + w * 16, 12 + h * 16)));
             widgets.add(Widgets.createSlotBase(new Rectangle(xx - 1, yy - 1, 2 + w * 16, 2 + h * 16)));
             int index = 0;
-            List<Text> list = Collections.singletonList(new TranslatableText("text.rei.working_station").method_27692(Formatting.YELLOW));
+            List<Text> list = Collections.singletonList(new TranslatableText("text.rei.working_station").formatted(Formatting.YELLOW));
             for (List<EntryStack> workingStation : workingStations) {
                 widgets.add(new RecipeViewingScreen.WorkstationSlotWidget(xx, yy, CollectionUtils.map(workingStation, stack -> stack.copy().setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, s -> list))));
                 index++;
@@ -352,7 +352,7 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen
                 Optional.ofNullable(recipeRenderers.get(i).getTooltip(new Point(mouseX, mouseY))).ifPresent(Tooltip::queue);
             }
         }
-        scrolling.renderScrollBar(0, scrollBarAlpha);
+        scrolling.renderScrollBar(0, scrollBarAlpha, REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
         ScissorsHandler.INSTANCE.removeLastScissor();
         RenderSystem.popMatrix();
         ScreenHelper.getLastOverlay().lateRender(matrices, mouseX, mouseY, delta);

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

@@ -66,13 +66,13 @@ public class WarningAndErrorScreen extends Screen {
     }
     
     private void addText(Text string) {
-        for (Text s : textRenderer.wrapStringToWidthAsList(string, width - 80)) {
+        for (Text s : textRenderer.wrapLines(string, width - 80)) {
             listWidget.creditsAddEntry(new TextItem(s));
         }
     }
     
     private void addLink(Text string, String link) {
-        for (Text s : textRenderer.wrapStringToWidthAsList(string, width - 80)) {
+        for (Text s : textRenderer.wrapLines(string, width - 80)) {
             listWidget.creditsAddEntry(new LinkItem(s.getString(), link));
         }
     }
@@ -84,7 +84,7 @@ public class WarningAndErrorScreen extends Screen {
         listWidget.creditsClearEntries();
         listWidget.creditsAddEntry(new EmptyItem());
         if (!RoughlyEnoughItemsState.getWarnings().isEmpty())
-            listWidget.creditsAddEntry(new TextItem(new LiteralText("Warnings:").method_27692(Formatting.RED)));
+            listWidget.creditsAddEntry(new TextItem(new LiteralText("Warnings:").formatted(Formatting.RED)));
         for (Pair<String, String> pair : RoughlyEnoughItemsState.getWarnings()) {
             addText(new LiteralText(pair.getLeft()));
             if (pair.getRight() != null)
@@ -97,7 +97,7 @@ public class WarningAndErrorScreen extends Screen {
             listWidget.creditsAddEntry(new EmptyItem());
         }
         if (!RoughlyEnoughItemsState.getErrors().isEmpty())
-            listWidget.creditsAddEntry(new TextItem(new LiteralText("Errors:").method_27692(Formatting.RED)));
+            listWidget.creditsAddEntry(new TextItem(new LiteralText("Errors:").formatted(Formatting.RED)));
         for (Pair<String, String> pair : RoughlyEnoughItemsState.getErrors()) {
             addText(new LiteralText(pair.getLeft()));
             if (pair.getRight() != null)
@@ -218,7 +218,7 @@ public class WarningAndErrorScreen extends Screen {
         
         @Override
         public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
-            MinecraftClient.getInstance().textRenderer.method_27517(matrices, text, x + 5, y, -1);
+            MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, text, x + 5, y, -1);
         }
         
         @Override
@@ -233,7 +233,7 @@ public class WarningAndErrorScreen extends Screen {
         
         @Override
         public int getWidth() {
-            return MinecraftClient.getInstance().textRenderer.method_27525(text) + 10;
+            return MinecraftClient.getInstance().textRenderer.getWidth(text) + 10;
         }
     }
     
@@ -270,7 +270,7 @@ public class WarningAndErrorScreen extends Screen {
         
         @Override
         public int getWidth() {
-            return MinecraftClient.getInstance().textRenderer.getStringWidth(text) + 10;
+            return MinecraftClient.getInstance().textRenderer.getWidth(text) + 10;
         }
         
         @Override

+ 8 - 7
src/main/java/me/shedaniel/rei/gui/config/entry/FilteringEntry.java

@@ -36,10 +36,11 @@ import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.rei.api.ConfigObject;
 import me.shedaniel.rei.api.EntryRegistry;
 import me.shedaniel.rei.api.EntryStack;
+import me.shedaniel.rei.api.REIHelper;
 import me.shedaniel.rei.api.widgets.Tooltip;
 import me.shedaniel.rei.gui.OverlaySearchField;
 import me.shedaniel.rei.gui.widget.EntryWidget;
-import me.shedaniel.rei.gui.widget.ScrollingContainer;
+import me.shedaniel.clothconfig2.api.ScrollingContainer;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.SearchArgument;
 import me.shedaniel.rei.utils.CollectionUtils;
@@ -111,21 +112,21 @@ public class FilteringEntry extends AbstractConfigListEntry<List<EntryStack>> {
         this.searchField = new OverlaySearchField(0, 0, 0, 0);
         {
             Text selectAllText = new TranslatableText("config.roughlyenoughitems.filteredEntries.selectAll");
-            this.selectAllButton = new ButtonWidget(0, 0, MinecraftClient.getInstance().textRenderer.method_27525(selectAllText) + 10, 20, selectAllText, button -> {
+            this.selectAllButton = new ButtonWidget(0, 0, MinecraftClient.getInstance().textRenderer.getWidth(selectAllText) + 10, 20, selectAllText, button -> {
                 this.selectionPoint = new Point(-Integer.MAX_VALUE / 2, -Integer.MAX_VALUE / 2);
                 this.secondPoint = new Point(Integer.MAX_VALUE / 2, Integer.MAX_VALUE / 2);
             });
         }
         {
             Text selectNoneText = new TranslatableText("config.roughlyenoughitems.filteredEntries.selectNone");
-            this.selectNoneButton = new ButtonWidget(0, 0, MinecraftClient.getInstance().textRenderer.method_27525(selectNoneText) + 10, 20, selectNoneText, button -> {
+            this.selectNoneButton = new ButtonWidget(0, 0, MinecraftClient.getInstance().textRenderer.getWidth(selectNoneText) + 10, 20, selectNoneText, button -> {
                 this.selectionPoint = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);
                 this.secondPoint = new Point(Integer.MAX_VALUE, Integer.MAX_VALUE);
             });
         }
         {
             Text hideText = new TranslatableText("config.roughlyenoughitems.filteredEntries.hide");
-            this.hideButton = new ButtonWidget(0, 0, MinecraftClient.getInstance().textRenderer.method_27525(hideText) + 10, 20, hideText, button -> {
+            this.hideButton = new ButtonWidget(0, 0, MinecraftClient.getInstance().textRenderer.getWidth(hideText) + 10, 20, hideText, button -> {
                 for (int i = 0; i < entryStacks.size(); i++) {
                     EntryStack stack = entryStacks.get(i);
                     EntryListEntry entry = entries.get(i);
@@ -139,7 +140,7 @@ public class FilteringEntry extends AbstractConfigListEntry<List<EntryStack>> {
         }
         {
             Text showText = new TranslatableText("config.roughlyenoughitems.filteredEntries.show");
-            this.showButton = new ButtonWidget(0, 0, MinecraftClient.getInstance().textRenderer.method_27525(showText) + 10, 20, showText, button -> {
+            this.showButton = new ButtonWidget(0, 0, MinecraftClient.getInstance().textRenderer.getWidth(showText) + 10, 20, showText, button -> {
                 for (int i = 0; i < entryStacks.size(); i++) {
                     EntryStack stack = entryStacks.get(i);
                     EntryListEntry entry = entries.get(i);
@@ -217,7 +218,7 @@ public class FilteringEntry extends AbstractConfigListEntry<List<EntryStack>> {
             nextIndex++;
         }
         updatePosition(delta);
-        scrolling.renderScrollBar(0xff000000, 1);
+        scrolling.renderScrollBar(0xff000000, 1, REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
         matrices.push();
         matrices.translate(0, 0, 300);
         this.searchField.laterRender(matrices, mouseX, mouseY, delta);
@@ -249,7 +250,7 @@ public class FilteringEntry extends AbstractConfigListEntry<List<EntryStack>> {
     
     @Override
     public boolean mouseDragged(double mouseX, double mouseY, int button, double dx, double dy) {
-        if (scrolling.mouseDragged(mouseX, mouseY, button, dx, dy, true))
+        if (scrolling.mouseDragged(mouseX, mouseY, button, dx, dy, ConfigObject.getInstance().doesSnapToRows(), entrySize()))
             return true;
         return super.mouseDragged(mouseX, mouseY, button, dx, dy);
     }

+ 4 - 4
src/main/java/me/shedaniel/rei/gui/credits/CreditsEntryListWidget.java

@@ -92,7 +92,7 @@ public class CreditsEntryListWidget extends DynamicNewSmoothScrollingEntryListWi
         
         @Override
         public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
-            MinecraftClient.getInstance().textRenderer.method_27517(matrices, text, x + 5, y + 5, -1);
+            MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, text, x + 5, y + 5, -1);
         }
         
         @Override
@@ -113,16 +113,16 @@ public class CreditsEntryListWidget extends DynamicNewSmoothScrollingEntryListWi
         
         public TranslationCreditsItem(Text language, Text translators, int width, int maxWidth) {
             this.language = language;
-            this.translators = MinecraftClient.getInstance().textRenderer.wrapStringToWidthAsList(translators, width);
+            this.translators = MinecraftClient.getInstance().textRenderer.wrapLines(translators, width);
             this.maxWidth = maxWidth;
         }
         
         @Override
         public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
-            MinecraftClient.getInstance().textRenderer.method_27517(matrices, language, x + 5, y + 5, -1);
+            MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, language, x + 5, y + 5, -1);
             int yy = y + 5;
             for (Text translator : translators) {
-                MinecraftClient.getInstance().textRenderer.method_27517(matrices, translator, x + 5 + maxWidth, yy, -1);
+                MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, translator, x + 5 + maxWidth, yy, -1);
                 yy += 12;
             }
         }

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

@@ -104,7 +104,7 @@ public class CreditsScreen extends Screen {
                     for (StackTraceElement traceElement : exception[0].getStackTrace())
                         entryListWidget.creditsAddEntry(new TextCreditsItem(new LiteralText("  at " + traceElement)));
                 } else {
-                    int maxWidth = translatorsMapped.stream().mapToInt(pair -> textRenderer.getStringWidth(pair.getLeft())).max().orElse(0) + 5;
+                    int maxWidth = translatorsMapped.stream().mapToInt(pair -> textRenderer.getWidth(pair.getLeft())).max().orElse(0) + 5;
                     for (Pair<String, String> pair : translatorsMapped) {
                         entryListWidget.creditsAddEntry(new TranslationCreditsItem(new TranslatableText(pair.getLeft()), new TranslatableText(pair.getRight()), i - maxWidth - 10, maxWidth));
                     }

+ 29 - 29
src/main/java/me/shedaniel/rei/gui/subsets/SubsetsMenu.java → src/main/java/me/shedaniel/rei/gui/modules/Menu.java

@@ -21,13 +21,14 @@
  * SOFTWARE.
  */
 
-package me.shedaniel.rei.gui.subsets;
+package me.shedaniel.rei.gui.modules;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.api.ScissorsHandler;
+import me.shedaniel.clothconfig2.api.ScrollingContainer;
 import me.shedaniel.math.Point;
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
@@ -35,10 +36,9 @@ import me.shedaniel.rei.api.EntryRegistry;
 import me.shedaniel.rei.api.EntryStack;
 import me.shedaniel.rei.api.REIHelper;
 import me.shedaniel.rei.api.subsets.SubsetsRegistry;
-import me.shedaniel.rei.gui.subsets.entries.EntryStackMenuEntry;
-import me.shedaniel.rei.gui.subsets.entries.SubMenuEntry;
+import me.shedaniel.rei.gui.modules.entries.EntryStackSubsetsMenuEntry;
+import me.shedaniel.rei.gui.modules.entries.SubSubsetsMenuEntry;
 import me.shedaniel.rei.gui.widget.LateRenderable;
-import me.shedaniel.rei.gui.widget.ScrollingContainer;
 import me.shedaniel.rei.gui.widget.WidgetWithBounds;
 import me.shedaniel.rei.impl.EntryRegistryImpl;
 import me.shedaniel.rei.utils.CollectionUtils;
@@ -56,14 +56,14 @@ import java.util.*;
 
 @ApiStatus.Experimental
 @ApiStatus.Internal
-public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
+public class Menu extends WidgetWithBounds implements LateRenderable {
     public final Point menuStartPoint;
-    private final List<SubsetsMenuEntry> entries = Lists.newArrayList();
+    private final List<MenuEntry> entries = Lists.newArrayList();
     public final ScrollingContainer scrolling = new ScrollingContainer() {
         @Override
         public int getMaxScrollHeight() {
             int i = 0;
-            for (SubsetsMenuEntry entry : children()) {
+            for (MenuEntry entry : children()) {
                 i += entry.getEntryHeight();
             }
             return i;
@@ -71,21 +71,21 @@ public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
         
         @Override
         public Rectangle getBounds() {
-            return SubsetsMenu.this.getInnerBounds();
+            return Menu.this.getInnerBounds();
         }
         
         @Override
         public boolean hasScrollBar() {
-            return SubsetsMenu.this.hasScrollBar();
+            return Menu.this.hasScrollBar();
         }
     };
     
-    public SubsetsMenu(Point menuStartPoint, Collection<SubsetsMenuEntry> entries) {
+    public Menu(Point menuStartPoint, Collection<MenuEntry> entries) {
         this.menuStartPoint = menuStartPoint;
         buildEntries(entries);
     }
     
-    public static SubsetsMenu createFromRegistry(Point menuStartPoint) {
+    public static Menu createSubsetsMenuFromRegistry(Point menuStartPoint) {
         List<EntryStack> stacks = EntryRegistry.getInstance().getStacksList();
         Map<String, Object> entries = Maps.newHashMap();
         {
@@ -130,7 +130,7 @@ public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
                     putEntryInMap(lastMap, firstStack);
             }
         }
-        return new SubsetsMenu(menuStartPoint, buildEntries(entries));
+        return new Menu(menuStartPoint, buildEntries(entries));
     }
     
     private static Map<String, Object> getOrCreateSubEntryInMap(Map<String, Object> parent, String pathSegment) {
@@ -153,23 +153,23 @@ public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
         items.add(stack);
     }
     
-    private static List<SubsetsMenuEntry> buildEntries(Map<String, Object> map) {
-        List<SubsetsMenuEntry> entries = Lists.newArrayList();
+    private static List<MenuEntry> buildEntries(Map<String, Object> map) {
+        List<MenuEntry> entries = Lists.newArrayList();
         for (Map.Entry<String, Object> entry : map.entrySet()) {
             if (entry.getKey().equals("items")) {
                 Set<EntryStack> items = (Set<EntryStack>) entry.getValue();
                 for (EntryStack item : items) {
-                    entries.add(new EntryStackMenuEntry(item));
+                    entries.add(new EntryStackSubsetsMenuEntry(item));
                 }
             } else {
                 Map<String, Object> entryMap = (Map<String, Object>) entry.getValue();
                 if (entry.getKey().startsWith("_item_group_")) {
-                    entries.add(new SubMenuEntry(I18n.translate(entry.getKey().replace("_item_group_", "itemGroup.")), buildEntries(entryMap)));
+                    entries.add(new SubSubsetsMenuEntry(I18n.translate(entry.getKey().replace("_item_group_", "itemGroup.")), buildEntries(entryMap)));
                 } else {
                     String translationKey = "subsets.rei." + entry.getKey().replace(':', '.');
                     if (!I18n.hasTranslation(translationKey))
                         RoughlyEnoughItemsCore.LOGGER.warn("Subsets menu " + translationKey + " does not have a translation");
-                    entries.add(new SubMenuEntry(I18n.translate(translationKey), buildEntries(entryMap)));
+                    entries.add(new SubSubsetsMenuEntry(I18n.translate(translationKey), buildEntries(entryMap)));
                 }
             }
         }
@@ -177,11 +177,11 @@ public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
     }
     
     @SuppressWarnings("deprecation")
-    private void buildEntries(Collection<SubsetsMenuEntry> entries) {
+    private void buildEntries(Collection<MenuEntry> entries) {
         this.entries.clear();
         this.entries.addAll(entries);
-        this.entries.sort(Comparator.comparing(entry -> entry instanceof SubMenuEntry ? 0 : 1).thenComparing(entry -> entry instanceof SubMenuEntry ? ((SubMenuEntry) entry).text : ""));
-        for (SubsetsMenuEntry entry : this.entries) {
+        this.entries.sort(Comparator.comparing(entry -> entry instanceof SubSubsetsMenuEntry ? 0 : 1).thenComparing(entry -> entry instanceof SubSubsetsMenuEntry ? ((SubSubsetsMenuEntry) entry).text : ""));
+        for (MenuEntry entry : this.entries) {
             entry.parent = this;
         }
     }
@@ -205,7 +205,7 @@ public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
     
     public int getMaxEntryWidth() {
         int i = 0;
-        for (SubsetsMenuEntry entry : children()) {
+        for (MenuEntry entry : children()) {
             if (entry.getEntryWidth() > i)
                 i = entry.getEntryWidth();
         }
@@ -216,12 +216,12 @@ public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
     public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
         Rectangle bounds = getBounds();
         Rectangle innerBounds = getInnerBounds();
-        fill(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), containsMouse(mouseX, mouseY) ? (REIHelper.getInstance().isDarkThemeEnabled() ? -17587 : -1) :-6250336);
+        fill(matrices, bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), containsMouse(mouseX, mouseY) ? (REIHelper.getInstance().isDarkThemeEnabled() ? -17587 : -1) : -6250336);
         fill(matrices, innerBounds.x, innerBounds.y, innerBounds.getMaxX(), innerBounds.getMaxY(), -16777216);
         boolean contains = innerBounds.contains(mouseX, mouseY);
-        SubsetsMenuEntry focused = getFocused() instanceof SubsetsMenuEntry ? (SubsetsMenuEntry) getFocused() : null;
+        MenuEntry focused = getFocused() instanceof MenuEntry ? (MenuEntry) getFocused() : null;
         int currentY = (int) (innerBounds.y - scrolling.scrollAmount);
-        for (SubsetsMenuEntry child : children()) {
+        for (MenuEntry child : children()) {
             boolean containsMouse = contains && mouseY >= currentY && mouseY < currentY + child.getEntryHeight();
             if (containsMouse) {
                 focused = child;
@@ -230,7 +230,7 @@ public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
         }
         currentY = (int) (innerBounds.y - scrolling.scrollAmount);
         ScissorsHandler.INSTANCE.scissor(scrolling.getScissorBounds());
-        for (SubsetsMenuEntry child : children()) {
+        for (MenuEntry child : children()) {
             boolean rendering = currentY + child.getEntryHeight() >= innerBounds.y && currentY <= innerBounds.getMaxY();
             boolean containsMouse = contains && mouseY >= currentY && mouseY < currentY + child.getEntryHeight();
             child.updateInformation(innerBounds.x, currentY, focused == child || containsMouse, containsMouse, rendering, getMaxEntryWidth());
@@ -240,7 +240,7 @@ public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
         }
         ScissorsHandler.INSTANCE.removeLastScissor();
         setFocused(focused);
-        scrolling.renderScrollBar();
+        scrolling.renderScrollBar(0, 1, REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
         scrolling.updatePosition(delta);
     }
     
@@ -264,8 +264,8 @@ public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
             scrolling.offset(ClothConfigInitializer.getScrollStep() * -amount, true);
             return true;
         }
-        for (SubsetsMenuEntry child : children()) {
-            if (child instanceof SubMenuEntry) {
+        for (MenuEntry child : children()) {
+            if (child instanceof SubSubsetsMenuEntry) {
                 if (child.mouseScrolled(mouseX, mouseY, amount))
                     return true;
             }
@@ -274,7 +274,7 @@ public class SubsetsMenu extends WidgetWithBounds implements LateRenderable {
     }
     
     @Override
-    public List<SubsetsMenuEntry> children() {
+    public List<MenuEntry> children() {
         return entries;
     }
 }

+ 4 - 4
src/main/java/me/shedaniel/rei/gui/subsets/SubsetsMenuEntry.java → src/main/java/me/shedaniel/rei/gui/modules/MenuEntry.java

@@ -21,18 +21,18 @@
  * SOFTWARE.
  */
 
-package me.shedaniel.rei.gui.subsets;
+package me.shedaniel.rei.gui.modules;
 
 import me.shedaniel.rei.gui.widget.Widget;
 import org.jetbrains.annotations.ApiStatus;
 
 @ApiStatus.Experimental
 @ApiStatus.Internal
-public abstract class SubsetsMenuEntry extends Widget {
+public abstract class MenuEntry extends Widget {
     @Deprecated
-    SubsetsMenu parent = null;
+    Menu parent = null;
     
-    public final SubsetsMenu getParent() {
+    public final Menu getParent() {
         return parent;
     }
     

+ 12 - 12
src/main/java/me/shedaniel/rei/gui/subsets/entries/EntryStackMenuEntry.java → src/main/java/me/shedaniel/rei/gui/modules/entries/EntryStackSubsetsMenuEntry.java

@@ -21,15 +21,15 @@
  * SOFTWARE.
  */
 
-package me.shedaniel.rei.gui.subsets.entries;
+package me.shedaniel.rei.gui.modules.entries;
 
 import me.shedaniel.math.Point;
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 import me.shedaniel.rei.api.*;
 import me.shedaniel.rei.gui.ContainerScreenOverlay;
-import me.shedaniel.rei.gui.subsets.SubsetsMenu;
-import me.shedaniel.rei.gui.subsets.SubsetsMenuEntry;
+import me.shedaniel.rei.gui.modules.Menu;
+import me.shedaniel.rei.gui.modules.MenuEntry;
 import me.shedaniel.rei.impl.EntryRegistryImpl;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.utils.CollectionUtils;
@@ -44,14 +44,14 @@ import java.util.List;
 
 @ApiStatus.Experimental
 @ApiStatus.Internal
-public class EntryStackMenuEntry extends SubsetsMenuEntry {
+public class EntryStackSubsetsMenuEntry extends MenuEntry {
     final EntryStack stack;
     private int x, y, width;
     private boolean selected, containsMouse, rendering;
     private boolean clickedLast = false;
     private Boolean isFiltered = null;
     
-    public EntryStackMenuEntry(EntryStack stack) {
+    public EntryStackSubsetsMenuEntry(EntryStack stack) {
         this.stack = stack;
     }
     
@@ -98,7 +98,7 @@ public class EntryStackMenuEntry extends SubsetsMenuEntry {
                     } else {
                         filteredStacks.add(stack.copy());
                     }
-                    SubsetsMenu subsetsMenu = ScreenHelper.getLastOverlay().getSubsetsMenu();
+                    Menu subsetsMenu = ScreenHelper.getLastOverlay().getSubsetsMenu();
                     if (subsetsMenu != null)
                         recalculateFilter(subsetsMenu);
                     ConfigManager.getInstance().saveConfig();
@@ -111,12 +111,12 @@ public class EntryStackMenuEntry extends SubsetsMenuEntry {
         stack.render(matrices, new Rectangle(x + (width / 2) - 8, y + 1, 16, 16), mouseX, mouseY, delta);
     }
     
-    void recalculateFilter(SubsetsMenu menu) {
-        for (SubsetsMenuEntry child : menu.children()) {
-            if (child instanceof SubMenuEntry && ((SubMenuEntry) child).getSubsetsMenu() != null)
-                recalculateFilter(((SubMenuEntry) child).getSubsetsMenu());
-            else if (child instanceof EntryStackMenuEntry && ((EntryStackMenuEntry) child).stack.equalsIgnoreAmount(stack))
-                ((EntryStackMenuEntry) child).isFiltered = null;
+    void recalculateFilter(Menu menu) {
+        for (MenuEntry child : menu.children()) {
+            if (child instanceof SubSubsetsMenuEntry && ((SubSubsetsMenuEntry) child).getSubsetsMenu() != null)
+                recalculateFilter(((SubSubsetsMenuEntry) child).getSubsetsMenu());
+            else if (child instanceof EntryStackSubsetsMenuEntry && ((EntryStackSubsetsMenuEntry) child).stack.equalsIgnoreAmount(stack))
+                ((EntryStackSubsetsMenuEntry) child).isFiltered = null;
         }
     }
     

+ 4 - 4
src/main/java/me/shedaniel/rei/gui/modules/GameModeMenuEntry.java → src/main/java/me/shedaniel/rei/gui/modules/entries/GameModeMenuEntry.java

@@ -21,12 +21,12 @@
  * SOFTWARE.
  */
 
-package me.shedaniel.rei.gui.modules;
+package me.shedaniel.rei.gui.modules.entries;
 
 import me.shedaniel.rei.api.ConfigObject;
 import me.shedaniel.rei.api.REIHelper;
 import me.shedaniel.rei.api.widgets.Tooltip;
-import me.shedaniel.rei.gui.subsets.SubsetsMenuEntry;
+import me.shedaniel.rei.gui.modules.MenuEntry;
 import me.shedaniel.rei.impl.ScreenHelper;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.Element;
@@ -40,7 +40,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 
-public class GameModeMenuEntry extends SubsetsMenuEntry {
+public class GameModeMenuEntry extends MenuEntry {
     public final String text;
     public final GameMode gameMode;
     private int x, y, width;
@@ -54,7 +54,7 @@ public class GameModeMenuEntry extends SubsetsMenuEntry {
     
     private int getTextWidth() {
         if (textWidth == -69) {
-            this.textWidth = Math.max(0, font.getStringWidth(text));
+            this.textWidth = Math.max(0, font.getWidth(text));
         }
         return this.textWidth;
     }

+ 28 - 28
src/main/java/me/shedaniel/rei/gui/subsets/entries/SubMenuEntry.java → src/main/java/me/shedaniel/rei/gui/modules/entries/SubSubsetsMenuEntry.java

@@ -21,7 +21,7 @@
  * SOFTWARE.
  */
 
-package me.shedaniel.rei.gui.subsets.entries;
+package me.shedaniel.rei.gui.modules.entries;
 
 import com.google.common.collect.Lists;
 import me.shedaniel.clothconfig2.api.ScissorsHandler;
@@ -30,8 +30,8 @@ import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.api.*;
 import me.shedaniel.rei.api.widgets.Tooltip;
 import me.shedaniel.rei.gui.ContainerScreenOverlay;
-import me.shedaniel.rei.gui.subsets.SubsetsMenu;
-import me.shedaniel.rei.gui.subsets.SubsetsMenuEntry;
+import me.shedaniel.rei.gui.modules.Menu;
+import me.shedaniel.rei.gui.modules.MenuEntry;
 import me.shedaniel.rei.gui.widget.TabWidget;
 import me.shedaniel.rei.impl.EntryRegistryImpl;
 import me.shedaniel.rei.impl.ScreenHelper;
@@ -51,40 +51,40 @@ import java.util.function.Supplier;
 
 @ApiStatus.Experimental
 @ApiStatus.Internal
-public class SubMenuEntry extends SubsetsMenuEntry {
+public class SubSubsetsMenuEntry extends MenuEntry {
     public final String text;
     private int textWidth = -69;
     private int x, y, width;
     private boolean selected, containsMouse, rendering;
-    private List<SubsetsMenuEntry> entries;
-    private SubsetsMenu subsetsMenu;
+    private List<MenuEntry> entries;
+    private Menu subsetsMenu;
     private Pair<Integer, Integer> filteredRatio = null;
     private long lastListHash = -1;
     private boolean clickedBefore = false;
     
-    public SubMenuEntry(String text) {
+    public SubSubsetsMenuEntry(String text) {
         this(text, Collections.emptyList());
     }
     
-    public SubMenuEntry(String text, Supplier<List<SubsetsMenuEntry>> entries) {
+    public SubSubsetsMenuEntry(String text, Supplier<List<MenuEntry>> entries) {
         this(text, entries.get());
     }
     
-    public SubMenuEntry(String text, List<SubsetsMenuEntry> entries) {
+    public SubSubsetsMenuEntry(String text, List<MenuEntry> entries) {
         this.text = text;
         this.entries = entries;
     }
     
     private int getTextWidth() {
         if (textWidth == -69) {
-            this.textWidth = Math.max(0, font.getStringWidth(text));
+            this.textWidth = Math.max(0, font.getWidth(text));
         }
         return this.textWidth;
     }
     
-    public SubsetsMenu getSubsetsMenu() {
+    public Menu getSubsetsMenu() {
         if (subsetsMenu == null) {
-            this.subsetsMenu = new SubsetsMenu(new Point(getParent().getBounds().getMaxX() - 1, y - 1), entries);
+            this.subsetsMenu = new Menu(new Point(getParent().getBounds().getMaxX() - 1, y - 1), entries);
         }
         return subsetsMenu;
     }
@@ -120,7 +120,7 @@ public class SubMenuEntry extends SubsetsMenuEntry {
         }
         if (selected) {
             if (!entries.isEmpty()) {
-                SubsetsMenu menu = getSubsetsMenu();
+                Menu menu = getSubsetsMenu();
                 menu.menuStartPoint.x = getParent().getBounds().getMaxX() - 1;
                 menu.menuStartPoint.y = y - 1;
                 List<Rectangle> areas = Lists.newArrayList(ScissorsHandler.INSTANCE.getScissorsAreas());
@@ -149,7 +149,7 @@ public class SubMenuEntry extends SubsetsMenuEntry {
             if (clickedBefore) {
                 clickedBefore = false;
                 List<EntryStack> filteredStacks = ConfigObject.getInstance().getFilteredStacks();
-                SubsetsMenu subsetsMenu = ScreenHelper.getLastOverlay().getSubsetsMenu();
+                Menu subsetsMenu = ScreenHelper.getLastOverlay().getSubsetsMenu();
                 setFiltered(filteredStacks, subsetsMenu, this, !(getFilteredRatio() > 0));
                 ConfigManager.getInstance().saveConfig();
                 ((EntryRegistryImpl) EntryRegistry.getInstance()).refilter();
@@ -164,20 +164,20 @@ public class SubMenuEntry extends SubsetsMenuEntry {
         return super.mouseClicked(mouseX, mouseY, button);
     }
     
-    private void setFiltered(List<EntryStack> filteredStacks, SubsetsMenu subsetsMenu, SubMenuEntry subMenuEntry, boolean filtered) {
-        for (SubsetsMenuEntry entry : subMenuEntry.entries) {
-            if (entry instanceof EntryStackMenuEntry) {
-                if (((EntryStackMenuEntry) entry).isFiltered() != filtered) {
+    private void setFiltered(List<EntryStack> filteredStacks, Menu subsetsMenu, SubSubsetsMenuEntry subSubsetsMenuEntry, boolean filtered) {
+        for (MenuEntry entry : subSubsetsMenuEntry.entries) {
+            if (entry instanceof EntryStackSubsetsMenuEntry) {
+                if (((EntryStackSubsetsMenuEntry) entry).isFiltered() != filtered) {
                     if (!filtered) {
-                        filteredStacks.removeIf(next -> next.equalsIgnoreAmount(((EntryStackMenuEntry) entry).stack));
+                        filteredStacks.removeIf(next -> next.equalsIgnoreAmount(((EntryStackSubsetsMenuEntry) entry).stack));
                     } else {
-                        filteredStacks.add(((EntryStackMenuEntry) entry).stack.copy());
+                        filteredStacks.add(((EntryStackSubsetsMenuEntry) entry).stack.copy());
                     }
                 }
                 if (subsetsMenu != null)
-                    ((EntryStackMenuEntry) entry).recalculateFilter(subsetsMenu);
-            } else if (entry instanceof SubMenuEntry) {
-                setFiltered(filteredStacks, subsetsMenu, (SubMenuEntry) entry, filtered);
+                    ((EntryStackSubsetsMenuEntry) entry).recalculateFilter(subsetsMenu);
+            } else if (entry instanceof SubSubsetsMenuEntry) {
+                setFiltered(filteredStacks, subsetsMenu, (SubSubsetsMenuEntry) entry, filtered);
             }
         }
     }
@@ -192,13 +192,13 @@ public class SubMenuEntry extends SubsetsMenuEntry {
         if (lastListHash != filteredStacks.hashCode()) {
             int size = 0;
             int filtered = 0;
-            for (SubsetsMenuEntry entry : entries) {
-                if (entry instanceof EntryStackMenuEntry) {
+            for (MenuEntry entry : entries) {
+                if (entry instanceof EntryStackSubsetsMenuEntry) {
                     size++;
-                    if (((EntryStackMenuEntry) entry).isFiltered())
+                    if (((EntryStackSubsetsMenuEntry) entry).isFiltered())
                         filtered++;
-                } else if (entry instanceof SubMenuEntry) {
-                    Pair<Integer, Integer> pair = ((SubMenuEntry) entry).getFilteredRatioPair();
+                } else if (entry instanceof SubSubsetsMenuEntry) {
+                    Pair<Integer, Integer> pair = ((SubSubsetsMenuEntry) entry).getFilteredRatioPair();
                     filtered += pair.getLeft();
                     size += pair.getRight();
                 }

+ 4 - 4
src/main/java/me/shedaniel/rei/gui/modules/WeatherMenuEntry.java → src/main/java/me/shedaniel/rei/gui/modules/entries/WeatherMenuEntry.java

@@ -21,12 +21,12 @@
  * SOFTWARE.
  */
 
-package me.shedaniel.rei.gui.modules;
+package me.shedaniel.rei.gui.modules.entries;
 
 import me.shedaniel.rei.api.ConfigObject;
 import me.shedaniel.rei.api.REIHelper;
 import me.shedaniel.rei.api.widgets.Tooltip;
-import me.shedaniel.rei.gui.subsets.SubsetsMenuEntry;
+import me.shedaniel.rei.gui.modules.MenuEntry;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.Weather;
 import net.minecraft.client.MinecraftClient;
@@ -41,7 +41,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 
-public class WeatherMenuEntry extends SubsetsMenuEntry {
+public class WeatherMenuEntry extends MenuEntry {
     public final String text;
     public final Weather weather;
     private int x, y, width;
@@ -55,7 +55,7 @@ public class WeatherMenuEntry extends SubsetsMenuEntry {
     
     private int getTextWidth() {
         if (textWidth == -69) {
-            this.textWidth = Math.max(0, font.getStringWidth(text));
+            this.textWidth = Math.max(0, font.getWidth(text));
         }
         return this.textWidth;
     }

+ 76 - 0
src/main/java/me/shedaniel/rei/gui/toast/ExportRecipeIdentifierToast.java

@@ -0,0 +1,76 @@
+/*
+ * This file is licensed under the MIT License, part of Roughly Enough Items.
+ * Copyright (c) 2018, 2019, 2020 shedaniel
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package me.shedaniel.rei.gui.toast;
+
+import com.mojang.blaze3d.systems.RenderSystem;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.toast.Toast;
+import net.minecraft.client.toast.ToastManager;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.util.Identifier;
+import org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.Nullable;
+
+@ApiStatus.Internal
+public class ExportRecipeIdentifierToast implements Toast {
+    
+    protected static final Identifier TOASTS_TEX = new Identifier("roughlyenoughitems", "textures/gui/toasts.png");
+    private String title;
+    private String subtitle;
+    private long startTime;
+    
+    public ExportRecipeIdentifierToast(String title, @Nullable String subtitleNullable) {
+        this.title = title;
+        this.subtitle = subtitleNullable;
+    }
+    
+    public static void addToast(String title, @Nullable String subtitleNullable) {
+        MinecraftClient.getInstance().getToastManager().add(new ExportRecipeIdentifierToast(title, subtitleNullable));
+    }
+    
+    @Override
+    public Visibility draw(MatrixStack matrices, ToastManager toastManager, long var2) {
+        toastManager.getGame().getTextureManager().bindTexture(TOASTS_TEX);
+        RenderSystem.color3f(1.0F, 1.0F, 1.0F);
+        toastManager.drawTexture(matrices, 0, 0, 0, 0, 160, 32);
+        if (this.subtitle == null) {
+            toastManager.getGame().textRenderer.draw(matrices, this.title, 18.0F, 12.0F, 11141120);
+        } else {
+            toastManager.getGame().textRenderer.draw(matrices, this.title, 18.0F, 7.0F, 11141120);
+            toastManager.getGame().textRenderer.draw(matrices, this.subtitle, 18.0F, 18.0F, -16777216);
+        }
+        
+        return var2 - this.startTime < 5000L ? Visibility.SHOW : Visibility.HIDE;
+    }
+    
+    @Override
+    public Object getType() {
+        return Type.THIS_IS_SURE_A_TYPE;
+    }
+    
+    public enum Type {
+        THIS_IS_SURE_A_TYPE
+    }
+    
+}

+ 5 - 5
src/main/java/me/shedaniel/rei/gui/widget/ClickableLabelWidget.java

@@ -73,17 +73,17 @@ public abstract class ClickableLabelWidget extends LabelWidget {
         if (isClickable() && isHovered(mouseX, mouseY))
             color = getHoveredColor();
         Point pos = getLocation();
-        int width = font.getStringWidth(getText());
+        int width = font.getWidth(getText());
         if (isCentered()) {
             if (isHasShadows())
-                font.method_27517(matrices, text, pos.x - width / 2f, pos.y, color);
+                font.drawWithShadow(matrices, text, pos.x - width / 2f, pos.y, color);
             else
-                font.method_27528(matrices, text, pos.x - width / 2f, pos.y, color);
+                font.draw(matrices, text, pos.x - width / 2f, pos.y, color);
         } else {
             if (isHasShadows())
-                font.method_27517(matrices, text, pos.x, pos.y, color);
+                font.drawWithShadow(matrices, text, pos.x, pos.y, color);
             else
-                font.method_27528(matrices, text, pos.x, pos.y, color);
+                font.draw(matrices, text, pos.x, pos.y, color);
         }
         drawTooltips(mouseX, mouseY);
     }

+ 5 - 5
src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java

@@ -26,6 +26,7 @@ package me.shedaniel.rei.gui.widget;
 import com.google.common.collect.Lists;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.api.ScissorsHandler;
+import me.shedaniel.clothconfig2.api.ScrollingContainer;
 import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWidget;
 import me.shedaniel.math.Point;
 import me.shedaniel.math.Rectangle;
@@ -44,7 +45,6 @@ import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.network.ClientPlayerEntity;
 import net.minecraft.client.render.Tessellator;
 import net.minecraft.client.render.VertexConsumerProvider;
-import net.minecraft.client.resource.language.I18n;
 import net.minecraft.client.util.math.MatrixStack;
 import net.minecraft.item.ItemGroup;
 import net.minecraft.text.LiteralText;
@@ -259,7 +259,7 @@ public class EntryListWidget extends WidgetWithBounds {
                 int z = getZ();
                 setZ(500);
                 Text debugText = new LiteralText(String.format("%d entries, avg. %.0fns, ttl. %.0fms, %s fps", size, time / (double) size, totalTime / 1000000d, minecraft.fpsDebugString.split(" ")[0]));
-                fillGradient(matrices, bounds.x, bounds.y, bounds.x + font.method_27525(debugText) + 2, bounds.y + font.fontHeight + 2, -16777216, -16777216);
+                fillGradient(matrices, bounds.x, bounds.y, bounds.x + font.getWidth(debugText) + 2, bounds.y + font.fontHeight + 2, -16777216, -16777216);
                 VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer());
                 matrices.push();
                 matrices.translate(0.0D, 0.0D, getZ());
@@ -317,7 +317,7 @@ public class EntryListWidget extends WidgetWithBounds {
             }
             updatePosition(delta);
             ScissorsHandler.INSTANCE.removeLastScissor();
-            scrolling.renderScrollBar();
+            scrolling.renderScrollBar(0, 1, REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
         } else {
             if (debugTime) {
                 int size = 0;
@@ -380,7 +380,7 @@ public class EntryListWidget extends WidgetWithBounds {
                 int z = getZ();
                 setZ(500);
                 Text debugText = new LiteralText(String.format("%d entries, avg. %.0fns, ttl. %.0fms, %s fps", size, time / (double) size, totalTime / 1000000d, minecraft.fpsDebugString.split(" ")[0]));
-                int stringWidth = font.method_27525(debugText);
+                int stringWidth = font.getWidth(debugText);
                 fillGradient(matrices, Math.min(bounds.x, minecraft.currentScreen.width - stringWidth - 2), bounds.y, bounds.x + stringWidth + 2, bounds.y + font.fontHeight + 2, -16777216, -16777216);
                 VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer());
                 matrices.push();
@@ -448,7 +448,7 @@ public class EntryListWidget extends WidgetWithBounds {
     
     @Override
     public boolean mouseDragged(double mouseX, double mouseY, int button, double dx, double dy) {
-        if (scrolling.mouseDragged(mouseX, mouseY, button, dx, dy, true))
+        if (scrolling.mouseDragged(mouseX, mouseY, button, dx, dy, ConfigObject.getInstance().doesSnapToRows(), entrySize()))
             return true;
         return super.mouseDragged(mouseX, mouseY, button, dx, dy);
     }

+ 3 - 2
src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java

@@ -26,6 +26,7 @@ package me.shedaniel.rei.gui.widget;
 import com.google.common.collect.Lists;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.api.ScissorsHandler;
+import me.shedaniel.clothconfig2.api.ScrollingContainer;
 import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWidget;
 import me.shedaniel.math.Point;
 import me.shedaniel.math.Rectangle;
@@ -130,7 +131,7 @@ public class FavoritesListWidget extends WidgetWithBounds {
             }
         }
         updatePosition(delta);
-        scrolling.renderScrollBar();
+        scrolling.renderScrollBar(0, 1, REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
         ScissorsHandler.INSTANCE.removeLastScissor();
         if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating() && !minecraft.player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets())
             Tooltip.create(new TranslatableText("text.rei.delete_items")).queue();
@@ -138,7 +139,7 @@ public class FavoritesListWidget extends WidgetWithBounds {
     
     @Override
     public boolean mouseDragged(double mouseX, double mouseY, int int_1, double double_3, double double_4) {
-        if (scrolling.mouseDragged(mouseX, mouseY, int_1, double_3, double_4, true))
+        if (scrolling.mouseDragged(mouseX, mouseY, int_1, double_3, double_4, ConfigObject.getInstance().doesSnapToRows(), entrySize()))
             return true;
         return super.mouseDragged(mouseX, mouseY, int_1, double_3, double_4);
     }

+ 6 - 6
src/main/java/me/shedaniel/rei/gui/widget/LabelWidget.java

@@ -157,7 +157,7 @@ public class LabelWidget extends WidgetWithBounds {
     @NotNull
     @Override
     public Rectangle getBounds() {
-        int width = font.method_27525(text);
+        int width = font.getWidth(text);
         Point pos = getLocation();
         if (isCentered())
             return new Rectangle(pos.x - width / 2 - 1, pos.y - 5, width + 2, 14);
@@ -171,18 +171,18 @@ public class LabelWidget extends WidgetWithBounds {
     
     @Override
     public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
-        int width = font.method_27525(text);
+        int width = font.getWidth(text);
         Point pos = getLocation();
         if (isCentered()) {
             if (hasShadows)
-                font.method_27517(matrices, text, pos.x - width / 2f, pos.y, defaultColor);
+                font.drawWithShadow(matrices, text, pos.x - width / 2f, pos.y, defaultColor);
             else
-                font.method_27528(matrices, text, pos.x - width / 2f, pos.y, defaultColor);
+                font.draw(matrices, text, pos.x - width / 2f, pos.y, defaultColor);
         } else {
             if (hasShadows)
-                font.method_27517(matrices, text, pos.x, pos.y, defaultColor);
+                font.drawWithShadow(matrices, text, pos.x, pos.y, defaultColor);
             else
-                font.method_27528(matrices, text, pos.x, pos.y, defaultColor);
+                font.draw(matrices, text, pos.x, pos.y, defaultColor);
         }
     }
     

+ 3 - 3
src/main/java/me/shedaniel/rei/gui/widget/RecipeChoosePageWidget.java

@@ -116,14 +116,14 @@ public class RecipeChoosePageWidget extends DraggableWidget {
             
             @Override
             public void render(MatrixStack matrices, int i, int i1, float v) {
-                font.method_27528(matrices, new TranslatableText("text.rei.choose_page"), bounds.x + 5, bounds.y + 5, REIHelper.getInstance().isDarkThemeEnabled() ? 0xFFBBBBBB : 0xFF404040);
+                font.draw(matrices, new TranslatableText("text.rei.choose_page"), bounds.x + 5, bounds.y + 5, REIHelper.getInstance().isDarkThemeEnabled() ? 0xFFBBBBBB : 0xFF404040);
                 String endString = String.format(" /%d", maxPage);
-                int width = font.getStringWidth(endString);
+                int width = font.getWidth(endString);
                 font.draw(matrices, endString, bounds.x + bounds.width - 5 - width, bounds.y + 22, REIHelper.getInstance().isDarkThemeEnabled() ? 0xFFBBBBBB : 0xFF404040);
             }
         });
         String endString = String.format(" /%d", maxPage);
-        int width = font.getStringWidth(endString);
+        int width = font.getWidth(endString);
         this.widgets.add(textFieldWidget = new TextFieldWidget(bounds.x + 7, bounds.y + 16, bounds.width - width - 12, 18));
         textFieldWidget.setMaxLength(10000);
         textFieldWidget.stripInvalid = s -> {

+ 0 - 203
src/main/java/me/shedaniel/rei/gui/widget/ScrollingContainer.java

@@ -1,203 +0,0 @@
-/*
- * This file is licensed under the MIT License, part of Roughly Enough Items.
- * Copyright (c) 2018, 2019, 2020 shedaniel
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package me.shedaniel.rei.gui.widget;
-
-import com.mojang.blaze3d.systems.RenderSystem;
-import me.shedaniel.clothconfig2.ClothConfigInitializer;
-import me.shedaniel.math.Rectangle;
-import me.shedaniel.math.impl.PointHelper;
-import me.shedaniel.rei.api.ConfigObject;
-import me.shedaniel.rei.api.REIHelper;
-import net.minecraft.client.render.BufferBuilder;
-import net.minecraft.client.render.Tessellator;
-import net.minecraft.client.render.VertexFormats;
-import net.minecraft.util.math.MathHelper;
-import org.jetbrains.annotations.ApiStatus;
-
-import static me.shedaniel.rei.gui.widget.EntryListWidget.entrySize;
-
-@ApiStatus.Internal
-public abstract class ScrollingContainer {
-    public double scrollAmount;
-    public double scrollTarget;
-    public long start;
-    public long duration;
-    public boolean draggingScrollBar = false;
-    
-    public abstract Rectangle getBounds();
-    
-    public Rectangle getScissorBounds() {
-        Rectangle bounds = getBounds();
-        if (hasScrollBar()) {
-            return new Rectangle(bounds.x, bounds.y, bounds.width - 6, bounds.height);
-        }
-        return bounds;
-    }
-    
-    public int getScrollBarX() {
-        return hasScrollBar() ? getBounds().getMaxX() - 6 : getBounds().getMaxX();
-    }
-    
-    public boolean hasScrollBar() {
-        return getMaxScrollHeight() > getBounds().height;
-    }
-    
-    public abstract int getMaxScrollHeight();
-    
-    public final int getMaxScroll() {
-        return Math.max(0, getMaxScrollHeight() - getBounds().height);
-    }
-    
-    public final double clamp(double v) {
-        return this.clamp(v, 200.0D);
-    }
-    
-    public final double clamp(double v, double clampExtension) {
-        return MathHelper.clamp(v, -clampExtension, (double) this.getMaxScroll() + clampExtension);
-    }
-    
-    public final void offset(double value, boolean animated) {
-        scrollTo(scrollTarget + value, animated);
-    }
-    
-    public final void scrollTo(double value, boolean animated) {
-        scrollTo(value, animated, ClothConfigInitializer.getScrollDuration());
-    }
-    
-    public final void scrollTo(double value, boolean animated, long duration) {
-        scrollTarget = clamp(value);
-        
-        if (animated) {
-            start = System.currentTimeMillis();
-            this.duration = duration;
-        } else
-            scrollAmount = scrollTarget;
-    }
-    
-    public void updatePosition(float delta) {
-        double[] target = new double[]{this.scrollTarget};
-        this.scrollAmount = ClothConfigInitializer.handleScrollingPosition(target, this.scrollAmount, this.getMaxScroll(), delta, this.start, this.duration);
-        this.scrollTarget = target[0];
-    }
-    
-    public void renderScrollBar() {
-        renderScrollBar(0, 1);
-    }
-    
-    public void renderScrollBar(int background, float alpha) {
-        if (hasScrollBar()) {
-            Rectangle bounds = getBounds();
-            int maxScroll = getMaxScroll();
-            int height = bounds.height * bounds.height / getMaxScrollHeight();
-            height = MathHelper.clamp(height, 32, bounds.height);
-            height -= Math.min((scrollAmount < 0 ? (int) -scrollAmount : scrollAmount > maxScroll ? (int) scrollAmount - maxScroll : 0), height * .95);
-            height = Math.max(10, height);
-            int minY = Math.min(Math.max((int) scrollAmount * (bounds.height - height) / maxScroll + bounds.y, bounds.y), bounds.getMaxY() - height);
-            
-            int scrollbarPositionMinX = getScrollBarX();
-            int scrollbarPositionMaxX = scrollbarPositionMinX + 6;
-            boolean hovered = (new Rectangle(scrollbarPositionMinX, minY, scrollbarPositionMaxX - scrollbarPositionMinX, height)).contains(PointHelper.ofMouse());
-            float bottomC = (hovered ? .67f : .5f) * (REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
-            float topC = (hovered ? .87f : .67f) * (REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
-            
-            RenderSystem.disableTexture();
-            RenderSystem.enableBlend();
-            RenderSystem.disableAlphaTest();
-            RenderSystem.blendFuncSeparate(770, 771, 1, 0);
-            RenderSystem.shadeModel(7425);
-            Tessellator tessellator = Tessellator.getInstance();
-            BufferBuilder buffer = tessellator.getBuffer();
-            {
-                float a = (background >> 24 & 255) / 255.0F;
-                float r = (background >> 16 & 255) / 255.0F;
-                float g = (background >> 8 & 255) / 255.0F;
-                float b = (background & 255) / 255.0F;
-                buffer.begin(7, VertexFormats.POSITION_COLOR);
-                buffer.vertex(scrollbarPositionMinX, bounds.getMaxY(), 0.0D).color(r, g, b, a).next();
-                buffer.vertex(scrollbarPositionMaxX, bounds.getMaxY(), 0.0D).color(r, g, b, a).next();
-                buffer.vertex(scrollbarPositionMaxX, bounds.y, 0.0D).color(r, g, b, a).next();
-                buffer.vertex(scrollbarPositionMinX, bounds.y, 0.0D).color(r, g, b, a).next();
-            }
-            tessellator.draw();
-            buffer.begin(7, VertexFormats.POSITION_COLOR);
-            buffer.vertex(scrollbarPositionMinX, minY + height, 0.0D).color(bottomC, bottomC, bottomC, alpha).next();
-            buffer.vertex(scrollbarPositionMaxX, minY + height, 0.0D).color(bottomC, bottomC, bottomC, alpha).next();
-            buffer.vertex(scrollbarPositionMaxX, minY, 0.0D).color(bottomC, bottomC, bottomC, alpha).next();
-            buffer.vertex(scrollbarPositionMinX, minY, 0.0D).color(bottomC, bottomC, bottomC, alpha).next();
-            tessellator.draw();
-            buffer.begin(7, VertexFormats.POSITION_COLOR);
-            buffer.vertex(scrollbarPositionMinX, (minY + height - 1), 0.0D).color(topC, topC, topC, alpha).next();
-            buffer.vertex((scrollbarPositionMaxX - 1), (minY + height - 1), 0.0D).color(topC, topC, topC, alpha).next();
-            buffer.vertex((scrollbarPositionMaxX - 1), minY, 0.0D).color(topC, topC, topC, alpha).next();
-            buffer.vertex(scrollbarPositionMinX, minY, 0.0D).color(topC, topC, topC, alpha).next();
-            tessellator.draw();
-            RenderSystem.shadeModel(7424);
-            RenderSystem.disableBlend();
-            RenderSystem.enableAlphaTest();
-            RenderSystem.enableTexture();
-        }
-    }
-    
-    public boolean mouseDragged(double mouseX, double mouseY, int button, double dx, double dy) {
-        return mouseDragged(mouseX, mouseY, button, dx, dy, false);
-    }
-    
-    public boolean mouseDragged(double mouseX, double mouseY, int button, double dx, double dy, boolean careSnapping) {
-        if (button == 0 && draggingScrollBar) {
-            float height = getMaxScrollHeight();
-            Rectangle bounds = getBounds();
-            int actualHeight = bounds.height;
-            if (mouseY >= bounds.y && mouseY <= bounds.getMaxY()) {
-                double maxScroll = Math.max(1, getMaxScroll());
-                double int_3 = MathHelper.clamp(((double) (actualHeight * actualHeight) / (double) height), 32, actualHeight - 8);
-                double double_6 = Math.max(1.0D, maxScroll / (actualHeight - int_3));
-                float to = MathHelper.clamp((float) (scrollAmount + dy * double_6), 0, getMaxScroll());
-                if (careSnapping && ConfigObject.getInstance().doesSnapToRows()) {
-                    double nearestRow = Math.round(to / (double) entrySize()) * (double) entrySize();
-                    scrollTo(nearestRow, false);
-                } else
-                    scrollTo(to, false);
-            }
-            return true;
-        }
-        return false;
-    }
-    
-    public boolean updateDraggingState(double mouseX, double mouseY, int button) {
-        if (!hasScrollBar())
-            return false;
-        double height = getMaxScroll();
-        Rectangle bounds = getBounds();
-        int actualHeight = bounds.height;
-        if (height > actualHeight && mouseY >= bounds.y && mouseY <= bounds.getMaxY()) {
-            double scrollbarPositionMinX = getScrollBarX();
-            if (mouseX >= scrollbarPositionMinX - 1 & mouseX <= scrollbarPositionMinX + 8) {
-                this.draggingScrollBar = true;
-                return true;
-            }
-        }
-        this.draggingScrollBar = false;
-        return false;
-    }
-}

+ 1 - 1
src/main/java/me/shedaniel/rei/gui/widget/TabWidget.java

@@ -120,7 +120,7 @@ public class TabWidget extends WidgetWithBounds {
     
     private void drawTooltip() {
         if (this.minecraft.options.advancedItemTooltips)
-            Tooltip.create(new LiteralText(categoryName), new LiteralText(category.getIdentifier().toString()).method_27692(Formatting.DARK_GRAY), ClientHelper.getInstance().getFormattedModFromIdentifier(category.getIdentifier())).queue();
+            Tooltip.create(new LiteralText(categoryName), new LiteralText(category.getIdentifier().toString()).formatted(Formatting.DARK_GRAY), ClientHelper.getInstance().getFormattedModFromIdentifier(category.getIdentifier())).queue();
         else
             Tooltip.create(new LiteralText(categoryName), ClientHelper.getInstance().getFormattedModFromIdentifier(category.getIdentifier())).queue();
     }

+ 8 - 8
src/main/java/me/shedaniel/rei/gui/widget/TextFieldWidget.java

@@ -403,8 +403,8 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
                     int_2 -= 4;
                 }
                 
-                String string_1 = this.font.method_27523(this.text.substring(this.field_2103), this.getWidth());
-                this.moveCursorTo(this.font.method_27523(string_1, int_2).length() + this.field_2103, true);
+                String string_1 = this.font.trimToWidth(this.text.substring(this.field_2103), this.getWidth());
+                this.moveCursorTo(this.font.trimToWidth(string_1, int_2).length() + this.field_2103, true);
                 return true;
             } else {
                 return false;
@@ -430,7 +430,7 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
             int color = this.editable ? this.editableColor : this.notEditableColor;
             int int_4 = this.cursorMax - this.field_2103;
             int int_5 = this.cursorMin - this.field_2103;
-            String string_1 = this.font.method_27523(this.text.substring(this.field_2103), this.getWidth());
+            String string_1 = this.font.trimToWidth(this.text.substring(this.field_2103), this.getWidth());
             boolean boolean_1 = int_4 >= 0 && int_4 <= string_1.length();
             boolean boolean_2 = this.focused && this.focusedTicks / 6 % 2 == 0 && boolean_1;
             int x = this.hasBorder ? this.bounds.x + 4 : this.bounds.x;
@@ -469,14 +469,14 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
             
             // Render selection overlay
             if (int_5 != int_4) {
-                int int_10 = x + this.font.getStringWidth(string_1.substring(0, int_5));
+                int int_10 = x + this.font.getWidth(string_1.substring(0, int_5));
                 this.renderSelection(matrices, int_9, y - 1, int_10 - 1, y + 9, color);
             }
         }
     }
     
     protected void renderSuggestion(MatrixStack matrices, int x, int y) {
-        this.font.drawWithShadow(matrices, this.font.method_27523(this.suggestion, this.getWidth()), x, y, -8355712);
+        this.font.drawWithShadow(matrices, this.font.trimToWidth(this.suggestion, this.getWidth()), x, y, -8355712);
     }
     
     protected void renderSelection(MatrixStack matrices, int x1, int y1, int x2, int y2, int color) {
@@ -596,10 +596,10 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
             }
             
             int int_3 = this.getWidth();
-            String string_1 = this.font.method_27523(this.text.substring(this.field_2103), int_3);
+            String string_1 = this.font.trimToWidth(this.text.substring(this.field_2103), int_3);
             int int_4 = string_1.length() + this.field_2103;
             if (this.cursorMin == this.field_2103) {
-                this.field_2103 -= this.font.method_27524(this.text, int_3, true).length();
+                this.field_2103 -= this.font.trimToWidth(this.text, int_3, true).length();
             }
             
             if (this.cursorMin > int_4) {
@@ -626,7 +626,7 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
     }
     
     public int method_1889(int int_1) {
-        return int_1 > this.text.length() ? this.bounds.x : this.bounds.x + this.font.getStringWidth(this.text.substring(0, int_1));
+        return int_1 > this.text.length() ? this.bounds.x : this.bounds.x + this.font.getWidth(this.text.substring(0, int_1));
     }
     
 }

+ 2 - 2
src/main/java/me/shedaniel/rei/impl/ClientHelperImpl.java

@@ -106,7 +106,7 @@ public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
         String mod = getModFromItem(item);
         if (mod.isEmpty())
             return NarratorManager.EMPTY;
-        return new LiteralText(mod).method_27695(Formatting.BLUE, Formatting.ITALIC);
+        return new LiteralText(mod).formatted(Formatting.BLUE, Formatting.ITALIC);
     }
     
     @Override
@@ -114,7 +114,7 @@ public class ClientHelperImpl implements ClientHelper, ClientModInitializer {
         String mod = getModFromIdentifier(identifier);
         if (mod.isEmpty())
             return NarratorManager.EMPTY;
-        return new LiteralText(mod).method_27695(Formatting.BLUE, Formatting.ITALIC);
+        return new LiteralText(mod).formatted(Formatting.BLUE, Formatting.ITALIC);
     }
     
     @Override

+ 1 - 1
src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java

@@ -374,7 +374,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
         private ModifierKeyCode focusSearchFieldKeybind = ModifierKeyCode.unknown();
         private ModifierKeyCode copyRecipeIdentifierKeybind = ModifierKeyCode.unknown();
         private ModifierKeyCode favoriteKeybind = ModifierKeyCode.of(InputUtil.Type.KEYSYM.createFromCode(65), Modifier.none());
-        @ConfigEntry.Gui.Excluded private ModifierKeyCode exportImageKeybind = ModifierKeyCode.unknown();
+        private ModifierKeyCode exportImageKeybind = ModifierKeyCode.unknown();
     }
     
     public static class Appearance {

+ 7 - 15
src/main/java/me/shedaniel/rei/impl/ItemEntryStack.java

@@ -30,6 +30,7 @@ import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.api.*;
 import me.shedaniel.rei.api.widgets.Tooltip;
 import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.render.DiffuseLighting;
 import net.minecraft.client.render.OverlayTexture;
 import net.minecraft.client.render.VertexConsumerProvider;
 import net.minecraft.client.render.model.BakedModel;
@@ -49,13 +50,9 @@ import org.jetbrains.annotations.Nullable;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
-import java.util.function.Predicate;
 
 @ApiStatus.Internal
 public class ItemEntryStack extends AbstractEntryStack implements OptimalEntryStack {
-    
-    private static final Predicate<BakedModel> IS_SIDE_LIT = BakedModel::isSideLit;
-    
     private ItemStack itemStack;
     
     public ItemEntryStack(ItemStack itemStack) {
@@ -301,12 +298,7 @@ public class ItemEntryStack extends AbstractEntryStack implements OptimalEntrySt
     }
     
     private BakedModel getModelFromStack(ItemStack stack) {
-        BakedModel model = MinecraftClient.getInstance().getItemRenderer().getModels().getModel(stack);
-        if (stack.getItem().hasPropertyGetters())
-            model = model.getItemPropertyOverrides().apply(model, stack, null, null);
-        if (model != null)
-            return model;
-        return MinecraftClient.getInstance().getItemRenderer().getModels().getModelManager().getMissingModel();
+        return MinecraftClient.getInstance().getItemRenderer().getHeldItemModel(stack, null, null);
     }
     
     @Override
@@ -319,13 +311,13 @@ public class ItemEntryStack extends AbstractEntryStack implements OptimalEntrySt
             matrices.scale(bounds.getWidth(), (bounds.getWidth() + bounds.getHeight()) / -2f, bounds.getHeight());
             VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
             BakedModel model = getModelFromStack(stack);
-            boolean bl = !IS_SIDE_LIT.test(model);
-            if (bl)
-                GlStateManager.setupGuiFlatDiffuseLighting();
+            boolean sideLit = !model.isSideLit();
+            if (sideLit)
+                DiffuseLighting.disableGuiDepthLighting();
             MinecraftClient.getInstance().getItemRenderer().renderItem(stack, ModelTransformation.Mode.GUI, false, matrices, immediate, 15728880, OverlayTexture.DEFAULT_UV, model);
             immediate.draw();
-            if (bl)
-                GlStateManager.setupGui3dDiffuseLighting();
+            if (sideLit)
+                DiffuseLighting.enableGuiDepthLighting();
             matrices.pop();
             ((ItemStackHook) (Object) stack).rei_setRenderEnchantmentGlint(false);
         }

+ 2 - 2
src/main/java/me/shedaniel/rei/impl/RenderingEntry.java

@@ -54,12 +54,12 @@ public abstract class RenderingEntry extends DrawableHelper implements EntryStac
     
     @Override
     public void setAmount(int amount) {
-    
+        
     }
     
     @Override
     public void setFloatingAmount(double amount) {
-    
+        
     }
     
     @Override

+ 8 - 8
src/main/java/me/shedaniel/rei/impl/widgets/LabelWidget.java

@@ -183,7 +183,7 @@ public final class LabelWidget extends Label {
     @NotNull
     @Override
     public final Rectangle getBounds() {
-        int width = font.method_27525(text);
+        int width = font.getWidth(text);
         Point point = getPoint();
         if (getHorizontalAlignment() == LEFT_ALIGNED)
             return new Rectangle(point.x - 1, point.y - 5, width + 2, 14);
@@ -200,26 +200,26 @@ public final class LabelWidget extends Label {
         if (isClickable() && isHovered(mouseX, mouseY))
             color = getHoveredColor();
         Point pos = getPoint();
-        int width = font.method_27525(getText());
+        int width = font.getWidth(getText());
         switch (getHorizontalAlignment()) {
             case LEFT_ALIGNED:
                 if (hasShadow())
-                    font.method_27517(matrices, getText(), pos.x, pos.y, color);
+                    font.drawWithShadow(matrices, getText(), pos.x, pos.y, color);
                 else
-                    font.method_27528(matrices, getText(), pos.x, pos.y, color);
+                    font.draw(matrices, getText(), pos.x, pos.y, color);
                 break;
             case RIGHT_ALIGNED:
                 if (hasShadow())
-                    font.method_27517(matrices, getText(), pos.x - width, pos.y, color);
+                    font.drawWithShadow(matrices, getText(), pos.x - width, pos.y, color);
                 else
-                    font.method_27528(matrices, getText(), pos.x - width, pos.y, color);
+                    font.draw(matrices, getText(), pos.x - width, pos.y, color);
                 break;
             case CENTER:
             default:
                 if (hasShadow())
-                    font.method_27517(matrices, getText(), pos.x - width / 2f, pos.y, color);
+                    font.drawWithShadow(matrices, getText(), pos.x - width / 2f, pos.y, color);
                 else
-                    font.method_27528(matrices, getText(), pos.x - width / 2f, pos.y, color);
+                    font.draw(matrices, getText(), pos.x - width / 2f, pos.y, color);
                 break;
         }
         if (isHovered(mouseX, mouseY)) {

+ 3 - 2
src/main/java/me/shedaniel/rei/plugin/beacon/DefaultBeaconBaseCategory.java

@@ -29,11 +29,12 @@ import me.shedaniel.clothconfig2.api.ScissorsHandler;
 import me.shedaniel.math.Point;
 import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.api.EntryStack;
+import me.shedaniel.rei.api.REIHelper;
 import me.shedaniel.rei.api.RecipeCategory;
 import me.shedaniel.rei.api.widgets.Slot;
 import me.shedaniel.rei.api.widgets.Widgets;
 import me.shedaniel.rei.gui.entries.RecipeEntry;
-import me.shedaniel.rei.gui.widget.ScrollingContainer;
+import me.shedaniel.clothconfig2.api.ScrollingContainer;
 import me.shedaniel.rei.gui.widget.Widget;
 import me.shedaniel.rei.gui.widget.WidgetWithBounds;
 import me.shedaniel.rei.plugin.DefaultPlugin;
@@ -169,7 +170,7 @@ public class DefaultBeaconBaseCategory implements RecipeCategory<DefaultBeaconBa
             }
             ScissorsHandler.INSTANCE.removeLastScissor();
             ScissorsHandler.INSTANCE.scissor(scrolling.getBounds());
-            scrolling.renderScrollBar(0xff000000, 1);
+            scrolling.renderScrollBar(0xff000000, 1, REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
             ScissorsHandler.INSTANCE.removeLastScissor();
         }
         

+ 3 - 3
src/main/java/me/shedaniel/rei/plugin/brewing/DefaultBrewingDisplay.java

@@ -43,14 +43,14 @@ public class DefaultBrewingDisplay implements RecipeDisplay {
     private List<EntryStack> reactant;
     
     public DefaultBrewingDisplay(ItemStack input, Ingredient reactant, ItemStack output) {
-        this.input = EntryStack.create(input).setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, stack -> Collections.singletonList(new TranslatableText("category.rei.brewing.input").method_27692(Formatting.YELLOW)));
+        this.input = EntryStack.create(input).setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, stack -> Collections.singletonList(new TranslatableText("category.rei.brewing.input").formatted(Formatting.YELLOW)));
         this.reactant = new ArrayList<>();
         for (ItemStack stack : reactant.getMatchingStacksClient()) {
             EntryStack entryStack = EntryStack.create(stack);
-            entryStack.setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, s -> Collections.singletonList(new TranslatableText("category.rei.brewing.reactant").method_27692(Formatting.YELLOW)));
+            entryStack.setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, s -> Collections.singletonList(new TranslatableText("category.rei.brewing.reactant").formatted(Formatting.YELLOW)));
             this.reactant.add(entryStack);
         }
-        this.output = EntryStack.create(output).setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, stack -> Collections.singletonList(new TranslatableText("category.rei.brewing.result").method_27692(Formatting.YELLOW)));
+        this.output = EntryStack.create(output).setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, stack -> Collections.singletonList(new TranslatableText("category.rei.brewing.result").formatted(Formatting.YELLOW)));
     }
     
     @Override

+ 1 - 1
src/main/java/me/shedaniel/rei/plugin/composting/DefaultCompostingCategory.java

@@ -74,7 +74,7 @@ public class DefaultCompostingCategory implements RecipeCategory<DefaultComposti
             
             @Override
             public void render(MatrixStack matrices, Rectangle rectangle, int mouseX, int mouseY, float delta) {
-                MinecraftClient.getInstance().textRenderer.method_27528(matrices, new TranslatableText("text.rei.composting.page", recipe.getPage() + 1), rectangle.x + 5, rectangle.y + 6, -1);
+                MinecraftClient.getInstance().textRenderer.draw(matrices, new TranslatableText("text.rei.composting.page", recipe.getPage() + 1), rectangle.x + 5, rectangle.y + 6, -1);
             }
         };
     }

+ 1 - 1
src/main/java/me/shedaniel/rei/plugin/cooking/DefaultCookingDisplay.java

@@ -45,7 +45,7 @@ public abstract class DefaultCookingDisplay implements TransferRecipeDisplay {
     private static List<EntryStack> fuel;
     
     static {
-        fuel = FurnaceBlockEntity.createFuelTimeMap().keySet().stream().map(Item::getStackForRender).map(EntryStack::create).map(e -> e.setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, stack -> Collections.singletonList(new TranslatableText("category.rei.smelting.fuel").method_27692(Formatting.YELLOW)))).collect(Collectors.toList());
+        fuel = FurnaceBlockEntity.createFuelTimeMap().keySet().stream().map(Item::getStackForRender).map(EntryStack::create).map(e -> e.setting(EntryStack.Settings.TOOLTIP_APPEND_EXTRA, stack -> Collections.singletonList(new TranslatableText("category.rei.smelting.fuel").formatted(Formatting.YELLOW)))).collect(Collectors.toList());
     }
     
     private AbstractCookingRecipe recipe;

+ 1 - 1
src/main/java/me/shedaniel/rei/plugin/fuel/DefaultFuelCategory.java

@@ -105,7 +105,7 @@ public class DefaultFuelCategory implements RecipeCategory<DefaultFuelDisplay> {
                 slot.setZ(getZ() + 50);
                 slot.getBounds().setLocation(bounds.x + 4, bounds.y + 2);
                 slot.render(matrices, mouseX, mouseY, delta);
-                MinecraftClient.getInstance().textRenderer.method_27517(matrices, new TranslatableText("category.rei.fuel.time_short.items", burnItems), bounds.x + 25, bounds.y + 8, -1);
+                MinecraftClient.getInstance().textRenderer.drawWithShadow(matrices, new TranslatableText("category.rei.fuel.time_short.items", burnItems), bounds.x + 25, bounds.y + 8, -1);
             }
         };
     }

+ 5 - 6
src/main/java/me/shedaniel/rei/plugin/information/DefaultInformationCategory.java

@@ -34,7 +34,7 @@ import me.shedaniel.rei.api.REIHelper;
 import me.shedaniel.rei.api.RecipeCategory;
 import me.shedaniel.rei.api.widgets.Widgets;
 import me.shedaniel.rei.gui.entries.RecipeEntry;
-import me.shedaniel.rei.gui.widget.ScrollingContainer;
+import me.shedaniel.clothconfig2.api.ScrollingContainer;
 import me.shedaniel.rei.gui.widget.Widget;
 import me.shedaniel.rei.gui.widget.WidgetWithBounds;
 import me.shedaniel.rei.impl.RenderingEntry;
@@ -46,7 +46,6 @@ import net.minecraft.client.render.BufferRenderer;
 import net.minecraft.client.render.Tessellator;
 import net.minecraft.client.render.VertexFormats;
 import net.minecraft.client.resource.language.I18n;
-import net.minecraft.client.util.Texts;
 import net.minecraft.client.util.math.MatrixStack;
 import net.minecraft.text.Text;
 import net.minecraft.util.Identifier;
@@ -91,7 +90,7 @@ public class DefaultInformationCategory implements RecipeCategory<DefaultInforma
             
             @Override
             public void render(MatrixStack matrices, Rectangle rectangle, int mouseX, int mouseY, float delta) {
-                MinecraftClient.getInstance().textRenderer.method_27528(matrices, name, rectangle.x + 5, rectangle.y + 6, -1);
+                MinecraftClient.getInstance().textRenderer.draw(matrices, name, rectangle.x + 5, rectangle.y + 6, -1);
             }
         };
     }
@@ -158,7 +157,7 @@ public class DefaultInformationCategory implements RecipeCategory<DefaultInforma
             for (Text text : texts) {
                 if (!this.texts.isEmpty())
                     this.texts.add(null);
-                this.texts.addAll(Texts.wrapLines(text, bounds.width - 11, MinecraftClient.getInstance().textRenderer));
+                this.texts.addAll(MinecraftClient.getInstance().textRenderer.wrapLines(text, bounds.width - 11));
             }
         }
         
@@ -199,13 +198,13 @@ public class DefaultInformationCategory implements RecipeCategory<DefaultInforma
             int currentY = (int) -scrolling.scrollAmount + innerBounds.y;
             for (Text text : texts) {
                 if (text != null && currentY + font.fontHeight >= innerBounds.y && currentY <= innerBounds.getMaxY()) {
-                    font.method_27528(matrices, text, innerBounds.x + 2, currentY + 2, REIHelper.getInstance().isDarkThemeEnabled() ? 0xFFBBBBBB : 0xFF090909);
+                    font.draw(matrices, text, innerBounds.x + 2, currentY + 2, REIHelper.getInstance().isDarkThemeEnabled() ? 0xFFBBBBBB : 0xFF090909);
                 }
                 currentY += text == null ? 4 : font.fontHeight;
             }
             ScissorsHandler.INSTANCE.removeLastScissor();
             ScissorsHandler.INSTANCE.scissor(scrolling.getBounds());
-            scrolling.renderScrollBar(0xff000000, 1);
+            scrolling.renderScrollBar(0xff000000, 1, REIHelper.getInstance().isDarkThemeEnabled() ? 0.8f : 1f);
             ScissorsHandler.INSTANCE.removeLastScissor();
         }
         

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7Press %s to add this to favorites.",
   "text.rei.remove_favorites_tooltip": " \n§7Press %s to remove this from favorites.",
   "text.rei.working_station": "Работна станция",
-  "text.rei.release_export": "§lRelease %s to export",
+  "text.rei.release_export": "Release %s to export",
   "text.rei.recipe_id": "\n%sИд.№ на рецепта: %s",
   "text.rei.recipe_screen_type.selection": "Recipe Screen Type Selection",
   "text.rei.recipe_screen_type.selection.sub": "You can always edit this setting again via the config screen.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7Drücke %s, um dieses zu Favoriten hinzuzufügen.",
   "text.rei.remove_favorites_tooltip": " \n§7Drücke %s, um dieses aus den Favoriten zu entfernen.",
   "text.rei.working_station": "Arbeitsstation",
-  "text.rei.release_export": "§lLasse %s los, um zu exportieren",
+  "text.rei.release_export": "Lasse %s los, um zu exportieren",
   "text.rei.recipe_id": "\n%sRezept-Id: %s",
   "text.rei.recipe_screen_type.selection": "Darstellung Rezept-Bildschirm",
   "text.rei.recipe_screen_type.selection.sub": "Du kannst diese Einstellung jederzeit über den Konfigurationsbildschirm wieder bearbeiten.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7Press %s to add this to favorites.",
   "text.rei.remove_favorites_tooltip": " \n§7Press %s to remove this from favorites.",
   "text.rei.working_station": "uoıʇɐʇS buıʞɹoM",
-  "text.rei.release_export": "§lRelease %s to export",
+  "text.rei.release_export": "Release %s to export",
   "text.rei.recipe_id": "\n%2$s :pI ǝdıɔǝᴚ%1$s",
   "text.rei.recipe_screen_type.selection": "uoıʇɔǝןǝS ǝdʎ⊥ uǝǝɹɔS ǝdıɔǝᴚ",
   "text.rei.recipe_screen_type.selection.sub": "˙uǝǝɹɔs bıɟuoɔ ǝɥʇ ɐıʌ uıɐbɐ buıʇʇǝs sıɥʇ ʇıpǝ sʎɐʍןɐ uɐɔ noʎ",

+ 5 - 2
src/main/resources/assets/roughlyenoughitems/lang/en_us.json

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7Press %s to add this to favorites.",
   "text.rei.remove_favorites_tooltip": " \n§7Press %s to remove this from favorites.",
   "text.rei.working_station": "Working Station",
-  "text.rei.release_export": "§lRelease %s to export",
+  "text.rei.release_export": "Release %s to export",
   "text.rei.recipe_id": "\n%sRecipe Id: %s",
   "text.rei.recipe_screen_type.selection": "Recipe Screen Type Selection",
   "text.rei.recipe_screen_type.selection.sub": "You can always edit this setting again via the config screen.",
@@ -95,6 +95,8 @@
   "tooltip.rei.fluid_amount": "§7%d Unit",
   "msg.rei.copied_recipe_id": "Copied Recipe Identifier",
   "msg.rei.recipe_id_details": "Recipe ID: %s",
+  "msg.rei.exported_recipe": "Exported Recipe",
+  "msg.rei.exported_recipe.desc": "Check the 'rei_exports' folder.",
   "subsets.rei.roughlyenoughitems.all_entries": "All Entries",
   "subsets.rei.roughlyenoughitems.item_groups": "Creative Tabs",
   "_comment": "Config Tooltips",
@@ -115,6 +117,7 @@
   "config.roughlyenoughitems.previousPageKeybind": "Previous Page:",
   "config.roughlyenoughitems.focusSearchFieldKeybind": "Focus Search Field:",
   "config.roughlyenoughitems.copyRecipeIdentifierKeybind": "Copy Recipe Identifier:",
+  "config.roughlyenoughitems.exportImageKeybind": "Export Recipe:",
   "config.roughlyenoughitems.favoriteKeybind": "Favorite Entry:",
   "config.roughlyenoughitems.favoritesEnabled": "Favorites Enabled:",
   "config.roughlyenoughitems.clickableRecipeArrows": "Clickable Recipe Arrows:",
@@ -141,7 +144,7 @@
   "config.roughlyenoughitems.recipeBorder.lighter": "Lighter",
   "config.roughlyenoughitems.recipeBorder.default": "Default",
   "config.roughlyenoughitems.recipeBorder.none": "None",
-  "config.roughlyenoughitems.maxRecipePerPage": "Maximum Recipes Per Page:",
+  "config.roughlyenoughitems.maxRecipesPerPage": "Maximum Recipes Per Page:",
   "config.roughlyenoughitems.mirrorItemPanel": "Item List Position:",
   "config.roughlyenoughitems.mirrorItemPanel.boolean.true": "Left Side",
   "config.roughlyenoughitems.mirrorItemPanel.boolean.false": "Right Side",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7Vajuta %s, et lisada see lemmikutesse.",
   "text.rei.remove_favorites_tooltip": " \n§7Vajuta %s, et eemaldada see lemmikutest.",
   "text.rei.working_station": "Tööjaam",
-  "text.rei.release_export": "§lVabasta eksportimiseks %s",
+  "text.rei.release_export": "Vabasta eksportimiseks %s",
   "text.rei.recipe_id": "\n%sRetsepti ID: %s",
   "text.rei.recipe_screen_type.selection": "Retseptide kuvatüübi valik",
   "text.rei.recipe_screen_type.selection.sub": "Sa saad seda seadistust alati seadistuskuvalt muuta.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7Appuyez sur %s pour l'ajouter aux favoris.",
   "text.rei.remove_favorites_tooltip": " \n§7Appuyez sur %s pour le retirer des favoris.",
   "text.rei.working_station": "Poste de travail",
-  "text.rei.release_export": "§lRelâchez %s pour exporter",
+  "text.rei.release_export": "Relâchez %s pour exporter",
   "text.rei.recipe_id": "\n%sID de recette : %s",
   "text.rei.recipe_screen_type.selection": "Sélection du type d'affichage des recettes",
   "text.rei.recipe_screen_type.selection.sub": "Vous pouvez toujours changer cette option dans l'écran de configuration.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7Press %s to add this to favorites.",
   "text.rei.remove_favorites_tooltip": " \n§7Press %s to remove this from favorites.",
   "text.rei.working_station": "作業台",
-  "text.rei.release_export": "§lRelease %s to export",
+  "text.rei.release_export": "Release %s to export",
   "text.rei.recipe_id": "\n%sレシピID: %s",
   "text.rei.recipe_screen_type.selection": "レシピ画面タイプの選択",
   "text.rei.recipe_screen_type.selection.sub": "設定画面でいつでも設定を変更できます。",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7Press %s to add this to favorites.",
   "text.rei.remove_favorites_tooltip": " \n§7Press %s to remove this from favorites.",
   "text.rei.working_station": "Wowking Station",
-  "text.rei.release_export": "§lRelease %s to export",
+  "text.rei.release_export": "Release %s to export",
   "text.rei.recipe_id": "\n%sWecipe Id: %s",
   "text.rei.recipe_screen_type.selection": "Wecipe Scween Type Sewection",
   "text.rei.recipe_screen_type.selection.sub": "You can awways edit dis setting again via de config scween.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7Press %s to add this to favorites.",
   "text.rei.remove_favorites_tooltip": " \n§7Press %s to remove this from favorites.",
   "text.rei.working_station": "Working Station",
-  "text.rei.release_export": "§lRelease %s to export",
+  "text.rei.release_export": "Release %s to export",
   "text.rei.recipe_id": "\n%sRecipe Id: %s",
   "text.rei.recipe_screen_type.selection": "Recipe Screen Type Selection",
   "text.rei.recipe_screen_type.selection.sub": "You can always edit this setting again via the config screen.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7Naciśnij %s aby dodać przedmiot do Ulubionych.",
   "text.rei.remove_favorites_tooltip": " \n§7Naciśnij %s aby usunąć przedmiot z Ulubionych.",
   "text.rei.working_station": "Stacja robocza",
-  "text.rei.release_export": "§lZwolnij %s aby wyeksportować",
+  "text.rei.release_export": "Zwolnij %s aby wyeksportować",
   "text.rei.recipe_id": "\n%sId receptury: %s",
   "text.rei.recipe_screen_type.selection": "Wybór typu ekranu receptur",
   "text.rei.recipe_screen_type.selection.sub": "Zawsze możesz zmienić tę opcję w Panelu Konfiguracyjnym.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " §7Pressione %s para colocar nos favoritos.",
   "text.rei.remove_favorites_tooltip": " §7Pressione %s para apagar dos favoritos.",
   "text.rei.working_station": "Estação de trabalho",
-  "text.rei.release_export": "§lRelease %s para exportar",
+  "text.rei.release_export": "Release %s para exportar",
   "text.rei.recipe_id": "\n%sID de receita: %s",
   "text.rei.recipe_screen_type.selection": "Seleção do tipo do menu de receitas",
   "text.rei.recipe_screen_type.selection.sub": "Você sempre pode editar essa opção denovo através do menu de configuração.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": "§7Pressione %s para adicionar aos favoritos.",
   "text.rei.remove_favorites_tooltip": " \n§7Pressione %s para remover dos favoritos.",
   "text.rei.working_station": "Estação de trabalho",
-  "text.rei.release_export": "§lLarge %s para exportar",
+  "text.rei.release_export": "Large %s para exportar",
   "text.rei.recipe_id": "\n%sID de receita: %s",
   "text.rei.recipe_screen_type.selection": "Seleção do tipo do menu de receitas",
   "text.rei.recipe_screen_type.selection.sub": "Você sempre pode editar essa opção denovo através do menu de configuração.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " §7Нажмите %s чтобы добавить в избранное.",
   "text.rei.remove_favorites_tooltip": " §7Нажмите %s чтобы убрать это из избранного.",
   "text.rei.working_station": "Рабочее место",
-  "text.rei.release_export": "§lОтпустите %s для экспорта",
+  "text.rei.release_export": "Отпустите %s для экспорта",
   "text.rei.recipe_id": "\n%sID рецепта: %s",
   "text.rei.recipe_screen_type.selection": "Выбор типа экрана рецепта",
   "text.rei.recipe_screen_type.selection.sub": "Вы всегда можете изменить эту настройку через окно конфигурации.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7按 %s 将其添加到收藏夹。",
   "text.rei.remove_favorites_tooltip": " \n§7按 %s 可以将其从收藏夹中移除。",
   "text.rei.working_station": "工作站",
-  "text.rei.release_export": "§l放开 %s 以汇出此食谱",
+  "text.rei.release_export": "放开 %s 以汇出此食谱",
   "text.rei.recipe_id": "\n%s配方 ID: %s",
   "text.rei.recipe_screen_type.selection": "合成界面类型选择",
   "text.rei.recipe_screen_type.selection.sub": "你始终可以通过配置界面再次编辑此设置.",

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

@@ -85,7 +85,7 @@
   "text.rei.favorites_tooltip": " \n§7按 %s 將其添加到我的最愛。",
   "text.rei.remove_favorites_tooltip": " \n§7按 %s 可以將其從我的最愛中移除。",
   "text.rei.working_station": "工作台",
-  "text.rei.release_export": "§l放開 %s 以匯出此食譜",
+  "text.rei.release_export": "放開 %s 以匯出此食譜",
   "text.rei.recipe_id": "\n%s合成識別碼: %s",
   "text.rei.recipe_screen_type.selection": "配方介面選擇",
   "text.rei.recipe_screen_type.selection.sub": "你可以在設置中改變配方介面.",