Sfoglia il codice sorgente

Improvements to Weather and GameMode options

Signed-off-by: shedaniel <daniel@shedaniel.me>
shedaniel 5 anni fa
parent
commit
cedc982143

+ 0 - 1
build.gradle

@@ -142,7 +142,6 @@ task releaseOnCf {
     }
     proc.waitFor()
     releaseChangelog = changes.toString()
-    println(releaseChangelog)
     dependsOn tasks.getByName("curseforge")
 }
 

+ 1 - 1
gradle.properties

@@ -1,4 +1,4 @@
-mod_version=4.2.0-unstable
+mod_version=4.2.1-unstable
 supported_version=20w17a
 minecraft_version=20w17a
 yarn_version=20w17a+build.2

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

@@ -34,6 +34,8 @@ 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.widget.*;
 import me.shedaniel.rei.impl.ClientHelperImpl;
@@ -54,6 +56,7 @@ import net.minecraft.client.sound.PositionedSoundInstance;
 import net.minecraft.client.util.NarratorManager;
 import net.minecraft.client.util.Window;
 import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.client.util.math.Vector4f;
 import net.minecraft.client.world.ClientWorld;
 import net.minecraft.item.ItemStack;
 import net.minecraft.screen.slot.Slot;
@@ -70,13 +73,17 @@ import org.jetbrains.annotations.ApiStatus;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
-import java.util.*;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
 
 @ApiStatus.Internal
 public class ContainerScreenOverlay extends WidgetWithBounds {
     
     private static final Identifier CHEST_GUI_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");
     private static final List<Tooltip> TOOLTIPS = Lists.newArrayList();
+    private static final List<Runnable> AFTER_RENDER = Lists.newArrayList();
     private static final EntryListWidget ENTRY_LIST_WIDGET = new EntryListWidget();
     private static FavoritesListWidget favoritesListWidget = null;
     private final List<Widget> widgets = Lists.newLinkedList();
@@ -122,6 +129,18 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
     private SubsetsMenu subsetsMenu = null;
     private Widget wrappedSubsetsMenu = null;
     
+    @Nullable
+    private SubsetsMenu weatherMenu = null;
+    private Widget wrappedWeatherMenu = null;
+    private boolean renderWeatherMenu = false;
+    private Button weatherButton = null;
+    
+    @Nullable
+    private SubsetsMenu gameModeMenu = null;
+    private Widget wrappedGameModeMenu = null;
+    private boolean renderGameModeMenu = false;
+    private Button gameModeButton = null;
+    
     public static EntryListWidget getEntryListWidget() {
         return ENTRY_LIST_WIDGET;
     }
@@ -137,6 +156,22 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
         return subsetsMenu;
     }
     
+    public void removeWeatherMenu() {
+        this.renderWeatherMenu = false;
+        Widget tmpWeatherMenu = wrappedWeatherMenu;
+        AFTER_RENDER.add(() -> this.widgets.remove(tmpWeatherMenu));
+        this.weatherMenu = null;
+        this.wrappedWeatherMenu = null;
+    }
+    
+    public void removeGameModeMenu() {
+        this.renderGameModeMenu = false;
+        Widget tmpGameModeMenu = wrappedGameModeMenu;
+        AFTER_RENDER.add(() -> this.widgets.remove(tmpGameModeMenu));
+        this.gameModeMenu = null;
+        this.wrappedGameModeMenu = null;
+    }
+    
     public void init(boolean useless) {
         init();
     }
@@ -147,6 +182,9 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
         this.children().clear();
         this.wrappedSubsetsMenu = null;
         this.subsetsMenu = null;
+        this.weatherMenu = null;
+        this.renderWeatherMenu = false;
+        this.weatherButton = null;
         this.window = MinecraftClient.getInstance().getWindow();
         @SuppressWarnings({"RawTypeCanBeGeneric", "rawtypes"})
         DisplayHelper.DisplayBoundsHandler boundsHandler = DisplayHelper.getInstance().getResponsibleBoundsHandler(MinecraftClient.getInstance().currentScreen.getClass());
