ContainerScreenOverlay.java 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  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.platform.Window;
  26. import com.mojang.blaze3d.systems.RenderSystem;
  27. import com.mojang.blaze3d.vertex.PoseStack;
  28. import com.mojang.blaze3d.vertex.Tesselator;
  29. import com.mojang.math.Matrix4f;
  30. import com.mojang.math.Vector4f;
  31. import me.shedaniel.math.Point;
  32. import me.shedaniel.math.Rectangle;
  33. import me.shedaniel.math.impl.PointHelper;
  34. import me.shedaniel.rei.RoughlyEnoughItemsCore;
  35. import me.shedaniel.rei.api.*;
  36. import me.shedaniel.rei.api.favorites.FavoriteEntry;
  37. import me.shedaniel.rei.api.widgets.Button;
  38. import me.shedaniel.rei.api.widgets.Tooltip;
  39. import me.shedaniel.rei.api.widgets.Widgets;
  40. import me.shedaniel.rei.gui.config.SearchFieldLocation;
  41. import me.shedaniel.rei.gui.modules.Menu;
  42. import me.shedaniel.rei.gui.modules.entries.GameModeMenuEntry;
  43. import me.shedaniel.rei.gui.modules.entries.WeatherMenuEntry;
  44. import me.shedaniel.rei.gui.widget.*;
  45. import me.shedaniel.rei.impl.*;
  46. import me.shedaniel.rei.utils.CollectionUtils;
  47. import net.minecraft.client.Minecraft;
  48. import net.minecraft.client.gui.chat.NarratorChatListener;
  49. import net.minecraft.client.gui.components.events.GuiEventListener;
  50. import net.minecraft.client.gui.screens.Screen;
  51. import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
  52. import net.minecraft.client.multiplayer.ClientLevel;
  53. import net.minecraft.client.renderer.MultiBufferSource;
  54. import net.minecraft.client.renderer.entity.ItemRenderer;
  55. import net.minecraft.client.resources.language.I18n;
  56. import net.minecraft.client.resources.sounds.SimpleSoundInstance;
  57. import net.minecraft.network.chat.Component;
  58. import net.minecraft.network.chat.TextComponent;
  59. import net.minecraft.network.chat.TranslatableComponent;
  60. import net.minecraft.resources.ResourceLocation;
  61. import net.minecraft.sounds.SoundEvents;
  62. import net.minecraft.util.FormattedCharSequence;
  63. import net.minecraft.world.InteractionResult;
  64. import net.minecraft.world.inventory.Slot;
  65. import net.minecraft.world.item.ItemStack;
  66. import net.minecraft.world.level.GameType;
  67. import net.minecraft.world.level.block.Blocks;
  68. import org.apache.logging.log4j.util.TriConsumer;
  69. import org.jetbrains.annotations.ApiStatus;
  70. import org.jetbrains.annotations.NotNull;
  71. import org.jetbrains.annotations.Nullable;
  72. import java.util.*;
  73. import java.util.function.Consumer;
  74. import java.util.function.Predicate;
  75. import java.util.stream.Collectors;
  76. @ApiStatus.Internal
  77. public class ContainerScreenOverlay extends WidgetWithBounds implements REIOverlay {
  78. private static final ResourceLocation CHEST_GUI_TEXTURE = new ResourceLocation("roughlyenoughitems", "textures/gui/recipecontainer.png");
  79. private static final List<Tooltip> TOOLTIPS = Lists.newArrayList();
  80. private static final List<Runnable> AFTER_RENDER = Lists.newArrayList();
  81. private static final EntryListWidget ENTRY_LIST_WIDGET = new EntryListWidget();
  82. private static FavoritesListWidget favoritesListWidget = null;
  83. private final List<Widget> widgets = Lists.newLinkedList();
  84. public boolean shouldReInit = false;
  85. private int tooltipWidth;
  86. private int tooltipHeight;
  87. private List<FormattedCharSequence> tooltipLines;
  88. private Rectangle bounds;
  89. private Window window;
  90. private Button leftButton, rightButton;
  91. @ApiStatus.Experimental
  92. private Rectangle subsetsButtonBounds;
  93. @Nullable
  94. private ContainerScreenOverlay.OverlayMenu overlayMenu = null;
  95. public static EntryListWidget getEntryListWidget() {
  96. return ENTRY_LIST_WIDGET;
  97. }
  98. @Nullable
  99. public static FavoritesListWidget getFavoritesListWidget() {
  100. return favoritesListWidget;
  101. }
  102. private static class OverlayMenu {
  103. @NotNull
  104. private UUID uuid;
  105. @NotNull
  106. private Menu menu;
  107. @NotNull
  108. private Widget wrappedMenu;
  109. @NotNull
  110. private Predicate<Point> inBounds;
  111. public OverlayMenu(@NotNull UUID uuid, @NotNull Menu menu, @NotNull Widget wrappedMenu, @NotNull Predicate<Point> inBounds) {
  112. this.uuid = uuid;
  113. this.menu = menu;
  114. this.wrappedMenu = wrappedMenu;
  115. this.inBounds = inBounds.or(point -> menu.getBounds().contains(point));
  116. }
  117. }
  118. public boolean isMenuOpened(UUID uuid) {
  119. return overlayMenu != null && overlayMenu.uuid.equals(uuid);
  120. }
  121. public boolean isAnyMenuOpened() {
  122. return overlayMenu != null;
  123. }
  124. public boolean isMenuInBounds(UUID uuid) {
  125. return isMenuOpened(uuid) && overlayMenu.inBounds.test(PointHelper.ofMouse());
  126. }
  127. private void proceedOpenMenu(UUID uuid, Runnable runnable) {
  128. proceedOpenMenuOrElse(uuid, runnable, menu -> {});
  129. }
  130. private void proceedOpenMenuOrElse(UUID uuid, Runnable runnable, Consumer<OverlayMenu> orElse) {
  131. if (overlayMenu == null || !overlayMenu.uuid.equals(uuid)) {
  132. removeOverlayMenu();
  133. runnable.run();
  134. } else {
  135. orElse.accept(this.overlayMenu);
  136. }
  137. }
  138. public void openMenu(UUID uuid, Menu menu, Predicate<Point> inPoint) {
  139. this.overlayMenu = new OverlayMenu(uuid, menu, InternalWidgets.wrapTranslate(menu, 0, 0, 400), inPoint);
  140. }
  141. @ApiStatus.Internal
  142. @Nullable
  143. public Menu getSubsetsMenu() {
  144. if (isMenuOpened(Menu.SUBSETS))
  145. return this.overlayMenu.menu;
  146. throw new IllegalStateException("Subsets menu accessed when subsets are not opened!");
  147. }
  148. @ApiStatus.Internal
  149. public void removeOverlayMenu() {
  150. OverlayMenu tmpOverlayMenu = this.overlayMenu;
  151. if (tmpOverlayMenu != null)
  152. AFTER_RENDER.add(() -> this.widgets.remove(tmpOverlayMenu.wrappedMenu));
  153. this.overlayMenu = null;
  154. }
  155. @Override
  156. public void queueReloadOverlay() {
  157. shouldReInit = true;
  158. }
  159. public void init(boolean useless) {
  160. init();
  161. }
  162. public void init() {
  163. this.shouldReInit = false;
  164. //Update Variables
  165. this.children().clear();
  166. this.removeOverlayMenu();
  167. this.window = Minecraft.getInstance().getWindow();
  168. this.bounds = DisplayHelper.getInstance().getOverlayBounds(ConfigObject.getInstance().getDisplayPanelLocation(), Minecraft.getInstance().screen);
  169. widgets.add(ENTRY_LIST_WIDGET);
  170. if (ConfigObject.getInstance().isFavoritesEnabled()) {
  171. if (favoritesListWidget == null)
  172. favoritesListWidget = new FavoritesListWidget();
  173. // favoritesListWidget.favoritePanel.resetRows();
  174. widgets.add(favoritesListWidget);
  175. }
  176. ENTRY_LIST_WIDGET.updateArea(ScreenHelper.getSearchField() == null ? "" : ScreenHelper.getSearchField().getText());
  177. if (ScreenHelper.getSearchField() == null) {
  178. ScreenHelper.setSearchField(new OverlaySearchField(0, 0, 0, 0));
  179. }
  180. ScreenHelper.getSearchField().getBounds().setBounds(getSearchFieldArea());
  181. this.widgets.add(ScreenHelper.getSearchField());
  182. ScreenHelper.getSearchField().setChangedListener(s -> ENTRY_LIST_WIDGET.updateSearch(s, false));
  183. if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  184. widgets.add(leftButton = Widgets.createButton(new Rectangle(bounds.x, bounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 5, 16, 16), new TranslatableComponent("text.rei.left_arrow"))
  185. .onClick(button -> {
  186. ENTRY_LIST_WIDGET.previousPage();
  187. if (ENTRY_LIST_WIDGET.getPage() < 0)
  188. ENTRY_LIST_WIDGET.setPage(ENTRY_LIST_WIDGET.getTotalPages() - 1);
  189. ENTRY_LIST_WIDGET.updateEntriesPosition();
  190. })
  191. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y))
  192. .tooltipLine(I18n.get("text.rei.previous_page"))
  193. .focusable(false));
  194. 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 TranslatableComponent("text.rei.right_arrow"))
  195. .onClick(button -> {
  196. ENTRY_LIST_WIDGET.nextPage();
  197. if (ENTRY_LIST_WIDGET.getPage() >= ENTRY_LIST_WIDGET.getTotalPages())
  198. ENTRY_LIST_WIDGET.setPage(0);
  199. ENTRY_LIST_WIDGET.updateEntriesPosition();
  200. })
  201. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y))
  202. .tooltipLine(I18n.get("text.rei.next_page"))
  203. .focusable(false));
  204. }
  205. final Rectangle configButtonArea = getConfigButtonArea();
  206. Widget tmp;
  207. widgets.add(tmp = InternalWidgets.wrapLateRenderable(InternalWidgets.mergeWidgets(
  208. Widgets.createButton(configButtonArea, NarratorChatListener.NO_TITLE)
  209. .onClick(button -> {
  210. if (Screen.hasShiftDown() || Screen.hasControlDown()) {
  211. ClientHelper.getInstance().setCheating(!ClientHelper.getInstance().isCheating());
  212. return;
  213. }
  214. ConfigManager.getInstance().openConfigScreen(REIHelper.getInstance().getPreviousContainerScreen());
  215. })
  216. .onRender((matrices, button) -> {
  217. if (ClientHelper.getInstance().isCheating() && RoughlyEnoughItemsCore.hasOperatorPermission()) {
  218. button.setTint(RoughlyEnoughItemsCore.hasPermissionToUsePackets() ? 721354752 : 1476440063);
  219. } else {
  220. button.removeTint();
  221. }
  222. })
  223. .focusable(false)
  224. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y))
  225. .tooltipSupplier(button -> {
  226. String tooltips = I18n.get("text.rei.config_tooltip");
  227. tooltips += "\n ";
  228. if (!ClientHelper.getInstance().isCheating())
  229. tooltips += "\n" + I18n.get("text.rei.cheating_disabled");
  230. else if (!RoughlyEnoughItemsCore.hasOperatorPermission()) {
  231. if (minecraft.gameMode.hasInfiniteItems())
  232. tooltips += "\n" + I18n.get("text.rei.cheating_limited_creative_enabled");
  233. else tooltips += "\n" + I18n.get("text.rei.cheating_enabled_no_perms");
  234. } else if (RoughlyEnoughItemsCore.hasPermissionToUsePackets())
  235. tooltips += "\n" + I18n.get("text.rei.cheating_enabled");
  236. else
  237. tooltips += "\n" + I18n.get("text.rei.cheating_limited_enabled");
  238. return tooltips;
  239. }),
  240. Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> {
  241. helper.setBlitOffset(helper.getBlitOffset() + 1);
  242. Minecraft.getInstance().getTextureManager().bind(CHEST_GUI_TEXTURE);
  243. helper.blit(matrices, configButtonArea.x + 3, configButtonArea.y + 3, 0, 0, 14, 14);
  244. })
  245. )
  246. ));
  247. tmp.setZ(600);
  248. if (ConfigObject.getInstance().doesShowUtilsButtons()) {
  249. widgets.add(Widgets.createButton(ConfigObject.getInstance().isLowerConfigButton() ? new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getGuiScaledWidth() - 30 : 10, 10, 20, 20) : new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getGuiScaledWidth() - 55 : 35, 10, 20, 20), NarratorChatListener.NO_TITLE)
  250. .onRender((matrices, button) -> {
  251. boolean isOpened = isMenuOpened(Menu.GAME_TYPE);
  252. if (isOpened || !isAnyMenuOpened()) {
  253. boolean inBounds = (button.isFocused() || button.containsMouse(PointHelper.ofMouse())) || isMenuInBounds(Menu.GAME_TYPE);
  254. if (isOpened != inBounds) {
  255. if (inBounds) {
  256. Menu menu = new Menu(new Point(button.getBounds().x, button.getBounds().getMaxY()),
  257. CollectionUtils.filterAndMap(Arrays.asList(GameType.values()), mode -> mode != GameType.NOT_SET, GameModeMenuEntry::new));
  258. if (ConfigObject.getInstance().isLeftHandSidePanel())
  259. menu.menuStartPoint.x -= menu.getBounds().width - button.getBounds().width;
  260. openMenu(Menu.GAME_TYPE, menu, point -> button.isFocused() && button.containsMouse(PointHelper.ofMouse()));
  261. } else {
  262. removeOverlayMenu();
  263. }
  264. }
  265. }
  266. button.setText(new TextComponent(getGameModeShortText(getCurrentGameMode())));
  267. })
  268. .focusable(false)
  269. .tooltipLine(I18n.get("text.rei.gamemode_button.tooltip.all"))
  270. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y)));
  271. Button weatherButton;
  272. widgets.add(weatherButton = Widgets.createButton(new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getGuiScaledWidth() - 30 : 10, 35, 20, 20), NarratorChatListener.NO_TITLE)
  273. .onRender((matrices, button) -> {
  274. boolean isOpened = isMenuOpened(Menu.WEATHER);
  275. if (isOpened || !isAnyMenuOpened()) {
  276. boolean inBounds = (button.isFocused() || button.containsMouse(PointHelper.ofMouse())) || isMenuInBounds(Menu.WEATHER);
  277. if (isOpened != inBounds) {
  278. if (inBounds) {
  279. Menu menu = new Menu(new Point(button.getBounds().x, button.getBounds().getMaxY()),
  280. CollectionUtils.map(Weather.values(), WeatherMenuEntry::new));
  281. if (ConfigObject.getInstance().isLeftHandSidePanel())
  282. menu.menuStartPoint.x -= menu.getBounds().width - button.getBounds().width;
  283. openMenu(Menu.WEATHER, menu, point -> button.isFocused() && button.containsMouse(PointHelper.ofMouse()));
  284. } else {
  285. removeOverlayMenu();
  286. }
  287. }
  288. }
  289. })
  290. .tooltipLine(I18n.get("text.rei.weather_button.tooltip.all"))
  291. .focusable(false)
  292. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y)));
  293. widgets.add(Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> {
  294. Minecraft.getInstance().getTextureManager().bind(CHEST_GUI_TEXTURE);
  295. RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
  296. helper.blit(matrices, weatherButton.getBounds().x + 3, weatherButton.getBounds().y + 3, getCurrentWeather().getId() * 14, 14, 14, 14);
  297. }));
  298. }
  299. subsetsButtonBounds = getSubsetsButtonBounds();
  300. if (ConfigObject.getInstance().isSubsetsEnabled()) {
  301. widgets.add(InternalWidgets.wrapLateRenderable(InternalWidgets.wrapTranslate(Widgets.createButton(subsetsButtonBounds, ClientHelperImpl.getInstance().isAprilFools.get() ? new TranslatableComponent("text.rei.tiny_potato") : new TranslatableComponent("text.rei.subsets"))
  302. .onClick(button -> {
  303. proceedOpenMenuOrElse(Menu.SUBSETS, () -> {
  304. openMenu(Menu.SUBSETS, Menu.createSubsetsMenuFromRegistry(new Point(this.subsetsButtonBounds.x, this.subsetsButtonBounds.getMaxY())), point -> true);
  305. }, menu -> {
  306. removeOverlayMenu();
  307. });
  308. }), 0, 0, 600)));
  309. }
  310. if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  311. widgets.add(Widgets.createClickableLabel(new Point(bounds.x + (bounds.width / 2), bounds.y + (ConfigObject.getInstance().getSearchFieldLocation() == SearchFieldLocation.TOP_SIDE ? 24 : 0) + 10), NarratorChatListener.NO_TITLE, label -> {
  312. ENTRY_LIST_WIDGET.setPage(0);
  313. ENTRY_LIST_WIDGET.updateEntriesPosition();
  314. }).tooltipLine(I18n.get("text.rei.go_back_first_page")).focusable(false).onRender((matrices, label) -> {
  315. label.setClickable(ENTRY_LIST_WIDGET.getTotalPages() > 1);
  316. label.setText(new TextComponent(String.format("%s/%s", ENTRY_LIST_WIDGET.getPage() + 1, Math.max(ENTRY_LIST_WIDGET.getTotalPages(), 1))));
  317. }).rainbow(new Random().nextFloat() < 1.0E-4D || ClientHelperImpl.getInstance().isAprilFools.get()));
  318. }
  319. if (ConfigObject.getInstance().isCraftableFilterEnabled()) {
  320. Rectangle area = getCraftableToggleArea();
  321. ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
  322. ItemStack icon = new ItemStack(Blocks.CRAFTING_TABLE);
  323. this.widgets.add(tmp = InternalWidgets.wrapLateRenderable(InternalWidgets.mergeWidgets(
  324. Widgets.createButton(area, NarratorChatListener.NO_TITLE)
  325. .focusable(false)
  326. .onClick(button -> {
  327. ConfigManager.getInstance().toggleCraftableOnly();
  328. ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
  329. })
  330. .onRender((matrices, button) -> button.setTint(ConfigManager.getInstance().isCraftableOnlyEnabled() ? 939579655 : 956235776))
  331. .containsMousePredicate((button, point) -> button.getBounds().contains(point) && isNotInExclusionZones(point.x, point.y))
  332. .tooltipSupplier(button -> I18n.get(ConfigManager.getInstance().isCraftableOnlyEnabled() ? "text.rei.showing_craftable" : "text.rei.showing_all")),
  333. Widgets.createDrawableWidget((helper, matrices, mouseX, mouseY, delta) -> {
  334. Vector4f vector = new Vector4f(area.x + 2, area.y + 2, helper.getBlitOffset() - 10, 1.0F);
  335. vector.transform(matrices.last().pose());
  336. itemRenderer.blitOffset = vector.z();
  337. itemRenderer.renderGuiItem(icon, (int) vector.x(), (int) vector.y());
  338. itemRenderer.blitOffset = 0.0F;
  339. }))
  340. ));
  341. tmp.setZ(600);
  342. }
  343. }
  344. private Rectangle getSubsetsButtonBounds() {
  345. if (ConfigObject.getInstance().isSubsetsEnabled()) {
  346. if (Minecraft.getInstance().screen instanceof RecipeViewingScreen) {
  347. RecipeViewingScreen widget = (RecipeViewingScreen) Minecraft.getInstance().screen;
  348. return new Rectangle(widget.getBounds().x, 3, widget.getBounds().width, 18);
  349. }
  350. if (Minecraft.getInstance().screen instanceof VillagerRecipeViewingScreen) {
  351. VillagerRecipeViewingScreen widget = (VillagerRecipeViewingScreen) Minecraft.getInstance().screen;
  352. return new Rectangle(widget.bounds.x, 3, widget.bounds.width, 18);
  353. }
  354. AbstractContainerScreen<?> containerScreen = REIHelper.getInstance().getPreviousContainerScreen();
  355. if (containerScreen != null)
  356. return new Rectangle(containerScreen.leftPos, 3, containerScreen.imageWidth, 18);
  357. }
  358. return null;
  359. }
  360. private Weather getNextWeather() {
  361. try {
  362. Weather current = getCurrentWeather();
  363. int next = current.getId() + 1;
  364. if (next >= 3)
  365. next = 0;
  366. return Weather.byId(next);
  367. } catch (Exception e) {
  368. return Weather.CLEAR;
  369. }
  370. }
  371. private Weather getCurrentWeather() {
  372. ClientLevel world = Minecraft.getInstance().level;
  373. if (world.isThundering())
  374. return Weather.THUNDER;
  375. if (world.getLevelData().isRaining())
  376. return Weather.RAIN;
  377. return Weather.CLEAR;
  378. }
  379. private String getGameModeShortText(GameType gameMode) {
  380. return I18n.get("text.rei.short_gamemode." + gameMode.getName());
  381. }
  382. private String getGameModeText(GameType gameMode) {
  383. return I18n.get("selectWorld.gameMode." + gameMode.getName());
  384. }
  385. private GameType getNextGameMode(boolean reverse) {
  386. try {
  387. GameType current = getCurrentGameMode();
  388. int next = current.getId() + 1;
  389. if (reverse)
  390. next -= 2;
  391. if (next > 3)
  392. next = 0;
  393. if (next < 0)
  394. next = 3;
  395. return GameType.byId(next);
  396. } catch (Exception e) {
  397. return GameType.NOT_SET;
  398. }
  399. }
  400. private GameType getCurrentGameMode() {
  401. return Minecraft.getInstance().getConnection().getPlayerInfo(Minecraft.getInstance().player.getGameProfile().getId()).getGameMode();
  402. }
  403. private Rectangle getSearchFieldArea() {
  404. int widthRemoved = 1;
  405. if (ConfigObject.getInstance().isCraftableFilterEnabled()) widthRemoved += 22;
  406. if (ConfigObject.getInstance().isLowerConfigButton()) widthRemoved += 22;
  407. SearchFieldLocation searchFieldLocation = ScreenHelper.getContextualSearchFieldLocation();
  408. switch (searchFieldLocation) {
  409. case TOP_SIDE:
  410. return getTopSideSearchFieldArea(widthRemoved);
  411. case BOTTOM_SIDE:
  412. return getBottomSideSearchFieldArea(widthRemoved);
  413. default:
  414. case CENTER: {
  415. for (OverlayDecider decider : DisplayHelper.getInstance().getSortedOverlayDeciders(Minecraft.getInstance().screen.getClass())) {
  416. if (decider instanceof DisplayHelper.DisplayBoundsProvider) {
  417. Rectangle containerBounds = ((DisplayHelper.DisplayBoundsProvider<Screen>) decider).getScreenBounds(Minecraft.getInstance().screen);
  418. return getBottomCenterSearchFieldArea(containerBounds, widthRemoved);
  419. }
  420. }
  421. return new Rectangle();
  422. }
  423. }
  424. }
  425. private Rectangle getTopSideSearchFieldArea(int widthRemoved) {
  426. return new Rectangle(bounds.x + 2, 4, bounds.width - 6 - widthRemoved, 18);
  427. }
  428. private Rectangle getBottomSideSearchFieldArea(int widthRemoved) {
  429. return new Rectangle(bounds.x + 2, window.getGuiScaledHeight() - 22, bounds.width - 6 - widthRemoved, 18);
  430. }
  431. private Rectangle getBottomCenterSearchFieldArea(Rectangle containerBounds, int widthRemoved) {
  432. return new Rectangle(containerBounds.x, window.getGuiScaledHeight() - 22, containerBounds.width - widthRemoved, 18);
  433. }
  434. private Rectangle getCraftableToggleArea() {
  435. Rectangle area = getSearchFieldArea();
  436. area.setLocation(area.x + area.width + 4, area.y - 1);
  437. area.setSize(20, 20);
  438. return area;
  439. }
  440. private Rectangle getConfigButtonArea() {
  441. if (ConfigObject.getInstance().isLowerConfigButton()) {
  442. Rectangle area = getSearchFieldArea();
  443. area.setLocation(area.x + area.width + (ConfigObject.getInstance().isCraftableFilterEnabled() ? 26 : 4), area.y - 1);
  444. area.setSize(20, 20);
  445. return area;
  446. }
  447. return new Rectangle(ConfigObject.getInstance().isLeftHandSidePanel() ? window.getGuiScaledWidth() - 30 : 10, 10, 20, 20);
  448. }
  449. private String getCheatModeText() {
  450. return I18n.get(String.format("%s%s", "text.rei.", ClientHelper.getInstance().isCheating() ? "cheat" : "nocheat"));
  451. }
  452. @NotNull
  453. @Override
  454. public Rectangle getBounds() {
  455. return bounds;
  456. }
  457. @Override
  458. public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
  459. if (shouldReInit) {
  460. ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
  461. init();
  462. } else {
  463. for (OverlayDecider decider : DisplayHelper.getInstance().getSortedOverlayDeciders(minecraft.screen.getClass())) {
  464. if (decider != null && decider.shouldRecalculateArea(ConfigObject.getInstance().getDisplayPanelLocation(), bounds)) {
  465. init();
  466. break;
  467. }
  468. }
  469. }
  470. if (ConfigManager.getInstance().isCraftableOnlyEnabled()) {
  471. Set<EntryStack> currentStacks = ClientHelperImpl.getInstance()._getInventoryItemsTypes();
  472. if (!currentStacks.equals(ScreenHelper.inventoryStacks)) {
  473. ScreenHelper.inventoryStacks = currentStacks;
  474. ENTRY_LIST_WIDGET.updateSearch(ScreenHelper.getSearchField().getText(), true);
  475. }
  476. }
  477. if (OverlaySearchField.isHighlighting) {
  478. matrices.pushPose();
  479. matrices.translate(0, 0, 200f);
  480. if (Minecraft.getInstance().screen instanceof AbstractContainerScreen) {
  481. AbstractContainerScreen<?> containerScreen = (AbstractContainerScreen<?>) Minecraft.getInstance().screen;
  482. int x = containerScreen.leftPos, y = containerScreen.topPos;
  483. for (Slot slot : containerScreen.getMenu().slots)
  484. if (!slot.hasItem() || !ENTRY_LIST_WIDGET.canLastSearchTermsBeAppliedTo(EntryStack.create(slot.getItem())))
  485. fillGradient(matrices, x + slot.x, y + slot.y, x + slot.x + 16, y + slot.y + 16, -601874400, -601874400);
  486. }
  487. matrices.popPose();
  488. }
  489. RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
  490. this.renderWidgets(matrices, mouseX, mouseY, delta);
  491. if (ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) {
  492. List<ResourceLocation> categories = null;
  493. Screen screen = Minecraft.getInstance().screen;
  494. ClickAreaHandler.ClickAreaContext context = new ClickAreaHandler.ClickAreaContext<Screen>() {
  495. @Override
  496. public Screen getScreen() {
  497. return screen;
  498. }
  499. @Override
  500. public Point getMousePosition() {
  501. return new Point(mouseX, mouseY);
  502. }
  503. };
  504. for (Map.Entry<Class<? extends Screen>, ClickAreaHandler<?>> area : ((RecipeHelperImpl) RecipeHelper.getInstance()).getClickAreas().entries()) {
  505. if (area.getKey().equals(screen.getClass())) {
  506. ClickAreaHandler.Result result = area.getValue().handle(context);
  507. if (result.isSuccessful()) {
  508. if (categories == null) {
  509. categories = result.getCategories().collect(Collectors.toList());
  510. } else categories.addAll(result.getCategories().collect(Collectors.toList()));
  511. }
  512. }
  513. }
  514. if (categories != null && !categories.isEmpty()) {
  515. String collect = CollectionUtils.mapAndJoinToString(categories, identifier -> RecipeHelper.getInstance().getCategory(identifier).getCategoryName(), ", ");
  516. Tooltip.create(new TranslatableComponent("text.rei.view_recipes_for", collect)).queue();
  517. }
  518. }
  519. }
  520. public void lateRender(PoseStack matrices, int mouseX, int mouseY, float delta) {
  521. if (ScreenHelper.isOverlayVisible()) {
  522. ScreenHelper.getSearchField().laterRender(matrices, mouseX, mouseY, delta);
  523. for (Widget widget : widgets) {
  524. if (widget instanceof LateRenderable && (overlayMenu == null || overlayMenu.wrappedMenu != widget))
  525. widget.render(matrices, mouseX, mouseY, delta);
  526. }
  527. }
  528. if (overlayMenu != null) {
  529. if (overlayMenu.wrappedMenu.containsMouse(mouseX, mouseY)) {
  530. TOOLTIPS.clear();
  531. }
  532. overlayMenu.wrappedMenu.render(matrices, mouseX, mouseY, delta);
  533. }
  534. Screen currentScreen = Minecraft.getInstance().screen;
  535. if (!(currentScreen instanceof RecipeViewingScreen) || !((RecipeViewingScreen) currentScreen).choosePageActivated)
  536. for (Tooltip tooltip : TOOLTIPS) {
  537. if (tooltip != null)
  538. renderTooltip(matrices, tooltip);
  539. }
  540. for (Runnable runnable : AFTER_RENDER) {
  541. runnable.run();
  542. }
  543. TOOLTIPS.clear();
  544. AFTER_RENDER.clear();
  545. }
  546. public void renderTooltip(PoseStack matrices, Tooltip tooltip) {
  547. renderTooltip(matrices, tooltip.getText(), tooltip.getX(), tooltip.getY());
  548. }
  549. public void renderTooltip(PoseStack matrices, List<Component> lines, int mouseX, int mouseY) {
  550. if (lines.isEmpty())
  551. return;
  552. List<FormattedCharSequence> orderedTexts = CollectionUtils.map(lines, Component::getVisualOrderText);
  553. renderTooltipInner(matrices, orderedTexts, mouseX, mouseY);
  554. }
  555. public void renderTooltipInner(PoseStack matrices, List<FormattedCharSequence> lines, int mouseX, int mouseY) {
  556. if (lines.isEmpty())
  557. return;
  558. matrices.pushPose();
  559. matrices.translate(0, 0, 500);
  560. minecraft.screen.renderTooltip(matrices, lines, mouseX, mouseY);
  561. matrices.popPose();
  562. }
  563. public void addTooltip(@Nullable Tooltip tooltip) {
  564. if (tooltip != null)
  565. TOOLTIPS.add(tooltip);
  566. }
  567. public void renderWidgets(PoseStack matrices, int mouseX, int mouseY, float delta) {
  568. if (!ScreenHelper.isOverlayVisible())
  569. return;
  570. if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  571. leftButton.setEnabled(ENTRY_LIST_WIDGET.getTotalPages() > 1);
  572. rightButton.setEnabled(ENTRY_LIST_WIDGET.getTotalPages() > 1);
  573. }
  574. for (Widget widget : widgets) {
  575. if (!(widget instanceof LateRenderable))
  576. widget.render(matrices, mouseX, mouseY, delta);
  577. }
  578. }
  579. @Override
  580. public boolean mouseScrolled(double mouseX, double mouseY, double amount) {
  581. if (!ScreenHelper.isOverlayVisible())
  582. return false;
  583. if (overlayMenu != null && overlayMenu.wrappedMenu.mouseScrolled(mouseX, mouseY, amount))
  584. return true;
  585. if (isInside(PointHelper.ofMouse())) {
  586. if (ENTRY_LIST_WIDGET.mouseScrolled(mouseX, mouseY, amount)) {
  587. return true;
  588. }
  589. if (!Screen.hasControlDown() && !ConfigObject.getInstance().isEntryListWidgetScrolled()) {
  590. if (amount > 0 && leftButton.isEnabled())
  591. leftButton.onClick();
  592. else if (amount < 0 && rightButton.isEnabled())
  593. rightButton.onClick();
  594. else
  595. return false;
  596. return true;
  597. }
  598. }
  599. if (isNotInExclusionZones(PointHelper.getMouseX(), PointHelper.getMouseY())) {
  600. if (favoritesListWidget != null && favoritesListWidget.mouseScrolled(mouseX, mouseY, amount))
  601. return true;
  602. }
  603. for (Widget widget : widgets)
  604. if (widget != ENTRY_LIST_WIDGET && (favoritesListWidget == null || widget != favoritesListWidget)
  605. && (overlayMenu == null || widget != overlayMenu.wrappedMenu)
  606. && widget.mouseScrolled(mouseX, mouseY, amount))
  607. return true;
  608. return false;
  609. }
  610. @Override
  611. public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
  612. if (ScreenHelper.isOverlayVisible()) {
  613. if (ScreenHelper.getSearchField().keyPressed(keyCode, scanCode, modifiers))
  614. return true;
  615. for (GuiEventListener listener : widgets)
  616. if (listener != ScreenHelper.getSearchField() && listener.keyPressed(keyCode, scanCode, modifiers))
  617. return true;
  618. }
  619. if (ConfigObject.getInstance().getHideKeybind().matchesKey(keyCode, scanCode)) {
  620. ScreenHelper.toggleOverlayVisible();
  621. return true;
  622. }
  623. EntryStack stack = RecipeHelper.getInstance().getScreenFocusedStack(Minecraft.getInstance().screen);
  624. if (stack != null && !stack.isEmpty()) {
  625. stack = stack.copy();
  626. if (ConfigObject.getInstance().getRecipeKeybind().matchesKey(keyCode, scanCode)) {
  627. return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addRecipesFor(stack).setOutputNotice(stack).fillPreferredOpenedCategory());
  628. } else if (ConfigObject.getInstance().getUsageKeybind().matchesKey(keyCode, scanCode)) {
  629. return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addUsagesFor(stack).setInputNotice(stack).fillPreferredOpenedCategory());
  630. } else if (ConfigObject.getInstance().getFavoriteKeyCode().matchesKey(keyCode, scanCode)) {
  631. FavoriteEntry favoriteEntry = FavoriteEntry.fromEntryStack(stack);
  632. if (!ConfigObject.getInstance().getFavoriteEntries().contains(favoriteEntry))
  633. ConfigObject.getInstance().getFavoriteEntries().add(favoriteEntry);
  634. ConfigManager.getInstance().saveConfig();
  635. FavoritesListWidget favoritesListWidget = ContainerScreenOverlay.getFavoritesListWidget();
  636. if (favoritesListWidget != null)
  637. favoritesListWidget.updateSearch(ContainerScreenOverlay.getEntryListWidget(), ScreenHelper.getSearchField().getText());
  638. return true;
  639. }
  640. }
  641. if (!ScreenHelper.isOverlayVisible())
  642. return false;
  643. if (ConfigObject.getInstance().getFocusSearchFieldKeybind().matchesKey(keyCode, scanCode)) {
  644. ScreenHelper.getSearchField().setFocused(true);
  645. setFocused(ScreenHelper.getSearchField());
  646. ScreenHelper.getSearchField().keybindFocusTime = System.currentTimeMillis();
  647. ScreenHelper.getSearchField().keybindFocusKey = keyCode;
  648. return true;
  649. }
  650. return false;
  651. }
  652. @Override
  653. public boolean charTyped(char char_1, int int_1) {
  654. if (!ScreenHelper.isOverlayVisible())
  655. return false;
  656. if (ScreenHelper.getSearchField().charTyped(char_1, int_1))
  657. return true;
  658. for (GuiEventListener listener : widgets)
  659. if (listener != ScreenHelper.getSearchField() && listener.charTyped(char_1, int_1))
  660. return true;
  661. return false;
  662. }
  663. @Override
  664. public List<Widget> children() {
  665. return widgets;
  666. }
  667. @Override
  668. public boolean mouseClicked(double mouseX, double mouseY, int button) {
  669. if (ConfigObject.getInstance().getHideKeybind().matchesMouse(button)) {
  670. ScreenHelper.toggleOverlayVisible();
  671. return true;
  672. }
  673. EntryStack stack = RecipeHelper.getInstance().getScreenFocusedStack(Minecraft.getInstance().screen);
  674. if (stack != null && !stack.isEmpty()) {
  675. stack = stack.copy();
  676. if (ConfigObject.getInstance().getRecipeKeybind().matchesMouse(button)) {
  677. return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addRecipesFor(stack).setOutputNotice(stack).fillPreferredOpenedCategory());
  678. } else if (ConfigObject.getInstance().getUsageKeybind().matchesMouse(button)) {
  679. return ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addUsagesFor(stack).setInputNotice(stack).fillPreferredOpenedCategory());
  680. } else if (ConfigObject.getInstance().getFavoriteKeyCode().matchesMouse(button)) {
  681. FavoriteEntry favoriteEntry = FavoriteEntry.fromEntryStack(stack);
  682. if (!ConfigObject.getInstance().getFavoriteEntries().contains(favoriteEntry))
  683. ConfigObject.getInstance().getFavoriteEntries().add(favoriteEntry);
  684. ConfigManager.getInstance().saveConfig();
  685. FavoritesListWidget favoritesListWidget = ContainerScreenOverlay.getFavoritesListWidget();
  686. if (favoritesListWidget != null)
  687. favoritesListWidget.updateSearch(ContainerScreenOverlay.getEntryListWidget(), ScreenHelper.getSearchField().getText());
  688. return true;
  689. }
  690. }
  691. if (!ScreenHelper.isOverlayVisible())
  692. return false;
  693. if (overlayMenu != null) {
  694. if (overlayMenu.wrappedMenu.mouseClicked(mouseX, mouseY, button)) {
  695. if (overlayMenu != null) this.setFocused(overlayMenu.wrappedMenu);
  696. else this.setFocused(null);
  697. if (button == 0)
  698. this.setDragging(true);
  699. ScreenHelper.getSearchField().setFocused(false);
  700. return true;
  701. } else if (!overlayMenu.inBounds.test(new Point(mouseX, mouseY))) {
  702. removeOverlayMenu();
  703. }
  704. }
  705. if (ConfigObject.getInstance().areClickableRecipeArrowsEnabled()) {
  706. List<ResourceLocation> categories = null;
  707. Screen screen = Minecraft.getInstance().screen;
  708. ClickAreaHandler.ClickAreaContext context = new ClickAreaHandler.ClickAreaContext<Screen>() {
  709. @Override
  710. public Screen getScreen() {
  711. return screen;
  712. }
  713. @Override
  714. public Point getMousePosition() {
  715. return new Point(mouseX, mouseY);
  716. }
  717. };
  718. for (Map.Entry<Class<? extends Screen>, ClickAreaHandler<?>> area : ((RecipeHelperImpl) RecipeHelper.getInstance()).getClickAreas().entries()) {
  719. if (area.getKey().equals(screen.getClass())) {
  720. ClickAreaHandler.Result result = area.getValue().handle(context);
  721. if (result.isSuccessful()) {
  722. if (categories == null) {
  723. categories = result.getCategories().collect(Collectors.toList());
  724. } else categories.addAll(result.getCategories().collect(Collectors.toList()));
  725. }
  726. }
  727. }
  728. if (categories != null && !categories.isEmpty()) {
  729. ClientHelper.getInstance().openView(ClientHelper.ViewSearchBuilder.builder().addCategories(categories).fillPreferredOpenedCategory());
  730. Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
  731. return true;
  732. }
  733. }
  734. for (GuiEventListener element : widgets)
  735. if ((overlayMenu == null || element != overlayMenu.wrappedMenu) && element.mouseClicked(mouseX, mouseY, button)) {
  736. this.setFocused(element);
  737. if (button == 0)
  738. this.setDragging(true);
  739. if (!(element instanceof OverlaySearchField))
  740. ScreenHelper.getSearchField().setFocused(false);
  741. return true;
  742. }
  743. if (ConfigObject.getInstance().getFocusSearchFieldKeybind().matchesMouse(button)) {
  744. ScreenHelper.getSearchField().setFocused(true);
  745. setFocused(ScreenHelper.getSearchField());
  746. ScreenHelper.getSearchField().keybindFocusTime = -1;
  747. ScreenHelper.getSearchField().keybindFocusKey = -1;
  748. return true;
  749. }
  750. return false;
  751. }
  752. @Override
  753. public boolean mouseDragged(double double_1, double double_2, int int_1, double double_3, double double_4) {
  754. if (!ScreenHelper.isOverlayVisible())
  755. return false;
  756. return (this.getFocused() != null && this.isDragging() && int_1 == 0) && this.getFocused().mouseDragged(double_1, double_2, int_1, double_3, double_4);
  757. }
  758. public boolean isInside(double mouseX, double mouseY) {
  759. return bounds.contains(mouseX, mouseY) && isNotInExclusionZones(mouseX, mouseY);
  760. }
  761. public boolean isNotInExclusionZones(double mouseX, double mouseY) {
  762. for (OverlayDecider decider : DisplayHelper.getInstance().getSortedOverlayDeciders(Minecraft.getInstance().screen.getClass())) {
  763. InteractionResult in = decider.isInZone(mouseX, mouseY);
  764. if (in != InteractionResult.PASS)
  765. return in == InteractionResult.SUCCESS;
  766. }
  767. return true;
  768. }
  769. public boolean isInside(Point point) {
  770. return isInside(point.getX(), point.getY());
  771. }
  772. }