2014-04-29 10:54:20 +10:00
|
|
|
package codechicken.nei.recipe;
|
|
|
|
|
|
2023-09-25 00:35:24 +02:00
|
|
|
import static codechicken.lib.gui.GuiDraw.changeTexture;
|
|
|
|
|
import static codechicken.lib.gui.GuiDraw.drawTexturedModalRect;
|
|
|
|
|
import static codechicken.lib.gui.GuiDraw.getMousePosition;
|
2022-06-24 12:32:13 +01:00
|
|
|
|
2023-09-25 00:35:24 +02:00
|
|
|
import java.awt.Point;
|
|
|
|
|
import java.awt.Rectangle;
|
2019-12-30 20:19:16 -08:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
import java.util.LinkedList;
|
2014-04-29 10:54:20 +10:00
|
|
|
import java.util.List;
|
2021-01-17 12:03:33 -08:00
|
|
|
import java.util.Objects;
|
2019-12-30 20:19:16 -08:00
|
|
|
import java.util.Random;
|
2021-01-17 12:03:33 -08:00
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.concurrent.ExecutionException;
|
|
|
|
|
import java.util.concurrent.locks.ReentrantLock;
|
|
|
|
|
import java.util.stream.Collectors;
|
2023-01-28 17:55:51 -08:00
|
|
|
|
2023-09-25 00:35:24 +02:00
|
|
|
import net.minecraft.client.gui.inventory.GuiContainer;
|
|
|
|
|
import net.minecraft.init.Blocks;
|
|
|
|
|
import net.minecraft.init.Items;
|
|
|
|
|
import net.minecraft.inventory.Container;
|
|
|
|
|
import net.minecraft.item.Item;
|
|
|
|
|
import net.minecraft.item.ItemStack;
|
|
|
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
|
|
|
import net.minecraft.tileentity.TileEntityFurnace;
|
|
|
|
|
|
|
|
|
|
import org.lwjgl.opengl.GL11;
|
|
|
|
|
|
|
|
|
|
import com.google.common.base.Stopwatch;
|
|
|
|
|
|
|
|
|
|
import codechicken.lib.vec.Rectangle4i;
|
|
|
|
|
import codechicken.nei.ItemList;
|
2024-02-04 14:09:24 +02:00
|
|
|
import codechicken.nei.ItemList.AllMultiItemFilter;
|
2023-09-25 00:35:24 +02:00
|
|
|
import codechicken.nei.NEIClientConfig;
|
|
|
|
|
import codechicken.nei.NEIClientUtils;
|
|
|
|
|
import codechicken.nei.NEIServerUtils;
|
|
|
|
|
import codechicken.nei.PositionedStack;
|
2024-07-26 18:44:54 +03:00
|
|
|
import codechicken.nei.PresetsList;
|
2023-09-25 00:35:24 +02:00
|
|
|
import codechicken.nei.api.DefaultOverlayRenderer;
|
|
|
|
|
import codechicken.nei.api.IOverlayHandler;
|
|
|
|
|
import codechicken.nei.api.IRecipeOverlayRenderer;
|
|
|
|
|
import codechicken.nei.api.IStackPositioner;
|
2024-02-04 14:09:24 +02:00
|
|
|
import codechicken.nei.api.ItemFilter;
|
|
|
|
|
import codechicken.nei.api.ItemInfo;
|
2023-09-25 00:35:24 +02:00
|
|
|
import codechicken.nei.guihook.GuiContainerManager;
|
|
|
|
|
import codechicken.nei.guihook.IContainerInputHandler;
|
|
|
|
|
import codechicken.nei.guihook.IContainerTooltipHandler;
|
2023-01-28 17:55:51 -08:00
|
|
|
|
2014-04-29 10:54:20 +10:00
|
|
|
/**
|
|
|
|
|
* A Template Recipe Handler! How about that. Because it was sooo hard, and more seriously required lots of copied code
|
|
|
|
|
* to make a handler in the past. you can now extend this class to make your custom recipe handlers much easier to
|
|
|
|
|
* create. Just look at the 5 handlers included by default to work out how to do stuff if you are still stuck.
|
|
|
|
|
*/
|
2022-06-24 12:32:13 +01:00
|
|
|
public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageHandler {
|
2023-01-28 17:55:51 -08:00
|
|
|
|
2021-01-17 12:03:33 -08:00
|
|
|
protected static ReentrantLock lock = new ReentrantLock();
|
|
|
|
|
|
|
|
|
|
public static void findFuelsOnce() {
|
|
|
|
|
// Ensure we only find fuels once, even if threaded
|
|
|
|
|
lock.lock();
|
|
|
|
|
try {
|
2022-06-24 12:32:13 +01:00
|
|
|
if (FurnaceRecipeHandler.afuels == null || FurnaceRecipeHandler.afuels.isEmpty()) findFuels(false);
|
2021-01-17 12:03:33 -08:00
|
|
|
} finally {
|
|
|
|
|
lock.unlock();
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-24 12:32:13 +01:00
|
|
|
|
2021-01-30 11:19:30 -08:00
|
|
|
public static void findFuelsOnceParallel() {
|
|
|
|
|
// Ensure we only find fuels once, even if threaded
|
|
|
|
|
lock.lock();
|
|
|
|
|
try {
|
2022-06-24 12:32:13 +01:00
|
|
|
if (FurnaceRecipeHandler.afuels == null || FurnaceRecipeHandler.afuels.isEmpty()) findFuels(true);
|
2021-01-30 11:19:30 -08:00
|
|
|
} finally {
|
|
|
|
|
lock.unlock();
|
2022-06-24 12:32:13 +01:00
|
|
|
}
|
2021-01-30 11:19:30 -08:00
|
|
|
}
|
2021-01-17 12:03:33 -08:00
|
|
|
|
2021-01-30 11:19:30 -08:00
|
|
|
private static Set<Item> efuels;
|
2022-06-24 12:32:13 +01:00
|
|
|
|
2021-01-17 12:03:33 -08:00
|
|
|
@SuppressWarnings("UnstableApiUsage")
|
2021-01-30 11:19:30 -08:00
|
|
|
private static void findFuels(boolean parallel) {
|
|
|
|
|
efuels = new HashSet<>();
|
2021-01-17 12:03:33 -08:00
|
|
|
efuels.add(Item.getItemFromBlock(Blocks.brown_mushroom));
|
|
|
|
|
efuels.add(Item.getItemFromBlock(Blocks.red_mushroom));
|
|
|
|
|
efuels.add(Item.getItemFromBlock(Blocks.standing_sign));
|
|
|
|
|
efuels.add(Item.getItemFromBlock(Blocks.wall_sign));
|
|
|
|
|
efuels.add(Item.getItemFromBlock(Blocks.wooden_door));
|
|
|
|
|
efuels.add(Item.getItemFromBlock(Blocks.trapped_chest));
|
2022-06-24 12:32:13 +01:00
|
|
|
|
2021-01-17 12:03:33 -08:00
|
|
|
Stopwatch stopwatch = Stopwatch.createStarted();
|
2021-01-30 11:19:30 -08:00
|
|
|
if (parallel) {
|
|
|
|
|
try {
|
2022-06-24 12:32:13 +01:00
|
|
|
FurnaceRecipeHandler.afuels = ItemList.forkJoinPool
|
|
|
|
|
.submit(
|
|
|
|
|
() -> ItemList.items.parallelStream().map(TemplateRecipeHandler::identifyFuel)
|
|
|
|
|
.filter(Objects::nonNull).collect(Collectors.toCollection(ArrayList::new)))
|
|
|
|
|
.get();
|
2021-01-30 11:19:30 -08:00
|
|
|
} catch (InterruptedException | ExecutionException e) {
|
2021-03-28 11:04:50 -07:00
|
|
|
FurnaceRecipeHandler.afuels = new ArrayList<>();
|
2021-01-30 11:19:30 -08:00
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2022-06-24 12:32:13 +01:00
|
|
|
FurnaceRecipeHandler.afuels = ItemList.items.stream().map(TemplateRecipeHandler::identifyFuel)
|
|
|
|
|
.filter(Objects::nonNull).collect(Collectors.toCollection(ArrayList::new));
|
2021-01-17 12:03:33 -08:00
|
|
|
}
|
|
|
|
|
|
2022-06-24 12:32:13 +01:00
|
|
|
NEIClientConfig.logger.info("FindFuels took " + stopwatch.stop());
|
2021-01-17 12:03:33 -08:00
|
|
|
}
|
2022-06-24 12:32:13 +01:00
|
|
|
|
2021-03-28 12:01:40 -07:00
|
|
|
private static FurnaceRecipeHandler.FuelPair identifyFuel(final ItemStack itemStack) {
|
2021-01-30 11:19:30 -08:00
|
|
|
if (efuels.contains(itemStack.getItem())) return null;
|
|
|
|
|
final int burnTime = TileEntityFurnace.getItemBurnTime(itemStack);
|
|
|
|
|
if (burnTime <= 0) return null;
|
2021-03-28 12:01:40 -07:00
|
|
|
return new FurnaceRecipeHandler.FuelPair(itemStack.copy(), burnTime);
|
2021-01-30 11:19:30 -08:00
|
|
|
}
|
2021-01-17 12:03:33 -08:00
|
|
|
|
2014-04-29 10:54:20 +10:00
|
|
|
/**
|
|
|
|
|
* This Recipe Handler runs on this internal class Fill the recipe array with subclasses of this to make
|
|
|
|
|
* transforming the different types of recipes out there into a nice format for NEI a much easier job.
|
|
|
|
|
*/
|
2022-06-24 12:32:13 +01:00
|
|
|
public abstract class CachedRecipe {
|
2023-01-28 17:55:51 -08:00
|
|
|
|
2014-04-29 10:54:20 +10:00
|
|
|
final long offset = System.currentTimeMillis();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return The item produced by this recipe, with position
|
|
|
|
|
*/
|
|
|
|
|
public abstract PositionedStack getResult();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The ingredients required to produce the result Use this if you have more than one ingredient
|
|
|
|
|
*
|
|
|
|
|
* @return A list of positioned ingredient items.
|
|
|
|
|
*/
|
|
|
|
|
public List<PositionedStack> getIngredients() {
|
2019-12-30 20:19:16 -08:00
|
|
|
ArrayList<PositionedStack> stacks = new ArrayList<>();
|
2014-04-29 10:54:20 +10:00
|
|
|
PositionedStack stack = getIngredient();
|
2022-06-24 12:32:13 +01:00
|
|
|
if (stack != null) stacks.add(stack);
|
2014-04-29 10:54:20 +10:00
|
|
|
return stacks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return The ingredient required to produce the result
|
|
|
|
|
*/
|
|
|
|
|
public PositionedStack getIngredient() {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return extra items that are not directly involved in the ingredient->result relationship. Eg fuels. Use this
|
|
|
|
|
* if you have more than one other stack
|
|
|
|
|
*
|
|
|
|
|
* @return A list of positioned items.
|
|
|
|
|
*/
|
|
|
|
|
public List<PositionedStack> getOtherStacks() {
|
2019-12-30 20:19:16 -08:00
|
|
|
ArrayList<PositionedStack> stacks = new ArrayList<>();
|
2020-03-04 16:39:23 -08:00
|
|
|
try {
|
|
|
|
|
PositionedStack stack = getOtherStack();
|
2022-06-24 12:32:13 +01:00
|
|
|
if (stack != null) stacks.add(stack);
|
2020-03-04 20:55:41 -08:00
|
|
|
} catch (ArithmeticException e) {
|
|
|
|
|
NEIClientConfig.logger.error("Error in getOtherStacks: " + e);
|
2020-03-04 16:39:23 -08:00
|
|
|
}
|
2014-04-29 10:54:20 +10:00
|
|
|
return stacks;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Simple utility
|
|
|
|
|
*
|
|
|
|
|
* @return The another positioned stack
|
|
|
|
|
*/
|
|
|
|
|
public PositionedStack getOtherStack() {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* This will perform default cycling of ingredients, mulitItem capable
|
2024-02-04 14:09:24 +02:00
|
|
|
*
|
2022-06-29 14:18:48 -04:00
|
|
|
* @param cycle Current cycle step
|
|
|
|
|
* @param ingredients List of ItemStacks to cycle
|
|
|
|
|
* @return The provided list of ingredients, with their permutations cycled to a different permutation, if one
|
|
|
|
|
* is available
|
2014-04-29 10:54:20 +10:00
|
|
|
*/
|
|
|
|
|
public List<PositionedStack> getCycledIngredients(int cycle, List<PositionedStack> ingredients) {
|
2022-08-19 15:03:42 +03:00
|
|
|
|
2024-02-04 14:09:24 +02:00
|
|
|
if (!NEIClientUtils.shiftKey() && !disableCycledIngredients) {
|
2023-02-06 00:57:09 +09:00
|
|
|
if (NEIClientConfig.useJEIStyledCycledIngredients()) {
|
|
|
|
|
jeiStyledRenderPermutation(ingredients, cycle);
|
|
|
|
|
} else {
|
2024-02-04 14:09:24 +02:00
|
|
|
randomRenderPermutation(ingredients, cycle);
|
2022-08-19 15:03:42 +03:00
|
|
|
}
|
|
|
|
|
}
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
return ingredients;
|
|
|
|
|
}
|
|
|
|
|
|
2024-06-19 02:25:26 +08:00
|
|
|
public void randomRenderPermutation(List<PositionedStack> stacks, long cycle) {
|
2024-02-04 14:09:24 +02:00
|
|
|
final ItemFilter filter = getItemFilter();
|
|
|
|
|
final int randCycle = Math.abs(new Random(cycle + offset).nextInt());
|
|
|
|
|
|
|
|
|
|
for (PositionedStack stack : stacks) {
|
|
|
|
|
if (stack.items.length <= 1) continue;
|
|
|
|
|
ArrayList<Integer> filtered = getFilteredIngredientAlternatives(stack, filter);
|
|
|
|
|
if (filtered.isEmpty()) {
|
|
|
|
|
stack.setPermutationToRender((int) (randCycle % stack.items.length));
|
|
|
|
|
} else {
|
|
|
|
|
stack.setPermutationToRender(filtered.get((int) (randCycle % filtered.size())));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-29 10:54:20 +10:00
|
|
|
}
|
|
|
|
|
|
2024-02-04 14:09:24 +02:00
|
|
|
protected void jeiStyledRenderPermutation(List<PositionedStack> stacks, long cycle) {
|
|
|
|
|
final ItemFilter filter = getItemFilter();
|
|
|
|
|
|
2023-02-06 00:57:09 +09:00
|
|
|
for (PositionedStack stack : stacks) {
|
2024-02-04 14:09:24 +02:00
|
|
|
if (stack.items.length <= 1) continue;
|
|
|
|
|
ArrayList<Integer> filtered = getFilteredIngredientAlternatives(stack, filter);
|
|
|
|
|
if (filtered.isEmpty()) {
|
|
|
|
|
stack.setPermutationToRender((int) (cycle % stack.items.length));
|
|
|
|
|
} else {
|
|
|
|
|
stack.setPermutationToRender(filtered.get((int) (cycle % filtered.size())));
|
|
|
|
|
}
|
2023-02-06 00:57:09 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-04 14:09:24 +02:00
|
|
|
@Deprecated
|
2024-06-19 02:25:26 +08:00
|
|
|
public void randomRenderPermutation(PositionedStack stack, long cycle) {
|
2024-02-04 14:09:24 +02:00
|
|
|
Random rand = new Random(cycle + offset);
|
|
|
|
|
stack.setPermutationToRender((int) (Math.abs(rand.nextInt()) % stack.items.length));
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-29 10:54:20 +10:00
|
|
|
public void setIngredientPermutation(Collection<PositionedStack> ingredients, ItemStack ingredient) {
|
|
|
|
|
for (PositionedStack stack : ingredients) {
|
|
|
|
|
for (int i = 0; i < stack.items.length; i++) {
|
|
|
|
|
if (NEIServerUtils.areStacksSameTypeCrafting(ingredient, stack.items[i])) {
|
|
|
|
|
stack.item = stack.items[i];
|
2023-06-01 14:20:24 +09:00
|
|
|
Items.feather.setDamage(stack.item, Items.feather.getDamage(ingredient));
|
2015-08-19 21:17:56 -07:00
|
|
|
if (ingredient.hasTagCompound()) {
|
2022-06-24 12:32:13 +01:00
|
|
|
stack.item.setTagCompound((NBTTagCompound) ingredient.getTagCompound().copy());
|
2015-08-19 21:17:56 -07:00
|
|
|
}
|
2022-06-24 12:32:13 +01:00
|
|
|
stack.items = new ItemStack[] { stack.item };
|
2014-04-29 10:54:20 +10:00
|
|
|
stack.setPermutationToRender(0);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2022-06-29 14:18:48 -04:00
|
|
|
* @param ingredients Collection of ItemStacks
|
|
|
|
|
* @param ingredient ItemStack we're looking for
|
|
|
|
|
* @return true if any of the permutations of the ingredients contain this ItemStack
|
2014-04-29 10:54:20 +10:00
|
|
|
*/
|
|
|
|
|
public boolean contains(Collection<PositionedStack> ingredients, ItemStack ingredient) {
|
2022-06-24 12:32:13 +01:00
|
|
|
for (PositionedStack stack : ingredients) if (stack.contains(ingredient)) return true;
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-08 16:29:51 +09:00
|
|
|
/**
|
|
|
|
|
* NBT-friendly version of {@link #contains(Collection, ItemStack)}
|
|
|
|
|
*/
|
|
|
|
|
public boolean containsWithNBT(Collection<PositionedStack> ingredients, ItemStack ingredient) {
|
2022-06-24 12:32:13 +01:00
|
|
|
for (PositionedStack stack : ingredients) if (stack.containsWithNBT(ingredient)) return true;
|
2022-02-08 16:29:51 +09:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-29 10:54:20 +10:00
|
|
|
/**
|
2022-06-29 14:18:48 -04:00
|
|
|
* @param ingredients Collection of ItemStacks
|
|
|
|
|
* @param ingredient Item we're looking for
|
|
|
|
|
* @return true if any of the permutations of the ingredients contain this Item
|
2014-04-29 10:54:20 +10:00
|
|
|
*/
|
2022-06-29 14:18:48 -04:00
|
|
|
public boolean contains(Collection<PositionedStack> ingredients, Item ingredient) {
|
|
|
|
|
for (PositionedStack stack : ingredients) if (stack.contains(ingredient)) return true;
|
2014-04-29 10:54:20 +10:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The Rectangle is an region of the gui relative to the corner of the recipe that will activate the recipe with the
|
|
|
|
|
* corresponding outputId apon being clicked. Apply this over fuel icons or arrows that the user may click to see
|
|
|
|
|
* all recipes pertaining to that action.
|
|
|
|
|
*/
|
2022-06-24 12:32:13 +01:00
|
|
|
public static class RecipeTransferRect {
|
2023-01-28 17:55:51 -08:00
|
|
|
|
2014-04-29 10:54:20 +10:00
|
|
|
public RecipeTransferRect(Rectangle rectangle, String outputId, Object... results) {
|
|
|
|
|
rect = rectangle;
|
|
|
|
|
this.outputId = outputId;
|
|
|
|
|
this.results = results;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean equals(Object obj) {
|
2022-06-24 12:32:13 +01:00
|
|
|
if (!(obj instanceof RecipeTransferRect)) return false;
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
return rect.equals(((RecipeTransferRect) obj).rect);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int hashCode() {
|
|
|
|
|
return rect.hashCode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Rectangle rect;
|
|
|
|
|
String outputId;
|
|
|
|
|
Object[] results;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 12:32:13 +01:00
|
|
|
public static class RecipeTransferRectHandler implements IContainerInputHandler, IContainerTooltipHandler {
|
2014-04-29 10:54:20 +10:00
|
|
|
|
2022-06-24 12:32:13 +01:00
|
|
|
private static final HashMap<Class<? extends GuiContainer>, HashSet<RecipeTransferRect>> guiMap = new HashMap<>();
|
2023-01-28 17:55:51 -08:00
|
|
|
|
2022-06-24 12:32:13 +01:00
|
|
|
public static void registerRectsToGuis(List<Class<? extends GuiContainer>> classes,
|
|
|
|
|
List<RecipeTransferRect> rects) {
|
|
|
|
|
if (classes == null) return;
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
for (Class<? extends GuiContainer> clazz : classes) {
|
2019-12-30 20:19:16 -08:00
|
|
|
HashSet<RecipeTransferRect> set = guiMap.computeIfAbsent(clazz, k -> new HashSet<>());
|
2014-04-29 10:54:20 +10:00
|
|
|
set.addAll(rects);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean canHandle(GuiContainer gui) {
|
|
|
|
|
return guiMap.containsKey(gui.getClass());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean lastKeyTyped(GuiContainer gui, char keyChar, int keyCode) {
|
2022-06-24 12:32:13 +01:00
|
|
|
if (!canHandle(gui)) return false;
|
2014-04-29 10:54:20 +10:00
|
|
|
|
2022-08-19 15:03:42 +03:00
|
|
|
if (NEIClientConfig.isKeyHashDown("gui.recipe")) {
|
|
|
|
|
return transferRect(gui, false);
|
|
|
|
|
} else if (NEIClientConfig.isKeyHashDown("gui.usage")) {
|
|
|
|
|
return transferRect(gui, true);
|
|
|
|
|
}
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean mouseClicked(GuiContainer gui, int mousex, int mousey, int button) {
|
2022-06-24 12:32:13 +01:00
|
|
|
if (!canHandle(gui)) return false;
|
2014-04-29 10:54:20 +10:00
|
|
|
|
2022-06-24 12:32:13 +01:00
|
|
|
if (button == 0) return transferRect(gui, false);
|
|
|
|
|
else if (button == 1) return transferRect(gui, true);
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean transferRect(GuiContainer gui, boolean usage) {
|
|
|
|
|
int[] offset = RecipeInfo.getGuiOffset(gui);
|
|
|
|
|
return TemplateRecipeHandler.transferRect(gui, guiMap.get(gui.getClass()), offset[0], offset[1], usage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2022-06-24 12:32:13 +01:00
|
|
|
public void onKeyTyped(GuiContainer gui, char keyChar, int keyID) {}
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
@Override
|
2022-06-24 12:32:13 +01:00
|
|
|
public void onMouseClicked(GuiContainer gui, int mousex, int mousey, int button) {}
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
@Override
|
2022-06-24 12:32:13 +01:00
|
|
|
public void onMouseUp(GuiContainer gui, int mousex, int mousey, int button) {}
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean keyTyped(GuiContainer gui, char keyChar, int keyID) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean mouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2022-06-24 12:32:13 +01:00
|
|
|
public void onMouseScrolled(GuiContainer gui, int mousex, int mousey, int scrolled) {}
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
|
2022-06-24 12:32:13 +01:00
|
|
|
if (!canHandle(gui)) return currenttip;
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
if (GuiContainerManager.shouldShowTooltip(gui) && currenttip.size() == 0) {
|
|
|
|
|
int[] offset = RecipeInfo.getGuiOffset(gui);
|
2022-06-24 12:32:13 +01:00
|
|
|
currenttip = TemplateRecipeHandler
|
|
|
|
|
.transferRectTooltip(gui, guiMap.get(gui.getClass()), offset[0], offset[1], currenttip);
|
2014-04-29 10:54:20 +10:00
|
|
|
}
|
|
|
|
|
return currenttip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public List<String> handleItemDisplayName(GuiContainer gui, ItemStack itemstack, List<String> currenttip) {
|
|
|
|
|
return currenttip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2022-06-24 12:32:13 +01:00
|
|
|
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
|
|
|
|
|
List<String> currenttip) {
|
2014-04-29 10:54:20 +10:00
|
|
|
return currenttip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2022-06-24 12:32:13 +01:00
|
|
|
public void onMouseDragged(GuiContainer gui, int mousex, int mousey, int button, long heldTime) {}
|
2014-04-29 10:54:20 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
GuiContainerManager.addInputHandler(new RecipeTransferRectHandler());
|
|
|
|
|
GuiContainerManager.addTooltipHandler(new RecipeTransferRectHandler());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Internal tick counter, initialised to random value and incremented every tick. Used for cycling similar
|
|
|
|
|
* ingredients and progress bars.
|
|
|
|
|
*/
|
|
|
|
|
public int cycleticks = Math.abs((int) System.currentTimeMillis());
|
|
|
|
|
/**
|
|
|
|
|
* The list of matching recipes
|
|
|
|
|
*/
|
2019-12-30 20:19:16 -08:00
|
|
|
public ArrayList<CachedRecipe> arecipes = new ArrayList<>();
|
2014-04-29 10:54:20 +10:00
|
|
|
/**
|
2021-01-17 12:03:33 -08:00
|
|
|
* A list of transferRects that when clicked or R is pressed will open a new recipe.
|
2014-04-29 10:54:20 +10:00
|
|
|
*/
|
2019-12-30 20:19:16 -08:00
|
|
|
public LinkedList<RecipeTransferRect> transferRects = new LinkedList<>();
|
2014-04-29 10:54:20 +10:00
|
|
|
|
2024-02-04 14:09:24 +02:00
|
|
|
public static boolean disableCycledIngredients = true;
|
|
|
|
|
|
2014-04-29 10:54:20 +10:00
|
|
|
public TemplateRecipeHandler() {
|
|
|
|
|
loadTransferRects();
|
|
|
|
|
RecipeTransferRectHandler.registerRectsToGuis(getRecipeTransferRectGuis(), transferRects);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-17 23:24:27 +03:00
|
|
|
public static ItemFilter getItemFilter() {
|
2024-02-04 14:09:24 +02:00
|
|
|
return new AllMultiItemFilter(
|
|
|
|
|
item -> !ItemInfo.hiddenItems.contains(item),
|
2024-07-26 18:44:54 +03:00
|
|
|
PresetsList.getItemFilter(),
|
2024-02-04 14:09:24 +02:00
|
|
|
GuiRecipe.searchField != null ? GuiRecipe.searchField.getFilter() : null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected static ArrayList<Integer> getFilteredIngredientAlternatives(PositionedStack stack, ItemFilter filter) {
|
|
|
|
|
final ArrayList<Integer> filtered = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < stack.items.length; i++) {
|
|
|
|
|
if (filter.matches(stack.items[i])) {
|
|
|
|
|
filtered.add(i);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return filtered;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-29 10:54:20 +10:00
|
|
|
/**
|
|
|
|
|
* Add all RecipeTransferRects to the transferRects list during this call. Afterward they may be added to the input
|
|
|
|
|
* handler for the corresponding guis from getRecipeTransferRectGuis
|
|
|
|
|
*/
|
2022-06-24 12:32:13 +01:00
|
|
|
public void loadTransferRects() {}
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* In this function you need to fill up the empty recipe array with recipes. The default passes it to a cleaner
|
|
|
|
|
* handler if outputId is an item
|
|
|
|
|
*
|
|
|
|
|
* @param outputId A String identifier representing the type of output produced. Eg. {"item", "fuel"}
|
|
|
|
|
* @param results Objects representing the results that matching recipes must produce.
|
|
|
|
|
*/
|
|
|
|
|
public void loadCraftingRecipes(String outputId, Object... results) {
|
2022-06-24 12:32:13 +01:00
|
|
|
if (outputId.equals("item")) loadCraftingRecipes((ItemStack) results[0]);
|
2014-04-29 10:54:20 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Simplified wrapper, implement this and fill the empty recipe array with recipes
|
|
|
|
|
*
|
|
|
|
|
* @param result The result the recipes must output.
|
|
|
|
|
*/
|
|
|
|
|
public void loadCraftingRecipes(ItemStack result) {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* In this function you need to fill up the empty recipe array with recipes The default passes it to a cleaner
|
|
|
|
|
* handler if inputId is an item
|
|
|
|
|
*
|
|
|
|
|
* @param inputId A String identifier representing the type of ingredients used. Eg. {"item", "fuel"}
|
|
|
|
|
* @param ingredients Objects representing the ingredients that matching recipes must contain.
|
|
|
|
|
*/
|
|
|
|
|
public void loadUsageRecipes(String inputId, Object... ingredients) {
|
2022-06-24 12:32:13 +01:00
|
|
|
if (inputId.equals("item")) loadUsageRecipes((ItemStack) ingredients[0]);
|
2014-04-29 10:54:20 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Simplified wrapper, implement this and fill the empty recipe array with recipes
|
|
|
|
|
*
|
|
|
|
|
* @param ingredient The ingredient the recipes must contain.
|
|
|
|
|
*/
|
|
|
|
|
public void loadUsageRecipes(ItemStack ingredient) {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return The filepath to the texture to use when drawing this recipe
|
|
|
|
|
*/
|
|
|
|
|
public abstract String getGuiTexture();
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Simply works with the {@link DefaultOverlayRenderer} If the current container has been registered with this
|
|
|
|
|
* identifier, the question mark appears and an overlay guide can be drawn.
|
|
|
|
|
*
|
|
|
|
|
* @return The overlay identifier of this recipe type.
|
|
|
|
|
*/
|
2022-01-23 07:37:54 +09:00
|
|
|
@Override
|
2014-04-29 10:54:20 +10:00
|
|
|
public String getOverlayIdentifier() {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Extension point for drawing progress bars and other overlays
|
|
|
|
|
*
|
|
|
|
|
* @param recipe The recipeIndex being drawn
|
|
|
|
|
*/
|
|
|
|
|
public void drawExtras(int recipe) {}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Draws a texture rectangle that changes size with time. Commonly used for progress bars.
|
|
|
|
|
*
|
|
|
|
|
* @param x X position on screen
|
|
|
|
|
* @param y Y position on screen
|
|
|
|
|
* @param tx Texture X position
|
|
|
|
|
* @param ty Texture Y position
|
|
|
|
|
* @param w Texture width
|
|
|
|
|
* @param h Texture height
|
|
|
|
|
* @param ticks The amount of ticks for the bar to complete
|
|
|
|
|
* @param direction 0 right, 1 down, 2 left, 3 up. If bit 3 is set the bar will shrink rather extend
|
|
|
|
|
*/
|
|
|
|
|
public void drawProgressBar(int x, int y, int tx, int ty, int w, int h, int ticks, int direction) {
|
|
|
|
|
drawProgressBar(x, y, tx, ty, w, h, cycleticks % ticks / (float) ticks, direction);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Draws a texture rectangle that changes size with time. Commonly used for progress bars. If for some reason you
|
|
|
|
|
* don't like the default counter use this and specify the progress percentage.
|
|
|
|
|
*
|
|
|
|
|
* @param x X position on screen
|
|
|
|
|
* @param y Y position on screen
|
|
|
|
|
* @param tx Texture X position
|
|
|
|
|
* @param ty Texture Y position
|
|
|
|
|
* @param w Texture width
|
|
|
|
|
* @param h Texture height
|
|
|
|
|
* @param completion the percentage of progress bar completion, 0-1
|
|
|
|
|
* @param direction 0 right, 1 down, 2 left, 3 up. If bit 3 is set the bar will shrink rather extend
|
|
|
|
|
*/
|
|
|
|
|
public void drawProgressBar(int x, int y, int tx, int ty, int w, int h, float completion, int direction) {
|
|
|
|
|
if (direction > 3) {
|
|
|
|
|
completion = 1 - completion;
|
|
|
|
|
direction %= 4;
|
|
|
|
|
}
|
|
|
|
|
int var = (int) (completion * (direction % 2 == 0 ? w : h));
|
|
|
|
|
|
|
|
|
|
switch (direction) {
|
2022-06-24 12:32:13 +01:00
|
|
|
case 0: // right
|
2014-04-29 10:54:20 +10:00
|
|
|
drawTexturedModalRect(x, y, tx, ty, var, h);
|
|
|
|
|
break;
|
2022-06-24 12:32:13 +01:00
|
|
|
case 1: // down
|
2014-04-29 10:54:20 +10:00
|
|
|
drawTexturedModalRect(x, y, tx, ty, w, var);
|
|
|
|
|
break;
|
2022-06-24 12:32:13 +01:00
|
|
|
case 2: // left
|
2014-04-29 10:54:20 +10:00
|
|
|
drawTexturedModalRect(x + w - var, y, tx + w - var, ty, var, h);
|
|
|
|
|
break;
|
2022-06-24 12:32:13 +01:00
|
|
|
case 3: // up
|
2014-04-29 10:54:20 +10:00
|
|
|
drawTexturedModalRect(x, y + h - var, tx, ty + h - var, w, var);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return The gui classes to which the transfer rects added in the constructor are to be located over. null if
|
|
|
|
|
* none.
|
|
|
|
|
*/
|
|
|
|
|
public List<Class<? extends GuiContainer>> getRecipeTransferRectGuis() {
|
|
|
|
|
Class<? extends GuiContainer> clazz = getGuiClass();
|
|
|
|
|
if (clazz != null) {
|
2019-12-30 20:19:16 -08:00
|
|
|
LinkedList<Class<? extends GuiContainer>> list = new LinkedList<>();
|
2014-04-29 10:54:20 +10:00
|
|
|
list.add(clazz);
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @return The class of the GuiContainer that this recipe would be crafted in.
|
|
|
|
|
*/
|
|
|
|
|
public Class<? extends GuiContainer> getGuiClass() {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public TemplateRecipeHandler newInstance() {
|
|
|
|
|
try {
|
2024-02-04 14:09:24 +02:00
|
|
|
// Use the non parallel version since we might already be using the forkJoinPool
|
|
|
|
|
// and might have no threads
|
2022-06-24 12:32:13 +01:00
|
|
|
// available
|
2021-01-30 11:19:30 -08:00
|
|
|
// This will ideally have been pre-cached elsewhere and will be a NOOP
|
2022-06-24 12:32:13 +01:00
|
|
|
findFuelsOnce();
|
2024-08-29 20:07:14 +02:00
|
|
|
return getClass().getConstructor().newInstance();
|
2014-04-29 10:54:20 +10:00
|
|
|
} catch (Exception e) {
|
|
|
|
|
throw new RuntimeException(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ICraftingHandler getRecipeHandler(String outputId, Object... results) {
|
|
|
|
|
TemplateRecipeHandler handler = newInstance();
|
|
|
|
|
handler.loadCraftingRecipes(outputId, results);
|
|
|
|
|
return handler;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IUsageHandler getUsageHandler(String inputId, Object... ingredients) {
|
|
|
|
|
TemplateRecipeHandler handler = newInstance();
|
|
|
|
|
handler.loadUsageRecipes(inputId, ingredients);
|
|
|
|
|
return handler;
|
|
|
|
|
}
|
|
|
|
|
|
2022-01-22 13:16:28 +09:00
|
|
|
/**
|
|
|
|
|
* First look up {@link RecipeCatalysts} whether target ingredient is registered for it. If so, load all recipes for
|
|
|
|
|
* this handler. Fallback to {@link TemplateRecipeHandler#getUsageHandler}.
|
|
|
|
|
*/
|
|
|
|
|
public IUsageHandler getUsageAndCatalystHandler(String inputId, Object... ingredients) {
|
|
|
|
|
TemplateRecipeHandler handler = newInstance();
|
|
|
|
|
if (inputId.equals("item")) {
|
|
|
|
|
ItemStack candidate = (ItemStack) ingredients[0];
|
2022-01-23 07:37:54 +09:00
|
|
|
if (RecipeCatalysts.containsCatalyst(handler, candidate)) {
|
2022-01-22 13:16:28 +09:00
|
|
|
for (RecipeTransferRect rect : transferRects) {
|
|
|
|
|
if (specifyTransferRect() == null || Objects.equals(rect.outputId, specifyTransferRect())) {
|
|
|
|
|
handler.loadCraftingRecipes(rect.outputId, rect.results);
|
|
|
|
|
return handler;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-06-24 12:32:13 +01:00
|
|
|
NEIClientConfig.logger.info(
|
|
|
|
|
"failed to load catalyst handler, implement `loadTransferRects` for your handler "
|
|
|
|
|
+ handler.getClass().getName());
|
2022-01-22 13:16:28 +09:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return this.getUsageHandler(inputId, ingredients);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Override this if you have multiple {@link RecipeTransferRect}s. Used for
|
|
|
|
|
* {@link TemplateRecipeHandler#getUsageAndCatalystHandler}.
|
|
|
|
|
*/
|
|
|
|
|
public String specifyTransferRect() {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-29 10:54:20 +10:00
|
|
|
public int numRecipes() {
|
|
|
|
|
return arecipes.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void drawBackground(int recipe) {
|
|
|
|
|
GL11.glColor4f(1, 1, 1, 1);
|
|
|
|
|
changeTexture(getGuiTexture());
|
|
|
|
|
drawTexturedModalRect(0, 0, 5, 11, 166, 65);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void drawForeground(int recipe) {
|
|
|
|
|
GL11.glColor4f(1, 1, 1, 1);
|
|
|
|
|
GL11.glDisable(GL11.GL_LIGHTING);
|
|
|
|
|
changeTexture(getGuiTexture());
|
|
|
|
|
drawExtras(recipe);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<PositionedStack> getIngredientStacks(int recipe) {
|
|
|
|
|
return arecipes.get(recipe).getIngredients();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public PositionedStack getResultStack(int recipe) {
|
2022-10-17 02:34:06 -07:00
|
|
|
try {
|
|
|
|
|
return arecipes.get(recipe).getResult();
|
|
|
|
|
} catch (ArrayIndexOutOfBoundsException ignored) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
2014-04-29 10:54:20 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<PositionedStack> getOtherStacks(int recipe) {
|
|
|
|
|
return arecipes.get(recipe).getOtherStacks();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void onUpdate() {
|
2022-06-24 12:32:13 +01:00
|
|
|
if (!NEIClientUtils.shiftKey()) cycleticks++;
|
2014-04-29 10:54:20 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean hasOverlay(GuiContainer gui, Container container, int recipe) {
|
2022-06-24 12:32:13 +01:00
|
|
|
return RecipeInfo.hasDefaultOverlay(gui, getOverlayIdentifier())
|
|
|
|
|
|| RecipeInfo.hasOverlayHandler(gui, getOverlayIdentifier());
|
2014-04-29 10:54:20 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IRecipeOverlayRenderer getOverlayRenderer(GuiContainer gui, int recipe) {
|
|
|
|
|
IStackPositioner positioner = RecipeInfo.getStackPositioner(gui, getOverlayIdentifier());
|
2022-06-24 12:32:13 +01:00
|
|
|
if (positioner == null) return null;
|
2014-04-29 10:54:20 +10:00
|
|
|
return new DefaultOverlayRenderer(getIngredientStacks(recipe), positioner);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public IOverlayHandler getOverlayHandler(GuiContainer gui, int recipe) {
|
|
|
|
|
return RecipeInfo.getOverlayHandler(gui, getOverlayIdentifier());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int recipiesPerPage() {
|
|
|
|
|
return 2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2022-06-29 14:18:48 -04:00
|
|
|
public List<String> handleTooltip(GuiRecipe<?> gui, List<String> currenttip, int recipe) {
|
2014-04-29 10:54:20 +10:00
|
|
|
if (GuiContainerManager.shouldShowTooltip(gui) && currenttip.size() == 0) {
|
|
|
|
|
Point offset = gui.getRecipePosition(recipe);
|
|
|
|
|
currenttip = transferRectTooltip(gui, transferRects, offset.x, offset.y, currenttip);
|
|
|
|
|
}
|
|
|
|
|
return currenttip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2022-06-29 14:18:48 -04:00
|
|
|
public List<String> handleItemTooltip(GuiRecipe<?> gui, ItemStack stack, List<String> currenttip, int recipe) {
|
2014-04-29 10:54:20 +10:00
|
|
|
return currenttip;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2022-06-29 14:18:48 -04:00
|
|
|
public boolean keyTyped(GuiRecipe<?> gui, char keyChar, int keyCode, int recipe) {
|
2022-08-19 15:03:42 +03:00
|
|
|
|
|
|
|
|
if (NEIClientConfig.isKeyHashDown("gui.recipe")) {
|
|
|
|
|
return transferRect(gui, recipe, false);
|
|
|
|
|
} else if (NEIClientConfig.isKeyHashDown("gui.usage")) {
|
|
|
|
|
return transferRect(gui, recipe, true);
|
|
|
|
|
}
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2022-06-29 14:18:48 -04:00
|
|
|
public boolean mouseClicked(GuiRecipe<?> gui, int button, int recipe) {
|
2024-02-04 14:09:24 +02:00
|
|
|
|
|
|
|
|
if (button == 0) {
|
|
|
|
|
return transferRect(gui, recipe, false);
|
|
|
|
|
} else if (button == 1) {
|
|
|
|
|
return transferRect(gui, recipe, true);
|
|
|
|
|
}
|
2014-04-29 10:54:20 +10:00
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2021-09-30 22:17:14 -06:00
|
|
|
@Override
|
2022-06-29 14:18:48 -04:00
|
|
|
public boolean mouseScrolled(GuiRecipe<?> gui, int scroll, int recipe) {
|
2022-08-19 15:03:42 +03:00
|
|
|
if (!NEIClientUtils.shiftKey()) return false;
|
|
|
|
|
|
|
|
|
|
final Point pos = getMousePosition();
|
2024-02-04 14:09:24 +02:00
|
|
|
final Point offset = gui.getRecipePosition(recipe);
|
2022-08-19 15:03:42 +03:00
|
|
|
final Point relMouse = new Point(pos.x - gui.guiLeft - offset.x, pos.y - gui.guiTop - offset.y);
|
2024-02-04 14:09:24 +02:00
|
|
|
final PositionedStack overStack = getIngredientMouseOver(relMouse.x, relMouse.y, recipe);
|
2022-08-19 15:03:42 +03:00
|
|
|
|
2024-02-04 14:09:24 +02:00
|
|
|
if (overStack != null && overStack.items.length > 1) {
|
|
|
|
|
final ItemFilter filter = getItemFilter();
|
2022-08-19 15:03:42 +03:00
|
|
|
|
2024-02-04 14:09:24 +02:00
|
|
|
if (NEIClientConfig.useJEIStyledCycledIngredients()) {
|
|
|
|
|
ItemStack stack = overStack.item;
|
|
|
|
|
for (PositionedStack pStack : getIngredientStacks(recipe)) {
|
|
|
|
|
shiftPermutationToRender(pStack, stack, scroll, filter);
|
2022-08-19 15:03:42 +03:00
|
|
|
}
|
2024-02-04 14:09:24 +02:00
|
|
|
} else {
|
|
|
|
|
shiftPermutationToRender(overStack, overStack.item, scroll, filter);
|
2022-08-19 15:03:42 +03:00
|
|
|
}
|
2024-02-04 14:09:24 +02:00
|
|
|
|
|
|
|
|
return true;
|
2022-08-19 15:03:42 +03:00
|
|
|
}
|
|
|
|
|
|
2021-09-30 22:17:14 -06:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2024-02-04 14:09:24 +02:00
|
|
|
private void shiftPermutationToRender(PositionedStack pStack, ItemStack stack, int scroll, ItemFilter filter) {
|
2024-08-17 23:24:27 +03:00
|
|
|
if (!pStack.containsWithNBT(stack)) return;
|
2024-02-04 14:09:24 +02:00
|
|
|
|
2024-08-17 23:24:27 +03:00
|
|
|
final List<Integer> filtered = getFilteredIngredientAlternatives(pStack, filter);
|
|
|
|
|
int index = 0;
|
2024-02-04 14:09:24 +02:00
|
|
|
|
2024-08-17 23:24:27 +03:00
|
|
|
if (filtered.isEmpty()) {
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < pStack.items.length; i++) {
|
|
|
|
|
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(pStack.items[i], stack)) {
|
|
|
|
|
index = i;
|
|
|
|
|
break;
|
2024-02-04 14:09:24 +02:00
|
|
|
}
|
2024-08-17 23:24:27 +03:00
|
|
|
}
|
2024-02-04 14:09:24 +02:00
|
|
|
|
2024-08-17 23:24:27 +03:00
|
|
|
pStack.setPermutationToRender((int) ((pStack.items.length - scroll + index) % pStack.items.length));
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < filtered.size(); i++) {
|
|
|
|
|
if (NEIServerUtils.areStacksSameTypeCraftingWithNBT(pStack.items[filtered.get(i)], stack)) {
|
|
|
|
|
index = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-02-04 14:09:24 +02:00
|
|
|
}
|
2024-08-17 23:24:27 +03:00
|
|
|
|
|
|
|
|
pStack.setPermutationToRender(filtered.get((int) ((filtered.size() - scroll + index) % filtered.size())));
|
2024-02-04 14:09:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private PositionedStack getIngredientMouseOver(int mousex, int mousey, int recipe) {
|
|
|
|
|
|
|
|
|
|
for (PositionedStack pStack : getIngredientStacks(recipe)) {
|
|
|
|
|
if ((new Rectangle4i(pStack.relx, pStack.rely, 18, 18)).contains(mousex, mousey)) {
|
|
|
|
|
return pStack;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-29 14:18:48 -04:00
|
|
|
private boolean transferRect(GuiRecipe<?> gui, int recipe, boolean usage) {
|
2014-04-29 10:54:20 +10:00
|
|
|
Point offset = gui.getRecipePosition(recipe);
|
|
|
|
|
return transferRect(gui, transferRects, offset.x, offset.y, usage);
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 12:32:13 +01:00
|
|
|
private static boolean transferRect(GuiContainer gui, Collection<RecipeTransferRect> transferRects, int offsetx,
|
|
|
|
|
int offsety, boolean usage) {
|
2014-04-29 10:54:20 +10:00
|
|
|
Point pos = getMousePosition();
|
|
|
|
|
Point relMouse = new Point(pos.x - gui.guiLeft - offsetx, pos.y - gui.guiTop - offsety);
|
|
|
|
|
for (RecipeTransferRect rect : transferRects) {
|
2022-06-24 12:32:13 +01:00
|
|
|
if (rect.rect.contains(relMouse) && (usage ? GuiUsageRecipe.openRecipeGui(rect.outputId, rect.results)
|
|
|
|
|
: GuiCraftingRecipe.openRecipeGui(rect.outputId, rect.results)))
|
|
|
|
|
return true;
|
2014-04-29 10:54:20 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-24 12:32:13 +01:00
|
|
|
private static List<String> transferRectTooltip(GuiContainer gui, Collection<RecipeTransferRect> transferRects,
|
|
|
|
|
int offsetx, int offsety, List<String> currenttip) {
|
2014-04-29 10:54:20 +10:00
|
|
|
Point pos = getMousePosition();
|
|
|
|
|
Point relMouse = new Point(pos.x - gui.guiLeft - offsetx, pos.y - gui.guiTop - offsety);
|
|
|
|
|
for (RecipeTransferRect rect : transferRects) {
|
|
|
|
|
if (rect.rect.contains(relMouse)) {
|
2015-04-26 04:39:53 +10:00
|
|
|
currenttip.add(NEIClientUtils.translate("recipe.tooltip"));
|
2014-04-29 10:54:20 +10:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return currenttip;
|
|
|
|
|
}
|
|
|
|
|
}
|