@@ -229,27 +267,52 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
         ));
         tmp.setZ(600);
         if (ConfigObject.getInstance().doesShowUtilsButtons()) {
-            widgets.add(Widgets.createButton(ConfigObject.getInstance().isLowerConfigButton() ? new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 30 : 10, 10, 20, 20) : new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 55 : 35, 10, 20, 20), NarratorManager.EMPTY)
-                    .onClick(button -> MinecraftClient.getInstance().player.sendChatMessage(ConfigObject.getInstance().getGamemodeCommand().replaceAll("\\{gamemode}", getNextGameMode(Screen.hasShiftDown()).getName())))
-                    .onRender((matrices, button) -> button.setText(new LiteralText(getGameModeShortText(getCurrentGameMode()))))
+            widgets.add(gameModeButton = Widgets.createButton(ConfigObject.getInstance().isLowerConfigButton() ? new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 30 : 10, 10, 20, 20) : new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 55 : 35, 10, 20, 20), NarratorManager.EMPTY)
+                    .onRender((matrices, button) -> {
+                        boolean tmpRender = renderGameModeMenu;
+                        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()),
+                                        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;
+                                this.wrappedGameModeMenu = InternalWidgets.wrapTranslate(InternalWidgets.wrapLateRenderable(gameModeMenu), 0, 0, 400);
+                                AFTER_RENDER.add(() -> this.widgets.add(wrappedGameModeMenu));
+                            } else {
+                                removeGameModeMenu();
+                            }
+                        }
+                        button.setText(new LiteralText(getGameModeShortText(getCurrentGameMode())));
+                    })
                     .focusable(false)
-                    .tooltipLine(I18n.translate("text.rei.gamemode_button.tooltip", getGameModeText(getNextGameMode(Screen.hasShiftDown()))))
+                    .tooltipLine(I18n.translate("text.rei.gamemode_button.tooltip.all"))
                     .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y)));
-            int xxx = ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 30 : 10;
-            for (Weather weather : Weather.values()) {
-                Button weatherButton;
-                widgets.add(weatherButton = Widgets.createButton(new Rectangle(xxx, 35, 20, 20), NarratorManager.EMPTY)
-                        .onClick(button -> MinecraftClient.getInstance().player.sendChatMessage(ConfigObject.getInstance().getWeatherCommand().replaceAll("\\{weather}", weather.name().toLowerCase(Locale.ROOT))))
-                        .tooltipLine(I18n.translate("text.rei.weather_button.tooltip", I18n.translate(weather.getTranslateKey())))
-                        .focusable(false)
-                        .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y)));
-                widgets.add(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> {
-                    MinecraftClient.getInstance().getTextureManager().bindTexture(CHEST_GUI_TEXTURE);
-                    RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
-                    helper.drawTexture(matrices, weatherButton.getBounds().x + 3, weatherButton.getBounds().y + 3, weather.getId() * 14, 14, 14, 14);
-                }));
-                xxx += ConfigObject.getInstance().isLeftHandSidePanel() ? -25 : 25;
-            }
+            widgets.add(weatherButton = Widgets.createButton(new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 30 : 10, 35, 20, 20), NarratorManager.EMPTY)
+                    .onRender((matrices, button) -> {
+                        boolean tmpRender = renderWeatherMenu;
+                        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()),
+                                        CollectionUtils.map(Weather.values(), WeatherMenuEntry::new));
+                                if (ConfigObject.getInstance().isLeftHandSidePanel())
+                                    this.weatherMenu.menuStartPoint.x -= this.weatherMenu.getBounds().width - this.weatherButton.getBounds().width;
+                                this.wrappedWeatherMenu = InternalWidgets.wrapTranslate(InternalWidgets.wrapLateRenderable(weatherMenu), 0, 0, 400);
+                                AFTER_RENDER.add(() -> this.widgets.add(wrappedWeatherMenu));
+                            } else {
+                                removeWeatherMenu();
+                            }
+                        }
+                    })
+                    .tooltipLine(I18n.translate("text.rei.weather_button.tooltip.all"))
+                    .focusable(false)
+                    .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y)));
+            widgets.add(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> {
+                MinecraftClient.getInstance().getTextureManager().bindTexture(CHEST_GUI_TEXTURE);
+                RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
+                helper.drawTexture(matrices, weatherButton.getBounds().x + 3, weatherButton.getBounds().y + 3, getCurrentWeather().getId() * 14, 14, 14, 14);
+            }));
         }
         subsetsButtonBounds = getSubsetsButtonBounds();
         if (ConfigObject.getInstance().isSubsetsEnabled()) {
@@ -289,8 +352,10 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
                             .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y))
                             .tooltipSupplier(button -> I18n.translate(ConfigManager.getInstance().isCraftableOnlyEnabled() ? "text.rei.showing_craftable" : "text.rei.showing_all")),
                     Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> {
-                        itemRenderer.zOffset = helper.getZOffset();
-                        itemRenderer.renderGuiItemIcon(icon, area.x + 2, area.y + 2);
+                        Vector4f vector = new Vector4f(area.x + 2, area.y + 2, helper.getZOffset() - 10, 1.0F);
+                        vector.transform(matrices.peek().getModel());
+                        itemRenderer.zOffset = vector.getZ();
+                        itemRenderer.renderGuiItemIcon(icon, (int) vector.getX(), (int) vector.getY());
                         itemRenderer.zOffset = 0.0F;
                     }))
             ));
