2025-04-24 18:48:40 +03:00
|
|
|
package codechicken.nei.recipe;
|
|
|
|
|
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
import net.minecraft.client.gui.inventory.GuiContainer;
|
|
|
|
|
|
|
|
|
|
import codechicken.nei.LRUCache;
|
|
|
|
|
import codechicken.nei.LayoutManager;
|
|
|
|
|
import codechicken.nei.api.IOverlayHandler;
|
|
|
|
|
import codechicken.nei.api.IRecipeOverlayRenderer;
|
|
|
|
|
import codechicken.nei.recipe.GuiOverlayButton.ItemOverlayState;
|
|
|
|
|
import codechicken.nei.recipe.Recipe.RecipeId;
|
|
|
|
|
|
|
|
|
|
public class RecipeHandlerRef {
|
|
|
|
|
|
2025-06-27 16:32:54 +03:00
|
|
|
private static final LRUCache<Class<?>, Boolean> transferAlghoritmCache = new LRUCache<>(200);
|
2025-04-24 18:48:40 +03:00
|
|
|
private static final LRUCache<RecipeId, RecipeHandlerRef> recipeRefCache = new LRUCache<>(200);
|
|
|
|
|
public final IRecipeHandler handler;
|
|
|
|
|
public final int recipeIndex;
|
|
|
|
|
|
|
|
|
|
private RecipeHandlerRef(IRecipeHandler handler, int recipeIndex) {
|
|
|
|
|
this.handler = handler;
|
|
|
|
|
this.recipeIndex = recipeIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static RecipeHandlerRef of(IRecipeHandler handler, int recipeIndex) {
|
|
|
|
|
return new RecipeHandlerRef(handler, recipeIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static RecipeHandlerRef of(RecipeId recipeId) {
|
|
|
|
|
|
2025-08-22 15:12:42 +03:00
|
|
|
if (recipeId != null && recipeId.getResult() != null && !recipeId.getIngredients().isEmpty()) {
|
2025-04-24 18:48:40 +03:00
|
|
|
return recipeRefCache.computeIfAbsent(recipeId, ri -> {
|
|
|
|
|
final List<ICraftingHandler> handlers = GuiCraftingRecipe
|
|
|
|
|
.getCraftingHandlers("recipeId", recipeId.getResult(), recipeId);
|
|
|
|
|
|
|
|
|
|
for (ICraftingHandler handler : handlers) {
|
|
|
|
|
int refIndex = SearchRecipeHandler.findFirst(
|
|
|
|
|
handler,
|
|
|
|
|
recipeIndex -> recipeId.equalsIngredients(handler.getIngredientStacks(recipeIndex)));
|
|
|
|
|
|
|
|
|
|
if (refIndex >= 0) {
|
|
|
|
|
return new RecipeHandlerRef(handler, refIndex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-07 16:34:41 +02:00
|
|
|
public static void clearCache() {
|
|
|
|
|
recipeRefCache.clear();
|
|
|
|
|
transferAlghoritmCache.clear();
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-24 18:48:40 +03:00
|
|
|
private GuiContainer prepareGui(GuiContainer firstGui) {
|
|
|
|
|
|
|
|
|
|
if (firstGui instanceof GuiRecipe gui) {
|
|
|
|
|
firstGui = gui.firstGui;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return firstGui != null && firstGui.inventorySlots != null ? firstGui : null;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-12 19:39:21 +03:00
|
|
|
public NEIRecipeWidget getRecipeWidget() {
|
|
|
|
|
return new NEIRecipeWidget(this);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-24 18:48:40 +03:00
|
|
|
public IOverlayHandler getOverlayHandler(GuiContainer gui) {
|
|
|
|
|
final GuiContainer firstGui = prepareGui(gui);
|
|
|
|
|
|
|
|
|
|
if (firstGui != null && this.handler.hasOverlay(firstGui, firstGui.inventorySlots, this.recipeIndex)) {
|
|
|
|
|
return this.handler.getOverlayHandler(firstGui, this.recipeIndex);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-26 18:29:59 -05:00
|
|
|
if (firstGui != null && canUseSmartOverlay(firstGui)) {
|
|
|
|
|
return SmartOverlayHandler.INSTANCE;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-24 18:48:40 +03:00
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-26 18:29:59 -05:00
|
|
|
private boolean canUseSmartOverlay(GuiContainer gui) {
|
|
|
|
|
if (!(this.handler instanceof TemplateRecipeHandler templateHandler)
|
|
|
|
|
|| templateHandler.getOverlayIdentifier() == null
|
|
|
|
|
|| templateHandler.getGuiClass() == null
|
|
|
|
|
|| !templateHandler.getGuiClass().isAssignableFrom(gui.getClass())) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return SmartOverlayHandler.canHandle(gui, this.handler, this.recipeIndex);
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-24 18:48:40 +03:00
|
|
|
public boolean canFillCraftingGrid(GuiContainer gui) {
|
|
|
|
|
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
|
|
|
|
|
|
|
|
|
|
if (overlayHandler != null) {
|
|
|
|
|
return overlayHandler.canFillCraftingGrid(prepareGui(gui), this.handler, this.recipeIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean canCraft(GuiContainer gui) {
|
|
|
|
|
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
|
|
|
|
|
|
|
|
|
|
if (overlayHandler != null && allowedTransferAlghoritm(gui)) {
|
|
|
|
|
return overlayHandler.canCraft(prepareGui(gui), this.handler, this.recipeIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<ItemOverlayState> getPresenceOverlay(GuiContainer gui) {
|
|
|
|
|
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
|
|
|
|
|
|
|
|
|
|
if (overlayHandler != null) {
|
|
|
|
|
return overlayHandler.presenceOverlay(prepareGui(gui), this.handler, this.recipeIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return Collections.emptyList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void fillCraftingGrid(GuiContainer gui, int multiplier) {
|
|
|
|
|
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
|
|
|
|
|
|
|
|
|
|
if (overlayHandler != null) {
|
|
|
|
|
final GuiContainer firstGui = prepareGui(gui);
|
|
|
|
|
|
|
|
|
|
if (!firstGui.equals(firstGui.mc.currentScreen)) {
|
|
|
|
|
firstGui.mc.displayGuiScreen(firstGui);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!allowedTransferAlghoritm(gui)) {
|
|
|
|
|
overlayHandler.overlayRecipe(firstGui, this.handler, this.recipeIndex, multiplier != 1);
|
|
|
|
|
} else {
|
|
|
|
|
overlayHandler.transferRecipe(firstGui, this.handler, this.recipeIndex, multiplier);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean craft(GuiContainer gui, int multiplier) {
|
|
|
|
|
final GuiContainer firstGui = prepareGui(gui);
|
|
|
|
|
final IOverlayHandler overlayHandler = getOverlayHandler(firstGui);
|
|
|
|
|
|
|
|
|
|
if (overlayHandler != null && overlayHandler.canCraft(firstGui, this.handler, this.recipeIndex)) {
|
|
|
|
|
|
|
|
|
|
if (!firstGui.equals(firstGui.mc.currentScreen)) {
|
|
|
|
|
firstGui.mc.displayGuiScreen(firstGui);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return overlayHandler.craft(firstGui, this.handler, this.recipeIndex, multiplier);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean allowedTransferAlghoritm(GuiContainer gui) {
|
|
|
|
|
final IOverlayHandler overlayHandler = getOverlayHandler(gui);
|
|
|
|
|
|
2025-06-27 16:32:54 +03:00
|
|
|
if (overlayHandler == null) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return transferAlghoritmCache.computeIfAbsent(overlayHandler.getClass(), clazz -> {
|
|
|
|
|
|
2025-04-24 18:48:40 +03:00
|
|
|
try {
|
2025-06-27 16:32:54 +03:00
|
|
|
|
|
|
|
|
if (overlayHandler instanceof DefaultOverlayHandler) {
|
|
|
|
|
final Class<?> overlayRecipeClazz = overlayHandler.getClass()
|
|
|
|
|
.getMethod(
|
|
|
|
|
"overlayRecipe",
|
|
|
|
|
GuiContainer.class,
|
|
|
|
|
IRecipeHandler.class,
|
|
|
|
|
int.class,
|
|
|
|
|
boolean.class)
|
|
|
|
|
.getDeclaringClass();
|
|
|
|
|
|
|
|
|
|
if (overlayRecipeClazz.equals(DefaultOverlayHandler.class)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-24 18:48:40 +03:00
|
|
|
return !overlayHandler.getClass()
|
2025-06-27 16:32:54 +03:00
|
|
|
.getMethod("transferRecipe", GuiContainer.class, IRecipeHandler.class, int.class, int.class)
|
2025-04-24 18:48:40 +03:00
|
|
|
.isDefault();
|
|
|
|
|
} catch (NoSuchMethodException e) {}
|
|
|
|
|
|
2025-06-27 16:32:54 +03:00
|
|
|
return false;
|
|
|
|
|
});
|
2025-04-24 18:48:40 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IRecipeOverlayRenderer getRecipeOverlayRenderer(GuiContainer gui) {
|
|
|
|
|
final GuiContainer firstGui = prepareGui(gui);
|
|
|
|
|
|
|
|
|
|
if (firstGui != null && this.handler.hasOverlay(firstGui, firstGui.inventorySlots, this.recipeIndex)) {
|
|
|
|
|
return this.handler.getOverlayRenderer(firstGui, this.recipeIndex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean canUseOverlayRenderer(GuiContainer gui) {
|
|
|
|
|
return getRecipeOverlayRenderer(gui) != null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void useOverlayRenderer(GuiContainer gui) {
|
|
|
|
|
final IRecipeOverlayRenderer renderer = getRecipeOverlayRenderer(gui);
|
|
|
|
|
|
|
|
|
|
if (renderer != null) {
|
|
|
|
|
final GuiContainer firstGui = prepareGui(gui);
|
|
|
|
|
|
|
|
|
|
if (!firstGui.equals(firstGui.mc.currentScreen)) {
|
|
|
|
|
firstGui.mc.displayGuiScreen(firstGui);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LayoutManager.overlayRenderer = renderer;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|