Skip to content

Commit

Permalink
Allow for 'Strictable' Recipes
Browse files Browse the repository at this point in the history
  • Loading branch information
IntegerLimit committed Nov 30, 2024
1 parent 38b2afd commit 4e79c8e
Show file tree
Hide file tree
Showing 11 changed files with 359 additions and 17 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import com.nomiceu.nomilabs.LabsValues
import com.nomiceu.nomilabs.groovy.ShapedConversionRecipe
import com.nomiceu.nomilabs.groovy.ShapedDummyRecipe
import com.nomiceu.nomilabs.groovy.SimpleIIngredient
import com.nomiceu.nomilabs.util.ItemMeta
import net.minecraft.item.ItemStack
import net.minecraft.util.text.TextFormatting
import net.minecraftforge.fml.common.Loader

import static com.nomiceu.nomilabs.groovy.GroovyHelpers.NBTClearingRecipeHelpers.*
import static com.nomiceu.nomilabs.groovy.GroovyHelpers.TranslationHelpers.*
Expand Down Expand Up @@ -43,17 +48,20 @@ crafting.shapedBuilder()
// Examples: NBT Clearing
// Note that provided OUTPUT must match the output item in ALL CASES for that recipe!
// Simplest Form, Same Item for Input and Output
nbtClearingRecipe(item('storagedrawers:compdrawers'))
if (Loader.isModLoaded(LabsValues.STORAGE_DRAWERS_MODID))
nbtClearingRecipe(item('storagedrawers:compdrawers'))

// Different Item for Input and Output
nbtClearingRecipe(item('forge:bucketfilled'), item('minecraft:bucket'))

// Same Input/Output Item, Custom NBT Clearer
nbtClearingRecipe(item('storagedrawers:basicdrawers'), {
var tag = transferSubTags(it, 'material') // Transfer material, saved generated tag
tag = transferDrawerUpgradeData(it, tag) // Transfer Upgrades
it.tagCompound = tag // Remember to Save!
})
if (Loader.isModLoaded(LabsValues.STORAGE_DRAWERS_MODID)) {
nbtClearingRecipe(item('storagedrawers:basicdrawers'), {
var tag = transferSubTags(it, 'material') // Transfer material, saved generated tag
tag = transferDrawerUpgradeData(it, tag) // Transfer Upgrades
it.tagCompound = tag // Remember to Save!
})
}

