1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-23 01:47:38 +00:00

Re-enable JEI integration

This commit is contained in:
Jonathan Coates
2025-07-12 21:41:50 +01:00
parent 4868c4aa32
commit 01de6110c6
4 changed files with 80 additions and 58 deletions

View File

@@ -14,7 +14,6 @@ plugins {
sourceSets.client {
java {
exclude("dan200/computercraft/client/integration/emi")
exclude("dan200/computercraft/client/integration/jei")
}
}

View File

@@ -8,13 +8,14 @@ import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.api.turtle.TurtleSide;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.integration.RecipeModHelpers;
import dan200.computercraft.shared.pocket.core.PocketSide;
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
import dan200.computercraft.shared.turtle.items.TurtleItem;
import mezz.jei.api.IModPlugin;
import mezz.jei.api.JeiPlugin;
import mezz.jei.api.constants.RecipeTypes;
import mezz.jei.api.constants.VanillaTypes;
import mezz.jei.api.ingredients.subtypes.IIngredientSubtypeInterpreter;
import mezz.jei.api.ingredients.subtypes.ISubtypeInterpreter;
import mezz.jei.api.registration.IAdvancedRegistration;
import mezz.jei.api.registration.ISubtypeRegistration;
import mezz.jei.api.runtime.IJeiRuntime;
@@ -46,7 +47,7 @@ public class JEIComputerCraft implements IModPlugin {
@Override
public void registerAdvanced(IAdvancedRegistration registry) {
registry.addRecipeManagerPlugin(new RecipeResolver(getRegistryAccess()));
registry.addSimpleRecipeManagerPlugin(RecipeTypes.CRAFTING, new RecipeResolver(getRegistryAccess()));
}
@Override
@@ -62,7 +63,7 @@ public class JEIComputerCraft implements IModPlugin {
// Hide all upgrade recipes
var category = registry.createRecipeLookup(RecipeTypes.CRAFTING);
category.get().forEach(wrapper -> {
if (RecipeModHelpers.shouldRemoveRecipe(wrapper.id())) {
if (RecipeModHelpers.shouldRemoveRecipe(wrapper.id().location())) {
registry.hideRecipes(RecipeTypes.CRAFTING, List.of(wrapper));
}
});
@@ -71,7 +72,7 @@ public class JEIComputerCraft implements IModPlugin {
/**
* Distinguishes turtles by upgrades and family.
*/
private static final IIngredientSubtypeInterpreter<ItemStack> turtleSubtype = (stack, ctx) -> {
private static final ISubtypeInterpreter<ItemStack> turtleSubtype = (stack, ctx) -> {
var name = new StringBuilder("turtle:");
// Add left and right upgrades to the identifier
@@ -87,12 +88,15 @@ public class JEIComputerCraft implements IModPlugin {
/**
* Distinguishes pocket computers by upgrade and family.
*/
private static final IIngredientSubtypeInterpreter<ItemStack> pocketSubtype = (stack, ctx) -> {
private static final ISubtypeInterpreter<ItemStack> pocketSubtype = (stack, ctx) -> {
var name = new StringBuilder("pocket:");
// Add the upgrade to the identifier
var upgrade = PocketComputerItem.getUpgradeWithData(stack);
if (upgrade != null) name.append(upgrade.holder().key().location());
var back = PocketComputerItem.getUpgradeWithData(stack, PocketSide.BACK);
var bottom = PocketComputerItem.getUpgradeWithData(stack, PocketSide.BOTTOM);
if (back != null) name.append(back.holder().key().location());
if (back != null && bottom != null) name.append('|');
if (bottom != null) name.append(bottom.holder().key().location());
return name.toString();
};
@@ -100,7 +104,7 @@ public class JEIComputerCraft implements IModPlugin {
/**
* Distinguishes disks by colour.
*/
private static final IIngredientSubtypeInterpreter<ItemStack> diskSubtype = (stack, ctx) -> Integer.toString(DyedItemColor.getOrDefault(stack, -1));
private static final ISubtypeInterpreter<ItemStack> diskSubtype = (stack, ctx) -> Integer.toString(DyedItemColor.getOrDefault(stack, -1));
private static RegistryAccess getRegistryAccess() {
return Minecraft.getInstance().level.registryAccess();

View File

@@ -8,71 +8,90 @@ import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.shared.integration.UpgradeRecipeGenerator;
import dan200.computercraft.shared.pocket.items.PocketComputerItem;
import dan200.computercraft.shared.turtle.items.TurtleItem;
import mezz.jei.api.constants.RecipeTypes;
import mezz.jei.api.recipe.IFocus;
import mezz.jei.api.recipe.RecipeType;
import mezz.jei.api.recipe.advanced.IRecipeManagerPlugin;
import mezz.jei.api.recipe.category.IRecipeCategory;
import mezz.jei.api.ingredients.ITypedIngredient;
import mezz.jei.api.recipe.advanced.ISimpleRecipeManagerPlugin;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingRecipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.*;
import net.minecraft.world.item.crafting.display.RecipeDisplay;
import net.minecraft.world.level.Level;
import java.util.List;
class RecipeResolver implements IRecipeManagerPlugin {
private final UpgradeRecipeGenerator<RecipeHolder<CraftingRecipe>> resolver;
class RecipeResolver implements ISimpleRecipeManagerPlugin<RecipeHolder<CraftingRecipe>> {
/**
* We need to generate unique ids for each recipe, as JEI will attempt to deduplicate them otherwise.
*/
private int nextId = 0;
private final UpgradeRecipeGenerator<RecipeHolder<CraftingRecipe>> resolver;
RecipeResolver(HolderLookup.Provider registries) {
resolver = new UpgradeRecipeGenerator<>(
x -> new RecipeHolder<>(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "upgrade_" + nextId++), x),
registries
);
resolver = new UpgradeRecipeGenerator<>(x -> new RecipeHolder<>(
ResourceKey.create(Registries.RECIPE, ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "upgrade_" + nextId++)),
new CraftingWrapper(x)
), registries);
}
@Override
public <V> List<RecipeType<?>> getRecipeTypes(IFocus<V> focus) {
var value = focus.getTypedValue().getIngredient();
if (!(value instanceof ItemStack stack)) return List.of();
return switch (focus.getRole()) {
case INPUT ->
stack.getItem() instanceof TurtleItem || stack.getItem() instanceof PocketComputerItem || resolver.isUpgrade(stack)
? List.of(RecipeTypes.CRAFTING)
: List.of();
case OUTPUT -> stack.getItem() instanceof TurtleItem || stack.getItem() instanceof PocketComputerItem
? List.of(RecipeTypes.CRAFTING)
: List.of();
default -> List.of();
};
public boolean isHandledInput(ITypedIngredient<?> input) {
return input.getIngredient() instanceof ItemStack stack
&& (stack.getItem() instanceof TurtleItem || stack.getItem() instanceof PocketComputerItem || resolver.isUpgrade(stack));
}
@Override
public <T, V> List<T> getRecipes(IRecipeCategory<T> recipeCategory, IFocus<V> focus) {
if (!(focus.getTypedValue().getIngredient() instanceof ItemStack stack) || recipeCategory.getRecipeType() != RecipeTypes.CRAFTING) {
return List.of();
}
return switch (focus.getRole()) {
case INPUT -> cast(RecipeTypes.CRAFTING, resolver.findRecipesWithInput(stack));
case OUTPUT -> cast(RecipeTypes.CRAFTING, resolver.findRecipesWithOutput(stack));
default -> List.of();
};
public boolean isHandledOutput(ITypedIngredient<?> output) {
return output.getIngredient() instanceof ItemStack stack
&& (stack.getItem() instanceof TurtleItem || stack.getItem() instanceof PocketComputerItem);
}
@Override
public <T> List<T> getRecipes(IRecipeCategory<T> recipeCategory) {
public List<RecipeHolder<CraftingRecipe>> getRecipesForInput(ITypedIngredient<?> input) {
return input.getIngredient() instanceof ItemStack stack ? resolver.findRecipesWithInput(stack) : List.of();
}
@Override
public List<RecipeHolder<CraftingRecipe>> getRecipesForOutput(ITypedIngredient<?> output) {
return output.getIngredient() instanceof ItemStack stack ? resolver.findRecipesWithOutput(stack) : List.of();
}
@Override
public List<RecipeHolder<CraftingRecipe>> getAllRecipes() {
return List.of();
}
@SuppressWarnings({ "unchecked", "rawtypes", "UnusedVariable" })
private static <T, U> List<T> cast(RecipeType<U> ignoredType, List<U> from) {
return (List) from;
private record CraftingWrapper(RecipeDisplay recipes) implements CraftingRecipe {
@Override
public RecipeSerializer<? extends CraftingRecipe> getSerializer() {
throw new IllegalStateException("Should not serialise CraftingWrapper");
}
@Override
public CraftingBookCategory category() {
return CraftingBookCategory.MISC;
}
@Override
public boolean matches(CraftingInput input, Level level) {
return false;
}
@Override
public ItemStack assemble(CraftingInput input, HolderLookup.Provider registries) {
return ItemStack.EMPTY;
}
@Override
public PlacementInfo placementInfo() {
return PlacementInfo.NOT_PLACEABLE;
}
@Override
public List<RecipeDisplay> display() {
return List.of(recipes);
}
}
}