Skip to content

Commit

Permalink
Manually set the proper icons for JEI's categories rather than having…
Browse files Browse the repository at this point in the history
… it attempt to figure them out. This fixes if other mod's add support for our categories and their JEIPlugin runs first that their item would show for the category. Also, properly take grandchildren into account for our JEI gui element handler and ghost ingredient handler, and add some missing checks related to if an element is visible
  • Loading branch information
pupnewfster committed Oct 19, 2021
1 parent 0f35046 commit 3799170
Show file tree
Hide file tree
Showing 12 changed files with 125 additions and 80 deletions.
Expand Up @@ -51,8 +51,7 @@ public class FissionReactorRecipeCategory extends BaseRecipeCategory<FissionJEIR
private final GuiGauge<?> wasteTank;

public FissionReactorRecipeCategory(IGuiHelper helper, ResourceLocation id) {
super(helper, id, GeneratorsLang.FISSION_REACTOR.translate(), 6, 13, 182, 60);
icon = helper.drawableBuilder(iconRL, 0, 0, 18, 18).setTextureSize(18, 18).build();
super(helper, id, GeneratorsLang.FISSION_REACTOR.translate(), createIcon(helper, iconRL), 6, 13, 182, 60);
addElement(new GuiInnerScreen(this, 45, 17, 105, 56, () -> Arrays.asList(
MekanismLang.STATUS.translate(EnumColor.BRIGHT_GREEN, ActiveDisabled.of(true)),
GeneratorsLang.GAS_BURN_RATE.translate(1.0),
Expand Down
21 changes: 14 additions & 7 deletions src/main/java/mekanism/client/jei/BaseRecipeCategory.java
Expand Up @@ -9,7 +9,7 @@
import javax.annotation.Nullable;
import mekanism.api.annotations.NonNull;
import mekanism.api.chemical.ChemicalStack;
import mekanism.api.providers.IBaseProvider;
import mekanism.api.providers.IItemProvider;
import mekanism.client.gui.IGuiWrapper;
import mekanism.client.gui.element.GuiRelativeElement;
import mekanism.client.gui.element.GuiTexturedElement;
Expand Down Expand Up @@ -43,28 +43,36 @@ public abstract class BaseRecipeCategory<RECIPE> implements IRecipeCategory<RECI
private static final IProgressInfoHandler CONSTANT_PROGRESS = () -> 1;
protected static final IBarInfoHandler FULL_BAR = () -> 1;

protected static IDrawable createIcon(IGuiHelper helper, ResourceLocation iconRL) {
return helper.drawableBuilder(iconRL, 0, 0, 18, 18).setTextureSize(18, 18).build();
}

protected static IDrawable createIcon(IGuiHelper helper, IItemProvider provider) {
return helper.createDrawableIngredient(provider.getItemStack());
}

private final Set<GuiTexturedElement> guiElements = new ObjectOpenHashSet<>();
private final ITextComponent component;
private final IGuiHelper guiHelper;
private final IDrawable background;
private final ResourceLocation id;
private final IDrawable icon;
private final int xOffset;
private final int yOffset;
@Nullable
private Map<GaugeOverlay, IDrawable> overlayLookup;
@Nullable
private ITickTimer timer;
@Nullable
protected IDrawable icon;

protected BaseRecipeCategory(IGuiHelper helper, IBaseProvider provider, int xOffset, int yOffset, int width, int height) {
this(helper, provider.getRegistryName(), provider.getTextComponent(), xOffset, yOffset, width, height);
protected BaseRecipeCategory(IGuiHelper helper, IItemProvider provider, int xOffset, int yOffset, int width, int height) {
this(helper, provider.getRegistryName(), provider.getTextComponent(), createIcon(helper, provider), xOffset, yOffset, width, height);
}

protected BaseRecipeCategory(IGuiHelper helper, ResourceLocation id, ITextComponent component, int xOffset, int yOffset, int width, int height) {
protected BaseRecipeCategory(IGuiHelper helper, ResourceLocation id, ITextComponent component, IDrawable icon, int xOffset, int yOffset, int width, int height) {
this.id = id;
this.component = component;
this.guiHelper = helper;
this.icon = icon;
this.xOffset = xOffset;
this.yOffset = yOffset;
this.background = new NOOPDrawable(width, height);
Expand Down Expand Up @@ -164,7 +172,6 @@ public IDrawable getBackground() {

@Override
public IDrawable getIcon() {
//Note: Even though we usually return null form here, this is allowed even though annotations imply it isn't supposed to be
return icon;
}

Expand Down
25 changes: 18 additions & 7 deletions src/main/java/mekanism/client/jei/GhostIngredientHandler.java
Expand Up @@ -11,6 +11,7 @@
import java.util.List;
import java.util.stream.Collectors;
import mekanism.client.gui.GuiMekanism;
import mekanism.client.gui.element.GuiElement;
import mekanism.client.gui.element.window.GuiWindow;
import mekanism.client.jei.interfaces.IJEIGhostTarget;
import mekanism.client.jei.interfaces.IJEIGhostTarget.IGhostIngredientConsumer;
Expand Down Expand Up @@ -78,12 +79,22 @@ public <INGREDIENT> List<Target<INGREDIENT>> getTargets(GUI gui, INGREDIENT ingr
private <INGREDIENT> List<TargetInfo<INGREDIENT>> getTargets(List<? extends IGuiEventListener> children, INGREDIENT ingredient) {
List<TargetInfo<INGREDIENT>> ghostTargets = new ArrayList<>();
for (IGuiEventListener child : children) {
if (child instanceof IJEIGhostTarget && child instanceof Widget) {
IJEIGhostTarget ghostTarget = (IJEIGhostTarget) child;
IGhostIngredientConsumer ghostHandler = ghostTarget.getGhostHandler();
if (ghostHandler != null && ghostHandler.supportsIngredient(ingredient)) {
Widget element = (Widget) child;
ghostTargets.add(new TargetInfo<>(ghostTarget, ghostHandler, element.x, element.y, element.getWidth(), element.getHeight()));
if (child instanceof Widget) {
Widget widget = (Widget) child;
if (widget.visible) {
if (widget instanceof GuiElement) {
//Start by adding any grandchild ghost targets we have as they are the "top" layer, and we want them
// to get checked/interacted with first
ghostTargets.addAll(getTargets(((GuiElement) widget).children(), ingredient));
}
//Then go ahead and check if our element is a ghost target and if it is, and it supports the ingredient add it
if (widget instanceof IJEIGhostTarget) {
IJEIGhostTarget ghostTarget = (IJEIGhostTarget) widget;
IGhostIngredientConsumer ghostHandler = ghostTarget.getGhostHandler();
if (ghostHandler != null && ghostHandler.supportsIngredient(ingredient)) {
ghostTargets.add(new TargetInfo<>(ghostTarget, ghostHandler, widget.x, widget.y, widget.getWidth(), widget.getHeight()));
}
}
}
}
}
Expand Down Expand Up @@ -117,7 +128,7 @@ private static void addVisibleAreas(List<Rectangle2d> visible, Rectangle2d area,
//If there are no more elements left, just add all the remaining visible parts
visible.addAll(uncoveredArea);
} else {
//Otherwise grab the remaining unchecked elements from the covering layer
//Otherwise, grab the remaining unchecked elements from the covering layer
List<Rectangle2d> coveredAreas = coveredArea.subList(i + 1, size);
//And check each of our sub visible areas
for (Rectangle2d visibleArea : uncoveredArea) {
Expand Down
104 changes: 68 additions & 36 deletions src/main/java/mekanism/client/jei/GuiElementHandler.java
Expand Up @@ -6,6 +6,7 @@
import java.util.List;
import javax.annotation.Nullable;
import mekanism.client.gui.GuiMekanism;
import mekanism.client.gui.element.GuiElement;
import mekanism.client.gui.element.GuiRelativeElement;
import mekanism.client.gui.element.window.GuiWindow;
import mekanism.client.jei.interfaces.IJEIIngredientHelper;
Expand All @@ -19,24 +20,33 @@

public class GuiElementHandler implements IGuiContainerHandler<GuiMekanism<?>> {

private static void addAreaIfOutside(List<Rectangle2d> areas, int parentX, int parentY, int parentWidth, int parentHeight, Widget element) {
if (element.visible) {
int x = element.x;
int y = element.y;
int width = element.getWidth();
int height = element.getHeight();
if (x < parentX || y < parentY || x + width > parentX + parentWidth || y + height > parentY + parentHeight) {
//If the element sticks out at all add it
areas.add(new Rectangle2d(x, y, width, height));
}
}
private static boolean areaSticksOut(int x, int y, int width, int height, int parentX, int parentY, int parentWidth, int parentHeight) {
return x < parentX || y < parentY || x + width > parentX + parentWidth || y + height > parentY + parentHeight;
}

public static List<Rectangle2d> getAreasFor(int parentX, int parentY, int parentWidth, int parentHeight, List<? extends IGuiEventListener> children) {
public static List<Rectangle2d> getAreasFor(int parentX, int parentY, int parentWidth, int parentHeight, Collection<? extends IGuiEventListener> children) {
List<Rectangle2d> areas = new ArrayList<>();
for (IGuiEventListener child : children) {
if (child instanceof Widget) {
addAreaIfOutside(areas, parentX, parentY, parentWidth, parentHeight, (Widget) child);
Widget widget = (Widget) child;
if (widget.visible) {
if (areaSticksOut(widget.x, widget.y, widget.getWidth(), widget.getHeight(), parentX, parentY, parentWidth, parentHeight)) {
//If the element sticks out at all add it
areas.add(new Rectangle2d(widget.x, widget.y, widget.getWidth(), widget.getHeight()));
}
if (widget instanceof GuiElement) {
//Start by getting all the areas in the grandchild that stick outside the child in theory this should cut down
// on our checks a fair bit as most children will fully contain all their grandchildren
for (Rectangle2d grandChildArea : getAreasFor(widget.x, widget.y, widget.getWidth(), widget.getHeight(), ((GuiElement) widget).children())) {
//Then check if that area that is sticking outside the child sticks outside the parent as well
if (areaSticksOut(grandChildArea.getX(), grandChildArea.getY(), grandChildArea.getWidth(), grandChildArea.getHeight(),
parentX, parentY, parentWidth, parentHeight)) {
//If it does, then add it to our areas
areas.add(grandChildArea);
}
}
}
}
}
}
return areas;
Expand All @@ -48,30 +58,40 @@ public List<Rectangle2d> getGuiExtraAreas(GuiMekanism<?> gui) {
int parentY = gui.getTop();
int parentWidth = gui.getWidth();
int parentHeight = gui.getHeight();
//Add any children the gui has and any windows the gui has including all grandchildren that poke out of the main gui
List<Rectangle2d> extraAreas = getAreasFor(parentX, parentY, parentWidth, parentHeight, gui.children());
for (GuiWindow window : gui.getWindows()) {
//Add the window itself and any areas that poke out from the main gui
addAreaIfOutside(extraAreas, parentX, parentY, parentWidth, parentHeight, window);
extraAreas.addAll(getAreasFor(parentX, parentY, parentWidth, parentHeight, window.children()));
}
extraAreas.addAll(getAreasFor(parentX, parentY, parentWidth, parentHeight, gui.getWindows()));
return extraAreas;
}

@Nullable
@Override
public Object getIngredientUnderMouse(GuiMekanism<?> gui, double mouseX, double mouseY) {
GuiWindow guiWindow = gui.getWindowHovering(mouseX, mouseY);
if (guiWindow == null) {
//If no window is being hovered, then check the elements in general
return getIngredientUnderMouse(gui.children(), mouseX, mouseY);
}
//Otherwise check the elements of the window
return getIngredientUnderMouse(guiWindow.children(), mouseX, mouseY);
//If no window is being hovered, then check the elements in general; otherwise, check the elements of the window
return getIngredientUnderMouse(guiWindow == null ? gui.children() : guiWindow.children(), mouseX, mouseY);
}

@Nullable
private Object getIngredientUnderMouse(List<? extends IGuiEventListener> children, double mouseX, double mouseY) {
for (IGuiEventListener child : children) {
if (child instanceof Widget) {
Widget widget = (Widget) child;
if (!widget.visible) {
//Skip this child if it isn't visible
continue;
}
if (widget instanceof GuiElement) {
GuiElement element = (GuiElement) widget;
//Start by checking if we have any grandchildren that have an element being hovered as if we do it is the one
// we want to take as the grandchildren in general should be a more "forward" facing layer
Object underGrandChild = getIngredientUnderMouse(element.children(), mouseX, mouseY);
if (underGrandChild != null) {
//If we have a grandchild that was an ingredient helper, return its ingredient
return underGrandChild;
}
}
}
if (child instanceof IJEIIngredientHelper && child.isMouseOver(mouseX, mouseY)) {
return ((IJEIIngredientHelper) child).getIngredient();
}
Expand All @@ -89,23 +109,35 @@ public Collection<IGuiClickableArea> getGuiClickableAreas(GuiMekanism<?> gui, do
//If no window is being hovered, then check the elements in general
return getGuiClickableArea(gui.children(), mouseX, mouseY);
}
//Otherwise check the elements of the window
//Otherwise, check the elements of the window
return getGuiClickableArea(guiWindow.children(), mouseX, mouseY);
}

private Collection<IGuiClickableArea> getGuiClickableArea(List<? extends IGuiEventListener> children, double mouseX, double mouseY) {
for (IGuiEventListener child : children) {
if (child instanceof GuiRelativeElement && child instanceof IJEIRecipeArea) {
IJEIRecipeArea<?> recipeArea = (IJEIRecipeArea<?>) child;
if (recipeArea.isActive()) {
ResourceLocation[] categories = recipeArea.getRecipeCategories();
//getRecipeCategory is a cheaper call than isMouseOver so we perform it first
if (categories != null && recipeArea.isMouseOverJEIArea(mouseX, mouseY)) {
GuiRelativeElement element = (GuiRelativeElement) child;
//TODO: Decide if we want our own implementation to overwrite the getTooltipStrings and have it show something like "Crusher Recipes"
IGuiClickableArea clickableArea = IGuiClickableArea.createBasic(element.getRelativeX(), element.getRelativeY(), element.getWidth(),
element.getHeight(), categories);
return Collections.singleton(clickableArea);
if (child instanceof GuiElement) {
GuiElement element = (GuiElement) child;
if (element.visible) {
//Start by checking if any of the grandchildren are JEI clickable areas that can be used
// as we want to start with the "top" layer
Collection<IGuiClickableArea> clickableGrandChildAreas = getGuiClickableArea(element.children(), mouseX, mouseY);
if (!clickableGrandChildAreas.isEmpty()) {
return clickableGrandChildAreas;
}
//If we couldn't find any, then we need to continue on to checking this element itself
if (element instanceof GuiRelativeElement && element instanceof IJEIRecipeArea) {
IJEIRecipeArea<?> recipeArea = (IJEIRecipeArea<?>) element;
if (recipeArea.isActive()) {
ResourceLocation[] categories = recipeArea.getRecipeCategories();
//getRecipeCategory is a cheaper call than isMouseOver, so we perform it first
if (categories != null && recipeArea.isMouseOverJEIArea(mouseX, mouseY)) {
GuiRelativeElement relativeElement = (GuiRelativeElement) element;
//TODO: Decide if we want our own implementation to overwrite the getTooltipStrings and have it show something like "Crusher Recipes"
IGuiClickableArea clickableArea = IGuiClickableArea.createBasic(relativeElement.getRelativeX(), relativeElement.getRelativeY(),
element.getWidth(), element.getHeight(), categories);
return Collections.singleton(clickableArea);
}
}
}
}
}
Expand Down
Expand Up @@ -52,10 +52,7 @@ public class BoilerRecipeCategory extends BaseRecipeCategory<BoilerJEIRecipe> {
private BoilerJEIRecipe recipe;

public BoilerRecipeCategory(IGuiHelper helper, ResourceLocation id) {
super(helper, id, MekanismLang.BOILER.translate(), 6, 13, 180, 60);
//Width 216, fission 195
//Height 166, fission 172
icon = helper.drawableBuilder(iconRL, 0, 0, 18, 18).setTextureSize(18, 18).build();
super(helper, id, MekanismLang.BOILER.translate(), createIcon(helper, iconRL), 6, 13, 180, 60);
//Note: All these elements except for the heatedCoolantTank and waterTank are in slightly different x positions than in the normal GUI
// so that they fit properly in JEI
addElement(new GuiInnerScreen(this, 48, 23, 96, 40, () -> {
Expand Down
Expand Up @@ -3,6 +3,7 @@
import java.util.Collections;
import mekanism.api.chemical.Chemical;
import mekanism.api.chemical.ChemicalStack;
import mekanism.api.providers.IItemProvider;
import mekanism.api.recipes.chemical.ItemStackToChemicalRecipe;
import mekanism.client.gui.element.gauge.GaugeType;
import mekanism.client.gui.element.gauge.GuiChemicalGauge;
Expand All @@ -15,6 +16,7 @@
import mekanism.common.tile.component.config.DataType;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.gui.IRecipeLayout;
import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.ingredients.IIngredientType;
import mezz.jei.api.ingredients.IIngredients;
Expand All @@ -29,9 +31,13 @@ public abstract class ItemStackToChemicalRecipeCategory<CHEMICAL extends Chemica
private final GuiGauge<?> output;
private final GuiSlot input;

protected ItemStackToChemicalRecipeCategory(IGuiHelper helper, ResourceLocation id, ITextComponent component, IIngredientType<STACK> ingredientType,
protected ItemStackToChemicalRecipeCategory(IGuiHelper helper, IItemProvider provider, IIngredientType<STACK> ingredientType, boolean isConversion) {
this(helper, provider.getRegistryName(), provider.getTextComponent(), createIcon(helper, provider), ingredientType, isConversion);
}

protected ItemStackToChemicalRecipeCategory(IGuiHelper helper, ResourceLocation id, ITextComponent component, IDrawable icon, IIngredientType<STACK> ingredientType,
boolean isConversion) {
super(helper, id, component, 20, 12, 132, 62);
super(helper, id, component, icon, 20, 12, 132, 62);
this.ingredientType = ingredientType;
output = addElement(getGauge(GaugeType.STANDARD.with(DataType.OUTPUT), 131, 13));
input = addSlot(SlotType.INPUT, 26, 36);
Expand Down
Expand Up @@ -45,10 +45,7 @@ public class ItemStackToEnergyRecipeCategory extends BaseRecipeCategory<ItemStac
private final GuiSlot input;

public ItemStackToEnergyRecipeCategory(IGuiHelper helper, ResourceLocation id) {
super(helper, id, MekanismLang.CONVERSION_ENERGY.translate(), 20, 12, 132, 62);
icon = helper.drawableBuilder(iconRL, 0, 0, 18, 18)
.setTextureSize(18, 18)
.build();
super(helper, id, MekanismLang.CONVERSION_ENERGY.translate(), createIcon(helper, iconRL), 20, 12, 132, 62);
gauge = addElement(GuiEnergyGauge.getDummy(GaugeType.STANDARD.with(DataType.OUTPUT), this, 133, 13));
input = addSlot(SlotType.INPUT, 26, 36);
addConstantProgress(ProgressType.LARGE_RIGHT, 64, 40);
Expand Down

0 comments on commit 3799170

Please sign in to comment.