diff --git a/dependencies.gradle b/dependencies.gradle index 1dbc8b9e0..62b54af87 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -47,8 +47,9 @@ final def mod_dependencies = [ 'the-aurorian-352137:4981736' : [project.debug_aurorian], 'avaritia_1_10-261348:3143349' : [project.debug_avaritia], 'atum-2-59621:3116599' : [project.debug_atum], - 'bwm-core-294335:2624990' : [project.debug_better_with_mods], - 'bwm-suite-246760:3289033' : [project.debug_better_with_mods], + 'better-with-addons-268326:2899407' : [project.debug_better_with_addons], + 'bwm-core-294335:2624990' : [project.debug_better_with_addons, project.debug_better_with_mods], + 'bwm-suite-246760:3289033' : [project.debug_better_with_addons, project.debug_better_with_mods], 'blood-arsenal-228823:2904183' : [project.debug_blood_arsenal], 'blood-magic-224791:2822288' : [project.debug_blood_arsenal, project.debug_blood_magic], 'guide-api-228832:2645992' : [project.debug_blood_arsenal, project.debug_blood_magic, project.debug_woot], @@ -180,6 +181,11 @@ dependencies { // runtimeOnly rfg.deobf('curse.maven:angry-pixel-the-betweenlands-mod-243363:4479688') } + compileOnly rfg.deobf('curse.maven:better-with-everything-896908:5202745') + if (!(project.debug_better_with_addons.toBoolean() || project.debug_better_with_mods.toBoolean()) && project.debug_better_with_everything.toBoolean()) { + runtimeOnly rfg.deobf('curse.maven:better-with-everything-896908:5202745') + } + compileOnly 'com.enderio:endercore:0.5.78' compileOnly 'crazypants:enderio:5.3.72' if (project.debug_enderio.toBoolean()) { diff --git a/examples/postInit/betterwithaddons.groovy b/examples/postInit/betterwithaddons.groovy new file mode 100644 index 000000000..09363b5b0 --- /dev/null +++ b/examples/postInit/betterwithaddons.groovy @@ -0,0 +1,260 @@ + +// Auto generated groovyscript example file +// MODS_LOADED: betterwithaddons + +log.info 'mod \'betterwithaddons\' detected, running script' + +// Drying Unit: +// Converts an input item into an output itemstack if placed within the appropriate multiblock. The multiblock is Sandstone +// directly below the Drying Box, 8 Sand around the Drying Box, and a Dead Bush placed on the Sand. Only functions in a +// non-snowy biome with sky access during the day, and functions twice as fast when in a hot biome. + +mods.betterwithaddons.drying_box.removeByInput(item('betterwithaddons:japanmat:2')) +mods.betterwithaddons.drying_box.removeByOutput(item('minecraft:sponge')) +// mods.betterwithaddons.drying_box.removeAll() + +mods.betterwithaddons.drying_box.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .register() + +mods.betterwithaddons.drying_box.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay') * 4) + .register() + + +// Fire Net: +// Converts an input item into any number of output itemstacks if placed within the appropriate multiblock. The multiblock +// is Lava or Fire directly below the Netted Screen, 8 Stone Brick around the Lava or Fire, and 8 Slat Blocks placed around +// the Netted Screen. + +mods.betterwithaddons.fire_net.removeByInput(item('betterwithaddons:iron_sand')) +mods.betterwithaddons.fire_net.removeByOutput(item('betterwithaddons:japanmat:12')) +// mods.betterwithaddons.fire_net.removeAll() + +mods.betterwithaddons.fire_net.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .register() + +mods.betterwithaddons.fire_net.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay') * 4, item('minecraft:diamond'), item('minecraft:diamond') * 2) + .register() + + +// Ancestral Infusion Crafting: +// Converts a custom crafting recipe an output itemstack, consuming Spirits from the Infused Soul Sand placed below the +// Ancestral Infuser if placed within the appropriate multiblock. The multiblock is either Soul Sand or Infused Soul Sand +// placed below the Ancestral Infuser and exclusively air blocks adjacent to the Infuser and Soul Sand blocks. + +mods.betterwithaddons.infuser.removeByInput(item('betterwithaddons:japanmat:16')) +mods.betterwithaddons.infuser.removeByOutput(item('betterwithaddons:ya')) +// mods.betterwithaddons.infuser.removeAll() + +mods.betterwithaddons.infuser.shapedBuilder() + .output(item('minecraft:stone')) + .matrix('BXX', + 'X B') + .key('B', item('minecraft:stone')) + .key('X', item('minecraft:gold_ingot')) + .spirits(1) + .mirrored() + .register() + +mods.betterwithaddons.infuser.shapedBuilder() + .output(item('minecraft:diamond') * 32) + .matrix([[item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot')], + [item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot')], + [item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot')]]) + .spirits(6) + .register() + +mods.betterwithaddons.infuser.shapelessBuilder() + .output(item('minecraft:clay') * 8) + .input(item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone')) + .register() + +mods.betterwithaddons.infuser.shapelessBuilder() + .output(item('minecraft:clay') * 32) + .input(item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond')) + .spirits(8) + .register() + + +// Alicio Tree Foods: +// Converts an input item into an amount of food for the tree to gradually consume, eventually summoning a random creature +// nearby. + +mods.betterwithaddons.lure_tree.removeByInput(item('minecraft:rotten_flesh')) +// mods.betterwithaddons.lure_tree.removeAll() + +mods.betterwithaddons.lure_tree.recipeBuilder() + .input(item('minecraft:diamond')) + .food(1000) + .register() + +mods.betterwithaddons.lure_tree.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .food(4) + .register() + + +mods.betterwithaddons.lure_tree.addBlacklist(entity('minecraft:chicken')) + +// Rotting Food: +// Converts an input item into an output itemstack after the given time has passed. Has the ability to customize the +// terminology used to indicate the age. + +mods.betterwithaddons.rotting.removeByInput(item('betterwithaddons:food_cooked_rice')) +mods.betterwithaddons.rotting.removeByOutput(item('minecraft:rotten_flesh')) +// mods.betterwithaddons.rotting.removeAll() + +mods.betterwithaddons.rotting.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .register() + +mods.betterwithaddons.rotting.recipeBuilder() + .input(item('placeholdername:snack')) + .time(100) + .key('groovy_example') + .rotted(item('minecraft:clay') * 4) + .register() + + +// Sand Net: +// Converts an input item into any number of output itemstacks if placed within the appropriate multiblock. The multiblock +// is a Slat Block directly below the Netted Screen, 8 Water Blocks around the Water, and 8 Slat Blocks placed around the +// Netted Screen. + +mods.betterwithaddons.sand_net.removeByInput(item('minecraft:iron_ingot')) +mods.betterwithaddons.sand_net.removeByOutput(item('minecraft:sand')) +mods.betterwithaddons.sand_net.removeByOutput(item('betterwithaddons:iron_sand')) +// mods.betterwithaddons.sand_net.removeAll() + +mods.betterwithaddons.sand_net.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .register() + +mods.betterwithaddons.sand_net.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:gold_ingot')) + .sand(2) + .register() + +mods.betterwithaddons.sand_net.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay') * 4, item('minecraft:diamond'), item('minecraft:diamond') * 2) + .sand(5) + .register() + + +// Soaking Unit: +// Converts an input item into an output itemstack if placed within the appropriate multiblock. The multiblock is Ice +// directly above the Soaking Box, 8 Water around the Soaking Box, and Water directly below the Soaking Box. + +mods.betterwithaddons.soaking_box.removeByInput(item('betterwithaddons:bamboo')) +mods.betterwithaddons.soaking_box.removeByOutput(item('betterwithaddons:japanmat:8')) +// mods.betterwithaddons.soaking_box.removeAll() + +mods.betterwithaddons.soaking_box.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .register() + +mods.betterwithaddons.soaking_box.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay') * 4) + .register() + + +// Spindle: +// Converts an input itemstack into an output itemstack, with the ability to consume the Spindle, when placed against a +// Spinning Wheel powered by Mechanical Power. + +mods.betterwithaddons.spindle.removeByInput(item('minecraft:vine')) +mods.betterwithaddons.spindle.removeByOutput(item('betterwithaddons:bolt')) +// mods.betterwithaddons.spindle.removeAll() + +mods.betterwithaddons.spindle.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .register() + +mods.betterwithaddons.spindle.recipeBuilder() + .input(item('minecraft:clay') * 3) + .output(item('minecraft:diamond')) + .popoff() + .register() + +mods.betterwithaddons.spindle.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay') * 4) + .register() + + +// Tatara: +// Converts an input item into an output itemstack if placed within the appropriate multiblock while fueled by Rice Ashes. +// The multiblock is Lava or Fire directly below the Tatara, 8 Clay around the Lava or Fire, 9 Nether Brick above the +// Tatara, 4 Stone Brick diagonal to the Tatara and two Iron Blocks across from each other adjacent to the Tatara. + +mods.betterwithaddons.tatara.removeByInput(item('betterwithaddons:japanmat:20')) +mods.betterwithaddons.tatara.removeByOutput(item('betterwithaddons:kera')) +// mods.betterwithaddons.tatara.removeAll() + +mods.betterwithaddons.tatara.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .register() + +mods.betterwithaddons.tatara.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay') * 4) + .register() + + +// Ancestral Infusion Transmutation: +// Converts an input item into an output itemstack, consuming Spirits from the Infused Soul Sand placed below the Ancestral +// Infuser if placed within the appropriate multiblock. The multiblock is either Soul Sand or Infused Soul Sand placed +// below the Ancestral Infuser and exclusively air blocks adjacent to the Infuser and Soul Sand blocks. + +mods.betterwithaddons.transmutation.removeByInput(item('minecraft:reeds')) +mods.betterwithaddons.transmutation.removeByOutput(item('betterwithaddons:crop_rice')) +// mods.betterwithaddons.transmutation.removeAll() + +mods.betterwithaddons.transmutation.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .spirits(0) + .register() + +mods.betterwithaddons.transmutation.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay') * 4) + .spirits(5) + .register() + + +// Water Net: +// Converts an input item into any number of output itemstacks if placed within the appropriate multiblock. The multiblock +// is a Water Block directly below the Netted Screen, 8 Sakura Planks around the Water Block, and 8 Slat Blocks placed +// around the Netted Screen. + +mods.betterwithaddons.water_net.removeByInput(item('betterwithaddons:iron_sand')) +mods.betterwithaddons.water_net.removeByOutput(item('betterwithaddons:food_sashimi')) +mods.betterwithaddons.water_net.removeByOutput(item('betterwithaddons:food_fugu_sac')) +// mods.betterwithaddons.water_net.removeAll() + +mods.betterwithaddons.water_net.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .register() + +mods.betterwithaddons.water_net.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay') * 4, item('minecraft:diamond'), item('minecraft:diamond') * 2) + .register() + + diff --git a/gradle.properties b/gradle.properties index d7ecd0f37..595a20b68 100644 --- a/gradle.properties +++ b/gradle.properties @@ -33,6 +33,8 @@ debug_atum = false debug_aurorian = false debug_avaritia = false +debug_better_with_addons = false +debug_better_with_everything = false debug_better_with_mods = false debug_betweenlands = false debug_blood_arsenal = false diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java index 0bee1eb2e..68a3b36ce 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java @@ -15,6 +15,7 @@ import com.cleanroommc.groovyscript.compat.mods.astralsorcery.AstralSorcery; import com.cleanroommc.groovyscript.compat.mods.atum.Atum; import com.cleanroommc.groovyscript.compat.mods.avaritia.Avaritia; +import com.cleanroommc.groovyscript.compat.mods.betterwithaddons.BetterWithAddons; import com.cleanroommc.groovyscript.compat.mods.betterwithmods.BetterWithMods; import com.cleanroommc.groovyscript.compat.mods.betweenlands.Betweenlands; import com.cleanroommc.groovyscript.compat.mods.bloodarsenal.BloodArsenal; @@ -98,6 +99,7 @@ public class ModSupport { public static final GroovyContainer ASTRAL_SORCERY = new InternalModContainer<>("astralsorcery", "Astral Sorcery", AstralSorcery::new, "astral"); public static final GroovyContainer ATUM = new InternalModContainer<>("atum", "Atum 2", Atum::new); public static final GroovyContainer AVARITIA = new InternalModContainer<>("avaritia", "Avaritia", Avaritia::new); + public static final GroovyContainer BETTER_WITH_ADDONS = new InternalModContainer<>("betterwithaddons", "Better With Addons", BetterWithAddons::new); public static final GroovyContainer BETTER_WITH_MODS = new InternalModContainer<>("betterwithmods", "Better With Mods", BetterWithMods::new); public static final GroovyContainer BETWEENLANDS = new InternalModContainer<>("thebetweenlands", "The Betweenlands", Betweenlands::new, "betweenlands"); public static final GroovyContainer BLOOD_ARSENAL = new InternalModContainer<>("bloodarsenal", "Blood Arsenal", BloodArsenal::new); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/actuallyadditions/Empowerer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/actuallyadditions/Empowerer.java index fa0633d2d..ef95133fb 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/actuallyadditions/Empowerer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/actuallyadditions/Empowerer.java @@ -182,7 +182,7 @@ public void validate(GroovyLog.Msg msg) { validateItems(msg, 4, 4, 1, 1); validateFluids(msg); msg.add(mainInput == null, "mainInput must be defined"); - msg.add(IngredientHelper.overMaxSize(mainInput, 1), "mainInput must have a stack size of 1"); + validateStackSize(msg, 1, "mainInput", mainInput); msg.add(energyPerStand < 0, "energyPerStand must be a non negative integer, yet it was {}", energyPerStand); msg.add(time <= 0, "time must be an integer greater than 0, yet it was {}", time); msg.add(red < 0 || red > 1, "red must be a float between 0 and 1, yet it was {}", red); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/BetterWithAddons.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/BetterWithAddons.java new file mode 100644 index 000000000..39fba6f0a --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/BetterWithAddons.java @@ -0,0 +1,44 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.util.IngredientSized; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; +import net.minecraft.item.crafting.Ingredient; +import net.minecraftforge.fml.common.Loader; + +public class BetterWithAddons extends GroovyPropertyContainer { + + public final DryingBox dryingBox = new DryingBox(); + public final FireNet fireNet = new FireNet(); + public final Infuser infuser = new Infuser(); + public final LureTree lureTree = new LureTree(); + public final Packing packing; + public final Rotting rotting = new Rotting(); + public final SandNet sandNet = new SandNet(); + public final SoakingBox soakingBox = new SoakingBox(); + public final Spindle spindle = new Spindle(); + public final Tatara tatara = new Tatara(); + public final Transmutation transmutation = new Transmutation(); + public final WaterNet waterNet = new WaterNet(); + + public BetterWithAddons() { + // the format of "PackingRecipe" has changed, and we cannot build against both. + packing = isBetterWithEverything() ? null : new Packing(); + } + + /** + * Because Better With Addons checks if the ingredient is an instanceof {@link betterwithaddons.util.IHasSize IHasSize} + * to determine if the Ingredient has an amount, we have to use their custom Ingredient. + *

+ * If this isn't used, then the recipe may appear correctly in JEI but will actually only consume 1 when done in-game. + */ + public static Ingredient fromIIngredient(IIngredient ingredient) { + return new IngredientSized(ingredient.toMcIngredient(), ingredient.getAmount()); + } + + public static boolean isBetterWithEverything() { + var entry = Loader.instance().getIndexedModList().get("betterwithaddons"); + if (entry == null) return false; + return entry.getMetadata().authorList.contains("ACGaming"); // TODO identify a better way to do this, if one exists + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/DryingBox.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/DryingBox.java new file mode 100644 index 000000000..e674627ca --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/DryingBox.java @@ -0,0 +1,85 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.block.EriottoMod.BlockCherryBox; +import betterwithaddons.crafting.manager.CraftingManagerDryingBox; +import betterwithaddons.crafting.recipes.CherryBoxRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription +public class DryingBox extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:diamond')).output(item('minecraft:clay'))"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay') * 4)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CraftingManagerDryingBox.instance().getRecipes(); + } + + @MethodDescription(example = @Example("item('betterwithaddons:japanmat:2')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getRecipeInputs()) { + if (input.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @MethodDescription(example = @Example("item('minecraft:sponge')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getRecipeOutputs()) { + if (output.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Drying Box recipe"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable CherryBoxRecipe register() { + if (!validate()) return null; + CherryBoxRecipe recipe = new CherryBoxRecipe(BlockCherryBox.CherryBoxType.DRYING, BetterWithAddons.fromIIngredient(input.get(0)), output.get(0)); + ModSupport.BETTER_WITH_ADDONS.get().dryingBox.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/FireNet.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/FireNet.java new file mode 100644 index 000000000..b6fc35518 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/FireNet.java @@ -0,0 +1,86 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.block.EriottoMod.BlockNettedScreen; +import betterwithaddons.crafting.manager.CraftingManagerFireNet; +import betterwithaddons.crafting.recipes.NetRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription(admonition = @Admonition("groovyscript.wiki.betterwithaddons.fire_net.note0")) +public class FireNet extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:diamond')).output(item('minecraft:clay'))"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay') * 4, item('minecraft:diamond'), item('minecraft:diamond') * 2)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CraftingManagerFireNet.getInstance().getRecipes(); + } + + @MethodDescription(example = @Example("item('betterwithaddons:iron_sand')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getInput()) { + if (input.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @MethodDescription(example = @Example("item('betterwithaddons:japanmat:12')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getOutput()) { + if (output.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(gte = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Fire Net recipe"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, Integer.MAX_VALUE); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable NetRecipe register() { + if (!validate()) return null; + NetRecipe recipe = new NetRecipe(BlockNettedScreen.SifterType.FIRE, BetterWithAddons.fromIIngredient(input.get(0)), 0, output.toArray(new ItemStack[0])); + ModSupport.BETTER_WITH_ADDONS.get().fireNet.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Infuser.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Infuser.java new file mode 100644 index 000000000..4e2644afb --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Infuser.java @@ -0,0 +1,56 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.crafting.manager.CraftingManagerInfuser; +import betterwithaddons.crafting.recipes.infuser.InfuserRecipe; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.Example; +import com.cleanroommc.groovyscript.api.documentation.annotations.MethodDescription; +import com.cleanroommc.groovyscript.api.documentation.annotations.RecipeBuilderDescription; +import com.cleanroommc.groovyscript.api.documentation.annotations.RegistryDescription; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; + +import java.util.Collection; + +@RegistryDescription +public class Infuser extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".output(item('minecraft:stone')).matrix('BXX', 'X B').key('B', item('minecraft:stone')).key('X', item('minecraft:gold_ingot')).spirits(1).mirrored()"), + @Example(".output(item('minecraft:diamond') * 32).matrix([[item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot')],[item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot')],[item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot')]]).spirits(6)") + }) + public InfuserRecipeBuilder.Shaped shapedBuilder() { + return new InfuserRecipeBuilder.Shaped(); + } + + @RecipeBuilderDescription(example = { + @Example(".output(item('minecraft:clay') * 8).input(item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'))"), + @Example(".output(item('minecraft:clay') * 32).input(item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:diamond')).spirits(8)") + }) + public InfuserRecipeBuilder.Shapeless shapelessBuilder() { + return new InfuserRecipeBuilder.Shapeless(); + } + + @Override + public Collection getRecipes() { + return CraftingManagerInfuser.getInstance().getRecipeList(); + } + + @MethodDescription(example = @Example("item('betterwithaddons:japanmat:16')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (var ingredient : r.internal.getIngredients()) { + for (var stack : ingredient.getMatchingStacks()) { + if (input.test(stack)) { + return doAddBackup(r); + } + } + } + return false; + }); + } + + @MethodDescription(example = @Example("item('betterwithaddons:ya')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> output.test(r.internal.getRecipeOutput()) && doAddBackup(r)); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/InfuserRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/InfuserRecipeBuilder.java new file mode 100644 index 000000000..b6b745ea8 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/InfuserRecipeBuilder.java @@ -0,0 +1,110 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.crafting.recipes.infuser.InfuserRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.documentation.annotations.Comp; +import com.cleanroommc.groovyscript.api.documentation.annotations.Property; +import com.cleanroommc.groovyscript.api.documentation.annotations.RecipeBuilderMethodDescription; +import com.cleanroommc.groovyscript.api.documentation.annotations.RecipeBuilderRegistrationMethod; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.vanilla.ShapedCraftingRecipe; +import com.cleanroommc.groovyscript.compat.vanilla.ShapelessCraftingRecipe; +import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.registry.AbstractCraftingRecipeBuilder; + +public interface InfuserRecipeBuilder { + + @RecipeBuilderMethodDescription + InfuserRecipeBuilder spirits(int spirits); + + class Shaped extends AbstractCraftingRecipeBuilder.AbstractShaped implements InfuserRecipeBuilder { + + @Property(comp = @Comp(gte = 0)) + protected int spirits; + + public Shaped() { + super(3, 3); + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_infuser_shaped_"; + } + + @Override + @RecipeBuilderMethodDescription + public Shaped spirits(int spirits) { + this.spirits = spirits; + return this; + } + + public boolean validate() { + GroovyLog.Msg msg = GroovyLog.msg("Error adding shaped Infuser Crafting recipe").error(); + msg.add((keyBasedMatrix == null || keyBasedMatrix.length == 0) && (ingredientMatrix == null || ingredientMatrix.isEmpty()), () -> "No matrix was defined"); + msg.add(keyBasedMatrix != null && ingredientMatrix != null, () -> "A key based matrix AND a ingredient based matrix was defined. This is not allowed!"); + msg.add(IngredientHelper.isEmpty(this.output), () -> "Output must not be empty"); + msg.add(spirits < 0, "spirits must be a nonnegative integer, yet it was {}", spirits); + return !msg.postIfNotEmpty(); + } + + @Override + @RecipeBuilderRegistrationMethod + public InfuserRecipe register() { + if (!validate()) return null; + GroovyLog.Msg msg = GroovyLog.msg("Error adding shaped Infuser Crafting recipe").error(); + + ShapedCraftingRecipe recipe = null; + if (keyBasedMatrix != null) { + recipe = validateShape(msg, errors, keyBasedMatrix, keyMap, ((width1, height1, ingredients) -> new ShapedCraftingRecipe(output, ingredients, width1, height1, mirrored, recipeFunction, recipeAction))); + } else if (ingredientMatrix != null) { + recipe = validateShape(msg, ingredientMatrix, ((width1, height1, ingredients) -> new ShapedCraftingRecipe(output.copy(), ingredients, width1, height1, mirrored, recipeFunction, recipeAction))); + } + if (msg.postIfNotEmpty()) return null; + + InfuserRecipe external = new InfuserRecipe(recipe, this.spirits); + ModSupport.BETTER_WITH_ADDONS.get().infuser.add(external); + return external; + } + } + + class Shapeless extends AbstractCraftingRecipeBuilder.AbstractShapeless implements InfuserRecipeBuilder { + + @Property(comp = @Comp(gte = 0)) + protected int spirits; + + public Shapeless() { + super(3, 3); + } + + @Override + public String getRecipeNamePrefix() { + return "groovyscript_infuser_shapeless_"; + } + + @Override + @RecipeBuilderMethodDescription + public Shapeless spirits(int spirits) { + this.spirits = spirits; + return this; + } + + public boolean validate() { + GroovyLog.Msg msg = GroovyLog.msg("Error adding shapeless Infuser Crafting recipe").error(); + msg.add(IngredientHelper.isEmpty(this.output), () -> "Output must not be empty"); + msg.add(ingredients.isEmpty(), () -> "inputs must not be empty"); + msg.add(ingredients.size() > width * height, () -> "maximum inputs are " + (width * height) + " but found " + ingredients.size()); + msg.add(spirits < 0, "spirits must be a nonnegative integer, yet it was {}", spirits); + return !msg.postIfNotEmpty(); + } + + @Override + @RecipeBuilderRegistrationMethod + public InfuserRecipe register() { + if (!validate()) return null; + ShapelessCraftingRecipe recipe = new ShapelessCraftingRecipe(output, ingredients, recipeFunction, recipeAction); + InfuserRecipe external = new InfuserRecipe(recipe, this.spirits); + ModSupport.BETTER_WITH_ADDONS.get().infuser.add(external); + return external; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/LureTree.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/LureTree.java new file mode 100644 index 000000000..7a816ff50 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/LureTree.java @@ -0,0 +1,118 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.tileentity.TileEntityLureTree; +import com.cleanroommc.groovyscript.api.GroovyBlacklist; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.core.mixin.betterwithaddons.TileEntityLureTreeAccessor; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.AbstractReloadableStorage; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import net.minecraft.entity.Entity; +import net.minecraftforge.fml.common.registry.EntityEntry; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription(category = RegistryDescription.Category.ENTRIES, admonition = @Admonition(value = "groovyscript.wiki.betterwithaddons.lure_tree.note0", type = Admonition.Type.INFO)) +public class LureTree extends StandardListRegistry { + + private final AbstractReloadableStorage> blacklistStorage = new AbstractReloadableStorage<>(); + + @Override + @GroovyBlacklist + @ApiStatus.Internal + public void onReload() { + super.onReload(); + getBlacklist().removeAll(blacklistStorage.removeScripted()); + getBlacklist().addAll(blacklistStorage.restoreFromBackup()); + } + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:diamond')).food(1000)"), + @Example(".input(item('minecraft:gold_ingot')).food(4)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return TileEntityLureTree.getTreeFoods(); + } + + @MethodDescription(type = MethodDescription.Type.QUERY) + public Collection> getBlacklist() { + return TileEntityLureTreeAccessor.getBlacklist(); + } + + @MethodDescription(example = @Example("item('minecraft:rotten_flesh')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> input.test(r.stack) && doAddBackup(r)); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public boolean addBlacklist(Class entity) { + return getBlacklist().add(entity) && blacklistStorage.addScripted(entity); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION, example = @Example("entity('minecraft:chicken')")) + public boolean addBlacklist(EntityEntry entity) { + return addBlacklist(entity.getEntityClass()); + } + + @MethodDescription + public boolean removeBlacklist(Class entity) { + return getBlacklist().removeIf(r -> entity.equals(r) && blacklistStorage.addBackup(r)); + } + + @MethodDescription + public boolean removeBlacklist(EntityEntry entity) { + return removeBlacklist(entity.getEntityClass()); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(gte = 0)) + private int food; + + @RecipeBuilderMethodDescription + public RecipeBuilder food(int food) { + this.food = food; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Lure Tree entry"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 0); + validateFluids(msg); + msg.add(food < 0, "food must be greater than or equal to 0, yet it was {}", food); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable TileEntityLureTree.TreeFood register() { + if (!validate()) return null; + TileEntityLureTree.TreeFood recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new TileEntityLureTree.TreeFood(stack, food); + ModSupport.BETTER_WITH_ADDONS.get().lureTree.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Packing.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Packing.java new file mode 100644 index 000000000..0e973d0de --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Packing.java @@ -0,0 +1,94 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.crafting.manager.CraftingManagerPacking; +import betterwithaddons.crafting.recipes.PackingRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import net.minecraft.block.state.IBlockState; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription +public class Packing extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:gold_ingot')).compress(blockstate('minecraft:clay'))"), + @Example(".input(item('minecraft:clay') * 10).compress(blockstate('minecraft:diamond_block'))"), + @Example(".input(item('minecraft:diamond')).compress(blockstate('minecraft:dirt')).jeiOutput(item('minecraft:diamond') * 64)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CraftingManagerPacking.getInstance().getRecipes(); + } + + @MethodDescription(example = @Example("blockstate('minecraft:gravel')")) + public boolean removeByOutput(IBlockState output) { + return getRecipes().removeIf(r -> output.equals(r.output) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("item('minecraft:clay_ball')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getRecipeInputs()) { + if (input.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(not = "null")) + private IBlockState compress; + @Property(defaultValue = "compress as ItemStack", comp = @Comp(not = "null")) + private ItemStack jeiOutput; + + @RecipeBuilderMethodDescription + public RecipeBuilder compress(IBlockState compress) { + this.compress = compress; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder jeiOutput(ItemStack jeiOutput) { + this.jeiOutput = jeiOutput; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Packing recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 0); + validateFluids(msg); + msg.add(compress == null, "compress cannot be null, yet it was"); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable PackingRecipe register() { + if (!validate()) return null; + PackingRecipe recipe = new PackingRecipe(BetterWithAddons.fromIIngredient(input.get(0)), compress); + recipe.setJeiOutput(IngredientHelper.isEmpty(jeiOutput) ? IngredientHelper.toItemStack(compress) : jeiOutput); + ModSupport.BETTER_WITH_ADDONS.get().packing.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Rotting.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Rotting.java new file mode 100644 index 000000000..22be4e306 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Rotting.java @@ -0,0 +1,158 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.handler.RotHandler; +import betterwithaddons.handler.RotHandler.RotInfo; +import betterwithaddons.interaction.InteractionBWA; +import betterwithaddons.item.ModItems; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.core.mixin.betterwithaddons.RotHandlerAccessor; +import com.cleanroommc.groovyscript.core.mixin.betterwithaddons.RotInfoAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import com.google.common.collect.Multimap; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Nullable; + +import java.util.Map; + +@RegistryDescription(category = RegistryDescription.Category.ENTRIES, admonition = @Admonition(value = "groovyscript.wiki.betterwithaddons.rotting.note0", type = Admonition.Type.WARNING)) +public class Rotting extends VirtualizedRegistry> { + + private static Item toKey(RotInfo recipe) { + return ((RotInfoAccessor) recipe).getItemStack().getItem(); + } + + private static Map.Entry toEntry(RotInfo recipe) { + return Pair.of(toKey(recipe), recipe); + } + + @Override + public boolean isEnabled() { + return InteractionBWA.ROTTEN_FOOD; + } + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:gold_ingot'))"), + @Example(".input(item('placeholdername:snack')).time(100).key('groovy_example').rotted(item('minecraft:clay') * 4)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public void onReload() { + removeScripted().forEach(recipe -> getEntries().entries().removeIf(r -> r.getKey().equals(recipe.getKey()) && r.getValue().equals(recipe.getValue()))); + restoreFromBackup().forEach(r -> getEntries().put(r.getKey(), r.getValue())); + } + + public Multimap getEntries() { + return RotHandlerAccessor.getRottingItems(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION, priority = 500) + public boolean add(RotInfo recipe) { + return recipe != null && getEntries().put(toKey(recipe), recipe) && doAddScripted(toEntry(recipe)); + } + + @MethodDescription(priority = 500) + public boolean add(Map.Entry recipe) { + return recipe != null && getEntries().put(recipe.getKey(), recipe.getValue()) && doAddScripted(recipe); + } + + @MethodDescription(priority = 500) + public boolean remove(Map.Entry recipe) { + return recipe != null && getEntries().entries().removeIf(r -> r == recipe) && doAddBackup(recipe); + } + + @MethodDescription(priority = 500) + public boolean remove(RotInfo recipe) { + return recipe != null && getEntries().entries().removeIf(r -> r.getValue() == recipe) && doAddBackup(toEntry(recipe)); + } + + @MethodDescription(example = @Example("item('betterwithaddons:food_cooked_rice')")) + public boolean removeByInput(IIngredient input) { + return getEntries().entries().removeIf(r -> input.test(((RotInfoAccessor) r.getValue()).getItemStack()) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("item('minecraft:rotten_flesh')")) + public boolean removeByOutput(IIngredient output) { + return getEntries().entries().removeIf(r -> output.test(((RotInfoAccessor) r.getValue()).getRottedStack()) && doAddBackup(r)); + } + + @MethodDescription(priority = 2000, example = @Example(commented = true)) + public void removeAll() { + var recipes = getEntries(); + recipes.entries().forEach(this::addBackup); + recipes.clear(); + } + + @MethodDescription(type = MethodDescription.Type.QUERY) + public SimpleObjectStream> streamRecipes() { + return new SimpleObjectStream<>(getEntries().entries()).setRemover(this::remove); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(defaultValue = "InteractionBWA.MISC_ROT_TIME", comp = @Comp(gte = 1)) + private long time = InteractionBWA.MISC_ROT_TIME; + @Property(defaultValue = "food", comp = @Comp(not = "null")) + private String key = "food"; + @Property(defaultValue = "new ItemStack(ModItems.ROTTEN_FOOD)", comp = @Comp(not = "empty")) + private ItemStack rotted = new ItemStack(ModItems.ROTTEN_FOOD); + + @RecipeBuilderMethodDescription + public RecipeBuilder time(long time) { + this.time = time; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder key(String key) { + this.key = key; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder rotted(ItemStack rotted) { + this.rotted = rotted; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Rotting recipe"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 0); + validateFluids(msg); + msg.add(time < 0, "time must be greater than or equal to 0, yet it was {}", time); + msg.add(rotted == null || rotted.isEmpty(), "rotted cannot be null or empty, yet it was"); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable RotHandler.RotInfo register() { + if (!validate()) return null; + RotHandler.RotInfo recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new RotHandler.RotInfo(stack, time, key, rotted); + ModSupport.BETTER_WITH_ADDONS.get().rotting.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/SandNet.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/SandNet.java new file mode 100644 index 000000000..5ebc2ea55 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/SandNet.java @@ -0,0 +1,99 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.block.EriottoMod.BlockNettedScreen; +import betterwithaddons.crafting.manager.CraftingManagerSandNet; +import betterwithaddons.crafting.recipes.NetRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription +public class SandNet extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:diamond')).output(item('minecraft:clay'))"), + @Example(".input(item('minecraft:diamond')).output(item('minecraft:gold_ingot')).sand(2)"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay') * 4, item('minecraft:diamond'), item('minecraft:diamond') * 2).sand(5)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CraftingManagerSandNet.getInstance().getRecipes(); + } + + @MethodDescription(example = @Example("item('minecraft:iron_ingot')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getInput()) { + if (input.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @MethodDescription(example = { + @Example("item('minecraft:sand')"), @Example("item('betterwithaddons:iron_sand')") + }) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getOutput()) { + if (output.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(gte = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(gte = 0, lte = 8)) + private int sand; + + @RecipeBuilderMethodDescription + public RecipeBuilder sand(int sand) { + this.sand = sand; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Sand Net recipe"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, Integer.MAX_VALUE); + validateFluids(msg); + msg.add(sand < 0 || sand > 8, "sand must be greater than or equal to 0 and less than or equal to 8, yet it was {}", sand); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable NetRecipe register() { + if (!validate()) return null; + NetRecipe recipe = new NetRecipe(BlockNettedScreen.SifterType.SAND, BetterWithAddons.fromIIngredient(input.get(0)), sand, output.toArray(new ItemStack[0])); + ModSupport.BETTER_WITH_ADDONS.get().sandNet.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/SoakingBox.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/SoakingBox.java new file mode 100644 index 000000000..7f4bd8930 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/SoakingBox.java @@ -0,0 +1,85 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.block.EriottoMod.BlockCherryBox; +import betterwithaddons.crafting.manager.CraftingManagerSoakingBox; +import betterwithaddons.crafting.recipes.CherryBoxRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription +public class SoakingBox extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:diamond')).output(item('minecraft:clay'))"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay') * 4)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CraftingManagerSoakingBox.instance().getRecipes(); + } + + @MethodDescription(example = @Example("item('betterwithaddons:bamboo')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getRecipeInputs()) { + if (input.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @MethodDescription(example = @Example("item('betterwithaddons:japanmat:8')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getRecipeOutputs()) { + if (output.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Soaking Box recipe"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable CherryBoxRecipe register() { + if (!validate()) return null; + CherryBoxRecipe recipe = new CherryBoxRecipe(BlockCherryBox.CherryBoxType.SOAKING, BetterWithAddons.fromIIngredient(input.get(0)), output.get(0)); + ModSupport.BETTER_WITH_ADDONS.get().soakingBox.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Spindle.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Spindle.java new file mode 100644 index 000000000..7ba87f7a3 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Spindle.java @@ -0,0 +1,95 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.crafting.manager.CraftingManagerSpindle; +import betterwithaddons.crafting.recipes.SpindleRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription +public class Spindle extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:diamond')).output(item('minecraft:clay'))"), + @Example(".input(item('minecraft:clay') * 3).output(item('minecraft:diamond')).popoff()"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay') * 4)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CraftingManagerSpindle.getInstance().getRecipes(); + } + + @MethodDescription(example = @Example("item('minecraft:vine')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getRecipeInputs()) { + if (input.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @MethodDescription(example = @Example("item('betterwithaddons:bolt')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getOutput()) { + if (output.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(gte = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property + private boolean popoff; + + @RecipeBuilderMethodDescription + public RecipeBuilder popoff(boolean popoff) { + this.popoff = popoff; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder popoff() { + return this.popoff(!popoff); + } + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Spindle recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, Integer.MAX_VALUE); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable SpindleRecipe register() { + if (!validate()) return null; + SpindleRecipe recipe = new SpindleRecipe(popoff, BetterWithAddons.fromIIngredient(input.get(0)), output.toArray(new ItemStack[0])); + ModSupport.BETTER_WITH_ADDONS.get().spindle.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Tatara.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Tatara.java new file mode 100644 index 000000000..bca79cf67 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Tatara.java @@ -0,0 +1,84 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.crafting.manager.CraftingManagerTatara; +import betterwithaddons.crafting.recipes.SmeltingRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription +public class Tatara extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:diamond')).output(item('minecraft:clay'))"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay') * 4)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CraftingManagerTatara.instance().getRecipes(); + } + + @MethodDescription(example = @Example("item('betterwithaddons:japanmat:20')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getRecipeInputs()) { + if (input.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @MethodDescription(example = @Example("item('betterwithaddons:kera')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getRecipeOutputs()) { + if (output.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Tatara recipe"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable SmeltingRecipe register() { + if (!validate()) return null; + SmeltingRecipe recipe = new SmeltingRecipe(BetterWithAddons.fromIIngredient(input.get(0)), output.get(0)); + ModSupport.BETTER_WITH_ADDONS.get().tatara.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Transmutation.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Transmutation.java new file mode 100644 index 000000000..85a268a5f --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/Transmutation.java @@ -0,0 +1,94 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.crafting.manager.CraftingManagerInfuserTransmutation; +import betterwithaddons.crafting.recipes.infuser.TransmutationRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription +public class Transmutation extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:diamond')).output(item('minecraft:clay')).spirits(0)"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay') * 4).spirits(5)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CraftingManagerInfuserTransmutation.getInstance().getRecipes(); + } + + @MethodDescription(example = @Example("item('minecraft:reeds')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getRecipeInputs()) { + if (input.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @MethodDescription(example = @Example("item('betterwithaddons:crop_rice')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getRecipeOutputs()) { + if (output.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(gte = 0)) + private int spirits; + + @RecipeBuilderMethodDescription + public RecipeBuilder spirits(int spirits) { + this.spirits = spirits; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Transmutation recipe"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + msg.add(spirits < 0, "spirits must be greater than or equal to 0, yet it was {}", spirits); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable TransmutationRecipe register() { + if (!validate()) return null; + TransmutationRecipe recipe = new TransmutationRecipe(BetterWithAddons.fromIIngredient(input.get(0)), spirits, output.get(0)); + ModSupport.BETTER_WITH_ADDONS.get().transmutation.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/WaterNet.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/WaterNet.java new file mode 100644 index 000000000..39f21d325 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithaddons/WaterNet.java @@ -0,0 +1,88 @@ +package com.cleanroommc.groovyscript.compat.mods.betterwithaddons; + +import betterwithaddons.block.EriottoMod.BlockNettedScreen; +import betterwithaddons.crafting.manager.CraftingManagerWaterNet; +import betterwithaddons.crafting.recipes.NetRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription +public class WaterNet extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:diamond')).output(item('minecraft:clay'))"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay') * 4, item('minecraft:diamond'), item('minecraft:diamond') * 2)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CraftingManagerWaterNet.getInstance().getRecipes(); + } + + @MethodDescription(example = @Example("item('betterwithaddons:iron_sand')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getInput()) { + if (input.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @MethodDescription(example = { + @Example("item('betterwithaddons:food_sashimi')"), @Example("item('betterwithaddons:food_fugu_sac')") + }) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> { + for (var itemstack : r.getOutput()) { + if (output.test(itemstack)) { + return doAddBackup(r); + } + } + return false; + }); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(gte = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Better With Addons Water Net recipe"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, Integer.MAX_VALUE); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable NetRecipe register() { + if (!validate()) return null; + NetRecipe recipe = new NetRecipe(BlockNettedScreen.SifterType.WATER, BetterWithAddons.fromIIngredient(input.get(0)), 0, output.toArray(new ItemStack[0])); + ModSupport.BETTER_WITH_ADDONS.get().waterNet.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Cauldron.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Cauldron.java index 949bfac1d..e13d0f1fe 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Cauldron.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Cauldron.java @@ -22,7 +22,6 @@ public class Cauldron extends StandardListRegistry { @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond')).heat(2)"), @Example(".input(item('minecraft:diamond')).output(item('minecraft:gold_ingot') * 16).ignoreHeat()") }) - @RecipeBuilderMethodDescription public RecipeBuilder recipeBuilder() { return new RecipeBuilder(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Crucible.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Crucible.java index 04bf83028..900e5ec2a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Crucible.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Crucible.java @@ -24,7 +24,6 @@ public class Crucible extends StandardListRegistry { @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond')).heat(2)"), @Example(".input(item('minecraft:diamond')).output(item('minecraft:gold_ingot') * 16).ignoreHeat()") }) - @RecipeBuilderMethodDescription public RecipeBuilder recipeBuilder() { return new RecipeBuilder(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/HopperFilters.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/HopperFilters.java index 7f0e273fd..27e0f0763 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/HopperFilters.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/HopperFilters.java @@ -125,7 +125,7 @@ public void validate(GroovyLog.Msg msg) { validateItems(msg, 0, Integer.MAX_VALUE, 0, 0); validateFluids(msg); msg.add(IngredientHelper.isEmpty(filter), "filter must be defined"); - msg.add(IngredientHelper.overMaxSize(filter, 1), "Filter must have stack size of 1, got {}", filter.getAmount()); + validateStackSize(msg, 1, "filter", filter); } @Override diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Saw.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Saw.java index b485982a6..c9abbdc5f 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Saw.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Saw.java @@ -19,7 +19,6 @@ public class Saw extends StandardListRegistry { @RecipeBuilderDescription(example = @Example(".input(item('minecraft:diamond_block')).output(item('minecraft:gold_ingot') * 16)")) - @RecipeBuilderMethodDescription public RecipeBuilder recipeBuilder() { return new RecipeBuilder(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Turntable.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Turntable.java index 4f74b95c2..fa7e70e51 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Turntable.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/Turntable.java @@ -24,7 +24,6 @@ public class Turntable extends StandardListRegistry { @Example(".input(item('minecraft:gold_block')).outputBlock(blockstate('minecraft:clay')).output(item('minecraft:gold_ingot') * 5).rotations(5)"), @Example(".input(item('minecraft:clay')).output(item('minecraft:gold_ingot')).rotations(2)") }) - @RecipeBuilderMethodDescription public RecipeBuilder recipeBuilder() { return new RecipeBuilder(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java index 6c0578fdf..482356b34 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java @@ -174,7 +174,7 @@ public String getErrorMsg() { public void validate(GroovyLog.Msg msg) { validateItems(msg, 1, 1, 1, 1); msg.add(catalyst == null, "Must have a catalyst ItemStack but didn't find any!"); - msg.add(IngredientHelper.overMaxSize(catalyst, 1), "Catalyst must have a stack size of 1!"); + validateStackSize(msg, 1, "catalyst", catalyst); } @Override diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SliceNSplice.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SliceNSplice.java index 648f6477d..44b466e34 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SliceNSplice.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SliceNSplice.java @@ -113,9 +113,7 @@ public void validate(GroovyLog.Msg msg) { int inputSize = input.getRealSize(); output.trim(); msg.add(inputSize < 1 || inputSize > 6, () -> "Must have 1 - 6 inputs, but found " + input.size()); - for (IIngredient ingredient : input) { - msg.add(IngredientHelper.overMaxSize(ingredient, 1), "Input {} must have a stack size of 1", ingredient); - } + validateStackSize(msg, 1, "input", input); msg.add(output.size() != 1, () -> "Must have exactly 1 output, but found " + output.size()); validateFluids(msg); if (energy <= 0) energy = 5000; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Vat.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Vat.java index 85805cb17..7eb022b30 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Vat.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Vat.java @@ -9,6 +9,7 @@ import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.helper.ingredient.IngredientList; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.helper.recipe.IRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import com.enderio.core.common.util.NNList; @@ -172,13 +173,8 @@ public boolean validate() { GroovyLog.Msg msg = GroovyLog.msg("Error adding EnderIO Vat recipe").error(); msg.add(IngredientHelper.isEmpty(input), () -> "fluid input must not be empty"); msg.add(IngredientHelper.isEmpty(output), () -> "fluid output must not be empty"); - for (IIngredient ingredient : itemInputs1) { - msg.add(IngredientHelper.overMaxSize(ingredient, 1), "First slot input {} must have a stack size of 1", ingredient); - } - for (IIngredient ingredient : itemInputs2) { - msg.add(IngredientHelper.overMaxSize(ingredient, 1), "Second slot input {} must have a stack size of 1", ingredient); - } - + AbstractRecipeBuilder.validateStackSize(msg, 1, "first slot input", itemInputs1); + AbstractRecipeBuilder.validateStackSize(msg, 1, "second slot input", itemInputs2); if (energy <= 0) energy = 5000; if (baseMultiplier <= 0) baseMultiplier = 1; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/Carpenter.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/Carpenter.java index 653c1db47..bc62b9360 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/Carpenter.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/Carpenter.java @@ -5,7 +5,6 @@ import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.core.mixin.forestry.CarpenterRecipeManagerAccessor; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; -import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import forestry.api.recipes.ICarpenterRecipe; @@ -198,10 +197,8 @@ public void validate(GroovyLog.Msg msg) { validateFluids(msg, 0, 1, 0, 0); validateItems(msg, 0, 0, 1, 1); validatePattern(msg, pattern, keys); - for (IIngredient ingredient : keys.values()) { - msg.add(IngredientHelper.overMaxSize(ingredient, 1), "Grid input {} must have a stack size of 1", ingredient); - } - msg.add(IngredientHelper.overMaxSize(box, 1), "Box must have a stack size of 1, got {}", box.getAmount()); + validateStackSize(msg, 1, "grid input", keys.values()); + validateStackSize(msg, 1, "box", box); } @Override diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/ThermionicFabricator.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/ThermionicFabricator.java index bbbaab459..0d3c4623f 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/ThermionicFabricator.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/forestry/ThermionicFabricator.java @@ -6,7 +6,6 @@ import com.cleanroommc.groovyscript.core.mixin.forestry.FabricatorRecipeManagerAccessor; import com.cleanroommc.groovyscript.helper.Alias; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; -import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import forestry.api.recipes.IFabricatorRecipe; @@ -162,10 +161,8 @@ public void validate(GroovyLog.Msg msg) { validateItems(msg, 0, 0, 1, 1); validateFluids(msg, 1, 1, 0, 0); Carpenter.validatePattern(msg, pattern, keys); - for (IIngredient ingredient : keys.values()) { - msg.add(IngredientHelper.overMaxSize(ingredient, 1), "Grid input {} must have a stack size of 1", ingredient); - } - msg.add(IngredientHelper.overMaxSize(catalyst, 1), "Box must have a stack size of 1, got {}", catalyst.getAmount()); + validateStackSize(msg, 1, "grid input", keys.values()); + validateStackSize(msg, 1, "catalyst", catalyst); } @Override diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Crucible.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Crucible.java index 723f497ab..1414ae131 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Crucible.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Crucible.java @@ -185,7 +185,7 @@ public String getErrorMsg() { public void validate(GroovyLog.Msg msg) { validateItems(msg, 0, 0, 1, 1); msg.add(IngredientHelper.isEmpty(catalyst), () -> "Catalyst must not be empty"); - msg.add(IngredientHelper.overMaxSize(catalyst, 1), () -> "Catalyst amount must be 1"); + validateStackSize(msg, 1, "catalyst", catalyst); msg.add(aspects.size() == 0, () -> "Aspects must not be empty"); if (researchKey == null) researchKey = ""; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/InfusionCrafting.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/InfusionCrafting.java index 12e553c50..703cec41c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/InfusionCrafting.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/InfusionCrafting.java @@ -207,7 +207,7 @@ public void validate(GroovyLog.Msg msg) { validateItems(msg, 1, 100, 1, 1); msg.add(IngredientHelper.isEmpty(mainInput), () -> "Main Input must not be empty"); // More than 1 item cannot be placed - msg.add(IngredientHelper.overMaxSize(mainInput, 1), () -> "Main input amount must be 1"); + validateStackSize(msg, 1, "mainInput", mainInput); if (researchKey == null) { researchKey = ""; } diff --git a/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java b/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java index 699f655b1..26c630fc2 100644 --- a/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java +++ b/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java @@ -14,6 +14,7 @@ public class LateMixin implements ILateMixinLoader { "advancedmortars", "appliedenergistics2", "astralsorcery", + "betterwithaddons", "betterwithmods", "thebetweenlands", "bloodmagic", diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/BWAJEIPluginMixin.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/BWAJEIPluginMixin.java new file mode 100644 index 000000000..6eb4a2fd0 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/BWAJEIPluginMixin.java @@ -0,0 +1,37 @@ +package com.cleanroommc.groovyscript.core.mixin.betterwithaddons; + +import betterwithaddons.interaction.jei.BWAJEIPlugin; +import com.cleanroommc.groovyscript.compat.mods.jei.ShapedRecipeWrapper; +import com.cleanroommc.groovyscript.compat.vanilla.ShapedCraftingRecipe; +import com.cleanroommc.groovyscript.compat.vanilla.ShapelessCraftingRecipe; +import mezz.jei.api.IJeiHelpers; +import mezz.jei.api.recipe.IRecipeWrapper; +import mezz.jei.plugins.vanilla.crafting.ShapelessRecipeWrapper; +import net.minecraft.item.crafting.IRecipe; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(value = BWAJEIPlugin.class, remap = false) +public abstract class BWAJEIPluginMixin { + + /** + * @reason This method only handles specific JEI Recipe Wrappers. This means that if there is an unknown IRecipe + * it cannot be handled. Thus, if the recipe is not a Vanilla, Forge, or CraftTweaker, it will return null + * and not display anything. + *

+ * Furthermore, due to the reference to CraftTweaker recipes, + * if CraftTweaker (an optional dependancy) is not installed, + * calling this method will generate a {@link ClassNotFoundException}. + *

+ * To resolve this we need to Inject before they are referenced, + * and the HEAD is the most logical place for it. + * @author WaitingIdly + */ + @Inject(method = "getCraftingRecipeWrapper", at = @At(value = "HEAD", ordinal = 0), cancellable = true) + private void useCustomGroovyScriptRecipe(IJeiHelpers jeiHelpers, IRecipe baseRecipe, CallbackInfoReturnable cir) { + if (baseRecipe instanceof ShapelessCraftingRecipe r) cir.setReturnValue(new ShapelessRecipeWrapper<>(jeiHelpers, r)); + if (baseRecipe instanceof ShapedCraftingRecipe r) cir.setReturnValue(new ShapedRecipeWrapper(jeiHelpers, r)); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/RotHandlerAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/RotHandlerAccessor.java new file mode 100644 index 000000000..362a2026a --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/RotHandlerAccessor.java @@ -0,0 +1,17 @@ +package com.cleanroommc.groovyscript.core.mixin.betterwithaddons; + +import betterwithaddons.handler.RotHandler; +import com.google.common.collect.Multimap; +import net.minecraft.item.Item; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + + +@Mixin(value = RotHandler.class, remap = false) +public interface RotHandlerAccessor { + + @Accessor("rottingItems") + static Multimap getRottingItems() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/RotInfoAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/RotInfoAccessor.java new file mode 100644 index 000000000..b65ca97c9 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/RotInfoAccessor.java @@ -0,0 +1,22 @@ +package com.cleanroommc.groovyscript.core.mixin.betterwithaddons; + +import betterwithaddons.handler.RotHandler; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(value = RotHandler.RotInfo.class, remap = false) +public interface RotInfoAccessor { + + @Accessor("itemStack") + ItemStack getItemStack(); + + @Accessor("rottedStack") + ItemStack getRottedStack(); + + @Accessor("baseName") + String getBaseName(); + + @Accessor("spoilTime") + long getSpoilTime(); +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/TileEntityLureTreeAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/TileEntityLureTreeAccessor.java new file mode 100644 index 000000000..b8d86982a --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/betterwithaddons/TileEntityLureTreeAccessor.java @@ -0,0 +1,17 @@ +package com.cleanroommc.groovyscript.core.mixin.betterwithaddons; + +import betterwithaddons.tileentity.TileEntityLureTree; +import net.minecraft.entity.Entity; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.ArrayList; + +@Mixin(value = TileEntityLureTree.class, remap = false) +public interface TileEntityLureTreeAccessor { + + @Accessor("BLACKLIST") + static ArrayList> getBlacklist() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/IngredientHelper.java b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/IngredientHelper.java index b1144566a..20984463b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/IngredientHelper.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/IngredientHelper.java @@ -48,6 +48,15 @@ public static ItemStack toItemStack(IIngredient ingredient) { return (ItemStack) (Object) ingredient; } + public static ItemStack toItemStack(IBlockState state) { + return toItemStack(state, 1); + } + + public static ItemStack toItemStack(IBlockState state, int amount) { + var block = state.getBlock(); + return new ItemStack(block, amount, block.getMetaFromState(state)); + } + public static FluidStack toFluidStack(IIngredient ingredient) { return (FluidStack) ingredient; } diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/recipe/AbstractRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/helper/recipe/AbstractRecipeBuilder.java index 403b9a6c6..239ae8ccc 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/recipe/AbstractRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/recipe/AbstractRecipeBuilder.java @@ -175,12 +175,7 @@ public void validateItems(GroovyLog.Msg msg, int minInput, int maxInput, int min output.trim(); validateCustom(msg, input, minInput, maxInput, "item input"); validateCustom(msg, output, minOutput, maxOutput, "item output"); - if (GroovyScriptConfig.compat.checkInputStackCounts) { - int maxAmountAllowed = getMaxItemInput(); - for (IIngredient ingredient : input) { - msg.add(IngredientHelper.overMaxSize(ingredient, maxAmountAllowed), "Expected stack size of {} for {}, got {}", maxAmountAllowed, ingredient, ingredient.getAmount()); - } - } + validateStackSize(msg, getMaxItemInput(), "input", input); } @GroovyBlacklist @@ -193,6 +188,22 @@ public void validateFluids(GroovyLog.Msg msg) { validateFluids(msg, 0, 0, 0, 0); } + @GroovyBlacklist + public static void validateStackSize(GroovyLog.Msg msg, int maxAmountAllowed, String name, Iterable ingredients) { + if (!GroovyScriptConfig.compat.checkInputStackCounts) return; + for (var ingredient : ingredients) { + msg.add(IngredientHelper.overMaxSize(ingredient, maxAmountAllowed), "Expected stack size of {} for {} in {}, got {}", maxAmountAllowed, ingredient, name, ingredient.getAmount()); + } + } + + @GroovyBlacklist + public static void validateStackSize(GroovyLog.Msg msg, int maxAmountAllowed, String name, IIngredient... ingredients) { + if (!GroovyScriptConfig.compat.checkInputStackCounts) return; + for (var ingredient : ingredients) { + msg.add(IngredientHelper.overMaxSize(ingredient, maxAmountAllowed), "Expected stack size of {} for {} in {}, got {}", maxAmountAllowed, ingredient, name, ingredient.getAmount()); + } + } + @GroovyBlacklist public static void validateCustom(GroovyLog.Msg msg, Collection collection, int min, int max, String type) { validateCustom(msg, collection.size(), min, max, type); diff --git a/src/main/resources/assets/groovyscript/lang/en_us.lang b/src/main/resources/assets/groovyscript/lang/en_us.lang index 35e3c9967..637edd236 100644 --- a/src/main/resources/assets/groovyscript/lang/en_us.lang +++ b/src/main/resources/assets/groovyscript/lang/en_us.lang @@ -506,6 +506,62 @@ groovyscript.wiki.atum.spinning_wheel.description=Converts three input items int groovyscript.wiki.atum.spinning_wheel.rotations.value=Sets the amount of rotation required to convert the input into the output +# Better With Addons +groovyscript.wiki.betterwithaddons.drying_box.title=Drying Unit +groovyscript.wiki.betterwithaddons.drying_box.description=Converts an input item into an output itemstack if placed within the appropriate multiblock. The multiblock is Sandstone directly below the Drying Box, 8 Sand around the Drying Box, and a Dead Bush placed on the Sand. Only functions in a non-snowy biome with sky access during the day, and functions twice as fast when in a hot biome. + +groovyscript.wiki.betterwithaddons.fire_net.title=Fire Net +groovyscript.wiki.betterwithaddons.fire_net.description=Converts an input item into any number of output itemstacks if placed within the appropriate multiblock. The multiblock is Lava or Fire directly below the Netted Screen, 8 Stone Brick around the Lava or Fire, and 8 Slat Blocks placed around the Netted Screen. +groovyscript.wiki.betterwithaddons.fire_net.note0=Because the Fire Net needs Lava/Fire below the net to work, items that are output below the net will be destroyed. + +groovyscript.wiki.betterwithaddons.infuser.title=Ancestral Infusion Crafting +groovyscript.wiki.betterwithaddons.infuser.description=Converts a custom crafting recipe an output itemstack, consuming Spirits from the Infused Soul Sand placed below the Ancestral Infuser if placed within the appropriate multiblock. The multiblock is either Soul Sand or Infused Soul Sand placed below the Ancestral Infuser and exclusively air blocks adjacent to the Infuser and Soul Sand blocks. +groovyscript.wiki.betterwithaddons.infuser.spirits.value=Sets the amount of spirits consumed + +groovyscript.wiki.betterwithaddons.lure_tree.title=Alicio Tree Foods +groovyscript.wiki.betterwithaddons.lure_tree.description=Converts an input item into an amount of food for the tree to gradually consume, eventually summoning a random creature nearby. +groovyscript.wiki.betterwithaddons.lure_tree.note0=The creature spawned will be a passive animal, and undesirable animals can be blacklisted. The blacklist has no entries by default. +groovyscript.wiki.betterwithaddons.lure_tree.food.value=Sets the value of the food +groovyscript.wiki.betterwithaddons.lure_tree.addBlacklist=Adds the given Entity to the blacklist +groovyscript.wiki.betterwithaddons.lure_tree.removeBlacklist=Removes the given Entity from the blacklist +groovyscript.wiki.betterwithaddons.lure_tree.getBlacklist=Returns a list of all blacklisted classes that the Alicio Tree cannot spawn + +groovyscript.wiki.betterwithaddons.packing.title=Packing +groovyscript.wiki.betterwithaddons.packing.description=Converts an input itemstack in the form of a EntityItems into an IBlockState after a piston extends if the piston and location the EntityItems are in are fully surrounded by solid blocks. +groovyscript.wiki.betterwithaddons.packing.compress.value=Sets the IBlockState that the input is compacted into +groovyscript.wiki.betterwithaddons.packing.jeiOutput.value=Sets output that appears in JEI, but has no bearing on the actual recipe + +groovyscript.wiki.betterwithaddons.rotting.title=Rotting Food +groovyscript.wiki.betterwithaddons.rotting.description=Converts an input item into an output itemstack after the given time has passed. Has the ability to customize the terminology used to indicate the age. +groovyscript.wiki.betterwithaddons.rotting.note0=When an item (regardless of metadata) is the input of any entry in the Rotting map, all items will gain a new NBT tag with the day they were obtained. This may be them annoying to interact with. +groovyscript.wiki.betterwithaddons.rotting.add=Adds the given entry to the Rotting map +groovyscript.wiki.betterwithaddons.rotting.key.value=Sets the base key for the lang keys used to localize the stage the rotting is at +groovyscript.wiki.betterwithaddons.rotting.time.value=Sets how long the item takes to rot +groovyscript.wiki.betterwithaddons.rotting.rotted.value=Sets the item the rotted item turns into when the time has passed +groovyscript.wiki.betterwithaddons.rotting.remove=Removes the given entry from the Rotting map + +groovyscript.wiki.betterwithaddons.sand_net.title=Sand Net +groovyscript.wiki.betterwithaddons.sand_net.description=Converts an input item into any number of output itemstacks if placed within the appropriate multiblock. The multiblock is a Slat Block directly below the Netted Screen, 8 Water Blocks around the Water, and 8 Slat Blocks placed around the Netted Screen. +groovyscript.wiki.betterwithaddons.sand_net.sand.value=Sets the amount of sand consumed when the recipe is processed + +groovyscript.wiki.betterwithaddons.soaking_box.title=Soaking Unit +groovyscript.wiki.betterwithaddons.soaking_box.description=Converts an input item into an output itemstack if placed within the appropriate multiblock. The multiblock is Ice directly above the Soaking Box, 8 Water around the Soaking Box, and Water directly below the Soaking Box. + +groovyscript.wiki.betterwithaddons.spindle.title=Spindle +groovyscript.wiki.betterwithaddons.spindle.description=Converts an input itemstack into an output itemstack, with the ability to consume the Spindle, when placed against a Spinning Wheel powered by Mechanical Power. +groovyscript.wiki.betterwithaddons.spindle.popoff.value=Sets if the Spindle will break and be consumed when crafting + +groovyscript.wiki.betterwithaddons.tatara.title=Tatara +groovyscript.wiki.betterwithaddons.tatara.description=Converts an input item into an output itemstack if placed within the appropriate multiblock while fueled by Rice Ashes. The multiblock is Lava or Fire directly below the Tatara, 8 Clay around the Lava or Fire, 9 Nether Brick above the Tatara, 4 Stone Brick diagonal to the Tatara and two Iron Blocks across from each other adjacent to the Tatara. + +groovyscript.wiki.betterwithaddons.transmutation.title=Ancestral Infusion Transmutation +groovyscript.wiki.betterwithaddons.transmutation.description=Converts an input item into an output itemstack, consuming Spirits from the Infused Soul Sand placed below the Ancestral Infuser if placed within the appropriate multiblock. The multiblock is either Soul Sand or Infused Soul Sand placed below the Ancestral Infuser and exclusively air blocks adjacent to the Infuser and Soul Sand blocks. +groovyscript.wiki.betterwithaddons.transmutation.spirits.value=Sets the amount of spirits consumed + +groovyscript.wiki.betterwithaddons.water_net.title=Water Net +groovyscript.wiki.betterwithaddons.water_net.description=Converts an input item into any number of output itemstacks if placed within the appropriate multiblock. The multiblock is a Water Block directly below the Netted Screen, 8 Sakura Planks around the Water Block, and 8 Slat Blocks placed around the Netted Screen. + + # Better With Mods groovyscript.wiki.betterwithmods.anvil_crafting.title=Anvil Crafting groovyscript.wiki.betterwithmods.anvil_crafting.description=Similar to a normal crafting table, but 4x4 instead. diff --git a/src/main/resources/mixin.groovyscript.betterwithaddons.json b/src/main/resources/mixin.groovyscript.betterwithaddons.json new file mode 100644 index 000000000..e523d651d --- /dev/null +++ b/src/main/resources/mixin.groovyscript.betterwithaddons.json @@ -0,0 +1,13 @@ +{ + "package": "com.cleanroommc.groovyscript.core.mixin.betterwithaddons", + "refmap": "mixins.groovyscript.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "BWAJEIPluginMixin", + "RotHandlerAccessor", + "RotInfoAccessor", + "TileEntityLureTreeAccessor" + ] +} \ No newline at end of file