ContainerScreenOverlay.java 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773
  1. /*
  2. * This file is licensed under the MIT License, part of Roughly Enough Items.
  3. * Copyright (c) 2018, 2019, 2020 shedaniel
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in all
  13. * copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. * SOFTWARE.
  22. */
  23. package me.shedaniel.rei.gui;
  24. import com.google.common.collect.Lists;
  25. import com.mojang.blaze3d.systems.RenderSystem;
  26. import me.shedaniel.math.Point;
  27. import me.shedaniel.math.Rectangle;
  28. import me.shedaniel.math.impl.PointHelper;
  29. import me.shedaniel.rei.RoughlyEnoughItemsCore;
  30. import me.shedaniel.rei.api.*;
  31. import me.shedaniel.rei.api.widgets.Button;
  32. import me.shedaniel.rei.api.widgets.Tooltip;
  33. import me.shedaniel.rei.api.widgets.Widgets;
  34. import me.shedaniel.rei.gui.config.SearchFieldLocation;
  35. import me.shedaniel.rei.gui.modules.Menu;
  36. import me.shedaniel.rei.gui.modules.entries.GameModeMenuEntry;
  37. import me.shedaniel.rei.gui.modules.entries.WeatherMenuEntry;
  38. import me.shedaniel.rei.gui.widget.*;
  39. import me.shedaniel.rei.impl.ClientHelperImpl;
  40. import me.shedaniel.rei.impl.InternalWidgets;
  41. import me.shedaniel.rei.impl.ScreenHelper;
  42. import me.shedaniel.rei.impl.Weather;
  43. import me.shedaniel.rei.utils.CollectionUtils;
  44. import net.minecraft.block.Blocks;
  45. import net.minecraft.client.MinecraftClient;
  46. import net.minecraft.client.gui.Element;
  47. import net.minecraft.client.gui.screen.Screen;
  48. import net.minecraft.client.gui.screen.ingame.ContainerScreen;
  49. import net.minecraft.client.render.Tessellator;
  50. import net.minecraft.client.render.VertexConsumerProvider;
  51. import net.minecraft.client.render.item.ItemRenderer;
  52. import net.minecraft.client.resource.language.I18n;
  53. import net.minecraft.client.sound.PositionedSoundInstance;
  54. import net.minecraft.client.util.NarratorManager;
  55. import net.minecraft.client.util.Window;
  56. import net.minecraft.client.util.math.MatrixStack;
  57. import net.minecraft.client.util.math.Vector4f;
  58. import net.minecraft.client.world.ClientWorld;
  59. import net.minecraft.item.ItemStack;
  60. import net.minecraft.screen.slot.Slot;
  61. import net.minecraft.sound.SoundEvents;
  62. import net.minecraft.text.LiteralText;
  63. import net.minecraft.text.Text;
  64. import net.minecraft.text.TranslatableText;
  65. import net.minecraft.util.ActionResult;
  66. import net.minecraft.util.Identifier;
  67. import net.minecraft.util.math.Matrix4f;
  68. import net.minecraft.world.GameMode;
  69. import org.apache.logging.log4j.util.TriConsumer;
  70. import org.jetbrains.annotations.ApiStatus;
  71. import org.jetbrains.annotations.NotNull;
  72. import org.jetbrains.annotations.Nullable;
  73. import java.util.Arrays;
  74. import java.util.Comparator;
  75. import java.util.LinkedList;
  76. import java.util.List;
  77. @ApiStatus.Internal
  78. public class ContainerScreenOverlay extends WidgetWithBounds {
  79. private static final Identifier CHEST_GUI_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");
  80. private static final List<Tooltip> TOOLTIPS = Lists.newArrayList();
  81. private static final List<Runnable> AFTER_RENDER = Lists.newArrayList();
  82. private static final EntryListWidget ENTRY_LIST_WIDGET = new EntryListWidget();
  83. private static FavoritesListWidget favoritesListWidget = null;
  84. private final List<Widget> widgets = Lists.newLinkedList();
  85. public boolean shouldReInit = false;
  86. private int tooltipWidth;
  87. private int tooltipHeight;
  88. private List<Text> tooltipLines;
  89. public final TriConsumer<MatrixStack, Point, Float> renderTooltipCallback = (matrices, mouse, aFloat) -> {
  90. RenderSystem.disableRescaleNormal();
  91. RenderSystem.disableDepthTest();
  92. matrices.push();
  93. matrices.translate(0, 0, 999);
  94. int x = mouse.x;
  95. int y = mouse.y;
  96. this.fillGradient(matrices, x - 3, y - 4, x + tooltipWidth + 3, y - 3, -267386864, -267386864);
  97. this.fillGradient(matrices, x - 3, y + tooltipHeight + 3, x + tooltipWidth + 3, y + tooltipHeight + 4, -267386864, -267386864);
  98. this.fillGradient(matrices, x - 3, y - 3, x + tooltipWidth + 3, y + tooltipHeight + 3, -267386864, -267386864);
  99. this.fillGradient(matrices, x - 4, y - 3, x - 3, y + tooltipHeight + 3, -267386864, -267386864);
  100. this.fillGradient(matrices, x + tooltipWidth + 3, y - 3, x + tooltipWidth + 4, y + tooltipHeight + 3, -267386864, -267386864);
  101. this.fillGradient(matrices, x - 3, y - 3 + 1, x - 3 + 1, y + tooltipHeight + 3 - 1, 1347420415, 1344798847);
  102. this.fillGradient(matrices, x + tooltipWidth + 2, y - 3 + 1, x + tooltipWidth + 3, y + tooltipHeight + 3 - 1, 1347420415, 1344798847);
  103. this.fillGradient(matrices, x - 3, y - 3, x + tooltipWidth + 3, y - 3 + 1, 1347420415, 1347420415);
  104. this.fillGradient(matrices, x - 3, y + tooltipHeight + 2, x + tooltipWidth + 3, y + tooltipHeight + 3, 1344798847, 1344798847);
  105. int currentY = y;
  106. VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer());
  107. Matrix4f matrix = matrices.peek().getModel();
  108. for (int lineIndex = 0; lineIndex < tooltipLines.size(); lineIndex++) {
  109. font.draw(tooltipLines.get(lineIndex), x, currentY, -1, true, matrix, immediate, false, 0, 15728880);
  110. currentY += lineIndex == 0 ? 12 : 10;
  111. }
  112. immediate.draw();
  113. matrices.pop();
  114. RenderSystem.enableDepthTest();
  115. RenderSystem.enableRescaleNormal();
  116. };
  117. private Rectangle bounds;
  118. private Window window;
  119. private Button leftButton, rightButton;
  120. @ApiStatus.Experimental
  121. private Rectangle subsetsButtonBounds;
  122. @ApiStatus.Experimental
  123. @Nullable
  124. private Menu subsetsMenu = null;
  125. private Widget wrappedSubsetsMenu = null;
  126. @Nullable
  127. private Menu weatherMenu = null;
  128. private Widget wrappedWeatherMenu = null;
  129. private boolean renderWeatherMenu = false;
  130. private Button weatherButton = null;
  131. @Nullable
  132. private Menu gameModeMenu = null;
  133. private Widget wrappedGameModeMenu = null;
  134. private boolean renderGameModeMenu = false;
  135. private Button gameModeButton = null;
  136. public static EntryListWidget getEntryListWidget() {
  137. return ENTRY_LIST_WIDGET;
  138. }
  139. @Nullable
  140. public static FavoritesListWidget getFavoritesListWidget() {
  141. return favoritesListWidget;
  142. }
  143. @ApiStatus.Experimental
  144. @Nullable
  145. public Menu getSubsetsMenu() {
  146. return subsetsMenu;
  147. }
  148. public void removeWeatherMenu() {
  149. this.renderWeatherMenu = false;
  150. Widget tmpWeatherMenu = wrappedWeatherMenu;
  151. AFTER_RENDER.add(() -> this.widgets.remove(tmpWeatherMenu));
  152. this.weatherMenu = null;
  153. this.wrappedWeatherMenu = null;
  154. }
  155. public void removeGameModeMenu() {
  156. this.renderGameModeMenu = false;
  157. Widget tmpGameModeMenu = wrappedGameModeMenu;
  158. AFTER_RENDER.add(() -> this.widgets.remove(tmpGameModeMenu));
  159. this.gameModeMenu = null;
  160. this.wrappedGameModeMenu = null;
  161. }
  162. public void init(boolean useless) {
  163. init();
  164. }
  165. public void init() {
  166. this.shouldReInit = false;
  167. //Update Variables
  168. this.children().clear();
  169. this.wrappedSubsetsMenu = null;
  170. this.subsetsMenu = null;
  171. this.weatherMenu = null;
  172. this.renderWeatherMenu = false;
  173. this.weatherButton = null;
  174. this.window = MinecraftClient.getInstance().getWindow();
  175. @SuppressWarnings({"RawTypeCanBeGeneric", "rawtypes"})
  176. DisplayHelper.DisplayBoundsHandler boundsHandler = DisplayHelper.getInstance().getResponsibleBoundsHandler(MinecraftClient.getInstance().currentScreen.getClass());
  177. this.bounds = ConfigObject.getInstance().isLeftHandSidePanel() ? boundsHandler.getLeftBounds(MinecraftClient.getInstance().currentScreen) : boundsHandler.getRightBounds(MinecraftClient.getInstance().currentScreen);
  178. widgets.add(ENTRY_LIST_WIDGET);
  179. if (ConfigObject.getInstance().isFavoritesEnabled()) {
  180. if (favoritesListWidget == null)
  181. favoritesListWidget = new FavoritesListWidget();
  182. widgets.add(favoritesListWidget);
  183. }
  184. ENTRY_LIST_WIDGET.updateArea(boundsHandler, ScreenHelper.getSearchField() == null ? "" : null);
  185. if (ScreenHelper.getSearchField() == null) {
  186. ScreenHelper.setSearchField(new OverlaySearchField(0, 0, 0, 0));
  187. }
  188. ScreenHelper.getSearchField().getBounds().setBounds(getSearchFieldArea());
  189. this.widgets.add(ScreenHelper.getSearchField());
  190. ScreenHelper.getSearchField().setChangedListener(s -> ENTRY_LIST_WIDGET.updateSearch(s, false));
  191. if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  192. widgets.add(leftButton = Widgets.createButton(new Rectangle(bounds.x, bounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 5, 16, 16), new TranslatableText("text.rei.left_arrow"))
  193. .onClick(button -> {
  194. ENTRY_LIST_WIDGET.previousPage();
  195. if (ENTRY_LIST_WIDGET.getPage() < 0)
  196. ENTRY_LIST_WIDGET.setPage(ENTRY_LIST_WIDGET.getTotalPages() - 1);
  197. ENTRY_LIST_WIDGET.updateEntriesPosition();
  198. })
  199. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y))
  200. .tooltipLine(I18n.translate("text.rei.previous_page"))
  201. .focusable(false));
  202. widgets.add(rightButton = Widgets.createButton(new Rectangle(bounds.x + bounds.width - 18, bounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 5, 16, 16), new TranslatableText("text.rei.right_arrow"))
  203. .onClick(button -> {
  204. ENTRY_LIST_WIDGET.nextPage();
  205. if (ENTRY_LIST_WIDGET.getPage() >= ENTRY_LIST_WIDGET.getTotalPages())
  206. ENTRY_LIST_WIDGET.setPage(0);
  207. ENTRY_LIST_WIDGET.updateEntriesPosition();
  208. })
  209. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y))
  210. .tooltipLine(I18n.translate("text.rei.next_page"))
  211. .focusable(false));
  212. }
  213. final Rectangle configButtonArea = getConfigButtonArea();
  214. Widget tmp;
  215. widgets.add(tmp = InternalWidgets.wrapLateRenderable(InternalWidgets.mergeWidgets(
  216. Widgets.createButton(configButtonArea, NarratorManager.EMPTY)
  217. .onClick(button -> {
  218. if (Screen.hasShiftDown()) {
  219. ClientHelper.getInstance().setCheating(!ClientHelper.getInstance().isCheating());
  220. return;
  221. }
  222. ConfigManager.getInstance().openConfigScreen(REIHelper.getInstance().getPreviousContainerScreen());
  223. })
  224. .onRender((matrices, button) -> {
  225. if (ClientHelper.getInstance().isCheating() && RoughlyEnoughItemsCore.hasOperatorPermission()) {
  226. button.setTint(RoughlyEnoughItemsCore.hasPermissionToUsePackets() ? 721354752 : 1476440063);
  227. } else {
  228. button.removeTint();
  229. }
  230. })
  231. .focusable(false)
  232. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y))
  233. .tooltipSupplier(button -> {
  234. String tooltips = I18n.translate("text.rei.config_tooltip");
  235. tooltips += "\n ";
  236. if (!ClientHelper.getInstance().isCheating())
  237. tooltips += "\n" + I18n.translate("text.rei.cheating_disabled");
  238. else if (!RoughlyEnoughItemsCore.hasOperatorPermission())
  239. tooltips += "\n" + I18n.translate("text.rei.cheating_enabled_no_perms");
  240. else if (RoughlyEnoughItemsCore.hasPermissionToUsePackets())
  241. tooltips += "\n" + I18n.translate("text.rei.cheating_enabled");
  242. else
  243. tooltips += "\n" + I18n.translate("text.rei.cheating_limited_enabled");
  244. return tooltips;
  245. }),
  246. Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> {
  247. helper.setZOffset(helper.getZOffset() + 1);
  248. MinecraftClient.getInstance().getTextureManager().bindTexture(CHEST_GUI_TEXTURE);
  249. helper.drawTexture(matrices, configButtonArea.x + 3, configButtonArea.y + 3, 0, 0, 14, 14);
  250. })
  251. )
  252. ));
  253. tmp.setZ(600);
  254. if (ConfigObject.getInstance().doesShowUtilsButtons()) {
  255. 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)
  256. .onRender((matrices, button) -> {
  257. boolean tmpRender = renderGameModeMenu;
  258. renderGameModeMenu = !renderWeatherMenu && (button.isFocused() || button.containsMouse(PointHelper.ofMouse()) || (wrappedGameModeMenu != null && wrappedGameModeMenu.containsMouse(PointHelper.ofMouse())));
  259. if (tmpRender != renderGameModeMenu) {
  260. if (renderGameModeMenu) {
  261. this.gameModeMenu = new Menu(new Point(button.getBounds().x, button.getBounds().getMaxY()),
  262. CollectionUtils.filterAndMap(Arrays.asList(GameMode.values()), mode -> mode != GameMode.NOT_SET, GameModeMenuEntry::new));
  263. if (ConfigObject.getInstance().isLeftHandSidePanel())
  264. this.gameModeMenu.menuStartPoint.x -= this.gameModeMenu.getBounds().width - this.gameModeButton.getBounds().width;
  265. this.wrappedGameModeMenu = InternalWidgets.wrapTranslate(InternalWidgets.wrapLateRenderable(gameModeMenu), 0, 0, 600);
  266. AFTER_RENDER.add(() -> this.widgets.add(wrappedGameModeMenu));
  267. } else {
  268. removeGameModeMenu();
  269. }
  270. }
  271. button.setText(new LiteralText(getGameModeShortText(getCurrentGameMode())));
  272. })
  273. .focusable(false)
  274. .tooltipLine(I18n.translate("text.rei.gamemode_button.tooltip.all"))
  275. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y)));
  276. widgets.add(weatherButton = Widgets.createButton(new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 30 : 10, 35, 20, 20), NarratorManager.EMPTY)
  277. .onRender((matrices, button) -> {
  278. boolean tmpRender = renderWeatherMenu;
  279. renderWeatherMenu = !renderGameModeMenu && (button.isFocused() || button.containsMouse(PointHelper.ofMouse()) || (wrappedWeatherMenu != null && wrappedWeatherMenu.containsMouse(PointHelper.ofMouse())));
  280. if (tmpRender != renderWeatherMenu) {
  281. if (renderWeatherMenu) {
  282. this.weatherMenu = new Menu(new Point(button.getBounds().x, button.getBounds().getMaxY()),
  283. CollectionUtils.map(Weather.values(), WeatherMenuEntry::new));
  284. if (ConfigObject.getInstance().isLeftHandSidePanel())
  285. this.weatherMenu.menuStartPoint.x -= this.weatherMenu.getBounds().width - this.weatherButton.getBounds().width;
  286. this.wrappedWeatherMenu = InternalWidgets.wrapTranslate(InternalWidgets.wrapLateRenderable(weatherMenu), 0, 0, 400);
  287. AFTER_RENDER.add(() -> this.widgets.add(wrappedWeatherMenu));
  288. } else {
  289. removeWeatherMenu();
  290. }
  291. }
  292. })
  293. .tooltipLine(I18n.translate("text.rei.weather_button.tooltip.all"))
  294. .focusable(false)
  295. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y)));
  296. widgets.add(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> {
  297. MinecraftClient.getInstance().getTextureManager().bindTexture(CHEST_GUI_TEXTURE);
  298. RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
  299. helper.drawTexture(matrices, weatherButton.getBounds().x + 3, weatherButton.getBounds().y + 3, getCurrentWeather().getId() * 14, 14, 14, 14);
  300. }));
  301. }
  302. subsetsButtonBounds = getSubsetsButtonBounds();
  303. if (ConfigObject.getInstance().isSubsetsEnabled()) {
  304. 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"))
  305. .onClick(button -> {
  306. if (subsetsMenu == null) {
  307. wrappedSubsetsMenu = InternalWidgets.wrapTranslate(InternalWidgets.wrapLateRenderable(this.subsetsMenu = Menu.createSubsetsMenuFromRegistry(new Point(this.subsetsButtonBounds.x, this.subsetsButtonBounds.getMaxY()))), 0, 0, 400);
  308. this.widgets.add(this.wrappedSubsetsMenu);
  309. } else {
  310. this.widgets.remove(this.wrappedSubsetsMenu);
  311. this.subsetsMenu = null;
  312. this.wrappedSubsetsMenu = null;
  313. }
  314. }), 0, 0, 600)));
  315. }
  316. if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  317. widgets.add(Widgets.createClickableLabel(new Point(bounds.x + (bounds.width / 2), bounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 10), NarratorManager.EMPTY, label -> {
  318. ENTRY_LIST_WIDGET.setPage(0);
  319. ENTRY_LIST_WIDGET.updateEntriesPosition();
  320. }).tooltipLine(I18n.translate("text.rei.go_back_first_page")).focusable(false).onRender((matrices, label) -> {
  321. label.setClickable(ENTRY_LIST_WIDGET.getTotalPages() > 1);
  322. label.setText(new LiteralText(String.format("%s/%s", ENTRY_LIST_WIDGET.getPage() + 1, Math.max(ENTRY_LIST_WIDGET.getTotalPages(), 1))));
  323. }));
  324. }
  325. if (ConfigObject.getInstance().isCraftableFilterEnabled()) {
  326. Rectangle area = getCraftableToggleArea();
  327. ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
  328. ItemStack icon = new ItemStack(Blocks.CRAFTING_TABLE);
  329. this.widgets.add(tmp = InternalWidgets.wrapLateRenderable(InternalWidgets.mergeWidgets(
  330. Widgets.createButton(area, NarratorManager.EMPTY)
  331. .focusable(false)
  332. .onClick(button -> {
  333. ConfigManager.getInstance().toggleCraftableOnly();
  334. ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
  335. })
  336. .onRender((matrices, button) -> button.setTint(ConfigManager.getInstance().isCraftableOnlyEnabled() ? 939579655 : 956235776))
  337. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y))
  338. .tooltipSupplier(button -> I18n.translate(ConfigManager.getInstance().isCraftableOnlyEnabled() ? "text.rei.showing_craftable" : "text.rei.showing_all")),
  339. Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> {
  340. Vector4f vector = new Vector4f(area.x + 2, area.y + 2, helper.getZOffset() - 10, 1.0F);
  341. vector.transform(matrices.peek().getModel());
  342. itemRenderer.zOffset = vector.getZ();
  343. itemRenderer.renderGuiItemIcon(icon, (int) vector.getX(), (int) vector.getY());
  344. itemRenderer.zOffset = 0.0F;
  345. }))
  346. ));
  347. tmp.setZ(600);
  348. }
  349. }
  350. @ApiStatus.Experimental
  351. private Rectangle getSubsetsButtonBounds() {
  352. if (ConfigObject.getInstance().isSubsetsEnabled()) {
  353. if (MinecraftClient.getInstance().currentScreen instanceof RecipeViewingScreen) {
  354. RecipeViewingScreen widget = (RecipeViewingScreen) MinecraftClient.getInstance().currentScreen;
  355. return new Rectangle(widget.getBounds().x, 3, widget.getBounds().width, 18);
  356. }
  357. if (MinecraftClient.getInstance().currentScreen instanceof VillagerRecipeViewingScreen) {
  358. VillagerRecipeViewingScreen widget = (VillagerRecipeViewingScreen) MinecraftClient.getInstance().currentScreen;
  359. return new Rectangle(widget.bounds.x, 3, widget.bounds.width, 18);
  360. }
  361. return new Rectangle(REIHelper.getInstance().getPreviousContainerScreen().x, 3, REIHelper.getInstance().getPreviousContainerScreen().containerWidth, 18);
  362. }
  363. return null;
  364. }
  365. private Weather getNextWeather() {
  366. try {
  367. Weather current = getCurrentWeather();
  368. int next = current.getId() + 1;
  369. if (next >= 3)
  370. next = 0;
  371. return Weather.byId(next);
  372. } catch (Exception e) {
  373. return Weather.CLEAR;
  374. }
  375. }
  376. private Weather getCurrentWeather() {
  377. ClientWorld world = MinecraftClient.getInstance().world;
  378. if (world.isThundering())
  379. return Weather.THUNDER;
  380. if (world.getLevelProperties().isRaining())
  381. return Weather.RAIN;
  382. return Weather.CLEAR;
  383. }
  384. private String getGameModeShortText(GameMode gameMode) {
  385. return I18n.translate("text.rei.short_gamemode." + gameMode.getName());
  386. }
  387. private String getGameModeText(GameMode gameMode) {
  388. return I18n.translate("selectWorld.gameMode." + gameMode.getName());
  389. }
  390. private GameMode getNextGameMode(boolean reverse) {
  391. try {
  392. GameMode current = getCurrentGameMode();
  393. int next = current.getId() + 1;
  394. if (reverse)
  395. next -= 2;
  396. if (next > 3)
  397. next = 0;
  398. if (next < 0)
  399. next = 3;
  400. return GameMode.byId(next);
  401. } catch (Exception e) {
  402. return GameMode.NOT_SET;
  403. }
  404. }
  405. private GameMode getCurrentGameMode() {
  406. return MinecraftClient.getInstance().getNetworkHandler().getPlayerListEntry(MinecraftClient.getInstance().player.getGameProfile().getId()).getGameMode();
  407. }
  408. private Rectangle getSearchFieldArea() {
  409. int widthRemoved = 1 + (ConfigObject.getInstance().isCraftableFilterEnabled() ? 22 : 0) + (ConfigObject.getInstance().isLowerConfigButton() ? 22 : 0);
  410. SearchFieldLocation searchFieldLocation = ConfigObject.getInstance().getSearchFieldLocation();
  411. if (searchFieldLocation == SearchFieldLocation.BOTTOM_SIDE)
  412. return new Rectangle(bounds.x + 2, window.getScaledHeight() - 22, bounds.width - 6 - widthRemoved, 18);
  413. if (searchFieldLocation == SearchFieldLocation.TOP_SIDE)
  414. return new Rectangle(bounds.x + 2, 4, bounds.width - 6 - widthRemoved, 18);
  415. if (MinecraftClient.getInstance().currentScreen instanceof RecipeViewingScreen) {
  416. RecipeViewingScreen widget = (RecipeViewingScreen) MinecraftClient.getInstance().currentScreen;
  417. return new Rectangle(widget.getBounds().x, window.getScaledHeight() - 22, widget.getBounds().width - widthRemoved, 18);
  418. }
  419. if (MinecraftClient.getInstance().currentScreen instanceof VillagerRecipeViewingScreen) {
  420. VillagerRecipeViewingScreen widget = (VillagerRecipeViewingScreen) MinecraftClient.getInstance().currentScreen;
  421. return new Rectangle(widget.bounds.x, window.getScaledHeight() - 22, widget.bounds.width - widthRemoved, 18);
  422. }
  423. return new Rectangle(REIHelper.getInstance().getPreviousContainerScreen().x, window.getScaledHeight() - 22, REIHelper.getInstance().getPreviousContainerScreen().containerWidth - widthRemoved, 18);
  424. }
  425. private Rectangle getCraftableToggleArea() {
  426. Rectangle area = getSearchFieldArea();
  427. area.setLocation(area.x + area.width + 4, area.y - 1);
  428. area.setSize(20, 20);
  429. return area;
  430. }
  431. private Rectangle getConfigButtonArea() {
  432. if (ConfigObject.getInstance().isLowerConfigButton()) {
  433. Rectangle area = getSearchFieldArea();
  434. area.setLocation(area.x + area.width + (ConfigObject.getInstance().isCraftableFilterEnabled() ? 26 : 4), area.y - 1);
  435. area.setSize(20, 20);
  436. return area;
  437. }
  438. return new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getScaledWidth() - 30 : 10, 10, 20, 20);
  439. }
  440. private String getCheatModeText() {
  441. return I18n.translate(String.format("%s%s", "text.rei.", ClientHelper.getInstance().isCheating() ? "cheat" : "nocheat"));
  442. }
  443. @NotNull
  444. @Override
  445. public Rectangle getBounds() {
  446. return bounds;
  447. }
  448. @Override
  449. public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
  450. List<ItemStack> currentStacks = ClientHelper.getInstance().getInventoryItemsTypes();
  451. if (shouldReInit) {
  452. ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
  453. init();
  454. } else {
  455. for (DisplayHelper.DisplayBoundsHandler<?> handler : DisplayHelper.getInstance().getSortedBoundsHandlers(minecraft.currentScreen.getClass())) {
  456. if (handler != null && handler.shouldRecalculateArea(!ConfigObject.getInstance().isLeftHandSidePanel(), bounds)) {
  457. init();
  458. break;
  459. }
  460. }
  461. }
  462. if (ConfigManager.getInstance().isCraftableOnlyEnabled() && ((currentStacks.size() != ScreenHelper.inventoryStacks.size()) || !hasSameListContent(new LinkedList<>(ScreenHelper.inventoryStacks), currentStacks))) {
  463. ScreenHelper.inventoryStacks = currentStacks;
  464. ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
  465. }
  466. if (OverlaySearchField.isSearching) {
  467. matrices.push();
  468. matrices.translate(0, 0, 200f);
  469. if (MinecraftClient.getInstance().currentScreen instanceof ContainerScreen) {
  470. ContainerScreen<?> containerScreen = (ContainerScreen<?>) MinecraftClient.getInstance().currentScreen;
  471. int x = containerScreen.x, y = containerScreen.y;
  472. for (Slot slot : containerScreen.getContainer().slots)
  473. if (!slot.hasStack() || !ENTRY_LIST_WIDGET.canLastSearchTermsBeAppliedTo(EntryStack.create(slot.getStack())))
  474. fillGradient(matrices, x + slot.xPosition, y + slot.yPosition, x + slot.xPosition + 16, y + slot.yPosition + 16, -601874400, -601874400);
  475. }
  476. matrices.pop();
  477. }
  478. RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
  479. this.renderWidgets(matrices, mouseX, mouseY, delta);
  480. if (MinecraftClient.getInstance().currentScreen instanceof ContainerScreen && ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) {
  481. ContainerScreen<?> containerScreen = (ContainerScreen<?>) MinecraftClient.getInstance().currentScreen;
  482. for (RecipeHelper.ScreenClickArea area : RecipeHelper.getInstance().getScreenClickAreas())
  483. if (area.getScreenClass().equals(MinecraftClient.getInstance().currentScreen.getClass()))
  484. if (area.getRectangle().contains(mouseX - containerScreen.x, mouseY - containerScreen.y)) {
  485. String collect = CollectionUtils.mapAndJoinToString(area.getCategories(), identifier -> RecipeHelper.getInstance().getCategory(identifier).getCategoryName(), ", ");
  486. TOOLTIPS.add(Tooltip.create(new TranslatableText("text.rei.view_recipes_for", collect)));
  487. break;
  488. }
  489. }
  490. }
  491. public void lateRender(MatrixStack matrices, int mouseX, int mouseY, float delta) {
  492. if (ScreenHelper.isOverlayVisible()) {
  493. ScreenHelper.getSearchField().laterRender(matrices, mouseX, mouseY, delta);
  494. for (Widget widget : widgets) {
  495. if (widget instanceof LateRenderable && wrappedSubsetsMenu != widget && wrappedWeatherMenu != widget && wrappedGameModeMenu != widget)
  496. widget.render(matrices, mouseX, mouseY, delta);
  497. }
  498. }
  499. if (wrappedWeatherMenu != null) {
  500. if (wrappedWeatherMenu.containsMouse(mouseX, mouseY)) {
  501. TOOLTIPS.clear();
  502. }
  503. wrappedWeatherMenu.render(matrices, mouseX, mouseY, delta);
  504. } else if (wrappedGameModeMenu != null) {
  505. if (wrappedGameModeMenu.containsMouse(mouseX, mouseY)) {
  506. TOOLTIPS.clear();
  507. }
  508. wrappedGameModeMenu.render(matrices, mouseX, mouseY, delta);
  509. }
  510. if (wrappedSubsetsMenu != null) {
  511. TOOLTIPS.clear();
  512. wrappedSubsetsMenu.render(matrices, mouseX, mouseY, delta);
  513. }
  514. Screen currentScreen = MinecraftClient.getInstance().currentScreen;
  515. if (!(currentScreen instanceof RecipeViewingScreen) || !((RecipeViewingScreen) currentScreen).choosePageActivated)
  516. for (Tooltip tooltip : TOOLTIPS) {
  517. if (tooltip != null)
  518. renderTooltip(matrices, tooltip);
  519. }
  520. for (Runnable runnable : AFTER_RENDER) {
  521. runnable.run();
  522. }
  523. TOOLTIPS.clear();
  524. AFTER_RENDER.clear();
  525. }
  526. public void renderTooltip(MatrixStack matrices, Tooltip tooltip) {
  527. renderTooltip(matrices, tooltip.getText(), tooltip.getX(), tooltip.getY());
  528. }
  529. public void renderTooltip(MatrixStack matrices, List<Text> lines, int mouseX, int mouseY) {
  530. if (lines.isEmpty())
  531. return;
  532. tooltipWidth = lines.stream().map(font::getWidth).max(Integer::compareTo).get();
  533. tooltipHeight = lines.size() <= 1 ? 8 : lines.size() * 10;
  534. tooltipLines = lines;
  535. ScreenHelper.drawHoveringWidget(matrices, mouseX, mouseY, renderTooltipCallback, tooltipWidth, tooltipHeight, 0);
  536. }
  537. private boolean hasSameListContent(List<ItemStack> list1, List<ItemStack> list2) {
  538. list1.sort(Comparator.comparing(Object::toString));
  539. list2.sort(Comparator.comparing(Object::toString));
  540. return CollectionUtils.mapAndJoinToString(list1, Object::toString, "").equals(CollectionUtils.mapAndJoinToString(list2, Object::toString, ""));
  541. }
  542. public void addTooltip(@Nullable Tooltip tooltip) {
  543. if (tooltip != null)
  544. TOOLTIPS.add(tooltip);
  545. }
  546. public void renderWidgets(MatrixStack matrices, int mouseX, int mouseY, float delta) {
  547. if (!ScreenHelper.isOverlayVisible())
  548. return;
  549. if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  550. leftButton.setEnabled(ENTRY_LIST_WIDGET.getTotalPages() > 1);
  551. rightButton.setEnabled(ENTRY_LIST_WIDGET.getTotalPages() > 1);
  552. }
  553. for (Widget widget : widgets) {
  554. if (!(widget instanceof LateRenderable))
  555. widget.render(matrices, mouseX, mouseY, delta);
  556. }
  557. }
  558. @Override
  559. public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
  560. if (!ScreenHelper.isOverlayVisible())
  561. return false;
  562. if (wrappedSubsetsMenu != null && wrappedSubsetsMenu.mouseScrolled(mouseX, mouseY, amount))
  563. return true;
  564. if (wrappedWeatherMenu != null && wrappedWeatherMenu.mouseScrolled(mouseX, mouseY, amount))
  565. return true;
  566. if (wrappedGameModeMenu != null && wrappedGameModeMenu.mouseScrolled(mouseX, mouseY, amount))
  567. return true;
  568. if (isInside(PointHelper.ofMouse())) {
  569. if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  570. if (amount > 0 && leftButton.isEnabled())
  571. leftButton.onClick();
  572. else if (amount < 0 && rightButton.isEnabled())
  573. rightButton.onClick();
  574. else
  575. return false;
  576. return true;
  577. } else if (ENTRY_LIST_WIDGET.mouseScrolled(mouseX, mouseY, amount))
  578. return true;
  579. }
  580. if (isNotInExclusionZones(PointHelper.getMouseX(), PointHelper.getMouseY())) {
  581. if (favoritesListWidget != null && favoritesListWidget.mouseScrolled(mouseX, mouseY, amount))
  582. return true;
  583. }
  584. for (Widget widget : widgets)
  585. if (widget != ENTRY_LIST_WIDGET && (favoritesListWidget == null || widget != favoritesListWidget)
  586. && (wrappedSubsetsMenu == null || widget != wrappedSubsetsMenu)
  587. && (wrappedWeatherMenu == null || widget != wrappedWeatherMenu)
  588. && (wrappedGameModeMenu == null || widget != wrappedGameModeMenu)
  589. && widget.mouseScrolled(mouseX, mouseY, amount))
  590. return true;
  591. return false;
  592. }
  593. @Override
  594. public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
  595. if (ScreenHelper.isOverlayVisible()) {
  596. if (ScreenHelper.getSearchField().keyPressed(keyCode, scanCode, modifiers))
  597. return true;
  598. for (Element listener : widgets)
  599. if (listener != ScreenHelper.getSearchField() && listener.keyPressed(keyCode, scanCode, modifiers))
  600. return true;
  601. }
  602. if (ConfigObject.getInstance().getHideKeybind().matchesKey(keyCode, scanCode)) {
  603. ScreenHelper.toggleOverlayVisible();
  604. return true;
  605. }
  606. ItemStack itemStack = null;
  607. if (MinecraftClient.getInstance().currentScreen instanceof ContainerScreen) {
  608. ContainerScreen<?> containerScreen = (ContainerScreen<?>) MinecraftClient.getInstance().currentScreen;
  609. if (containerScreen.focusedSlot != null && !containerScreen.focusedSlot.getStack().isEmpty())
  610. itemStack = containerScreen.focusedSlot.getStack();
  611. }
  612. if (itemStack != null && !itemStack.isEmpty()) {
  613. EntryStack stack = EntryStack.create(itemStack.copy());
  614. if (ConfigObject.getInstance().getRecipeKeybind().matchesKey(keyCode, scanCode)) {
  615. return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addRecipesFor(stack).setOutputNotice(stack).fillPreferredOpenedCategory());
  616. } else if (ConfigObject.getInstance().getUsageKeybind().matchesKey(keyCode, scanCode)) {
  617. return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addUsagesFor(stack).setInputNotice(stack).fillPreferredOpenedCategory());
  618. } else if (ConfigObject.getInstance().getFavoriteKeyCode().matchesKey(keyCode, scanCode)) {
  619. stack.setAmount(127);
  620. if (!CollectionUtils.anyMatchEqualsEntryIgnoreAmount(ConfigObject.getInstance().getFavorites(), stack))
  621. ConfigObject.getInstance().getFavorites().add(stack);
  622. ConfigManager.getInstance().saveConfig();
  623. FavoritesListWidget favoritesListWidget = ContainerScreenOverlay.getFavoritesListWidget();
  624. if (favoritesListWidget != null)
  625. favoritesListWidget.updateSearch(ContainerScreenOverlay.getEntryListWidget(), ScreenHelper.getSearchField().getText());
  626. return true;
  627. }
  628. }
  629. if (!ScreenHelper.isOverlayVisible())
  630. return false;
  631. if (ConfigObject.getInstance().getFocusSearchFieldKeybind().matchesKey(keyCode, scanCode)) {
  632. ScreenHelper.getSearchField().setFocused(true);
  633. setFocused(ScreenHelper.getSearchField());
  634. ScreenHelper.getSearchField().keybindFocusTime = System.currentTimeMillis();
  635. ScreenHelper.getSearchField().keybindFocusKey = keyCode;
  636. return true;
  637. }
  638. return false;
  639. }
  640. @Override
  641. public boolean charTyped(char char_1, int int_1) {
  642. if (!ScreenHelper.isOverlayVisible())
  643. return false;
  644. if (ScreenHelper.getSearchField().charTyped(char_1, int_1))
  645. return true;
  646. for (Element listener : widgets)
  647. if (listener != ScreenHelper.getSearchField() && listener.charTyped(char_1, int_1))
  648. return true;
  649. return false;
  650. }
  651. @Override
  652. public List<Widget> children() {
  653. return widgets;
  654. }
  655. @Override
  656. public boolean mouseClicked(double double_1, double double_2, int int_1) {
  657. if (!ScreenHelper.isOverlayVisible())
  658. return false;
  659. if (wrappedSubsetsMenu != null && wrappedSubsetsMenu.mouseClicked(double_1, double_2, int_1)) {
  660. this.setFocused(wrappedSubsetsMenu);
  661. if (int_1 == 0)
  662. this.setDragging(true);
  663. ScreenHelper.getSearchField().setFocused(false);
  664. return true;
  665. }
  666. if (wrappedWeatherMenu != null) {
  667. if (wrappedWeatherMenu.mouseClicked(double_1, double_2, int_1)) {
  668. this.setFocused(wrappedWeatherMenu);
  669. if (int_1 == 0)
  670. this.setDragging(true);
  671. ScreenHelper.getSearchField().setFocused(false);
  672. return true;
  673. } else if (!wrappedWeatherMenu.containsMouse(double_1, double_2) && !weatherButton.containsMouse(double_1, double_2)) {
  674. removeWeatherMenu();
  675. }
  676. }
  677. if (wrappedGameModeMenu != null) {
  678. if (wrappedGameModeMenu.mouseClicked(double_1, double_2, int_1)) {
  679. this.setFocused(wrappedGameModeMenu);
  680. if (int_1 == 0)
  681. this.setDragging(true);
  682. ScreenHelper.getSearchField().setFocused(false);
  683. return true;
  684. } else if (!wrappedGameModeMenu.containsMouse(double_1, double_2) && !gameModeButton.containsMouse(double_1, double_2)) {
  685. removeGameModeMenu();
  686. }
  687. }
  688. if (MinecraftClient.getInstance().currentScreen instanceof ContainerScreen && ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) {
  689. ContainerScreen<?> containerScreen = (ContainerScreen<?>) MinecraftClient.getInstance().currentScreen;
  690. for (RecipeHelper.ScreenClickArea area : RecipeHelper.getInstance().getScreenClickAreas())
  691. if (area.getScreenClass().equals(containerScreen.getClass()))
  692. if (area.getRectangle().contains(double_1 - containerScreen.x, double_2 - containerScreen.y)) {
  693. ClientHelper.getInstance().executeViewAllRecipesFromCategories(Arrays.asList(area.getCategories()));
  694. MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
  695. return true;
  696. }
  697. }
  698. for (Element element : widgets)
  699. if (element != wrappedSubsetsMenu && element != wrappedWeatherMenu && element != wrappedGameModeMenu && element.mouseClicked(double_1, double_2, int_1)) {
  700. this.setFocused(element);
  701. if (int_1 == 0)
  702. this.setDragging(true);
  703. if (!(element instanceof OverlaySearchField))
  704. ScreenHelper.getSearchField().setFocused(false);
  705. return true;
  706. }
  707. return false;
  708. }
  709. @Override
  710. public boolean mouseDragged(double double_1, double double_2, int int_1, double double_3, double double_4) {
  711. if (!ScreenHelper.isOverlayVisible())
  712. return false;
  713. return (this.getFocused() != null && this.isDragging() && int_1 == 0) && this.getFocused().mouseDragged(double_1, double_2, int_1, double_3, double_4);
  714. }
  715. public boolean isInside(double mouseX, double mouseY) {
  716. return bounds.contains(mouseX, mouseY) && isNotInExclusionZones(mouseX, mouseY);
  717. }
  718. public boolean isNotInExclusionZones(double mouseX, double mouseY) {
  719. for (DisplayHelper.DisplayBoundsHandler<?> handler : DisplayHelper.getInstance().getSortedBoundsHandlers(MinecraftClient.getInstance().currentScreen.getClass())) {
  720. ActionResult in = handler.isInZone(mouseX, mouseY);
  721. if (in != ActionResult.PASS)
  722. return in == ActionResult.SUCCESS;
  723. }
  724. return true;
  725. }
  726. public boolean isInside(Point point) {
  727. return isInside(point.getX(), point.getY());
  728. }
  729. }