@@ -456,10 +521,21 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
         if (ScreenHelper.isOverlayVisible()) {
             ScreenHelper.getSearchField().laterRender(matrices, mouseX, mouseY, delta);
             for (Widget widget : widgets) {
-                if (widget instanceof LateRenderable && wrappedSubsetsMenu != widget)
+                if (widget instanceof LateRenderable && wrappedSubsetsMenu != widget && wrappedWeatherMenu != widget && wrappedGameModeMenu != widget)
                     widget.render(matrices, mouseX, mouseY, delta);
             }
         }
+        if (wrappedWeatherMenu != null) {
+            if (wrappedWeatherMenu.containsMouse(mouseX, mouseY)) {
+                TOOLTIPS.clear();
+            }
+            wrappedWeatherMenu.render(matrices, mouseX, mouseY, delta);
+        } else if (wrappedGameModeMenu != null) {
+            if (wrappedGameModeMenu.containsMouse(mouseX, mouseY)) {
+                TOOLTIPS.clear();
+            }
+            wrappedGameModeMenu.render(matrices, mouseX, mouseY, delta);
+        }
         if (wrappedSubsetsMenu != null) {
             TOOLTIPS.clear();
             wrappedSubsetsMenu.render(matrices, mouseX, mouseY, delta);
@@ -470,7 +546,11 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
                 if (tooltip != null)
                     renderTooltip(matrices, tooltip);
             }
+        for (Runnable runnable : AFTER_RENDER) {
+            runnable.run();
+        }
         TOOLTIPS.clear();
+        AFTER_RENDER.clear();
     }
     
     public void renderTooltip(MatrixStack matrices, Tooltip tooltip) {
@@ -516,6 +596,10 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
             return false;
         if (wrappedSubsetsMenu != null && wrappedSubsetsMenu.mouseScrolled(mouseX, mouseY, amount))
             return true;
+        if (wrappedWeatherMenu != null && wrappedWeatherMenu.mouseScrolled(mouseX, mouseY, amount))
+            return true;
+        if (wrappedGameModeMenu != null && wrappedGameModeMenu.mouseScrolled(mouseX, mouseY, amount))
+            return true;
         if (isInside(PointHelper.ofMouse())) {
             if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
                 if (amount > 0 && leftButton.isEnabled())
@@ -533,7 +617,11 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
                 return true;
         }
         for (Widget widget : widgets)
-            if (widget != ENTRY_LIST_WIDGET && (favoritesListWidget == null || widget != favoritesListWidget) && (wrappedSubsetsMenu == null || widget != wrappedSubsetsMenu) && widget.mouseScrolled(mouseX, mouseY, amount))
+            if (widget != ENTRY_LIST_WIDGET && (favoritesListWidget == null || widget != favoritesListWidget)
+                && (wrappedSubsetsMenu == null || widget != wrappedSubsetsMenu)
+                && (wrappedWeatherMenu == null || widget != wrappedWeatherMenu)
+                && (wrappedGameModeMenu == null || widget != wrappedGameModeMenu)
+                && widget.mouseScrolled(mouseX, mouseY, amount))
                 return true;
         return false;
     }
@@ -603,6 +691,28 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
             ScreenHelper.getSearchField().setFocused(false);
             return true;
         }
+        if (wrappedWeatherMenu != null) {
+            if (wrappedWeatherMenu.mouseClicked(double_1, double_2, int_1)) {
+                this.setFocused(wrappedWeatherMenu);
+                if (int_1 == 0)
+                    this.setDragging(true);
+                ScreenHelper.getSearchField().setFocused(false);
+                return true;
+            } else if (!wrappedWeatherMenu.containsMouse(double_1, double_2) && !weatherButton.containsMouse(double_1, double_2)) {
+                removeWeatherMenu();
+            }
+        }
+        if (wrappedGameModeMenu != null) {
+            if (wrappedGameModeMenu.mouseClicked(double_1, double_2, int_1)) {
+                this.setFocused(wrappedGameModeMenu);
+                if (int_1 == 0)
+                    this.setDragging(true);
+                ScreenHelper.getSearchField().setFocused(false);
+                return true;
+            } else if (!wrappedGameModeMenu.containsMouse(double_1, double_2) && !gameModeButton.containsMouse(double_1, double_2)) {
+                removeGameModeMenu();
+            }
+        }
         if (MinecraftClient.getInstance().currentScreen instanceof HandledScreen && ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) {
             HandledScreen<?> handledScreen = (HandledScreen<?>) MinecraftClient.getInstance().currentScreen;
             for (RecipeHelper.ScreenClickArea area : RecipeHelper.getInstance().getScreenClickAreas())
@@ -614,7 +724,7 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
                     }
         }
         for (Element element : widgets)
