diff --git a/dependencies.gradle b/dependencies.gradle index f2e6b1f5a..6205ee975 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -43,6 +43,8 @@ final def mod_dependencies = [ 'lemonlib-306926:2639879' : [project.debug_arcane_world, project.debug_arcane_world_rotn], 'arcane-world-302852:2972860' : [project.debug_arcane_world], 'arcane-world-rotn-edition-475553:3523150' : [project.debug_arcane_world_rotn], + 'armor-plus-237366:2952741' : [project.debug_armor_plus], + 'thedragonlib-248055:2580332' : [project.debug_armor_plus], 'astralsorcery-sorcery-241721:3044416' : [project.debug_astral], 'baubles-227083:2518667' : [project.debug_blood_arsenal, project.debug_astral, project.debug_botania, project.debug_botania_tweaks, project.debug_botanic_additions, project.debug_essentialcraft_4, project.debug_extra_botany, project.debug_thaum], 'the-aurorian-352137:4981736' : [project.debug_aurorian], diff --git a/examples/postInit/armorplus.groovy b/examples/postInit/armorplus.groovy new file mode 100644 index 000000000..dfda95f60 --- /dev/null +++ b/examples/postInit/armorplus.groovy @@ -0,0 +1,118 @@ + +// Auto generated groovyscript example file +// MODS_LOADED: armorplus + +log.info 'mod \'armorplus\' detected, running script' + +// Champion Bench: +// A normal crafting recipe, but with a 9x9 grid and in the Champion Bench. + +// mods.armorplus.champion_bench.removeByOutput() +// mods.armorplus.champion_bench.removeAll() + + +mods.armorplus.champion_bench.shapedBuilder() + .output(item('minecraft:stone') * 64) + .matrix('DLLLLLDDD', + ' DNIGIND', + 'DDDNIGIND', + ' DLLLLLD') + .key('D', item('minecraft:diamond')) + .key('L', item('minecraft:redstone')) + .key('N', item('minecraft:stone')) + .key('I', item('minecraft:iron_ingot')) + .key('G', item('minecraft:gold_ingot')) + .register() + + +mods.armorplus.champion_bench.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')) + .register() + + +// High-Tech Bench: +// A normal crafting recipe, but with a 5x5 grid and in the High-Tech Bench. + +mods.armorplus.high_tech_bench.removeByOutput(item('armorplus:emerald_helmet')) +// mods.armorplus.high_tech_bench.removeAll() + + +mods.armorplus.high_tech_bench.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')]]) + .register() + + +mods.armorplus.high_tech_bench.shapelessBuilder() + .output(item('minecraft:clay') * 8) + .input(item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone')) + .register() + + +// Lava Infuser: +// Convert input itemstack to output itemstack over a second, with the ability to reward a configurable amount of +// experience based on the output itemstack. Consumes lava at a rate of 1 bucket per 10 seconds. + +mods.armorplus.lava_infuser.removeByInput(item('armorplus:lava_crystal')) +mods.armorplus.lava_infuser.removeByOutput(item('armorplus:lava_infused_obsidian')) +// mods.armorplus.lava_infuser.removeAll() + +mods.armorplus.lava_infuser.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay') * 2) + .register() + +mods.armorplus.lava_infuser.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond')) + .experience(5.0d) + .register() + + +// Ultimate Bench: +// A normal crafting recipe, but with a 7x7 grid and in the Ultimate Bench. + +mods.armorplus.ultimate_bench.removeByOutput(item('armorplus:the_ultimate_helmet')) +// mods.armorplus.ultimate_bench.removeAll() + + +mods.armorplus.ultimate_bench.shapedBuilder() + .output(item('minecraft:diamond')) + .matrix('BXXXBX') + .mirrored() + .key('B', item('minecraft:stone')) + .key('X', item('minecraft:gold_ingot')) + .register() + + +mods.armorplus.ultimate_bench.shapelessBuilder() + .output(item('minecraft:stone') * 64) + .input(item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone')) + .register() + + +// WorkBench: +// A normal crafting recipe, but with a 3x3 grid and in the WorkBench. + +mods.armorplus.work_bench.removeByOutput(item('armorplus:the_gift_of_the_gods')) +// mods.armorplus.work_bench.removeAll() + + +mods.armorplus.work_bench.shapedBuilder() + .output(item('minecraft:stone') * 8) + .matrix('BXX') + .mirrored() + .key('B', item('minecraft:stone')) + .key('X', item('minecraft:gold_ingot')) + .register() + + +mods.armorplus.work_bench.shapelessBuilder() + .output(item('minecraft:clay') * 8) + .input(item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone')) + .register() + + diff --git a/gradle.properties b/gradle.properties index e966eab10..772df2faa 100644 --- a/gradle.properties +++ b/gradle.properties @@ -29,6 +29,7 @@ debug_applied_energistics_2 = false debug_arcane_archives = false debug_arcane_world = false debug_arcane_world_rotn = false +debug_armor_plus = false debug_astral = false debug_atum = false debug_aurorian = 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 e32c4df48..9ebaaeb9b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java @@ -12,6 +12,7 @@ import com.cleanroommc.groovyscript.compat.mods.appliedenergistics2.AppliedEnergistics2; import com.cleanroommc.groovyscript.compat.mods.arcanearchives.ArcaneArchives; import com.cleanroommc.groovyscript.compat.mods.arcaneworld.ArcaneWorld; +import com.cleanroommc.groovyscript.compat.mods.armorplus.ArmorPlus; import com.cleanroommc.groovyscript.compat.mods.astralsorcery.AstralSorcery; import com.cleanroommc.groovyscript.compat.mods.atum.Atum; import com.cleanroommc.groovyscript.compat.mods.avaritia.Avaritia; @@ -101,6 +102,7 @@ public class ModSupport { public static final GroovyContainer APPLIED_ENERGISTICS_2 = new InternalModContainer<>("appliedenergistics2", "Applied Energistics 2", AppliedEnergistics2::new, "ae2"); public static final GroovyContainer ARCANE_ARCHIVES = new InternalModContainer<>("arcanearchives", "Arcane Archives", ArcaneArchives::new); public static final GroovyContainer ARCANE_WORLD = new InternalModContainer<>("arcaneworld", "Arcane World", ArcaneWorld::new); + public static final GroovyContainer ARMOR_PLUS = new InternalModContainer<>("armorplus", "Armor Plus", ArmorPlus::new); 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); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/AbstractBenchRegistry.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/AbstractBenchRegistry.java new file mode 100644 index 000000000..bf1f7b075 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/AbstractBenchRegistry.java @@ -0,0 +1,46 @@ +package com.cleanroommc.groovyscript.compat.mods.armorplus; + +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.documentation.annotations.MethodDescription; +import com.cleanroommc.groovyscript.api.documentation.annotations.RecipeBuilderDescription; +import com.cleanroommc.groovyscript.core.mixin.armorplus.BaseCraftingManagerAccessor; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import com.sofodev.armorplus.api.crafting.IRecipe; +import com.sofodev.armorplus.api.crafting.base.BaseCraftingManager; + +import java.util.Collection; + +public abstract class AbstractBenchRegistry extends StandardListRegistry { + + public abstract BaseCraftingManager getInstance(); + + @Override + public Collection getRecipes() { + return getInstance().getRecipeList(); + } + + private int size() { + return ((BaseCraftingManagerAccessor) getInstance()).getSize(); + } + + @RecipeBuilderDescription + public BenchRecipeBuilder.Shaped shapedBuilder() { + return new BenchRecipeBuilder.Shaped(this, size()); + } + + @RecipeBuilderDescription + public BenchRecipeBuilder.Shapeless shapelessBuilder() { + return new BenchRecipeBuilder.Shapeless(this, size()); + } + + // so the of BaseCraftingManager does this sorting... before any recipes are added to the list. and never again. +// @Override +// public void afterScriptLoad() { +// getInstance().getRecipeList().sort((left, right) -> Integer.compare(right.getRecipeSize(), left.getRecipeSize())); +// } + + @MethodDescription + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(x -> output.test(x.getRecipeOutput())); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/ArmorPlus.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/ArmorPlus.java new file mode 100644 index 000000000..9c113cac7 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/ArmorPlus.java @@ -0,0 +1,12 @@ +package com.cleanroommc.groovyscript.compat.mods.armorplus; + +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; + +public class ArmorPlus extends GroovyPropertyContainer { + + public final ChampionBench championBench = new ChampionBench(); + public final HighTechBench highTechBench = new HighTechBench(); + public final LavaInfuser lavaInfuser = new LavaInfuser(); + public final UltimateBench ultimateBench = new UltimateBench(); + public final WorkBench workBench = new WorkBench(); +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/BenchRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/BenchRecipeBuilder.java new file mode 100644 index 000000000..47c5f29b5 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/BenchRecipeBuilder.java @@ -0,0 +1,70 @@ +package com.cleanroommc.groovyscript.compat.mods.armorplus; + +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.documentation.annotations.RecipeBuilderRegistrationMethod; +import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.registry.AbstractCraftingRecipeBuilder; +import com.sofodev.armorplus.api.crafting.IRecipe; +import com.sofodev.armorplus.api.crafting.IShapedRecipe; + +public interface BenchRecipeBuilder { + + class Shaped extends AbstractCraftingRecipeBuilder.AbstractShaped implements BenchRecipeBuilder { + + private final AbstractBenchRegistry registry; + + public Shaped(AbstractBenchRegistry registry, int size) { + super(size, size); + this.registry = registry; + } + + @Override + @RecipeBuilderRegistrationMethod + public IRecipe register() { + GroovyLog.Msg msg = GroovyLog.msg("Error adding shaped Armor Plus Bench recipe") + .error() + .add((keyBasedMatrix == null || keyBasedMatrix.length == 0) && (ingredientMatrix == null || ingredientMatrix.isEmpty()), () -> "No matrix was defined") + .add(keyBasedMatrix != null && ingredientMatrix != null, () -> "A key based matrix AND a ingredient based matrix was defined. This is not allowed!"); + if (msg.postIfNotEmpty()) return null; + msg.add(IngredientHelper.isEmpty(this.output), () -> "Output must not be empty"); + IShapedRecipe recipe = null; + if (keyBasedMatrix != null) { + recipe = validateShape(msg, errors, keyBasedMatrix, keyMap, ((width1, height1, ingredients) -> BenchShapedRecipe.make(width, output, ingredients, width1, height1, mirrored, recipeFunction, recipeAction))); + } else if (ingredientMatrix != null) { + recipe = validateShape(msg, ingredientMatrix, ((width1, height1, ingredients) -> BenchShapedRecipe.make(width, output.copy(), ingredients, width1, height1, mirrored, recipeFunction, recipeAction))); + } + if (msg.postIfNotEmpty()) return null; + if (recipe != null) { + registry.add(recipe); + } + return recipe; + } + } + + class Shapeless extends AbstractCraftingRecipeBuilder.AbstractShapeless implements BenchRecipeBuilder { + + private final AbstractBenchRegistry registry; + + public Shapeless(AbstractBenchRegistry registry, int size) { + super(size, size); + this.registry = registry; + } + + public boolean validate() { + GroovyLog.Msg msg = GroovyLog.msg("Error adding shapeless Armor Plus Bench 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()); + return !msg.postIfNotEmpty(); + } + + @Override + @RecipeBuilderRegistrationMethod + public IRecipe register() { + if (!validate()) return null; + IRecipe recipe = BenchShapelessRecipe.make(output.copy(), ingredients, recipeFunction, recipeAction); + registry.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/BenchShapedRecipe.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/BenchShapedRecipe.java new file mode 100644 index 000000000..fac6ff390 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/BenchShapedRecipe.java @@ -0,0 +1,95 @@ +package com.cleanroommc.groovyscript.compat.mods.armorplus; + +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.vanilla.ShapedCraftingRecipe; +import com.sofodev.armorplus.api.crafting.IRecipe; +import com.sofodev.armorplus.api.crafting.IShapedRecipe; +import com.sofodev.armorplus.api.crafting.base.BaseShapedOreRecipe; +import com.sofodev.armorplus.common.container.base.InventoryCraftingImproved; +import groovy.lang.Closure; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.util.NonNullList; +import net.minecraft.world.World; +import org.apache.commons.lang3.StringUtils; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; + +public class BenchShapedRecipe extends BaseShapedOreRecipe implements IRecipe, IShapedRecipe { + + private final int size; + private final ShapedCraftingRecipe groovyRecipe; + private final Object[] input; + + private BenchShapedRecipe(int size, ShapedCraftingRecipe groovyRecipe, Object[] shapeDummy, Object[] input) { + super(size, groovyRecipe.getRecipeOutput(), shapeDummy); + this.size = size; + this.groovyRecipe = groovyRecipe; + this.input = input; + } + + public static BenchShapedRecipe make(int size, ItemStack output, List input, int width, int height, boolean mirrored, @Nullable Closure recipeFunction, @Nullable Closure recipeAction) { + ShapedCraftingRecipe recipe = new ShapedCraftingRecipe(output, input, width, height, mirrored, recipeFunction, recipeAction); + Object[] jeiInput = new Object[width * height]; + for (int i = 0; i < recipe.getIngredients().size(); i++) { + jeiInput[i] = Arrays.asList(recipe.getIngredients().get(i).getMatchingStacks()); + } + Object[] shapeDummy = new Object[height + 2]; + var row = StringUtils.repeat(' ', width); + int i = 0; + while (i < height) { + shapeDummy[i++] = row; + } + shapeDummy[i++] = ' '; + shapeDummy[i] = ItemStack.EMPTY; + + return new BenchShapedRecipe(size, recipe, shapeDummy, jeiInput); + } + + public @NotNull NonNullList getIngredients() { + return groovyRecipe.getIngredients(); + } + + @Override + public int getRecipeWidth() { + return size; + } + + @Override + public int getRecipeHeight() { + return size; + } + + @Override + public boolean matches(@NotNull InventoryCraftingImproved inv, @NotNull World world) { + return groovyRecipe.matches(inv, world); + } + + @Override + public @NotNull ItemStack getCraftingResult(@NotNull InventoryCraftingImproved inv) { + return groovyRecipe.getCraftingResult(inv); + } + + @Override + public int getRecipeSize() { + return size * size; + } + + @Override + public @NotNull ItemStack getRecipeOutput() { + return groovyRecipe.getRecipeOutput(); + } + + @Override + public Object[] getInput() { + return this.input; + } + + @Override + public NonNullList getRemainingItems(InventoryCraftingImproved inv) { + return groovyRecipe.getRemainingItems(inv); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/BenchShapelessRecipe.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/BenchShapelessRecipe.java new file mode 100644 index 000000000..ad56d1776 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/BenchShapelessRecipe.java @@ -0,0 +1,72 @@ +package com.cleanroommc.groovyscript.compat.mods.armorplus; + +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.vanilla.ShapelessCraftingRecipe; +import com.sofodev.armorplus.api.crafting.IRecipe; +import com.sofodev.armorplus.api.crafting.base.BaseShapelessOreRecipe; +import com.sofodev.armorplus.common.container.base.InventoryCraftingImproved; +import groovy.lang.Closure; +import net.minecraft.item.ItemStack; +import net.minecraft.item.crafting.Ingredient; +import net.minecraft.util.NonNullList; +import net.minecraft.world.World; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Arrays; +import java.util.List; + +public class BenchShapelessRecipe extends BaseShapelessOreRecipe implements IRecipe { + + private final ShapelessCraftingRecipe groovyRecipe; + private final NonNullList input; + + public BenchShapelessRecipe(ShapelessCraftingRecipe groovyRecipe, NonNullList input) { + super(groovyRecipe.getRecipeOutput()); + this.groovyRecipe = groovyRecipe; + this.input = input; + } + + public static BenchShapelessRecipe make(ItemStack output, List input, @Nullable Closure recipeFunction, @Nullable Closure recipeAction) { + ShapelessCraftingRecipe recipe = new ShapelessCraftingRecipe(output, input, recipeFunction, recipeAction); + NonNullList jeiInput = NonNullList.create(); + for (var ingredient : recipe.getIngredients()) { + jeiInput.add(Arrays.asList(ingredient.getMatchingStacks())); + } + return new BenchShapelessRecipe(recipe, jeiInput); + } + + public @NotNull NonNullList getIngredients() { + return groovyRecipe.getIngredients(); + } + + @Override + public boolean matches(@NotNull InventoryCraftingImproved inv, @NotNull World world) { + return groovyRecipe.matches(inv, world); + } + + @Override + public @NotNull ItemStack getCraftingResult(@NotNull InventoryCraftingImproved inv) { + return groovyRecipe.getCraftingResult(inv); + } + + @Override + public int getRecipeSize() { + return input.size(); + } + + @Override + public @NotNull ItemStack getRecipeOutput() { + return groovyRecipe.getRecipeOutput(); + } + + @Override + public NonNullList getRemainingItems(InventoryCraftingImproved inv) { + return groovyRecipe.getRemainingItems(inv); + } + + @Override + public NonNullList getInput() { + return this.input; + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/ChampionBench.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/ChampionBench.java new file mode 100644 index 000000000..f2907c307 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/ChampionBench.java @@ -0,0 +1,22 @@ +package com.cleanroommc.groovyscript.compat.mods.armorplus; + +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.sofodev.armorplus.api.crafting.base.BaseCraftingManager; + +@RegistryDescription(override = @MethodOverride(recipeBuilder = { + @RecipeBuilderDescription( + method = "shapedBuilder", + override = @RecipeBuilderOverride(requirement = @Property(property = "ingredientMatrix", comp = @Comp(gte = 1, lte = 9, unique = "groovyscript.wiki.craftingrecipe.matrix.required"))), + example = @Example(".output(item('minecraft:stone') * 64).matrix('DLLLLLDDD', ' DNIGIND', 'DDDNIGIND', ' DLLLLLD').key('D', item('minecraft:diamond')).key('L', item('minecraft:redstone')).key('N', item('minecraft:stone')).key('I', item('minecraft:iron_ingot')).key('G', item('minecraft:gold_ingot'))")), + @RecipeBuilderDescription( + method = "shapelessBuilder", + override = @RecipeBuilderOverride(requirement = @Property(property = "ingredients", comp = @Comp(gte = 1, lte = 9, unique = "groovyscript.wiki.craftingrecipe.matrix.required"))), + example = @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'))")) +}, method = @MethodDescription(method = "removeByOutput", example = @Example(commented = true)))) +public class ChampionBench extends AbstractBenchRegistry { + + @Override + public BaseCraftingManager getInstance() { + return BaseCraftingManager.getCBInstance(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/HighTechBench.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/HighTechBench.java new file mode 100644 index 000000000..30e765fe7 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/HighTechBench.java @@ -0,0 +1,22 @@ +package com.cleanroommc.groovyscript.compat.mods.armorplus; + +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.sofodev.armorplus.api.crafting.base.BaseCraftingManager; + +@RegistryDescription(override = @MethodOverride(recipeBuilder = { + @RecipeBuilderDescription( + method = "shapedBuilder", + override = @RecipeBuilderOverride(requirement = @Property(property = "ingredientMatrix", comp = @Comp(gte = 1, lte = 9, unique = "groovyscript.wiki.craftingrecipe.matrix.required"))), + example = @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')]])")), + @RecipeBuilderDescription( + method = "shapelessBuilder", + override = @RecipeBuilderOverride(requirement = @Property(property = "ingredients", comp = @Comp(gte = 1, lte = 9, unique = "groovyscript.wiki.craftingrecipe.matrix.required"))), + example = @Example(".output(item('minecraft:clay') * 8).input(item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'))")) +}, method = @MethodDescription(method = "removeByOutput", example = @Example("item('armorplus:emerald_helmet')")))) +public class HighTechBench extends AbstractBenchRegistry { + + @Override + public BaseCraftingManager getInstance() { + return BaseCraftingManager.getHTBInstance(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/LavaInfuser.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/LavaInfuser.java new file mode 100644 index 000000000..0a23886d9 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/LavaInfuser.java @@ -0,0 +1,101 @@ +package com.cleanroommc.groovyscript.compat.mods.armorplus; + +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.armorplus.LavaInfuserManagerAccessor; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import com.sofodev.armorplus.api.lavainfuser.LavaInfuserManager; +import com.sofodev.armorplus.common.compat.crafttweaker.lavainfuser.LavaInfuserRecipe; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; + +@RegistryDescription(admonition = @Admonition(type = Admonition.Type.WARNING, value = "groovyscript.wiki.armorplus.lava_infuser.note0")) +public class LavaInfuser extends StandardListRegistry { + + @Override + public Collection getRecipes() { + return LavaInfuserManager.getInstance().getRecipeList(); + } + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay') * 2)"), + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond')).experience(5.0d)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public void afterScriptLoad() { + // we have to store duplicates of all the values + // but still iterate through everything the exact same way. + var instance = LavaInfuserManager.getInstance(); + var infusing = instance.getInfusingList(); + var experience = ((LavaInfuserManagerAccessor) instance).getExperienceList(); + infusing.clear(); + experience.clear(); + for (var recipe : getRecipes()) { + infusing.put(recipe.input, recipe.output); + // you may be thinking "won't this have the potential to override the xp value of prior recipes" + // yup, that it does. although this actually just copies this problem from the vanilla furnace. + experience.put(recipe.output, recipe.xp); + } + } + + @MethodDescription(example = @Example("item('armorplus:lava_crystal')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(x -> input.test(x.input)); + } + + @MethodDescription(example = @Example("item('armorplus:lava_infused_obsidian')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(x -> output.test(x.output)); + } + + @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 double experience; + + @RecipeBuilderMethodDescription + public RecipeBuilder experience(double experience) { + this.experience = experience; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Armor Plus Lava Infuser recipe"; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + msg.add(experience < 0.0d, "experience must be a double greater than or equal to 0, yet it was {}", experience); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable LavaInfuserRecipe register() { + if (!validate()) return null; + LavaInfuserRecipe recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new LavaInfuserRecipe(stack, output.get(0), experience); + ModSupport.ARMOR_PLUS.get().lavaInfuser.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/UltimateBench.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/UltimateBench.java new file mode 100644 index 000000000..4e262c353 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/UltimateBench.java @@ -0,0 +1,22 @@ +package com.cleanroommc.groovyscript.compat.mods.armorplus; + +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.sofodev.armorplus.api.crafting.base.BaseCraftingManager; + +@RegistryDescription(override = @MethodOverride(recipeBuilder = { + @RecipeBuilderDescription( + method = "shapedBuilder", + override = @RecipeBuilderOverride(requirement = @Property(property = "ingredientMatrix", comp = @Comp(gte = 1, lte = 9, unique = "groovyscript.wiki.craftingrecipe.matrix.required"))), + example = @Example(".output(item('minecraft:diamond')).matrix('BXXXBX').mirrored().key('B', item('minecraft:stone')).key('X', item('minecraft:gold_ingot'))")), + @RecipeBuilderDescription( + method = "shapelessBuilder", + override = @RecipeBuilderOverride(requirement = @Property(property = "ingredients", comp = @Comp(gte = 1, lte = 9, unique = "groovyscript.wiki.craftingrecipe.matrix.required"))), + example = @Example(".output(item('minecraft:stone') * 64).input(item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'))")) +}, method = @MethodDescription(method = "removeByOutput", example = @Example("item('armorplus:the_ultimate_helmet')")))) +public class UltimateBench extends AbstractBenchRegistry { + + @Override + public BaseCraftingManager getInstance() { + return BaseCraftingManager.getUTBInstance(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/WorkBench.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/WorkBench.java new file mode 100644 index 000000000..fe2b16707 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/armorplus/WorkBench.java @@ -0,0 +1,22 @@ +package com.cleanroommc.groovyscript.compat.mods.armorplus; + +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.sofodev.armorplus.api.crafting.base.BaseCraftingManager; + +@RegistryDescription(override = @MethodOverride(recipeBuilder = { + @RecipeBuilderDescription( + method = "shapedBuilder", + override = @RecipeBuilderOverride(requirement = @Property(property = "ingredientMatrix", comp = @Comp(gte = 1, lte = 9, unique = "groovyscript.wiki.craftingrecipe.matrix.required"))), + example = @Example(".output(item('minecraft:stone') * 8).matrix('BXX').mirrored().key('B', item('minecraft:stone')).key('X', item('minecraft:gold_ingot'))")), + @RecipeBuilderDescription( + method = "shapelessBuilder", + override = @RecipeBuilderOverride(requirement = @Property(property = "ingredients", comp = @Comp(gte = 1, lte = 9, unique = "groovyscript.wiki.craftingrecipe.matrix.required"))), + example = @Example(".output(item('minecraft:clay') * 8).input(item('minecraft:stone'), item('minecraft:stone'), item('minecraft:stone'))")) +}, method = @MethodDescription(method = "removeByOutput", example = @Example("item('armorplus:the_gift_of_the_gods')")))) +public class WorkBench extends AbstractBenchRegistry { + + @Override + public BaseCraftingManager getInstance() { + return BaseCraftingManager.getWBInstance(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/AnvilRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/AnvilRecipeBuilder.java index 85d285491..ef6bb2e2e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/AnvilRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betterwithmods/AnvilRecipeBuilder.java @@ -37,7 +37,6 @@ public IRecipe register() { } if (msg.postIfNotEmpty()) return null; if (recipe != null) { - handleReplace(); ModSupport.BETTER_WITH_MODS.get().anvilCrafting.add(recipe); } return recipe; diff --git a/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java b/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java index 26c630fc2..cab30d7e3 100644 --- a/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java +++ b/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java @@ -13,6 +13,7 @@ public class LateMixin implements ILateMixinLoader { public static final List modMixins = ImmutableList.of( "advancedmortars", "appliedenergistics2", + "armorplus", "astralsorcery", "betterwithaddons", "betterwithmods", diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/armorplus/BaseCraftingManagerAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/armorplus/BaseCraftingManagerAccessor.java new file mode 100644 index 000000000..2d5f121bd --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/armorplus/BaseCraftingManagerAccessor.java @@ -0,0 +1,12 @@ +package com.cleanroommc.groovyscript.core.mixin.armorplus; + +import com.sofodev.armorplus.api.crafting.base.BaseCraftingManager; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(value = BaseCraftingManager.class, remap = false) +public interface BaseCraftingManagerAccessor { + + @Accessor("xy") + int getSize(); +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/armorplus/LavaInfuserManagerAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/armorplus/LavaInfuserManagerAccessor.java new file mode 100644 index 000000000..3515eb1d6 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/armorplus/LavaInfuserManagerAccessor.java @@ -0,0 +1,15 @@ +package com.cleanroommc.groovyscript.core.mixin.armorplus; + +import com.sofodev.armorplus.api.lavainfuser.LavaInfuserManager; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(value = LavaInfuserManager.class, remap = false) +public interface LavaInfuserManagerAccessor { + + @Accessor("experienceList") + Map getExperienceList(); +} diff --git a/src/main/java/com/cleanroommc/groovyscript/documentation/helper/descriptor/DescriptorHelper.java b/src/main/java/com/cleanroommc/groovyscript/documentation/helper/descriptor/DescriptorHelper.java index e6827f6ee..1ddf87389 100644 --- a/src/main/java/com/cleanroommc/groovyscript/documentation/helper/descriptor/DescriptorHelper.java +++ b/src/main/java/com/cleanroommc/groovyscript/documentation/helper/descriptor/DescriptorHelper.java @@ -270,7 +270,7 @@ public Set getValidMethods() { var output = descriptorToMethod.get(target); if (output != null) return output; var methodSignatures = nameToSignatures.get(target); - if (methodSignatures.size() > 1) { + if (methodSignatures != null && methodSignatures.size() > 1) { GroovyLog.msg("The target '{}' is a duplicate name, use one of the following descriptors instead", target) .add("'" + String.join("', '", methodSignatures) + "'") .warn() diff --git a/src/main/resources/assets/groovyscript/lang/en_us.lang b/src/main/resources/assets/groovyscript/lang/en_us.lang index 2686c4778..b8baf3507 100644 --- a/src/main/resources/assets/groovyscript/lang/en_us.lang +++ b/src/main/resources/assets/groovyscript/lang/en_us.lang @@ -416,6 +416,26 @@ groovyscript.wiki.arcanearchives.gem_cutting_table.description=Converts any numb groovyscript.wiki.arcanearchives.gem_cutting_table.note0=While more than 8 items can function as the input of a Stygian Iron Anvil recipe, only the first 8 are shown in JEI. +# Armor Plus +groovyscript.wiki.armorplus.champion_bench.title=Champion Bench +groovyscript.wiki.armorplus.champion_bench.description=A normal crafting recipe, but with a 9x9 grid and in the Champion Bench. +#A 9x9 crafting grid capable of everything the vanilla crafting grid can do, but in the Champion Bench + +groovyscript.wiki.armorplus.high_tech_bench.title=High-Tech Bench +groovyscript.wiki.armorplus.high_tech_bench.description=A normal crafting recipe, but with a 5x5 grid and in the High-Tech Bench + +groovyscript.wiki.armorplus.lava_infuser.title=Lava Infuser +groovyscript.wiki.armorplus.lava_infuser.description=Convert input itemstack to output itemstack over a second, with the ability to reward a configurable amount of experience based on the output itemstack. Consumes lava at a rate of 1 bucket per 10 seconds. +groovyscript.wiki.armorplus.lava_infuser.experience.value=Sets the experience provided by the output +groovyscript.wiki.armorplus.lava_infuser.note0=Experience provided is based on the output itemstack. Experience is a fallback value, only used if the itemstack provides no experience when smelting. + +groovyscript.wiki.armorplus.ultimate_bench.title=Ultimate Bench +groovyscript.wiki.armorplus.ultimate_bench.description=A normal crafting recipe, but with a 7x7 grid and in the Ultimate Bench + +groovyscript.wiki.armorplus.work_bench.title=WorkBench +groovyscript.wiki.armorplus.work_bench.description=A normal crafting recipe, but with a 3x3 grid and in the WorkBench + + # Arcane World groovyscript.wiki.arcaneworld.ritual.title=Ritual groovyscript.wiki.arcaneworld.ritual.description=Converts up to 5 input itemstacks into a wide number of possible effects, including spawning entities, opening a portal to a dungeon dimension to fight a mob, awarding an output itemstack, running commands, and even entirely customized effects. diff --git a/src/main/resources/mixin.groovyscript.armorplus.json b/src/main/resources/mixin.groovyscript.armorplus.json new file mode 100644 index 000000000..e2322d1b4 --- /dev/null +++ b/src/main/resources/mixin.groovyscript.armorplus.json @@ -0,0 +1,11 @@ +{ + "package": "com.cleanroommc.groovyscript.core.mixin.armorplus", + "refmap": "mixins.groovyscript.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "BaseCraftingManagerAccessor", + "LavaInfuserManagerAccessor" + ] +} \ No newline at end of file