Fix JEI compat

This commit is contained in:
thedarkcolour 2026-05-14 23:49:19 -07:00
parent aa7bf56d0f
commit 964c82b709
19 changed files with 282 additions and 196 deletions

View File

@ -60,7 +60,6 @@ sourceSets.main.resources { srcDir 'src/generated/resources' }
// Exclude compat packages for libraries without 1.26.1 support yet
sourceSets.main.java.exclude(
'**/compat/jei/**',
'**/compat/emi/**',
'**/compat/jade/**',
'**/compat/kubejs/**',
@ -124,9 +123,9 @@ dependencies {
//}
// JADE OPTIONAL
//implementation("curse.maven:jade-324717:6291517")
// JEI OPTIONAL
//compileOnly("mezz.jei:jei-${mc_version}-neoforge-api:${jei_version}")
//runtimeOnly("mezz.jei:jei-${mc_version}-neoforge:${jei_version}")
// JEI OPTIONAL todo change back to mc_version
compileOnly("mezz.jei:jei-${'26.1.2'}-neoforge-api:${jei_version}")
runtimeOnly("mezz.jei:jei-${'26.1.2'}-neoforge:${jei_version}")
// EMI OPTIONAL
//compileOnly("dev.emi:emi-neoforge:${emi_version}+${mc_version}:api")
//runtimeOnly("dev.emi:emi-neoforge:${emi_version}+${mc_version}")

View File

@ -10,7 +10,7 @@ neo_version=26.1.1.1-beta
neo_version_range=[26.1,)
loader_version_range=[4,)
#jei_version=19.25.0.323
jei_version=29.5.0.28
#emi_version=1.1.21
#cloth_config_version=15.0.127
#top_version=12.0.3-5

View File

@ -2,26 +2,36 @@ package thedarkcolour.exdeorum.compat;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.state.BlockState;
import thedarkcolour.exdeorum.ExDeorum;
import thedarkcolour.exdeorum.client.RenderUtil;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.material.DefaultMaterials;
// TODO: port ClientXeiUtil to MC 26.x:
// - GuiGraphics GuiGraphicsExtractor
// - BakedModel/ItemRenderer removed; use new item rendering API
// - BlockRenderDispatcher/renderSingleBlock removed
// - ItemBlockRenderTypes.getRenderLayer removed; use FluidStateModelSet/FluidModel
// - RenderTypeHelper removed
// - ModelData moved package
// - OAK_BARREL_COMPOSTING removed from ClientHandler (ModelResourceLocation removed)
// client-only logic shared between JEI and EMI
public class ClientXeiUtil {
private static final ItemStack OAK_BARREL = new ItemStack(DefaultMaterials.OAK_BARREL.getItem());
public static void renderBlock(GuiGraphicsExtractor guiGraphics, BlockState state, float x, float y, float z, float scale) {
// TODO: port block/fluid rendering using 26.x FluidRenderer and block model APIs
var fluidState = state.getFluidState();
if (!fluidState.isEmpty()) {
var sprite = RenderUtil.getFluidSprite(fluidState.getType());
guiGraphics.blitSprite(RenderPipelines.GUI_TEXTURED, sprite, Math.round(x), Math.round(y), Math.round(scale), Math.round(scale));
return;
}
var stack = new ItemStack(state.getBlock());
if (!stack.isEmpty()) {
renderScaledItem(guiGraphics, stack, x, y, scale);
}
}
public static void renderItemWithAsterisk(GuiGraphicsExtractor graphics, net.minecraft.world.item.ItemStack stack) {
// TODO: port item rendering using 26.x item model API
public static void renderItemWithAsterisk(GuiGraphicsExtractor graphics, ItemStack stack) {
graphics.fakeItem(stack, 0, 0);
renderAsterisk(graphics, 0, 0);
}
public static void renderAsterisk(GuiGraphicsExtractor graphics, int xOffset, int yOffset) {
@ -31,7 +41,9 @@ public class ClientXeiUtil {
}
public static void renderFilledCompostBarrel(GuiGraphicsExtractor guiGraphics, int xOffset, int yOffset) {
// TODO: port using 26.x item model API (ModelResourceLocation/OAK_BARREL_COMPOSTING removed)
guiGraphics.fakeItem(OAK_BARREL, xOffset, yOffset);
var sprite = RenderUtil.getBlockSprite(ExDeorum.loc("block/compost_dirt"));
guiGraphics.blitSprite(RenderPipelines.GUI_TEXTURED, sprite, xOffset + 4, yOffset + 5, 8, 8);
}
// Takes a decimal probability and returns a user-friendly percentage value
@ -39,4 +51,13 @@ public class ClientXeiUtil {
var chance = XeiUtil.FORMATTER.format(probability * 100);
return Component.translatable(TranslationKeys.SIEVE_RECIPE_CHANCE, chance).withStyle(ChatFormatting.GRAY);
}
private static void renderScaledItem(GuiGraphicsExtractor graphics, ItemStack stack, float x, float y, float scale) {
var pose = graphics.pose();
pose.pushMatrix();
pose.translate(x, y);
pose.scale(scale / 16f);
graphics.fakeItem(stack, 0, 0);
pose.popMatrix();
}
}

View File

@ -24,10 +24,10 @@ import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.IFocusGroup;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import mezz.jei.api.recipe.types.IRecipeType;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component;
import thedarkcolour.exdeorum.compat.ClientXeiUtil;
import thedarkcolour.exdeorum.data.TranslationKeys;
@ -37,20 +37,18 @@ class BarrelCompostCategory implements IRecipeCategory<BarrelCompostRecipe> {
public static final int WIDTH = 120;
public static final int HEIGHT = 18;
private final IDrawable background;
private final IDrawable slot;
private final IDrawable icon;
private final Component title;
public BarrelCompostCategory(IGuiHelper helper) {
this.background = helper.createBlankDrawable(WIDTH, HEIGHT);
this.slot = helper.getSlotDrawable();
this.icon = new DrawableIcon();
this.title = Component.translatable(TranslationKeys.BARREL_COMPOST_CATEGORY_TITLE);
}
@Override
public RecipeType<BarrelCompostRecipe> getRecipeType() {
public IRecipeType<BarrelCompostRecipe> getRecipeType() {
return ExDeorumJeiPlugin.BARREL_COMPOST;
}
@ -60,8 +58,13 @@ class BarrelCompostCategory implements IRecipeCategory<BarrelCompostRecipe> {
}
@Override
public IDrawable getBackground() {
return this.background;
public int getWidth() {
return WIDTH;
}
@Override
public int getHeight() {
return HEIGHT;
}
@Override
@ -71,17 +74,17 @@ class BarrelCompostCategory implements IRecipeCategory<BarrelCompostRecipe> {
@Override
public void setRecipe(IRecipeLayoutBuilder builder, BarrelCompostRecipe recipe, IFocusGroup focuses) {
builder.addSlot(RecipeIngredientRole.INPUT, 1, 1).addIngredients(recipe.ingredient());
builder.addSlot(RecipeIngredientRole.INPUT, 1, 1).add(recipe.ingredient());
}
@Override
public void draw(BarrelCompostRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
public void draw(BarrelCompostRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphicsExtractor graphics, double mouseX, double mouseY) {
this.slot.draw(graphics);
var volume = recipe.getVolume();
var volumeLabel = Component.translatable(TranslationKeys.BARREL_COMPOST_RECIPE_VOLUME, volume);
graphics.drawString(Minecraft.getInstance().font, volumeLabel, 24, 5, 0xff808080, false);
graphics.text(Minecraft.getInstance().font, volumeLabel, 24, 5, 0xff808080, false);
}
private static class DrawableIcon implements IDrawable {
@ -96,7 +99,7 @@ class BarrelCompostCategory implements IRecipeCategory<BarrelCompostRecipe> {
}
@Override
public void draw(GuiGraphics guiGraphics, int xOffset, int yOffset) {
public void draw(GuiGraphicsExtractor guiGraphics, int xOffset, int yOffset) {
ClientXeiUtil.renderFilledCompostBarrel(guiGraphics, xOffset, yOffset);
}
}

View File

@ -24,10 +24,10 @@ import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.IFocusGroup;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import mezz.jei.api.recipe.types.IRecipeType;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@ -41,7 +41,6 @@ public abstract class BarrelMixingCategory<T> implements IRecipeCategory<T> {
public static final int WIDTH = 120;
public static final int HEIGHT = 18;
private final IDrawable background;
private final IDrawable slot;
private final IDrawable plus;
private final IDrawable arrow;
@ -49,7 +48,6 @@ public abstract class BarrelMixingCategory<T> implements IRecipeCategory<T> {
private final Component title;
public BarrelMixingCategory(IGuiHelper helper, IDrawable plus, IDrawable arrow, String titleKey, Item iconItem) {
this.background = helper.createBlankDrawable(WIDTH, HEIGHT);
this.slot = helper.getSlotDrawable();
this.plus = plus;
this.arrow = arrow;
@ -63,8 +61,13 @@ public abstract class BarrelMixingCategory<T> implements IRecipeCategory<T> {
}
@Override
public IDrawable getBackground() {
return this.background;
public int getWidth() {
return WIDTH;
}
@Override
public int getHeight() {
return HEIGHT;
}
@Override
@ -73,7 +76,7 @@ public abstract class BarrelMixingCategory<T> implements IRecipeCategory<T> {
}
@Override
public void draw(T recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
public void draw(T recipe, IRecipeSlotsView recipeSlotsView, GuiGraphicsExtractor graphics, double mouseX, double mouseY) {
this.slot.draw(graphics);
this.plus.draw(graphics, 21, 5);
this.slot.draw(graphics, 18 + 3 + 3 + 8, 0);
@ -89,12 +92,12 @@ public abstract class BarrelMixingCategory<T> implements IRecipeCategory<T> {
@Override
public void setRecipe(IRecipeLayoutBuilder builder, BarrelMixingRecipe recipe, IFocusGroup focuses) {
JeiUtil.addFluidIngredient(builder.addSlot(RecipeIngredientRole.INPUT, 1, 1), recipe.fluid).setFluidRenderer(1000, false, 16, 16);
builder.addSlot(RecipeIngredientRole.INPUT, 33, 1).addIngredients(recipe.ingredient());
builder.addSlot(RecipeIngredientRole.OUTPUT, 79, 1).addItemStack(recipe.result.create());
builder.addSlot(RecipeIngredientRole.INPUT, 33, 1).add(recipe.ingredient());
builder.addSlot(RecipeIngredientRole.OUTPUT, 79, 1).add(recipe.result.create());
}
@Override
public RecipeType<BarrelMixingRecipe> getRecipeType() {
public IRecipeType<BarrelMixingRecipe> getRecipeType() {
return ExDeorumJeiPlugin.BARREL_MIXING;
}
}
@ -113,18 +116,18 @@ public abstract class BarrelMixingCategory<T> implements IRecipeCategory<T> {
var additiveSlot = JeiUtil.addFluidIngredient(builder.addSlot(RecipeIngredientRole.INPUT, 33, 1), recipe.additiveFluid(), 1000)
.setFluidRenderer(1000, false, 16, 16);
if (recipe.consumesAdditive()) {
additiveSlot.addTooltipCallback((view, tooltip) -> tooltip.add(CONTENTS_ARE_CONSUMED_TOOLTIP));
additiveSlot.addRichTooltipCallback((_, tooltip) -> tooltip.add(CONTENTS_ARE_CONSUMED_TOOLTIP));
}
builder.addSlot(RecipeIngredientRole.OUTPUT, 79, 1).addItemStack(recipe.result().create());
builder.addSlot(RecipeIngredientRole.OUTPUT, 79, 1).add(recipe.result().create());
}
@Override
public RecipeType<BarrelFluidMixingRecipe> getRecipeType() {
public IRecipeType<BarrelFluidMixingRecipe> getRecipeType() {
return ExDeorumJeiPlugin.BARREL_FLUID_MIXING;
}
@Override
public void draw(BarrelFluidMixingRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
public void draw(BarrelFluidMixingRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphicsExtractor graphics, double mouseX, double mouseY) {
super.draw(recipe, recipeSlotsView, graphics, mouseX, mouseY);
if (recipe.consumesAdditive()) {

View File

@ -18,7 +18,6 @@
package thedarkcolour.exdeorum.compat.jei;
import com.mojang.blaze3d.systems.RenderSystem;
import mezz.jei.api.ingredients.IIngredientRenderer;
import mezz.jei.api.ingredients.IIngredientType;
import mezz.jei.api.ingredients.ITypedIngredient;
@ -27,7 +26,7 @@ import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.runtime.IIngredientManager;
import mezz.jei.api.runtime.IRecipesGui;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
@ -41,10 +40,11 @@ import java.util.List;
import java.util.function.Consumer;
class ClientJeiUtil {
// todo is this still needed? i'm not supporting REI anymore
// Required due to broken JEI implementation in REI plugin compatibility
static <T> void checkTypedIngredient(IIngredientManager manager, IIngredientType<T> ingredientType, @Nullable T uncheckedIngredient, Consumer<ITypedIngredient<T>> action) {
if ((uncheckedIngredient instanceof ItemStack stack && !stack.isEmpty()) || (uncheckedIngredient instanceof FluidStack fluidStack && !fluidStack.isEmpty())) {
manager.createTypedIngredient(ingredientType, uncheckedIngredient).ifPresent(action);
manager.createTypedIngredient(ingredientType, uncheckedIngredient, false).ifPresent(action);
}
}
@ -57,7 +57,7 @@ class ClientJeiUtil {
static <T> void showUsages(IFocusFactory focusFactory, ITypedIngredient<T> ingredient) {
if (Minecraft.getInstance().screen instanceof IRecipesGui recipesGui) {
// input + catalyst
recipesGui.show(List.of(focusFactory.createFocus(RecipeIngredientRole.INPUT, ingredient), focusFactory.createFocus(RecipeIngredientRole.CATALYST, ingredient)));
recipesGui.show(List.of(focusFactory.createFocus(RecipeIngredientRole.INPUT, ingredient), focusFactory.createFocus(RecipeIngredientRole.CRAFTING_STATION, ingredient)));
}
}
@ -65,13 +65,10 @@ class ClientJeiUtil {
INSTANCE;
@Override
public void render(GuiGraphics graphics, @Nullable ItemStack ingredient) {
public void render(GuiGraphicsExtractor graphics, @Nullable ItemStack ingredient) {
if (ingredient != null) {
// From mezz.jei.library.render.ItemStackRenderer
RenderSystem.enableDepthTest();
// From mezz.jei.library.render.ItemStackRenderer.render
ClientXeiUtil.renderItemWithAsterisk(graphics, ingredient);
// From end of DrawableIngredient
RenderSystem.disableDepthTest();
}
}

View File

@ -1,7 +1,7 @@
package thedarkcolour.exdeorum.compat.jei;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.types.IRecipeType;
import net.minecraft.network.chat.Component;
import thedarkcolour.exdeorum.compat.XeiSieveRecipe;
import thedarkcolour.exdeorum.data.TranslationKeys;
@ -13,7 +13,7 @@ class CompressedSieveCategory extends SieveCategory {
}
@Override
public RecipeType<XeiSieveRecipe> getRecipeType() {
public IRecipeType<XeiSieveRecipe> getRecipeType() {
return ExDeorumJeiPlugin.COMPRESSED_SIEVE;
}
}

View File

@ -23,17 +23,22 @@ import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
import mezz.jei.api.gui.builder.ITooltipBuilder;
import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.gui.inputs.IJeiInputHandler;
import mezz.jei.api.gui.inputs.IJeiUserInput;
import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
import mezz.jei.api.gui.widgets.IRecipeExtrasBuilder;
import mezz.jei.api.helpers.IJeiHelpers;
import mezz.jei.api.helpers.IModIdHelper;
import mezz.jei.api.recipe.IFocusFactory;
import mezz.jei.api.recipe.IFocusGroup;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import mezz.jei.api.recipe.types.IRecipeType;
import mezz.jei.api.runtime.IIngredientManager;
import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
@ -44,8 +49,10 @@ import thedarkcolour.exdeorum.registry.EItems;
public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
private static final Component REQUIRES_CERTAIN_STATE = Component.translatable(TranslationKeys.CROOK_CATEGORY_REQUIRES_STATE).withStyle(ChatFormatting.GRAY);
private static final int WIDTH = 120;
private static final int HEIGHT = 48;
private static final ScreenRectangle BLOCK_AREA = new ScreenRectangle(12, 10, 32, 32);
private final IDrawable background;
private final IDrawable icon;
private final IDrawable arrow;
private final IDrawable slot;
@ -59,7 +66,6 @@ public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
public CrookCategory(IJeiHelpers helpers, IDrawable arrow) {
var helper = helpers.getGuiHelper();
this.background = helper.createBlankDrawable(120, 48);
this.icon = helper.createDrawableItemStack(new ItemStack(EItems.CROOK.get()));
this.arrow = arrow;
this.slot = helper.getSlotDrawable();
@ -71,7 +77,7 @@ public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
}
@Override
public RecipeType<CrookJeiRecipe> getRecipeType() {
public IRecipeType<CrookJeiRecipe> getRecipeType() {
return ExDeorumJeiPlugin.CROOK;
}
@ -81,8 +87,13 @@ public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
}
@Override
public IDrawable getBackground() {
return this.background;
public int getWidth() {
return WIDTH;
}
@Override
public int getHeight() {
return HEIGHT;
}
@Override
@ -93,14 +104,29 @@ public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
@Override
public void setRecipe(IRecipeLayoutBuilder builder, CrookJeiRecipe recipe, IFocusGroup focuses) {
recipe.addIngredients(builder);
builder.addSlot(RecipeIngredientRole.OUTPUT, 80, 18).addItemStack(recipe.result).addRichTooltipCallback((recipeSlotView, tooltip) -> {
builder.addSlot(RecipeIngredientRole.OUTPUT, 80, 18).add(recipe.result).addRichTooltipCallback((_, tooltip) -> {
tooltip.add(ClientXeiUtil.formatChance(recipe.chance));
});
}
@Override
public void draw(CrookJeiRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
this.timer.onDraw();
public void createRecipeExtras(IRecipeExtrasBuilder builder, CrookJeiRecipe recipe, IFocusGroup focuses) {
builder.addInputHandler(new IJeiInputHandler() {
@Override
public ScreenRectangle getArea() {
return BLOCK_AREA;
}
@Override
public boolean handleInput(double mouseX, double mouseY, IJeiUserInput input) {
return CrookCategory.this.handleBlockInput(recipe, input);
}
});
}
@Override
public void draw(CrookJeiRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphicsExtractor graphics, double mouseX, double mouseY) {
this.timer.onDraw(Minecraft.getInstance().hasShiftDown());
this.arrow.draw(graphics, 50, 18);
this.slot.draw(graphics, 79, 17);
@ -126,22 +152,24 @@ public class CrookCategory implements IRecipeCategory<CrookJeiRecipe> {
}
}
@Override
public boolean handleInput(CrookJeiRecipe recipe, double mouseX, double mouseY, InputConstants.Key input) {
if (input.getType() == InputConstants.Type.MOUSE && (input.getValue() == InputConstants.MOUSE_BUTTON_LEFT || input.getValue() == InputConstants.MOUSE_BUTTON_RIGHT)) {
if (12 < mouseX && mouseX < 44 && 10 < mouseY && mouseY < 42) {
var block = this.timer.getCycledItem(recipe.states).getBlock();
ClientJeiUtil.checkTypedIngredient(this.ingredientManager, VanillaTypes.ITEM_STACK, new ItemStack(block.asItem()), ingredient -> {
if (input.getValue() == InputConstants.MOUSE_BUTTON_LEFT) {
ClientJeiUtil.showRecipes(this.focusFactory, ingredient);
} else if (input.getValue() == InputConstants.MOUSE_BUTTON_RIGHT) {
ClientJeiUtil.showUsages(this.focusFactory, ingredient);
}
});
private boolean handleBlockInput(CrookJeiRecipe recipe, IJeiUserInput input) {
var key = input.getKey();
if (key.getType() == InputConstants.Type.MOUSE && (key.getValue() == InputConstants.MOUSE_BUTTON_LEFT || key.getValue() == InputConstants.MOUSE_BUTTON_RIGHT)) {
if (input.isSimulate()) {
return true;
}
var block = this.timer.getCycledItem(recipe.states).getBlock();
ClientJeiUtil.checkTypedIngredient(this.ingredientManager, VanillaTypes.ITEM_STACK, new ItemStack(block.asItem()), ingredient -> {
if (key.getValue() == InputConstants.MOUSE_BUTTON_LEFT) {
ClientJeiUtil.showRecipes(this.focusFactory, ingredient);
} else {
ClientJeiUtil.showUsages(this.focusFactory, ingredient);
}
});
return true;
}
return false;
}

View File

@ -25,11 +25,12 @@ import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemStackTemplate;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.Nullable;
import thedarkcolour.exdeorum.compat.XeiUtil;
import thedarkcolour.exdeorum.recipe.BlockPredicate;
import thedarkcolour.exdeorum.recipe.crook.CrookRecipe;
@ -40,10 +41,10 @@ import java.util.List;
public sealed abstract class CrookJeiRecipe {
public final List<BlockState> states;
public ItemStack result;
public ItemStackTemplate result;
public float chance;
public CrookJeiRecipe(List<BlockState> states, ItemStack result, float chance) {
public CrookJeiRecipe(List<BlockState> states, ItemStackTemplate result, float chance) {
this.states = states;
this.result = result;
this.chance = chance;
@ -78,7 +79,12 @@ public sealed abstract class CrookJeiRecipe {
private final List<ItemStack> itemIngredients;
public final List<Component> requirements;
StatesRecipe(@Nullable BlockPredicate.BlockStatePredicate predicate, List<BlockState> states, ItemStack result, float chance) {
StatesRecipe(
BlockPredicate.@Nullable BlockStatePredicate predicate,
List<BlockState> states,
ItemStackTemplate result,
float chance
) {
super(states, result, chance);
ImmutableList.Builder<ItemStack> itemIngredients = ImmutableList.builder();
@ -112,30 +118,31 @@ public sealed abstract class CrookJeiRecipe {
static final class TagRecipe extends StatesRecipe {
public final TagKey<Block> tag;
public TagRecipe(TagKey<Block> tag, List<BlockState> states, ItemStack result, float chance) {
public TagRecipe(TagKey<Block> tag, List<BlockState> states, ItemStackTemplate result, float chance) {
super(null, states, result, chance);
this.tag = tag;
}
}
static final class BlockRecipe extends CrookJeiRecipe {
private final ItemStack itemIngredient;
@Nullable
private final ItemStackTemplate itemIngredient;
BlockRecipe(Block block, ItemStack result, float chance) {
BlockRecipe(Block block, ItemStackTemplate result, float chance) {
super(ImmutableList.of(block.defaultBlockState()), result, chance);
var item = block.asItem();
if (item == Items.AIR) {
this.itemIngredient = ItemStack.EMPTY;
this.itemIngredient = null;
} else {
this.itemIngredient = new ItemStack(item);
this.itemIngredient = new ItemStackTemplate(item);
}
}
@Override
public void addIngredients(IRecipeLayoutBuilder builder) {
if (!this.itemIngredient.isEmpty()) {
builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).addItemStack(this.itemIngredient);
if (this.itemIngredient != null) {
builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).add(this.itemIngredient);
}
}
}

View File

@ -21,7 +21,7 @@ package thedarkcolour.exdeorum.compat.jei;
import mezz.jei.api.gui.builder.IRecipeSlotBuilder;
import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.types.IRecipeType;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@ -36,12 +36,12 @@ abstract class CrucibleCategory extends OneToOneCategory<CrucibleRecipe> {
@Override
protected void addInput(IRecipeSlotBuilder slot, CrucibleRecipe recipe) {
slot.addIngredients(recipe.ingredient());
slot.add(recipe.ingredient());
}
@Override
protected void addOutput(IRecipeSlotBuilder slot, CrucibleRecipe recipe) {
slot.addFluidStack(recipe.getResult().fluid().value(), recipe.getResult().amount())
slot.add(recipe.getResult().fluid().value(), recipe.getResult().amount())
.setFluidRenderer(Math.max(1000, recipe.getResult().amount()), false, 16, 16);
}
@ -51,7 +51,7 @@ abstract class CrucibleCategory extends OneToOneCategory<CrucibleRecipe> {
}
@Override
public RecipeType<CrucibleRecipe> getRecipeType() {
public IRecipeType<CrucibleRecipe> getRecipeType() {
return ExDeorumJeiPlugin.LAVA_CRUCIBLE;
}
}
@ -62,7 +62,7 @@ abstract class CrucibleCategory extends OneToOneCategory<CrucibleRecipe> {
}
@Override
public RecipeType<CrucibleRecipe> getRecipeType() {
public IRecipeType<CrucibleRecipe> getRecipeType() {
return ExDeorumJeiPlugin.WATER_CRUCIBLE;
}
}

View File

@ -22,6 +22,8 @@ import mezz.jei.api.ingredients.IIngredientType;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
// constructor must be different from field types to make generics happy
@SuppressWarnings("ClassCanBeRecord")
final class CrucibleHeatSourceRecipe {
private final int meltRate;
private final BlockState blockState;

View File

@ -21,18 +21,24 @@ package thedarkcolour.exdeorum.compat.jei;
import com.mojang.blaze3d.platform.InputConstants;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.gui.builder.IRecipeLayoutBuilder;
import mezz.jei.api.gui.builder.ITooltipBuilder;
import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.gui.inputs.IJeiInputHandler;
import mezz.jei.api.gui.inputs.IJeiUserInput;
import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
import mezz.jei.api.gui.widgets.IRecipeExtrasBuilder;
import mezz.jei.api.helpers.IJeiHelpers;
import mezz.jei.api.helpers.IModIdHelper;
import mezz.jei.api.ingredients.IIngredientType;
import mezz.jei.api.recipe.IFocusFactory;
import mezz.jei.api.recipe.IFocusGroup;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import mezz.jei.api.recipe.types.IRecipeType;
import mezz.jei.api.runtime.IIngredientManager;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
@ -41,13 +47,11 @@ import thedarkcolour.exdeorum.compat.ClientXeiUtil;
import thedarkcolour.exdeorum.data.TranslationKeys;
import thedarkcolour.exdeorum.material.DefaultMaterials;
import java.util.List;
class CrucibleHeatSourcesCategory implements IRecipeCategory<CrucibleHeatSourceRecipe> {
public static final int WIDTH = 120;
public static final int HEIGHT = 48;
private static final ScreenRectangle HEAT_SOURCE_AREA = new ScreenRectangle(44, 16, 32, 32);
private final IDrawable background;
private final IDrawable icon;
private final Component title;
@ -57,7 +61,6 @@ class CrucibleHeatSourcesCategory implements IRecipeCategory<CrucibleHeatSourceR
public CrucibleHeatSourcesCategory(IJeiHelpers helpers) {
var helper = helpers.getGuiHelper();
this.background = helper.createBlankDrawable(WIDTH, HEIGHT);
this.title = Component.translatable(TranslationKeys.CRUCIBLE_HEAT_SOURCE_CATEGORY_TITLE);
this.icon = helper.createDrawableItemStack(new ItemStack(DefaultMaterials.PORCELAIN_CRUCIBLE.getItem()));
@ -67,7 +70,7 @@ class CrucibleHeatSourcesCategory implements IRecipeCategory<CrucibleHeatSourceR
}
@Override
public RecipeType<CrucibleHeatSourceRecipe> getRecipeType() {
public IRecipeType<CrucibleHeatSourceRecipe> getRecipeType() {
return ExDeorumJeiPlugin.CRUCIBLE_HEAT_SOURCES;
}
@ -77,8 +80,13 @@ class CrucibleHeatSourcesCategory implements IRecipeCategory<CrucibleHeatSourceR
}
@Override
public IDrawable getBackground() {
return this.background;
public int getWidth() {
return WIDTH;
}
@Override
public int getHeight() {
return HEIGHT;
}
@Override
@ -89,61 +97,75 @@ class CrucibleHeatSourcesCategory implements IRecipeCategory<CrucibleHeatSourceR
@Override
public void setRecipe(IRecipeLayoutBuilder builder, CrucibleHeatSourceRecipe recipe, IFocusGroup focuses) {
if (recipe.ingredientType() != null && recipe.ingredient() != null) {
builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).addIngredient(recipe.ingredientType(), recipe.ingredient());
builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).add(recipe.ingredientType(), recipe.ingredient());
} else {
builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).addIngredient(VanillaTypes.ITEM_STACK, ItemStack.EMPTY);
builder.addInvisibleIngredients(RecipeIngredientRole.INPUT).add(VanillaTypes.ITEM_STACK, ItemStack.EMPTY);
}
}
@Override
public void draw(CrucibleHeatSourceRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
public void createRecipeExtras(IRecipeExtrasBuilder builder, CrucibleHeatSourceRecipe recipe, IFocusGroup focuses) {
builder.addInputHandler(new IJeiInputHandler() {
@Override
public ScreenRectangle getArea() {
return HEAT_SOURCE_AREA;
}
@Override
public boolean handleInput(double mouseX, double mouseY, IJeiUserInput input) {
return CrucibleHeatSourcesCategory.this.handleHeatSourceInput(recipe, input);
}
});
}
@Override
public void draw(CrucibleHeatSourceRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphicsExtractor graphics, double mouseX, double mouseY) {
var volume = recipe.meltRate();
var volumeLabel = Component.translatable(TranslationKeys.CRUCIBLE_HEAT_SOURCE_CATEGORY_MULTIPLIER, volume);
var font = Minecraft.getInstance().font;
graphics.drawString(font, volumeLabel, 60 - font.width(volumeLabel) / 2, 5, 0xff808080, false);
graphics.text(font, volumeLabel, 60 - font.width(volumeLabel) / 2, 5, 0xff808080, false);
ClientXeiUtil.renderBlock(graphics, recipe.blockState(), 60, 24, 10, 20F);
}
@Override
public List<Component> getTooltipStrings(CrucibleHeatSourceRecipe recipe, IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) {
public void getTooltip(ITooltipBuilder tooltip, CrucibleHeatSourceRecipe recipe, IRecipeSlotsView recipeSlotsView, double mouseX, double mouseY) {
if (44.0 < mouseX && mouseX < 76.0 && 16 < mouseY && mouseY < 48) {
if (recipe.ingredientType() != null && recipe.ingredient() != null) {
var tooltip = this.ingredientManager.getIngredientRenderer(recipe.ingredientType()).getTooltip(recipe.ingredient(), Minecraft.getInstance().options.advancedItemTooltips ? TooltipFlag.ADVANCED : TooltipFlag.NORMAL);
return this.modIdHelper.addModNameToIngredientTooltip(tooltip, recipe.ingredient(), this.ingredientManager.getIngredientHelper(recipe.ingredientType()));
var tooltipLines = this.ingredientManager.getIngredientRenderer(recipe.ingredientType()).getTooltip(recipe.ingredient(), Minecraft.getInstance().options.advancedItemTooltips ? TooltipFlag.ADVANCED : TooltipFlag.NORMAL);
tooltip.addAll(tooltipLines);
this.ingredientManager.createTypedIngredient(recipe.ingredientType(), recipe.ingredient(), false)
.flatMap(this.modIdHelper::getModNameForTooltip)
.ifPresent(tooltip::add);
} else {
var block = recipe.blockState().getBlock();
var modId = BuiltInRegistries.BLOCK.getKey(block).getNamespace();
return List.of(Component.translatable(block.getDescriptionId()), Component.literal(this.modIdHelper.getFormattedModNameForModId(modId)));
tooltip.add(Component.translatable(block.getDescriptionId()));
tooltip.add(Component.literal(this.modIdHelper.getFormattedModNameForModId(modId)));
}
}
return List.of();
}
@Override
public boolean handleInput(CrucibleHeatSourceRecipe recipe, double mouseX, double mouseY, InputConstants.Key input) {
if (input.getType() == InputConstants.Type.MOUSE && (input.getValue() == InputConstants.MOUSE_BUTTON_LEFT || input.getValue() == InputConstants.MOUSE_BUTTON_RIGHT)) {
if (44.0 < mouseX && mouseX < 76.0 && 16 < mouseY && mouseY < 48) {
if (recipe.ingredientType() != null) {
ClientJeiUtil.checkTypedIngredient(this.ingredientManager, recipe.ingredientType(), recipe.ingredient(), ingredient -> {
if (input.getValue() == InputConstants.MOUSE_BUTTON_LEFT) {
ClientJeiUtil.showRecipes(this.focusFactory, ingredient);
} else if (input.getValue() == InputConstants.MOUSE_BUTTON_RIGHT) {
ClientJeiUtil.showUsages(this.focusFactory, ingredient);
}
});
}
private boolean handleHeatSourceInput(CrucibleHeatSourceRecipe recipe, IJeiUserInput input) {
var key = input.getKey();
if (key.getType() == InputConstants.Type.MOUSE && (key.getValue() == InputConstants.MOUSE_BUTTON_LEFT || key.getValue() == InputConstants.MOUSE_BUTTON_RIGHT)) {
if (input.isSimulate()) {
return true;
}
if (recipe.ingredientType() != null) {
ClientJeiUtil.checkTypedIngredient(this.ingredientManager, recipe.ingredientType(), recipe.ingredient(), ingredient -> {
if (key.getValue() == InputConstants.MOUSE_BUTTON_LEFT) {
ClientJeiUtil.showRecipes(this.focusFactory, ingredient);
} else {
ClientJeiUtil.showUsages(this.focusFactory, ingredient);
}
});
}
return true;
}
return false;
}
@Override
public int getHeight() {
return 48;
}
}

View File

@ -42,8 +42,8 @@ public class CycleTimer {
return list.get(Math.toIntExact(index));
}
public void onDraw() {
if (!Screen.hasShiftDown()) {
public void onDraw(boolean hasShiftDown) {
if (!hasShiftDown) {
if (pausedDuration > 0) {
this.startTime += this.pausedDuration;
this.pausedDuration = 0;

View File

@ -25,7 +25,7 @@ import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.gui.handlers.IGuiClickableArea;
import mezz.jei.api.gui.handlers.IGuiContainerHandler;
import mezz.jei.api.neoforge.NeoForgeTypes;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.types.IRecipeType;
import mezz.jei.api.registration.IGuiHandlerRegistration;
import mezz.jei.api.registration.IRecipeCatalystRegistration;
import mezz.jei.api.registration.IRecipeCategoryRegistration;
@ -75,22 +75,22 @@ import java.util.function.Supplier;
public class ExDeorumJeiPlugin implements IModPlugin {
public static final Identifier EX_DEORUM_JEI_TEXTURE = ExDeorum.loc("textures/gui/jei/enr_jei.png");
static final RecipeType<BarrelCompostRecipe> BARREL_COMPOST = recipeType("barrel_compost", BarrelCompostRecipe.class);
static final RecipeType<BarrelMixingRecipe> BARREL_MIXING = recipeType("barrel_mixing", BarrelMixingRecipe.class);
static final RecipeType<BarrelFluidMixingRecipe> BARREL_FLUID_MIXING = recipeType("barrel_fluid_mixing", BarrelFluidMixingRecipe.class);
static final RecipeType<CrucibleRecipe> LAVA_CRUCIBLE = recipeType("lava_crucible", CrucibleRecipe.class);
static final RecipeType<CrucibleRecipe> WATER_CRUCIBLE = recipeType("water_crucible", CrucibleRecipe.class);
static final RecipeType<CrucibleHeatSourceRecipe> CRUCIBLE_HEAT_SOURCES = recipeType("crucible_heat_sources", CrucibleHeatSourceRecipe.class);
static final RecipeType<XeiSieveRecipe> SIEVE = recipeType("sieve", XeiSieveRecipe.class);
static final RecipeType<XeiSieveRecipe> COMPRESSED_SIEVE = recipeType("compressed_sieve", XeiSieveRecipe.class);
static final RecipeType<HammerRecipe> HAMMER = recipeType("hammer", HammerRecipe.class);
static final RecipeType<HammerRecipe> COMPRESSED_HAMMER = recipeType("compressed_hammer", CompressedHammerRecipe.class);
static final RecipeType<CrookJeiRecipe> CROOK = recipeType("crook", CrookJeiRecipe.class);
static final IRecipeType<BarrelCompostRecipe> BARREL_COMPOST = recipeType("barrel_compost", BarrelCompostRecipe.class);
static final IRecipeType<BarrelMixingRecipe> BARREL_MIXING = recipeType("barrel_mixing", BarrelMixingRecipe.class);
static final IRecipeType<BarrelFluidMixingRecipe> BARREL_FLUID_MIXING = recipeType("barrel_fluid_mixing", BarrelFluidMixingRecipe.class);
static final IRecipeType<CrucibleRecipe> LAVA_CRUCIBLE = recipeType("lava_crucible", CrucibleRecipe.class);
static final IRecipeType<CrucibleRecipe> WATER_CRUCIBLE = recipeType("water_crucible", CrucibleRecipe.class);
static final IRecipeType<CrucibleHeatSourceRecipe> CRUCIBLE_HEAT_SOURCES = recipeType("crucible_heat_sources", CrucibleHeatSourceRecipe.class);
static final IRecipeType<XeiSieveRecipe> SIEVE = recipeType("sieve", XeiSieveRecipe.class);
static final IRecipeType<XeiSieveRecipe> COMPRESSED_SIEVE = recipeType("compressed_sieve", XeiSieveRecipe.class);
static final IRecipeType<HammerRecipe> HAMMER = recipeType("hammer", HammerRecipe.class);
static final IRecipeType<HammerRecipe> COMPRESSED_HAMMER = recipeType("compressed_hammer", CompressedHammerRecipe.class);
static final IRecipeType<CrookJeiRecipe> CROOK = recipeType("crook", CrookJeiRecipe.class);
private static <T> RecipeType<T> recipeType(String path, Class<? extends T> type) {
private static <T> IRecipeType<T> recipeType(String path, Class<? extends T> type) {
// use alternative namespace so that EMI doesn't skip JEI compatibility
String namespace = ModList.get().isLoaded(ModIds.EMI) ? ExDeorum.ID + "_" + ModIds.EMI : ExDeorum.ID;
return RecipeType.create(namespace, path, type);
return IRecipeType.create(namespace, path, type);
}
@Override
@ -127,42 +127,42 @@ public class ExDeorumJeiPlugin implements IModPlugin {
for (var barrel : barrels) {
var stack = new ItemStack(barrel);
registration.addRecipeCatalyst(stack, BARREL_COMPOST);
registration.addRecipeCatalyst(stack, BARREL_MIXING);
registration.addRecipeCatalyst(stack, BARREL_FLUID_MIXING);
registration.addCraftingStation(BARREL_COMPOST, stack);
registration.addCraftingStation(BARREL_MIXING, stack);
registration.addCraftingStation(BARREL_FLUID_MIXING, stack);
}
for (var lavaCrucible : lavaCrucibles) {
var stack = new ItemStack(lavaCrucible);
registration.addRecipeCatalyst(stack, LAVA_CRUCIBLE);
registration.addRecipeCatalyst(stack, CRUCIBLE_HEAT_SOURCES);
registration.addCraftingStation(LAVA_CRUCIBLE, stack);
registration.addCraftingStation(CRUCIBLE_HEAT_SOURCES, stack);
}
for (var waterCrucible : waterCrucibles) {
registration.addRecipeCatalyst(new ItemStack(waterCrucible), WATER_CRUCIBLE);
registration.addCraftingStation(WATER_CRUCIBLE, new ItemStack(waterCrucible));
}
for (var sieve : sieves) {
registration.addRecipeCatalyst(new ItemStack(sieve), SIEVE);
registration.addCraftingStation(SIEVE, new ItemStack(sieve));
}
for (var compressedSieve : compressedSieves) {
registration.addRecipeCatalyst(new ItemStack(compressedSieve), COMPRESSED_SIEVE);
registration.addCraftingStation(COMPRESSED_SIEVE, new ItemStack(compressedSieve));
}
registration.addRecipeCatalyst(new ItemStack(EItems.WOODEN_HAMMER.get()), HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.STONE_HAMMER.get()), HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.GOLDEN_HAMMER.get()), HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.IRON_HAMMER.get()), HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.DIAMOND_HAMMER.get()), HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.NETHERITE_HAMMER.get()), HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.MECHANICAL_HAMMER.get()), HAMMER);
registration.addCraftingStation(HAMMER, new ItemStack(EItems.WOODEN_HAMMER.get()));
registration.addCraftingStation(HAMMER, new ItemStack(EItems.STONE_HAMMER.get()));
registration.addCraftingStation(HAMMER, new ItemStack(EItems.GOLDEN_HAMMER.get()));
registration.addCraftingStation(HAMMER, new ItemStack(EItems.IRON_HAMMER.get()));
registration.addCraftingStation(HAMMER, new ItemStack(EItems.DIAMOND_HAMMER.get()));
registration.addCraftingStation(HAMMER, new ItemStack(EItems.NETHERITE_HAMMER.get()));
registration.addCraftingStation(HAMMER, new ItemStack(EItems.MECHANICAL_HAMMER.get()));
registration.addRecipeCatalyst(new ItemStack(EItems.COMPRESSED_WOODEN_HAMMER.get()), COMPRESSED_HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.COMPRESSED_STONE_HAMMER.get()), COMPRESSED_HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.COMPRESSED_GOLDEN_HAMMER.get()), COMPRESSED_HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.COMPRESSED_IRON_HAMMER.get()), COMPRESSED_HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.COMPRESSED_DIAMOND_HAMMER.get()), COMPRESSED_HAMMER);
registration.addRecipeCatalyst(new ItemStack(EItems.COMPRESSED_NETHERITE_HAMMER.get()), COMPRESSED_HAMMER);
registration.addCraftingStation(COMPRESSED_HAMMER, new ItemStack(EItems.COMPRESSED_WOODEN_HAMMER.get()));
registration.addCraftingStation(COMPRESSED_HAMMER, new ItemStack(EItems.COMPRESSED_STONE_HAMMER.get()));
registration.addCraftingStation(COMPRESSED_HAMMER, new ItemStack(EItems.COMPRESSED_GOLDEN_HAMMER.get()));
registration.addCraftingStation(COMPRESSED_HAMMER, new ItemStack(EItems.COMPRESSED_IRON_HAMMER.get()));
registration.addCraftingStation(COMPRESSED_HAMMER, new ItemStack(EItems.COMPRESSED_DIAMOND_HAMMER.get()));
registration.addCraftingStation(COMPRESSED_HAMMER, new ItemStack(EItems.COMPRESSED_NETHERITE_HAMMER.get()));
registration.addRecipeCatalyst(new ItemStack(EItems.CROOK.get()), CROOK);
registration.addRecipeCatalyst(new ItemStack(EItems.BONE_CROOK.get()), CROOK);
registration.addCraftingStation(CROOK, new ItemStack(EItems.CROOK.get()));
registration.addCraftingStation(CROOK, new ItemStack(EItems.BONE_CROOK.get()));
}
@Override
@ -299,7 +299,7 @@ public class ExDeorumJeiPlugin implements IModPlugin {
});
}
private static <C extends RecipeInput, T extends Recipe<C>> void addRecipes(IRecipeRegistration registration, RecipeType<T> category, Supplier<net.minecraft.world.item.crafting.RecipeType<T>> type) {
private static <C extends RecipeInput, T extends Recipe<C>> void addRecipes(IRecipeRegistration registration, IRecipeType<T> category, Supplier<net.minecraft.world.item.crafting.RecipeType<T>> type) {
registration.addRecipes(category, CompatUtil.collectAllRecipes(type.get(), Function.identity()));
}
}

View File

@ -21,7 +21,7 @@ package thedarkcolour.exdeorum.compat.jei;
import mezz.jei.api.gui.builder.IRecipeSlotBuilder;
import mezz.jei.api.gui.drawable.IDrawable;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.types.IRecipeType;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
@ -31,30 +31,30 @@ import thedarkcolour.exdeorum.recipe.hammer.HammerRecipe;
import java.util.function.Supplier;
class HammerCategory extends OneToOneCategory<HammerRecipe> {
private final RecipeType<HammerRecipe> recipeType;
private final IRecipeType<HammerRecipe> recipeType;
public HammerCategory(IGuiHelper helper, IDrawable arrow, Supplier<? extends Item> icon, Component title, RecipeType<HammerRecipe> recipeType) {
public HammerCategory(IGuiHelper helper, IDrawable arrow, Supplier<? extends Item> icon, Component title, IRecipeType<HammerRecipe> recipeType) {
super(helper, arrow, helper.createDrawableItemStack(new ItemStack(icon.get())), title);
this.recipeType = recipeType;
}
@Override
public RecipeType<HammerRecipe> getRecipeType() {
public IRecipeType<HammerRecipe> getRecipeType() {
return this.recipeType;
}
@Override
protected void addInput(IRecipeSlotBuilder slot, HammerRecipe recipe) {
slot.addIngredients(recipe.ingredient());
slot.add(recipe.ingredient());
}
@Override
protected void addOutput(IRecipeSlotBuilder slot, HammerRecipe recipe) {
if (recipe.resultAmount instanceof ConstantValue constant) {
slot.addItemStack(recipe.result.count() == 1 ? recipe.result.create() : recipe.result.withCount((int) constant.value()).create());
if (recipe.resultAmount instanceof ConstantValue(float value)) {
slot.add(recipe.result.count() == 1 ? recipe.result.create() : recipe.result.withCount((int) value).create());
} else {
slot.addItemStack(recipe.result.create());
slot.add(recipe.result.create());
SieveCategory.addTooltips(slot, false, recipe.resultAmount);
}
}

View File

@ -10,8 +10,8 @@ class JeiUtil {
}
public static IRecipeSlotBuilder addFluidIngredient(IRecipeSlotBuilder builder, FluidIngredient ingredient, int amount) {
for (var stack : ingredient.getStacks()) {
builder.addFluidStack(stack.getFluid(), amount);
for (var fluidHolder : ingredient.fluids()) {
builder.add(fluidHolder.value(), amount);
}
return builder;
}

View File

@ -26,21 +26,19 @@ import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.IFocusGroup;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.recipe.category.IRecipeCategory;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component;
abstract class OneToOneCategory<T> implements IRecipeCategory<T> {
public static final int WIDTH = 72;
public static final int HEIGHT = 18;
private final IDrawable background;
private final IDrawable arrow;
private final IDrawable icon;
private final IDrawable slot;
private final Component title;
public OneToOneCategory(IGuiHelper helper, IDrawable arrow, IDrawable icon, Component title) {
this.background = helper.createBlankDrawable(WIDTH, HEIGHT);
this.arrow = arrow;
this.icon = icon;
this.slot = helper.getSlotDrawable();
@ -48,6 +46,7 @@ abstract class OneToOneCategory<T> implements IRecipeCategory<T> {
}
protected abstract void addInput(IRecipeSlotBuilder slot, T recipe);
protected abstract void addOutput(IRecipeSlotBuilder slot, T recipe);
@Override
@ -62,8 +61,13 @@ abstract class OneToOneCategory<T> implements IRecipeCategory<T> {
}
@Override
public IDrawable getBackground() {
return this.background;
public int getWidth() {
return WIDTH;
}
@Override
public int getHeight() {
return HEIGHT;
}
@Override
@ -72,7 +76,7 @@ abstract class OneToOneCategory<T> implements IRecipeCategory<T> {
}
@Override
public void draw(T recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
public void draw(T recipe, IRecipeSlotsView recipeSlotsView, GuiGraphicsExtractor graphics, double mouseX, double mouseY) {
this.slot.draw(graphics);
this.arrow.draw(graphics, 25, 1);
this.slot.draw(graphics, 54, 0);

View File

@ -26,9 +26,9 @@ import mezz.jei.api.gui.ingredient.IRecipeSlotsView;
import mezz.jei.api.helpers.IGuiHelper;
import mezz.jei.api.recipe.IFocusGroup;
import mezz.jei.api.recipe.RecipeIngredientRole;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.category.IRecipeCategory;
import net.minecraft.client.gui.GuiGraphics;
import mezz.jei.api.recipe.types.IRecipeType;
import net.minecraft.client.gui.GuiGraphicsExtractor;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.ItemLike;
@ -59,7 +59,7 @@ class SieveCategory implements IRecipeCategory<XeiSieveRecipe> {
}
@Override
public RecipeType<XeiSieveRecipe> getRecipeType() {
public IRecipeType<XeiSieveRecipe> getRecipeType() {
return ExDeorumJeiPlugin.SIEVE;
}
@ -85,12 +85,12 @@ class SieveCategory implements IRecipeCategory<XeiSieveRecipe> {
@Override
public void setRecipe(IRecipeLayoutBuilder builder, XeiSieveRecipe recipe, IFocusGroup focuses) {
builder.addSlot(RecipeIngredientRole.INPUT, 59, 1).addIngredients(recipe.ingredient());
builder.addSlot(RecipeIngredientRole.CATALYST, 87, 1).addItemStack(recipe.mesh());
builder.addSlot(RecipeIngredientRole.INPUT, 59, 1).add(recipe.ingredient());
builder.addSlot(RecipeIngredientRole.CRAFTING_STATION, 87, 1).add(recipe.mesh());
for (int i = 0; i < recipe.results().size(); i++) {
var result = recipe.results().get(i);
var slot = builder.addSlot(RecipeIngredientRole.OUTPUT, 1 + (i % 9) * 18, 1 + XeiUtil.SIEVE_ROW_START + 18 * (i / 9)).addItemStack(result.item);
var slot = builder.addSlot(RecipeIngredientRole.OUTPUT, 1 + (i % 9) * 18, 1 + XeiUtil.SIEVE_ROW_START + 18 * (i / 9)).add(result.item);
addTooltips(slot, result.byHandOnly, result.provider);
}
@ -100,13 +100,13 @@ class SieveCategory implements IRecipeCategory<XeiSieveRecipe> {
if (byHandOnly) {
slot.setCustomRenderer(VanillaTypes.ITEM_STACK, ClientJeiUtil.AsteriskItemRenderer.INSTANCE);
}
slot.addRichTooltipCallback((slotView, tooltip) -> {
slot.addRichTooltipCallback((_, tooltip) -> {
XeiUtil.addSieveDropTooltip(byHandOnly, provider, tooltip::add);
});
}
@Override
public void draw(XeiSieveRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphics graphics, double mouseX, double mouseY) {
public void draw(XeiSieveRecipe recipe, IRecipeSlotsView recipeSlotsView, GuiGraphicsExtractor graphics, double mouseX, double mouseY) {
this.slot.draw(graphics, 58, 0);
this.slot.draw(graphics, 86, 0);

View File

@ -16,5 +16,5 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@javax.annotation.ParametersAreNonnullByDefault
@org.jspecify.annotations.NullMarked
package thedarkcolour.exdeorum.compat.jei;