package codechicken.nei.recipe; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import net.minecraft.item.ItemStack; import codechicken.nei.NEIClientConfig; import codechicken.nei.Widget; import codechicken.nei.recipe.widget.RecipeWidget; import codechicken.nei.scroll.ScrollContainer; public class RecipePageManager { private SearchRecipeHandler handler; private ScrollContainer container; private HandlerInfo handlerInfo; private String cacheKey = ""; private int currentPageIndex = -1; private List> pageWidgets = new ArrayList<>(); public RecipePageManager(SearchRecipeHandler handler, HandlerInfo handlerInfo, ScrollContainer container) { this.handler = handler; this.handlerInfo = handlerInfo; this.container = container; rebuildPages(); } public boolean rebuildPages() { final String cacheKey = handlerInfo.getHandlerName() + ":" + getNumRecipes() + ":" + this.container.getVisibleHeight() + ":" + GuiRecipe.searchField.text(); if (cacheKey.equals(this.cacheKey)) { return false; } this.cacheKey = cacheKey; final List pausedWidgets = getPausedWidgets(); this.pageWidgets.clear(); final boolean allowOverflowY = this.handlerInfo.isAllowOverflowY(); final int handlerHeight = this.handlerInfo.getHeight() + this.handlerInfo.getYShift(); final boolean multipleWidgetsAllowed = !allowOverflowY && handlerInfo.isMultipleWidgetsAllowed(); final boolean infiniteScroll = !allowOverflowY && NEIClientConfig.getBooleanSetting("inventory.guirecipe.infiniteScroll"); final int heightAvailable = this.container.getVisibleHeight(); final int width = Math.max(166, this.handlerInfo.getWidth()); final List searchRecipes = this.handler.getFilteredRecipes(); final int numRecipes = searchRecipes.size(); final List> groupedRecipes = new ArrayList<>(); final Map groupEndIndices = new HashMap<>(); List widgets = new ArrayList<>(); int shiftY = 0; for (int i = 0; i < numRecipes; i++) { final int recipeIndex = searchRecipes.get(i); final Object groupId = this.handler.original.getRecipeGroupId(recipeIndex); final int groupIndex = groupId != null ? groupEndIndices.computeIfAbsent(groupId, k -> groupedRecipes.size()) : groupedRecipes.size(); if (groupedRecipes.size() <= groupIndex) { groupedRecipes.add(new ArrayList<>()); } groupedRecipes.get(groupIndex).add(recipeIndex); } for (int groupIndex = 0; groupIndex < groupedRecipes.size(); groupIndex++) { final RecipeWidget widget = new RecipeWidget(this.handler.original, groupedRecipes.get(groupIndex)); // keep the pause of the rebuilt widgets for (RecipeWidget paused : pausedWidgets) { final int pausedIndex = paused.getRecipeHandlerRef().recipeIndex; if (widget.containsRecipeIndex(pausedIndex)) { widget.pinRecipe(pausedIndex, paused.getPinnedIngredients()); } } widget.w = width; if (allowOverflowY) { widget.h = Math.min(handlerHeight, heightAvailable); } if (!widgets.isEmpty() && (!multipleWidgetsAllowed || !infiniteScroll && shiftY + widget.h > heightAvailable)) { this.pageWidgets.add(widgets); widgets = new ArrayList<>(); shiftY = 0; } widgets.add(widget); shiftY += widget.h; } if (!widgets.isEmpty()) { this.pageWidgets.add(widgets); } changePage(0); return true; } public boolean isMultipleWidgetsAllowed() { return !this.handlerInfo.isAllowOverflowY() && this.handlerInfo.isMultipleWidgetsAllowed(); } public int getNumRecipes() { return this.handler.numRecipes(); } public int getCurrentPageIndex() { return this.currentPageIndex; } public int getNumPages() { return this.pageWidgets.size(); } public void changePage(int delta) { final int numPages = getNumPages(); final int page = numPages > 0 ? (numPages + Math.max(0, this.currentPageIndex) + delta) % numPages : 0; if (this.currentPageIndex == page) { return; } this.currentPageIndex = page; this.container.setVerticalScrollOffset(0); } public boolean gotoRecipeIndex(int recipeIndex) { for (int page = 0; page < this.pageWidgets.size(); page++) { for (Widget widget : this.pageWidgets.get(page)) { if (widget instanceof RecipeWidget recipeWidget && recipeWidget.containsRecipeIndex(recipeIndex)) { changePage(page - this.currentPageIndex); return true; } } } return false; } private List getPausedWidgets() { final List paused = new ArrayList<>(); for (List widgets : this.pageWidgets) { for (Widget widget : widgets) { if (widget instanceof RecipeWidget recipeWidget && recipeWidget.isPaused()) { paused.add(recipeWidget); } } } return paused; } public boolean pinRecipe(int recipeIndex, List ingredients) { for (List widgets : this.pageWidgets) { for (Widget widget : widgets) { if (widget instanceof RecipeWidget recipeWidget && recipeWidget.containsRecipeIndex(recipeIndex)) { return recipeWidget.pinRecipe(recipeIndex, ingredients); } } } return false; } public List getCurrentPageWidgets() { if (this.pageWidgets.isEmpty()) { return Collections.emptyList(); } List currentWidgets = this.pageWidgets.get(this.currentPageIndex); int shiftY = 0; for (Widget widget : currentWidgets) { if (widget instanceof RecipeWidget recipeWidget) { recipeWidget.setLocation(2, shiftY); } shiftY += widget.h; } return currentWidgets; } public List getRecipeIndices() { if (this.pageWidgets.isEmpty()) { return Collections.emptyList(); } final List recipeIndices = new ArrayList<>(); for (Widget widget : this.pageWidgets.get(this.currentPageIndex)) { if (widget instanceof RecipeWidget recipeWidget) { recipeIndices.add(recipeWidget.getRecipeHandlerRef().recipeIndex); } } return recipeIndices; } }