Skip to content

Commit

Permalink
Add support for GuiScreen and for dragging ghost items
Browse files Browse the repository at this point in the history
  • Loading branch information
mezz committed Nov 26, 2017
1 parent d308937 commit d53e9e5
Show file tree
Hide file tree
Showing 27 changed files with 747 additions and 124 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Expand Up @@ -5,4 +5,4 @@ curse_project_id=238222

version_major=4
version_minor=8
version_patch=3
version_patch=4
24 changes: 21 additions & 3 deletions src/api/java/mezz/jei/api/IModRegistry.java
@@ -1,9 +1,8 @@
package mezz.jei.api;

import java.util.Collection;
import java.util.List;

import mezz.jei.api.gui.IAdvancedGuiHandler;
import mezz.jei.api.gui.IGhostIngredientHandler;
import mezz.jei.api.gui.IGuiScreenHandler;
import mezz.jei.api.ingredients.IIngredientRegistry;
import mezz.jei.api.recipe.IRecipeCategory;
import mezz.jei.api.recipe.IRecipeCategoryRegistration;
Expand All @@ -14,9 +13,13 @@
import mezz.jei.api.recipe.IVanillaRecipeFactory;
import mezz.jei.api.recipe.VanillaRecipeCategoryUid;
import mezz.jei.api.recipe.transfer.IRecipeTransferRegistry;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;

import java.util.Collection;
import java.util.List;

/**
* Entry point for the JEI API, functions for registering recipes are available from here.
* The IModRegistry instance is passed to your mod plugin in {@link IModPlugin#register(IModRegistry)}.
Expand Down Expand Up @@ -85,6 +88,21 @@ public interface IModRegistry {
*/
void addAdvancedGuiHandlers(IAdvancedGuiHandler<?>... advancedGuiHandlers);

/**
* Add a handler to let JEI draw next to a specific class (or subclass) of {@link GuiScreen}.
* By default, JEI can only draw next to {@link GuiContainer}.
* @since JEI 4.8.4
*/
<T extends GuiScreen> void addGuiScreenHandler(Class<T> guiClass, IGuiScreenHandler<T> handler);

/**
* Lets mods accept ghost ingredients from JEI.
* These ingredients are dragged from the ingredient list on to your gui, and are useful
* for setting recipes or anything else that does not need the real ingredient to exist.
* @since JEI 4.8.4
*/
<T extends GuiScreen> void addGhostIngredientHandler(Class<T> guiClass, IGhostIngredientHandler<T> handler);

/**
* Add an info page for an ingredient.
* Description pages show in the recipes for an ingredient and tell the player a little bit about it.
Expand Down
52 changes: 52 additions & 0 deletions src/api/java/mezz/jei/api/gui/IGhostIngredientHandler.java
@@ -0,0 +1,52 @@
package mezz.jei.api.gui;

import net.minecraft.client.gui.GuiScreen;

import java.awt.Rectangle;
import java.util.List;
import java.util.function.Consumer;

/**
* Lets mods accept ghost ingredients from JEI.
* These ingredients are dragged from the ingredient list on to your gui, and are useful
* for setting recipes or anything else that does not need the real ingredient to exist.
* @since JEI 4.8.4
*/
public interface IGhostIngredientHandler<T extends GuiScreen> {
/**
* Called when a player wants to drag an ingredient on to your gui.
* Return the targets that can accept the ingredient.
*
* This is called when a player hovers over an ingredient with doStart=false,
* and called again when they pick up the ingredient with doStart=true.
*/
<I> List<Target<I>> getTargets(T gui, I ingredient, boolean doStart);

/**
* Called when the player is done dragging an ingredient.
* If the drag succeeded, {@link Target#accept(Object)} was called before this.
* Otherwise, the player failed to drag an ingredient to a {@link Target}.
*/
void onComplete();

/**
* @return true if JEI should highlight the targets for the player.
* false to handle highlighting yourself.
*/
default boolean shouldHighlightTargets() {
return true;
}

interface Target<I> extends Consumer<I> {
/**
* @return the area (in screen coordinates) where the ingredient can be dropped.
*/
Rectangle getArea();

/**
* Called with the ingredient when it is dropped on the target.
*/
@Override
void accept(I ingredient);
}
}
17 changes: 17 additions & 0 deletions src/api/java/mezz/jei/api/gui/IGuiProperties.java
@@ -0,0 +1,17 @@
package mezz.jei.api.gui;

import net.minecraft.client.gui.GuiScreen;

/**
* Defines the properties of a gui so that JEI can draw next to it.
* @since JEI 4.8.4
*/
public interface IGuiProperties {
Class<? extends GuiScreen> getGuiClass();
int getGuiLeft();
int getGuiTop();
int getGuiXSize();
int getGuiYSize();
int getScreenWidth();
int getScreenHeight();
}
19 changes: 19 additions & 0 deletions src/api/java/mezz/jei/api/gui/IGuiScreenHandler.java
@@ -0,0 +1,19 @@
package mezz.jei.api.gui;

import mezz.jei.api.IModRegistry;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;

import java.util.function.Function;

/**
* Creates {@link IGuiProperties} from a {@link GuiScreen} so JEI can draw next to it.
* By default, JEI already handles this for all {@link GuiContainer}.
* Register a {@link IGuiScreenHandler} with JEI by using {@link IModRegistry#addGuiScreenHandler(Class, IGuiScreenHandler)}
* @since JEI 4.8.4
*/
@FunctionalInterface
public interface IGuiScreenHandler<T extends GuiScreen> extends Function<T, IGuiProperties> {
@Override
IGuiProperties apply(T guiScreen);
}
18 changes: 18 additions & 0 deletions src/main/java/mezz/jei/gui/GuiEventHandler.java
Expand Up @@ -12,6 +12,8 @@
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraftforge.client.event.GuiContainerEvent;
import net.minecraftforge.client.event.GuiOpenEvent;
import net.minecraftforge.client.event.GuiScreenEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
Expand Down Expand Up @@ -74,6 +76,22 @@ public void onDrawBackgroundEventPost(GuiScreenEvent.BackgroundDrawnEvent event)
}
}