-            if (element != wrappedSubsetsMenu && element.mouseClicked(double_1, double_2, int_1)) {
+            if (element != wrappedSubsetsMenu && element != wrappedWeatherMenu && element != wrappedGameModeMenu && element.mouseClicked(double_1, double_2, int_1)) {
                 this.setFocused(element);
                 if (int_1 == 0)
                     this.setDragging(true);

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

@@ -101,7 +101,7 @@ public class PreRecipeViewingScreen extends Screen {
     }
     
     @Override
-    protected void init() {
+    public void init() {
         this.children.clear();
         this.widgets.clear();
         this.widgets.add(Widgets.createButton(new Rectangle(width / 2 - 100, height - 40, 200, 20), NarratorManager.EMPTY)

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

@@ -139,7 +139,7 @@ public class VillagerRecipeViewingScreen extends Screen implements RecipeScreen
     }
     
     @Override
-    protected void init() {
+    public void init() {
         super.init();
         boolean isCompactTabs = ConfigObject.getInstance().isUsingCompactTabs();
         int tabSize = isCompactTabs ? 24 : 28;

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

@@ -78,7 +78,7 @@ public class WarningAndErrorScreen extends Screen {
     }
     
     @Override
-    protected void init() {
+    public void init() {
         children.add(listWidget = new StringEntryListWidget(client, width, height, 32, height - 32));
         listWidget.max = 80;
         listWidget.creditsClearEntries();

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

@@ -69,7 +69,7 @@ public class CreditsScreen extends Screen {
     }
     
     @Override
-    protected void init() {
+    public void init() {
         children.add(entryListWidget = new CreditsEntryListWidget(client, width, height, 32, height - 32));
         entryListWidget.creditsClearEntries();
         List<Pair<String, String>> translators = Lists.newArrayList();

+ 85 - 0
src/main/java/me/shedaniel/rei/gui/modules/GameModeMenuEntry.java

@@ -0,0 +1,85 @@
+package me.shedaniel.rei.gui.modules;
+
+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.impl.ScreenHelper;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.Element;
+import net.minecraft.client.sound.PositionedSoundInstance;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.sound.SoundEvents;
+import net.minecraft.text.TranslatableText;
+import net.minecraft.world.GameMode;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+public class GameModeMenuEntry extends SubsetsMenuEntry {
+    public final String text;
+    public final GameMode gameMode;
+    private int x, y, width;
+    private boolean selected, containsMouse, rendering;
+    private int textWidth = -69;
+    
+    public GameModeMenuEntry(GameMode gameMode) {
+        this.text = gameMode.getTranslatableName().getString();
+        this.gameMode = gameMode;
+    }
+    
+    private int getTextWidth() {
+        if (textWidth == -69) {
+            this.textWidth = Math.max(0, font.getStringWidth(text));
+        }
+        return this.textWidth;
+    }
+    
+    @Override
+    public int getEntryWidth() {
+        return getTextWidth() + 4;
+    }
+    
+    @Override
+    public int getEntryHeight() {
+        return 12;
+    }
+    
+    @Override
+    public List<? extends Element> children() {
+        return Collections.emptyList();
+    }
+    
+    @Override
+    public void updateInformation(int xPos, int yPos, boolean selected, boolean containsMouse, boolean rendering, int width) {
+        this.x = xPos;
+        this.y = yPos;
+        this.selected = selected;
+        this.containsMouse = containsMouse;
+        this.rendering = rendering;
+        this.width = width;
+    }
+    
+    @Override
+    public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
+        if (selected) {
+            fill(matrices, x, y, x + width, y + 12, -12237499);
+        }
+        if (selected && containsMouse) {
+            REIHelper.getInstance().queueTooltip(Tooltip.create(new TranslatableText("text.rei.gamemode_button.tooltip.entry", text)));
+        }
+        font.draw(matrices, text, x + 2, y + 2, selected ? 16777215 : 8947848);
+    }
+    
+    @Override
+    public boolean mouseClicked(double mouseX, double mouseY, int button) {
+        if (rendering && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 12) {
+            MinecraftClient.getInstance().player.sendChatMessage(ConfigObject.getInstance().getGamemodeCommand().replaceAll("\\{gamemode}", gameMode.name().toLowerCase(Locale.ROOT)));
+            minecraft.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
+            ScreenHelper.getLastOverlay().removeGameModeMenu();
+            return true;
+        }
+        return super.mouseClicked(mouseX, mouseY, button);
+    }
+}

+ 86 - 0
src/main/java/me/shedaniel/rei/gui/modules/WeatherMenuEntry.java

@@ -0,0 +1,86 @@
+package me.shedaniel.rei.gui.modules;
+
+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.impl.ScreenHelper;
+import me.shedaniel.rei.impl.Weather;
+import net.minecraft.client.MinecraftClient;
+import net.minecraft.client.gui.Element;
+import net.minecraft.client.resource.language.I18n;
+import net.minecraft.client.sound.PositionedSoundInstance;
+import net.minecraft.client.util.math.MatrixStack;
+import net.minecraft.sound.SoundEvents;
+import net.minecraft.text.TranslatableText;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+public class WeatherMenuEntry extends SubsetsMenuEntry {
+    public final String text;
+    public final Weather weather;
+    private int x, y, width;
+    private boolean selected, containsMouse, rendering;
+    private int textWidth = -69;
+    
+    public WeatherMenuEntry(Weather weather) {
+        this.text = I18n.translate(weather.getTranslateKey());
+        this.weather = weather;
+    }
+    
+    private int getTextWidth() {
+        if (textWidth == -69) {
+            this.textWidth = Math.max(0, font.getStringWidth(text));
+        }
+        return this.textWidth;
+    }
+    
+    @Override
+    public int getEntryWidth() {
+        return getTextWidth() + 4;
+    }
+    
+    @Override
+    public int getEntryHeight() {
+        return 12;
+    }
+    
+    @Override
+    public List<? extends Element> children() {
+        return Collections.emptyList();
+    }
+    
+    @Override
+    public void updateInformation(int xPos, int yPos, boolean selected, boolean containsMouse, boolean rendering, int width) {
+        this.x = xPos;
+        this.y = yPos;
+        this.selected = selected;
+        this.containsMouse = containsMouse;
+        this.rendering = rendering;
+        this.width = width;
+    }
+    
+    @Override
+    public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
+        if (selected) {
+            fill(matrices, x, y, x + width, y + 12, -12237499);
+        }
+        if (selected && containsMouse) {
+            REIHelper.getInstance().queueTooltip(Tooltip.create(new TranslatableText("text.rei.weather_button.tooltip.entry", text)));
+        }
+        font.draw(matrices, text, x + 2, y + 2, selected ? 16777215 : 8947848);
+    }
+    
+    @Override
+    public boolean mouseClicked(double mouseX, double mouseY, int button) {
+        if (rendering && mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + 12) {
+            MinecraftClient.getInstance().player.sendChatMessage(ConfigObject.getInstance().getWeatherCommand().replaceAll("\\{weather}", weather.name().toLowerCase(Locale.ROOT)));
+            minecraft.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
+            ScreenHelper.getLastOverlay().removeWeatherMenu();
+            return true;
+        }
+        return super.mouseClicked(mouseX, mouseY, button);
+    }
+}

+ 2 - 1
src/main/java/me/shedaniel/rei/gui/subsets/SubsetsMenu.java

@@ -33,6 +33,7 @@ import me.shedaniel.math.Rectangle;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 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;
@@ -215,7 +216,7 @@ 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(), -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;

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

@@ -60,8 +60,10 @@
   "text.rei.view_all_categories": "View All Categories",
   "text.rei.go_back_first_page": "Back to Page 1",
   "text.rei.choose_page": "Choose Page",
-  "text.rei.gamemode_button.tooltip": "Switch Game Mode\n§7Switch to %s mode.\n\n§7Shift-Click to switch in a reverse cycle.",
-  "text.rei.weather_button.tooltip": "Switch Weather\n§7Switch to %s.",
+  "text.rei.gamemode_button.tooltip.all": "Switch Game Mode",
+  "text.rei.gamemode_button.tooltip.entry": "Switch to %s",
+  "text.rei.weather_button.tooltip.all": "Switch Weather",
+  "text.rei.weather_button.tooltip.entry": "Switch to %s",
   "text.rei.reload_config": "Reload Plugins",
   "text.rei.config.is.reloading": "Plugins are reloading!",
   "text.rei.enabled": "Yes",