// Different Input/Output Item, Custom NBT Clearer, Custom CanClear/Warning Tooltips
nbtClearingRecipe(item('minecraft:water_bucket'), item('minecraft:bucket'),
Expand All @@ -64,3 +72,62 @@ nbtClearingRecipe(item('minecraft:water_bucket'), item('minecraft:bucket'),
translatableLiteral('Warning: Great Water?').addFormat(TextFormatting.RED)
)

// Examples: Strict Recipes

/**
* This means, in JEI, the list of 'matching stacks' will be displayed
* exactly as set, instead of expanding wildcards and removing duplicates.
*/
// Only JEI display is affected! This is only useful with custom IIngredients!

// Custom IIngredient: Returns different NBTs of Stone (NBT's are auto-condensed by JEI)
class TestStone extends SimpleIIngredient {

ItemStack stone = item('minecraft:stone')

@Override
ItemStack[] getMatchingStacks() {
return [
item('minecraft:stone'),
item('minecraft:stone').withNbt(['display': ['Name': 'Test']]),
item('minecraft:stone').withNbt(['display': ['Name': 'Test 2']]),
item('minecraft:stone').withNbt(['display': ['Name': 'Test 3']]),
].toArray()
}

@Override
boolean test(ItemStack itemStack) {
return ItemMeta.compare(itemStack, stone)
}
}

// Without Strict: Shaped
crafting.shapedBuilder()
.name('shaped-no-strict')
.output(item('minecraft:dirt'))
.matrix([[new TestStone()]])
.register()

// With Strict: Shaped
crafting.shapedBuilder()
.name('shaped-strict')
.output(item('minecraft:dirt'))
.matrix([[new TestStone()]])
.strictJEIHandling()
.register()

// Without Strict: Shapeless
crafting.shapelessBuilder()
.name('shapeless-no-strict')
.output(item('minecraft:dirt'))
.input(new TestStone())
.register()

// With Strict: Shapeless
crafting.shapelessBuilder()
.name('shapeless-strict')
.output(item('minecraft:dirt'))
.input(new TestStone())
.strictJEIHandling()
.register()

4 changes: 3 additions & 1 deletion src/main/groovy-tests/dmeSimChamberTests.groovy
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
//MODS_LOADED: deepmoblearning

import com.nomiceu.nomilabs.LabsValues
import mustapelto.deepmoblearning.common.metadata.MetadataDataModel
import mustapelto.deepmoblearning.common.metadata.MetadataManager
import net.minecraftforge.fml.common.Loader

// Demonstration of Dynamically Generated DME Sim Chamber Recipes. (Goes in Post Init)
// DOES NOT WORK IF DME IS NOT INCLUDED IN LOAD!
// WILL NOT LOAD IF DME IS NOT INCLUDED!

def models = MetadataManager.dataModelMetadataList
for (var model : models) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
//MODS_LOADED: nuclearcraft

import com.nomiceu.nomilabs.groovy.NCActiveCoolerHelper

import static nc.enumm.MetaEnums.CoolerType.*

// Does not load if NuclearCraft is not loaded!

/**
* Change a NuclearCraft Active Cooler Recipe.<br>
* Inputs:<br>
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/com/nomiceu/nomilabs/groovy/SimpleIIngredient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.nomiceu.nomilabs.groovy;

import net.minecraft.item.crafting.Ingredient;

import org.jetbrains.annotations.Nullable;

import com.cleanroommc.groovyscript.api.IIngredient;

/**
* A template for a simple implementation of IIngredient, with stack size 1, no marks, and no copying.
* <p>
* Also sets `toMcIngredient` to return an ingredient of the matching stacks.
*/
public abstract class SimpleIIngredient implements IIngredient {

@Override
public Ingredient toMcIngredient() {
return Ingredient.fromStacks(getMatchingStacks());
}

@Override
public int getAmount() {
return 1;
}

@Override
public void setAmount(int amount) {}

@Override
public IIngredient exactCopy() {
return this;
}

@Nullable
@Override
public String getMark() {
return null;
}

@Override
public void setMark(String mark) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package com.nomiceu.nomilabs.groovy.mixinhelper;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.IRecipe;
import net.minecraftforge.common.crafting.IShapedRecipe;

import org.jetbrains.annotations.NotNull;

import com.cleanroommc.groovyscript.compat.mods.jei.ShapedRecipeWrapper;

import mezz.jei.api.IJeiHelpers;
import mezz.jei.api.ingredients.IIngredients;
import mezz.jei.api.ingredients.VanillaTypes;
import mezz.jei.api.recipe.IStackHelper;
import mezz.jei.plugins.vanilla.crafting.ShapelessRecipeWrapper;
import mezz.jei.recipes.BrokenCraftingRecipeException;
import mezz.jei.util.ErrorUtil;

/**
* Recipe wrappers that can return the matching stacks exactly for JEI,
* ignoring duplicates according to JEI and wildcard itemstacks.
*/
public class StrictableItemRecipeWrappers {

public static void getIngredientsImpl(@NotNull IIngredients ingredients, IRecipe recipe, IJeiHelpers jeiHelpers) {
ItemStack recipeOutput = recipe.getRecipeOutput();
List<List<ItemStack>> inputLists;

try {
if (recipe instanceof StrictableRecipe strict && strict.labs$getIsStrict()) {
inputLists = new ArrayList<>();
for (var input : recipe.getIngredients()) {
inputLists.add(new ArrayList<>(Arrays.asList(input.getMatchingStacks())));
}
} else {
IStackHelper stackHelper = jeiHelpers.getStackHelper();
inputLists = stackHelper.expandRecipeItemStackInputs(recipe.getIngredients());
}
ingredients.setInputLists(VanillaTypes.ITEM, inputLists);
ingredients.setOutput(VanillaTypes.ITEM, recipeOutput);
} catch (RuntimeException e) {
String info = ErrorUtil.getInfoFromBrokenCraftingRecipe(recipe, recipe.getIngredients(), recipeOutput);
throw new BrokenCraftingRecipeException(info, e);
}
}

public static class Shapeless extends ShapelessRecipeWrapper<IRecipe> {

protected final IJeiHelpers jeiHelpers;

public Shapeless(IJeiHelpers jeiHelpers, IRecipe recipe) {
super(jeiHelpers, recipe);
this.jeiHelpers = jeiHelpers;
}

@Override
public void getIngredients(@NotNull IIngredients ingredients) {
StrictableItemRecipeWrappers.getIngredientsImpl(ingredients, recipe, jeiHelpers);
}
}

public static class Shaped extends ShapedRecipeWrapper {

protected final IJeiHelpers jeiHelpers;

public Shaped(IJeiHelpers jeiHelpers, IShapedRecipe recipe) {
super(jeiHelpers, recipe);
this.jeiHelpers = jeiHelpers;
}

@Override
public void getIngredients(@NotNull IIngredients ingredients) {
StrictableItemRecipeWrappers.getIngredientsImpl(ingredients, recipe, jeiHelpers);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.nomiceu.nomilabs.groovy.mixinhelper;

/**
* A recipe that can return the matching stacks exactly for JEI,
* ignoring duplicates according to JEI and wildcard itemstacks.
*/
public interface StrictableRecipe {

void labs$setStrict();

boolean labs$getIsStrict();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.nomiceu.nomilabs.mixin.groovyscript;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;

import com.cleanroommc.groovyscript.compat.vanilla.CraftingRecipe;
import com.nomiceu.nomilabs.groovy.mixinhelper.StrictableRecipe;

/**
* Allows for recipes to be 'strict'. This means, in JEI, the list of 'matching stacks' will be displayed
* exactly as set, instead of expanding wildcards and removing duplicates.
*/
@Mixin(value = CraftingRecipe.class, remap = false)
public class CraftingRecipeMixin implements StrictableRecipe {

@Unique
private boolean labs$isStrict = false;

@Override
@Unique
public boolean labs$getIsStrict() {
return labs$isStrict;
}

@Override
@Unique
public void labs$setStrict() {
labs$isStrict = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.nomiceu.nomilabs.mixin.groovyscript;

import net.minecraft.item.crafting.IRecipe;
import net.minecraftforge.common.crafting.IShapedRecipe;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;

import com.cleanroommc.groovyscript.compat.mods.jei.JeiPlugin;
import com.cleanroommc.groovyscript.compat.mods.jei.ShapedRecipeWrapper;
import com.nomiceu.nomilabs.groovy.mixinhelper.StrictableItemRecipeWrappers;

import mezz.jei.api.IJeiHelpers;
import mezz.jei.plugins.vanilla.crafting.ShapelessRecipeWrapper;

/**
* Registers recipes with the new 'strictable' wrappers.
*/
@Mixin(value = JeiPlugin.class, remap = false)
public class JEIPluginMixin {

@Redirect(method = "lambda$register$0",
at = @At(value = "NEW",
target = "(Lmezz/jei/api/IJeiHelpers;Lnet/minecraftforge/common/crafting/IShapedRecipe;)Lcom/cleanroommc/groovyscript/compat/mods/jei/ShapedRecipeWrapper;"))
private static ShapedRecipeWrapper returnNewHandlerShaped(IJeiHelpers jeiHelpers, IShapedRecipe recipe) {
return new StrictableItemRecipeWrappers.Shaped(jeiHelpers, recipe);
}

@Redirect(method = "lambda$register$1",
at = @At(value = "NEW",
target = "(Lmezz/jei/api/IJeiHelpers;Lnet/minecraft/item/crafting/IRecipe;)Lmezz/jei/plugins/vanilla/crafting/ShapelessRecipeWrapper;"))
private static ShapelessRecipeWrapper<?> returnNewHandlerShapeless(IJeiHelpers jeiHelpers, IRecipe recipe) {
return new StrictableItemRecipeWrappers.Shapeless(jeiHelpers, recipe);
}
}
Loading

0 comments on commit 4e79c8e

Please sign in to comment.