/**
* Draws above most GuiContainer elements, but below the tooltips.
*/
@SubscribeEvent
public void onDrawForegroundEvent(GuiContainerEvent.DrawForeground event) {
IngredientListOverlay ingredientListOverlay = runtime.getItemListOverlay();
GuiContainer gui = event.getGuiContainer();

if (ingredientListOverlay.isEnabled()) {
GlStateManager.pushMatrix();
GlStateManager.translate(-gui.getGuiLeft(), -gui.getGuiTop(), 0);
ingredientListOverlay.drawOnForeground(gui.mc, event.getMouseX(), event.getMouseY());
GlStateManager.popMatrix();
}
}

@SubscribeEvent
public void onDrawScreenEventPost(GuiScreenEvent.DrawScreenEvent.Post event) {
GuiScreen gui = event.getGui();
Expand Down
118 changes: 118 additions & 0 deletions src/main/java/mezz/jei/gui/ghost/GhostIngredientDrag.java
@@ -0,0 +1,118 @@
package mezz.jei.gui.ghost;

import mezz.jei.api.gui.IGhostIngredientHandler;
import mezz.jei.api.gui.IGhostIngredientHandler.Target;
import mezz.jei.api.ingredients.IIngredientRenderer;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.RenderItem;
import org.lwjgl.opengl.GL11;

import javax.annotation.Nullable;
import java.awt.Color;
import java.awt.Rectangle;
import java.util.List;

public class GhostIngredientDrag<T> {
private static final Color targetColor = new Color(19, 201, 10, 64);
private static final Color hoverColor = new Color(76, 201, 25, 128);

private final IGhostIngredientHandler<?> handler;
private final List<Target<T>> targets;
private final IIngredientRenderer<T> ingredientRenderer;
private final T ingredient;
@Nullable
private final Rectangle origin;

public GhostIngredientDrag(IGhostIngredientHandler<?> handler, List<Target<T>> targets, IIngredientRenderer<T> ingredientRenderer, T ingredient, @Nullable Rectangle origin) {
this.handler = handler;
this.targets = targets;
this.ingredientRenderer = ingredientRenderer;
this.ingredient = ingredient;
this.origin = origin;
}

public void drawTargets(int mouseX, int mouseY) {
if (handler.shouldHighlightTargets()) {
@SuppressWarnings("unchecked")
List<Target<Object>> targets = (List<Target<Object>>) (Object) this.targets;
drawTargets(mouseX, mouseY, targets);
}
}

public void drawItem(Minecraft minecraft, int mouseX, int mouseY) {
if (origin != null) {
int originX = origin.x + (origin.width / 2);
int originY = origin.y + (origin.height / 2);
int xDist = originX - mouseX;
int yDist = originY - mouseY;
float lineWidth = 2;
if (minecraft.currentScreen != null) {
long distanceSq = xDist * xDist + yDist * yDist;
int screenDim = minecraft.currentScreen.width * minecraft.currentScreen.height;
float percentOfDim = Math.min(1, distanceSq / (float) screenDim);
lineWidth = 1 + ((1 - (percentOfDim)) * 3);
}
GL11.glDisable(GL11.GL_TEXTURE_2D);
GlStateManager.disableDepth();
GL11.glLineWidth(lineWidth);
GL11.glEnable(GL11.GL_LINE_SMOOTH);
GL11.glHint(GL11.GL_LINE_SMOOTH_HINT, GL11.GL_NICEST);
GL11.glBegin(GL11.GL_LINES);
GL11.glColor4f(targetColor.getRed() / 255f, targetColor.getGreen() / 255f, targetColor.getBlue() / 255f, targetColor.getAlpha() / 255f);
GL11.glVertex3f(mouseX, mouseY, 150);
GL11.glVertex3f(originX, originY, 150);
GL11.glEnd();
GlStateManager.enableDepth();
GL11.glEnable(GL11.GL_TEXTURE_2D);
}

RenderItem renderItem = minecraft.getRenderItem();
renderItem.zLevel += 150.0F;
ingredientRenderer.render(minecraft, mouseX - 8, mouseY - 8, ingredient);
renderItem.zLevel -= 150.0F;
}

public static void drawTargets(int mouseX, int mouseY, List<Target<Object>> targets) {
GlStateManager.disableLighting();
GlStateManager.disableDepth();
for (Target target : targets) {
Rectangle area = target.getArea();
Color color;
if (area.contains(mouseX, mouseY)) {
color = hoverColor;
} else {
color = targetColor;
}
Gui.drawRect(area.x, area.y, area.x + area.width, area.y + area.height, color.getRGB());
}
GlStateManager.color(1f, 1f, 1f, 1f);
}

public boolean onClick(int mouseX, int mouseY) {
for (Target<T> target : targets) {
Rectangle area = target.getArea();
if (area.contains(mouseX, mouseY)) {
target.accept(ingredient);
handler.onComplete();
return true;
}
}
handler.onComplete();
return false;
}

public IIngredientRenderer<T> getIngredientRenderer() {
return ingredientRenderer;
}

public T getIngredient() {
return ingredient;
}

@Nullable
public Rectangle getOrigin() {
return origin;
}
}

0 comments on commit d53e9e5

Please sign in to comment.