diff --git a/dependencies.gradle b/dependencies.gradle index e7bd7fb19..1dbc8b9e0 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -120,6 +120,22 @@ final def mod_dependencies = [ 'woot-244049:2712670' : [project.debug_woot], ] +// Maps mods from CurseMaven to the properties that enable the mod. +// These mods will be enabled at runtime, but will not be compiled. +// Sorted alphabetically. +final Map> runtime_dependencies = [ + 'com.cleanroommc:configanytime:3.0' : [project.debug_universal_tweaks], + 'curse.maven:aainfo-573154:3627065' : [project.debug_actually_advanced_info], + 'curse.maven:dropt-284973:3758733' : [project.debug_pyrotech], + 'curse.maven:jei-bees-248370:2490058' : [project.debug_forestry], + 'curse.maven:just-enough-petroleum-291727:2549332' : [project.debug_immersive_petroleum], + 'curse.maven:mouse-tweaks-unofficial-461660:5876158': [project.debug_mouse_tweaks_unofficial], + 'curse.maven:reid-629017:5502915' : [project.debug_roughly_enough_ids], + 'curse.maven:thaumic_jei-285492:2705304' : [project.debug_thaum], + 'curse.maven:universal-tweaks-705000:5860191' : [project.debug_universal_tweaks], + 'curse.maven:vintagefix-871198:5536276' : [project.debug_vintagefix], +] + dependencies { embed "org.apache.groovy:groovy:${project.groovy_version}" @@ -149,8 +165,19 @@ dependencies { } } - if (project.debug_thaum.toBoolean()) { - runtimeOnly 'curse.maven:thaumic_jei-285492:2705304' + // enables mods for runtime + runtime_dependencies.each { k, v -> + if (v.any { it.toBoolean() }) { + runtimeOnly k + } + } + + compileOnly rfg.deobf('curse.maven:angry-pixel-the-betweenlands-mod-243363:4479688') + if (project.debug_betweenlands.toBoolean()) { + // TODO: allow development toggling of the coremod + // until this is resolved, download and install the jar from + // https://www.curseforge.com/minecraft/mc-mods/angry-pixel-the-betweenlands-mod/files/4479688 + // runtimeOnly rfg.deobf('curse.maven:angry-pixel-the-betweenlands-mod-243363:4479688') } compileOnly 'com.enderio:endercore:0.5.78' @@ -178,24 +205,9 @@ dependencies { runtimeOnly rfg.deobf('curse.maven:industrialcraft_classic-242942:3093607') } - - if (project.debug_forestry.toBoolean()) { - runtimeOnly rfg.deobf('curse.maven:jei-bees-248370:2490058') - } - - if (project.debug_immersive_petroleum.toBoolean()) { - runtimeOnly rfg.deobf('curse.maven:just-enough-petroleum-291727:2549332') - } - - if (project.debug_pyrotech.toBoolean()) { - runtimeOnly rfg.deobf("curse.maven:dropt-284973:3758733") - } - compileOnly rfg.deobf('TechReborn:TechReborn-ModCompatibility-1.12.2:1.4.0.76:universal') if (project.debug_tech_reborn.toBoolean()) { runtimeOnly rfg.deobf('TechReborn:TechReborn-ModCompatibility-1.12.2:1.4.0.76:universal') } - runtimeOnly 'com.cleanroommc:strip-latest-forge-requirements:1.0' - } diff --git a/examples/postInit/thebetweenlands.groovy b/examples/postInit/thebetweenlands.groovy new file mode 100644 index 000000000..c910efbfd --- /dev/null +++ b/examples/postInit/thebetweenlands.groovy @@ -0,0 +1,209 @@ + +// Auto generated groovyscript example file +// MODS_LOADED: thebetweenlands + +log.info 'mod \'thebetweenlands\' detected, running script' + +// Animator: +// Converts an input item, Life amount from Life Crystals, and Fuel from Sulfur into an output itemstack, summoning an +// entity, a random item from a loottable, or summoning an entity and outputting an itemstack. + +mods.thebetweenlands.animator.removeByEntity(entity('thebetweenlands:sporeling')) +mods.thebetweenlands.animator.removeByInput(item('thebetweenlands:bone_leggings')) +mods.thebetweenlands.animator.removeByLootTable(resource('thebetweenlands:animator/scroll')) +mods.thebetweenlands.animator.removeByOutput(item('thebetweenlands:items_misc:46')) +// mods.thebetweenlands.animator.removeAll() + +mods.thebetweenlands.animator.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond')) + .life(1) + .fuel(1) + .register() + +mods.thebetweenlands.animator.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .lootTable(resource('minecraft:entities/zombie')) + .life(5) + .fuel(1) + .register() + +mods.thebetweenlands.animator.recipeBuilder() + .input(item('minecraft:gold_block')) + .entity(entity('minecraft:zombie').getEntityClass()) + .life(1) + .fuel(5) + .register() + +mods.thebetweenlands.animator.recipeBuilder() + .input(item('minecraft:diamond')) + .entity(entity('minecraft:enderman')) + .output(item('minecraft:clay')) + .life(3) + .fuel(10) + .register() + + +// Compost: +// Converts an input itemstack into an amount of compost. + +mods.thebetweenlands.compost.removeByInput(item('thebetweenlands:items_misc:13')) +// mods.thebetweenlands.compost.removeAll() + +mods.thebetweenlands.compost.recipeBuilder() + .input(item('minecraft:clay')) + .amount(20) + .time(30) + .register() + +mods.thebetweenlands.compost.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .amount(1) + .time(5) + .register() + + +// Crab Pot Filter Bubbler: +// Converts an input item into an output itemstack when a Bubbler Crab is placed inside a Crab Pot Filter. + +mods.thebetweenlands.crab_pot_filter_bubbler.removeByInput(item('thebetweenlands:silt')) +mods.thebetweenlands.crab_pot_filter_bubbler.removeByOutput(item('thebetweenlands:swamp_dirt')) +// mods.thebetweenlands.crab_pot_filter_bubbler.removeAll() + +mods.thebetweenlands.crab_pot_filter_bubbler.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond')) + .register() + +mods.thebetweenlands.crab_pot_filter_bubbler.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay')) + .register() + + +// Crab Pot Filter Silt: +// Converts an input item into an output itemstack when a Silt Crab is placed inside a Crab Pot Filter. + +mods.thebetweenlands.crab_pot_filter_silt.removeByInput(item('thebetweenlands:mud')) +mods.thebetweenlands.crab_pot_filter_silt.removeByOutput(item('thebetweenlands:mud')) +// mods.thebetweenlands.crab_pot_filter_silt.removeAll() + +mods.thebetweenlands.crab_pot_filter_silt.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond')) + .register() + +mods.thebetweenlands.crab_pot_filter_silt.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay')) + .register() + + +// Druid Altar: +// Converts 4 input items into an output itemstack. + +// mods.thebetweenlands.druid_altar.removeByInput(item('thebetweenlands:swamp_talisman:1')) +mods.thebetweenlands.druid_altar.removeByOutput(item('thebetweenlands:swamp_talisman')) +// mods.thebetweenlands.druid_altar.removeAll() + +mods.thebetweenlands.druid_altar.recipeBuilder() + .input(item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay')) + .output(item('minecraft:diamond')) + .register() + +mods.thebetweenlands.druid_altar.recipeBuilder() + .input(item('minecraft:diamond'), item('minecraft:gold_block'), item('minecraft:gold_ingot'), item('minecraft:clay')) + .output(item('minecraft:clay')) + .register() + + +// Pestle And Mortar: +// Converts an input item into an output itemstack in a Pestle and Mortar by using a Pestle tool in the Mortar. + +mods.thebetweenlands.pestle_and_mortar.removeByInput(item('thebetweenlands:limestone')) +mods.thebetweenlands.pestle_and_mortar.removeByOutput(item('thebetweenlands:fish_bait')) +// mods.thebetweenlands.pestle_and_mortar.removeAll() + +mods.thebetweenlands.pestle_and_mortar.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond')) + .register() + +mods.thebetweenlands.pestle_and_mortar.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay')) + .register() + + +// Purifier: +// Converts an input item into an output itemstack, consuming Sulfur and Swamp Water as fuel. + +mods.thebetweenlands.purifier.removeByInput(item('thebetweenlands:items_misc:64')) +mods.thebetweenlands.purifier.removeByOutput(item('thebetweenlands:cragrock')) +// mods.thebetweenlands.purifier.removeAll() + +mods.thebetweenlands.purifier.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond')) + .register() + +mods.thebetweenlands.purifier.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay')) + .register() + + +// Smoking Rack: +// Converts an input item into an output itemstack over a configurable period of time, consuming Fallen Leaves to do so. + +mods.thebetweenlands.smoking_rack.removeByInput(item('thebetweenlands:anadia')) +mods.thebetweenlands.smoking_rack.removeByOutput(item('thebetweenlands:barnacle_smoked')) +// mods.thebetweenlands.smoking_rack.removeAll() + +mods.thebetweenlands.smoking_rack.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond')) + .register() + +mods.thebetweenlands.smoking_rack.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay')) + .time(50) + .register() + + +// Steeping Pot: +// Converts a 1,000mb of fluid into either 1,000mb of a fluid, an output itemstack, or both, consuming up to 4 items from a +// Silk Bundle placed inside the Steeping Pot to do so. The Silk Bundle is converted into a Dirty Silk Bundle in the +// process. The Silk Bundle can only hold specific items, which are also configurable. + +mods.thebetweenlands.steeping_pot.removeAcceptedItem(item('thebetweenlands:items_crushed:5')) +mods.thebetweenlands.steeping_pot.removeByInput(fluid('clean_water')) +mods.thebetweenlands.steeping_pot.removeByInput(item('thebetweenlands:items_crushed:13')) +mods.thebetweenlands.steeping_pot.removeByOutput(fluid('dye_fluid').withNbt(['type': 14])) +// mods.thebetweenlands.steeping_pot.removeByOutput(item('thebetweenlands:limestone')) +// mods.thebetweenlands.steeping_pot.removeAll() +// mods.thebetweenlands.steeping_pot.removeAllAcceptedItem() + +mods.thebetweenlands.steeping_pot.recipeBuilder() + .input(item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay')) + .fluidInput(fluid('lava')) + .fluidOutput(fluid('water')) + .register() + +mods.thebetweenlands.steeping_pot.recipeBuilder() + .input(item('minecraft:diamond')) + .fluidInput(fluid('lava')) + .fluidOutput(fluid('dye_fluid')) + .meta(5) + .register() + +mods.thebetweenlands.steeping_pot.recipeBuilder() + .input(item('minecraft:emerald')) + .fluidInput(fluid('lava')) + .fluidOutput(fluid('water')) + .register() + + +mods.thebetweenlands.steeping_pot.addAcceptedItem(item('minecraft:gold_block')) + diff --git a/gradle.properties b/gradle.properties index 707c112e7..d7ecd0f37 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,6 +9,12 @@ debug_generate_wiki = false debug_generate_and_crash = false debug_disable_cache = false +debug_actually_advanced_info = false +debug_mouse_tweaks_unofficial = false +debug_roughly_enough_ids = false +debug_universal_tweaks = false +debug_vintagefix = false + # END SECTION: development environment settings # SECTION: debug mod compat @@ -28,6 +34,7 @@ debug_aurorian = false debug_avaritia = false debug_better_with_mods = false +debug_betweenlands = false debug_blood_arsenal = false debug_blood_magic = false debug_botania = false @@ -201,7 +208,7 @@ includeCommonDevEnvMods = true # and cannot launch with the forge version required, enable this to strip the forge version requirements from that mod. # This will add 'strip-latest-forge-requirements' as 'runtimeOnlyNonPublishable'. # Requires useMixins or forceEnableMixins to be true, as the mod uses mixins to function. -stripForgeRequirements = false +stripForgeRequirements = true # If enabled, you may use 'shadowCompile' for dependencies. They will be integrated in your jar. It is your diff --git a/src/main/java/com/cleanroommc/groovyscript/api/IOreDicts.java b/src/main/java/com/cleanroommc/groovyscript/api/IOreDicts.java new file mode 100644 index 000000000..2ff243962 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/api/IOreDicts.java @@ -0,0 +1,19 @@ +package com.cleanroommc.groovyscript.api; + +import java.util.List; + +/** + * Indicates that the IIngredient represents one or more oredicts. + */ +public interface IOreDicts extends IIngredient { + // TODO + // There are a large number of places currently in the GroovyScript codebase + // that check if something is "instanceof OreDictIngredient". + // these should be replaced by checks against IOreDicts, + // and surrounding code changed appropriately. + + /** + * @return a list of oredict strings + */ + List getOreDicts(); +} 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 207bad668..0bee1eb2e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java @@ -16,6 +16,7 @@ import com.cleanroommc.groovyscript.compat.mods.atum.Atum; import com.cleanroommc.groovyscript.compat.mods.avaritia.Avaritia; import com.cleanroommc.groovyscript.compat.mods.betterwithmods.BetterWithMods; +import com.cleanroommc.groovyscript.compat.mods.betweenlands.Betweenlands; import com.cleanroommc.groovyscript.compat.mods.bloodarsenal.BloodArsenal; import com.cleanroommc.groovyscript.compat.mods.bloodmagic.BloodMagic; import com.cleanroommc.groovyscript.compat.mods.botania.Botania; @@ -98,6 +99,7 @@ public class ModSupport { 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_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); public static final GroovyContainer BLOOD_MAGIC = new InternalModContainer<>("bloodmagic", "Blood Magic: Alchemical Wizardry", BloodMagic::new, "bm"); public static final GroovyContainer BOTANIA = new InternalModContainer<>("botania", "Botania", Botania::new); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Animator.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Animator.java new file mode 100644 index 000000000..62a5e9e90 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Animator.java @@ -0,0 +1,189 @@ +package com.cleanroommc.groovyscript.compat.mods.betweenlands; + +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.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.WorldServer; +import net.minecraft.world.storage.loot.LootContext; +import net.minecraft.world.storage.loot.LootTable; +import net.minecraftforge.fml.common.registry.EntityEntry; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import thebetweenlands.api.recipes.IAnimatorRecipe; +import thebetweenlands.common.recipe.misc.AnimatorRecipe; + +import java.util.Collection; +import java.util.List; + +@RegistryDescription +public class Animator extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond')).life(1).fuel(1)"), + @Example(".input(item('minecraft:gold_ingot')).lootTable(resource('minecraft:entities/zombie')).life(5).fuel(1)"), + @Example(".input(item('minecraft:gold_block')).entity(entity('minecraft:zombie').getEntityClass()).life(1).fuel(5)"), + @Example(".input(item('minecraft:diamond')).entity(entity('minecraft:enderman')).output(item('minecraft:clay')).life(3).fuel(10)"), + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return AnimatorRecipe.getRecipes(); + } + + @MethodDescription(example = @Example("item('thebetweenlands:bone_leggings')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> r instanceof AnimatorRecipe recipe && input.test(recipe.getInput()) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("item('thebetweenlands:items_misc:46')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> r instanceof AnimatorRecipe recipe && output.test(recipe.getResult(recipe.getInput())) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("resource('thebetweenlands:animator/scroll')")) + public boolean removeByLootTable(ResourceLocation lootTable) { + return getRecipes().removeIf(r -> r instanceof AnimatorRecipe recipe && lootTable.equals(recipe.getLootTable()) && doAddBackup(r)); + } + + @MethodDescription + public boolean removeByEntity(Class entity) { + return getRecipes().removeIf(r -> r instanceof AnimatorRecipe recipe && entity.equals(recipe.getSpawnEntityClass(recipe.getInput())) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("entity('thebetweenlands:sporeling')")) + public boolean removeByEntity(EntityEntry entity) { + return removeByEntity(entity.getEntityClass()); + } + + @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 life; + @Property(comp = @Comp(gte = 0)) + private int fuel; + @Property + private ResourceLocation lootTable; + @Property + private Class entity; + @Property + private ResourceLocation render; + + @RecipeBuilderMethodDescription + public RecipeBuilder life(int life) { + this.life = life; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder fuel(int fuel) { + this.fuel = fuel; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder lootTable(ResourceLocation lootTable) { + this.lootTable = lootTable; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder entity(Class entity) { + this.entity = entity; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder entity(EntityEntry entity) { + return entity(entity.getEntityClass()); + } + + @RecipeBuilderMethodDescription + public RecipeBuilder render(ResourceLocation render) { + this.render = render; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Betweenlands Animator recipe"; + } + + @Override + @GroovyBlacklist + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 1); + validateFluids(msg); + msg.add(life < 0, "life must be a positive integer greater than 0, yet it was {}", life); + msg.add(fuel < 0, "fuel must be a positive integer greater than 0, yet it was {}", fuel); + if (lootTable != null) { + validateCustom(msg, output, 0, 0, "item output"); + msg.add(entity != null, "entity was defined even though lootTable was defined"); + msg.add(!output.isEmpty(), "output was defined even though lootTable was defined"); + } + msg.add(output.isEmpty() && lootTable == null && entity == null, "output, lootTable, and entity were all not defined. one of them should be defined to properly create the recipe"); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable IAnimatorRecipe register() { + if (!validate()) return null; + AnimatorRecipe recipe = null; + if (lootTable != null) { + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new AnimatorRecipe(stack, fuel, life, lootTable) { + + /** + * In order to get Loot Table recipes to display properly we need to do this. + * This snippet of code is copied a few times in {@link thebetweenlands.common.registries.RecipeRegistry#registerAnimatorRecipes} + * with the only difference being the `lootTable` being used here. + * Don't know why Betweenlands doesn't just make a class to handle it? Seems like it would make sense... + */ + @Override + public @NotNull ItemStack onAnimated(World world, BlockPos pos, ItemStack stack) { + LootTable table = world.getLootTableManager().getLootTableFromLocation(lootTable); + LootContext.Builder lootBuilder = new LootContext.Builder((WorldServer) world); + List loot = table.generateLootForPools(world.rand, lootBuilder.build()); + return loot.isEmpty() ? ItemStack.EMPTY : loot.get(world.rand.nextInt(loot.size())); + } + }; + ModSupport.BETWEENLANDS.get().animator.add(recipe); + } + } else if (entity != null) { + if (output.isEmpty()) { + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new AnimatorRecipe(stack, fuel, life, entity); + recipe.setRenderEntity(render); + ModSupport.BETWEENLANDS.get().animator.add(recipe); + } + } else { + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new AnimatorRecipe(stack, fuel, life, output.get(0), entity); + recipe.setRenderEntity(render); + ModSupport.BETWEENLANDS.get().animator.add(recipe); + } + } + } + ModSupport.BETWEENLANDS.get().animator.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Betweenlands.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Betweenlands.java new file mode 100644 index 000000000..664ed341b --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Betweenlands.java @@ -0,0 +1,16 @@ +package com.cleanroommc.groovyscript.compat.mods.betweenlands; + +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; + +public class Betweenlands extends GroovyPropertyContainer { + + public final Animator animator = new Animator(); + public final Compost compost = new Compost(); + public final CrabPotFilterBubbler crabPotFilterBubbler = new CrabPotFilterBubbler(); + public final CrabPotFilterSilt crabPotFilterSilt = new CrabPotFilterSilt(); + public final DruidAltar druidAltar = new DruidAltar(); + public final PestleAndMortar pestleAndMortar = new PestleAndMortar(); + public final Purifier purifier = new Purifier(); + public final SmokingRack smokingRack = new SmokingRack(); + public final SteepingPot steepingPot = new SteepingPot(); +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Compost.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Compost.java new file mode 100644 index 000000000..3312b7afc --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Compost.java @@ -0,0 +1,88 @@ +package com.cleanroommc.groovyscript.compat.mods.betweenlands; + +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.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import org.jetbrains.annotations.Nullable; +import thebetweenlands.api.recipes.ICompostBinRecipe; +import thebetweenlands.common.recipe.misc.CompostRecipe; + +import java.util.Collection; + +@RegistryDescription +public class Compost extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).amount(20).time(30)"), + @Example(".input(item('minecraft:gold_ingot')).amount(1).time(5)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CompostRecipe.RECIPES; + } + + @MethodDescription(example = @Example("item('thebetweenlands:items_misc:13')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> r instanceof CompostRecipe recipe && input.test(recipe.getInput()) && doAddBackup(r)); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(gte = 1)) + private int amount; + @Property(comp = @Comp(gte = 1)) + private int time; + + @RecipeBuilderMethodDescription + public RecipeBuilder amount(int amount) { + this.amount = amount; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Betweenlands Compost recipe"; + } + + @Override + @GroovyBlacklist + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 0); + validateFluids(msg); + msg.add(amount <= 0, "amount must be a positive integer greater than 0, yet it was {}", amount); + msg.add(time <= 0, "time must be a positive integer greater than 0, yet it was {}", time); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable ICompostBinRecipe register() { + if (!validate()) return null; + ICompostBinRecipe recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new CompostRecipe(amount, time, stack); + ModSupport.BETWEENLANDS.get().compost.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/CrabPotFilterBubbler.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/CrabPotFilterBubbler.java new file mode 100644 index 000000000..da3e42895 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/CrabPotFilterBubbler.java @@ -0,0 +1,76 @@ +package com.cleanroommc.groovyscript.compat.mods.betweenlands; + +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.thebetweenlands.CrabPotFilterRecipeBubblerAccessor; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import org.jetbrains.annotations.Nullable; +import thebetweenlands.api.recipes.ICrabPotFilterRecipeBubbler; +import thebetweenlands.common.recipe.misc.CrabPotFilterRecipeBubbler; + +import java.util.Collection; + +@RegistryDescription +public class CrabPotFilterBubbler extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond'))"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay'))") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CrabPotFilterRecipeBubblerAccessor.getRecipes(); + } + + @MethodDescription(example = @Example("item('thebetweenlands:silt')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> input.test(r.getInput()) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("item('thebetweenlands:swamp_dirt')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> output.test(r.getOutput(r.getInput())) && doAddBackup(r)); + } + + @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 Betweenlands Crab Pot Filter Bubbler recipe"; + } + + @Override + @GroovyBlacklist + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable ICrabPotFilterRecipeBubbler register() { + if (!validate()) return null; + ICrabPotFilterRecipeBubbler recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new CrabPotFilterRecipeBubbler(output.get(0), stack); + ModSupport.BETWEENLANDS.get().crabPotFilterBubbler.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/CrabPotFilterSilt.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/CrabPotFilterSilt.java new file mode 100644 index 000000000..fee6afaf2 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/CrabPotFilterSilt.java @@ -0,0 +1,76 @@ +package com.cleanroommc.groovyscript.compat.mods.betweenlands; + +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.thebetweenlands.CrabPotFilterRecipeSiltAccessor; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import org.jetbrains.annotations.Nullable; +import thebetweenlands.api.recipes.ICrabPotFilterRecipeSilt; +import thebetweenlands.common.recipe.misc.CrabPotFilterRecipeSilt; + +import java.util.Collection; + +@RegistryDescription +public class CrabPotFilterSilt extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond'))"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay'))") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return CrabPotFilterRecipeSiltAccessor.getRecipes(); + } + + @MethodDescription(example = @Example("item('thebetweenlands:mud')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> input.test(r.getInput()) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("item('thebetweenlands:mud')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> output.test(r.getOutput(r.getInput())) && doAddBackup(r)); + } + + @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 Betweenlands Crab Pot Filter Silt recipe"; + } + + @Override + @GroovyBlacklist + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable ICrabPotFilterRecipeSilt register() { + if (!validate()) return null; + ICrabPotFilterRecipeSilt recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new CrabPotFilterRecipeSilt(output.get(0), stack); + ModSupport.BETWEENLANDS.get().crabPotFilterSilt.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/DruidAltar.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/DruidAltar.java new file mode 100644 index 000000000..ac0a5c054 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/DruidAltar.java @@ -0,0 +1,82 @@ +package com.cleanroommc.groovyscript.compat.mods.betweenlands; + +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.thebetweenlands.DruidAltarRecipeAccessor; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import org.jetbrains.annotations.Nullable; +import thebetweenlands.api.recipes.IDruidAltarRecipe; +import thebetweenlands.common.recipe.misc.DruidAltarRecipe; + +import java.util.Collection; + +@RegistryDescription(admonition = @Admonition(value = "groovyscript.wiki.thebetweenlands.druid_altar.note0", type = Admonition.Type.WARNING)) +public class DruidAltar extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay')).output(item('minecraft:diamond'))"), + @Example(".input(item('minecraft:diamond'), item('minecraft:gold_block'), item('minecraft:gold_ingot'), item('minecraft:clay')).output(item('minecraft:clay'))") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return DruidAltarRecipeAccessor.getRecipes(); + } + + @MethodDescription(example = @Example(value = "item('thebetweenlands:swamp_talisman:1')", commented = true)) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> r instanceof DruidAltarRecipe recipe && recipe.getInputs().stream().anyMatch(input) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("item('thebetweenlands:swamp_talisman')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> r instanceof DruidAltarRecipe recipe && output.test(recipe.getDefaultOutput()) && doAddBackup(r)); + } + + @Property(property = "input", comp = @Comp(eq = 4)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Betweenlands Druid Altar recipe"; + } + + @Override + @GroovyBlacklist + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 4, 4, 1, 1); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable IDruidAltarRecipe register() { + if (!validate()) return null; + IDruidAltarRecipe recipe = null; + for (var input1 : input.get(0).getMatchingStacks()) { + for (var input2 : input.get(1).getMatchingStacks()) { + for (var input3 : input.get(2).getMatchingStacks()) { + for (var input4 : input.get(3).getMatchingStacks()) { + recipe = new DruidAltarRecipe(input1, input2, input3, input4, output.get(0)); + ModSupport.BETWEENLANDS.get().druidAltar.add(recipe); + } + } + } + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/PestleAndMortar.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/PestleAndMortar.java new file mode 100644 index 000000000..280b4d8fb --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/PestleAndMortar.java @@ -0,0 +1,77 @@ +package com.cleanroommc.groovyscript.compat.mods.betweenlands; + +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.thebetweenlands.PestleAndMortarRecipeAccessor; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; +import thebetweenlands.api.recipes.IPestleAndMortarRecipe; +import thebetweenlands.common.recipe.mortar.PestleAndMortarRecipe; + +import java.util.Collection; + +@RegistryDescription +public class PestleAndMortar extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond'))"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay'))") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return PestleAndMortarRecipeAccessor.getRecipes(); + } + + @MethodDescription(example = @Example("item('thebetweenlands:limestone')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> input.test(r.getInputs()) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("item('thebetweenlands:fish_bait')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> output.test(r.getOutput(r.getInputs(), ItemStack.EMPTY)) && doAddBackup(r)); + } + + @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 Betweenlands Pestle And Mortar recipe"; + } + + @Override + @GroovyBlacklist + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable IPestleAndMortarRecipe register() { + if (!validate()) return null; + IPestleAndMortarRecipe recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new PestleAndMortarRecipe(output.get(0), stack); + ModSupport.BETWEENLANDS.get().pestleAndMortar.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Purifier.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Purifier.java new file mode 100644 index 000000000..12490bfcc --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/Purifier.java @@ -0,0 +1,76 @@ +package com.cleanroommc.groovyscript.compat.mods.betweenlands; + +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.thebetweenlands.PurifierRecipeAccessor; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import org.jetbrains.annotations.Nullable; +import thebetweenlands.api.recipes.IPurifierRecipe; +import thebetweenlands.common.recipe.purifier.PurifierRecipeStandard; + +import java.util.Collection; + +@RegistryDescription +public class Purifier extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond'))"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay'))") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return PurifierRecipeAccessor.getRecipes(); + } + + @MethodDescription(example = @Example("item('thebetweenlands:items_misc:64')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> r instanceof PurifierRecipeStandard recipe && input.test(recipe.getInput()) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("item('thebetweenlands:cragrock')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> r instanceof PurifierRecipeStandard recipe && output.test(r.getOutput(recipe.getInput())) && doAddBackup(r)); + } + + @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 Betweenlands Purifier recipe"; + } + + @Override + @GroovyBlacklist + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable IPurifierRecipe register() { + if (!validate()) return null; + IPurifierRecipe recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new PurifierRecipeStandard(output.get(0), stack); + ModSupport.BETWEENLANDS.get().purifier.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/SmokingRack.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/SmokingRack.java new file mode 100644 index 000000000..285550fd1 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/SmokingRack.java @@ -0,0 +1,86 @@ +package com.cleanroommc.groovyscript.compat.mods.betweenlands; + +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.thebetweenlands.SmokingRackRecipeAccessor; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import org.jetbrains.annotations.Nullable; +import thebetweenlands.api.recipes.ISmokingRackRecipe; +import thebetweenlands.common.recipe.misc.SmokingRackRecipe; + +import java.util.Collection; + +@RegistryDescription +public class SmokingRack extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond'))"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay')).time(50)") + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return SmokingRackRecipeAccessor.getRecipes(); + } + + @MethodDescription(example = @Example("item('thebetweenlands:anadia')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> input.test(r.getInput()) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("item('thebetweenlands:barnacle_smoked')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> output.test(r.getOutput(r.getInput())) && doAddBackup(r)); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(defaultValue = "1", comp = @Comp(gte = 1)) + private int time = 1; + + @RecipeBuilderMethodDescription + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Betweenlands Smoking Rack recipe"; + } + + @Override + @GroovyBlacklist + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + msg.add(time <= 0, "time must be a positive integer greater than 0, yet it was {}", time); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable ISmokingRackRecipe register() { + if (!validate()) return null; + ISmokingRackRecipe recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new SmokingRackRecipe(output.get(0), time, stack); + ModSupport.BETWEENLANDS.get().smokingRack.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/SteepingPot.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/SteepingPot.java new file mode 100644 index 000000000..64dacb983 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/betweenlands/SteepingPot.java @@ -0,0 +1,192 @@ +package com.cleanroommc.groovyscript.compat.mods.betweenlands; + +import com.cleanroommc.groovyscript.api.GroovyBlacklist; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.IOreDicts; +import com.cleanroommc.groovyscript.api.documentation.annotations.*; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.core.mixin.thebetweenlands.SteepingPotRecipesAccessor; +import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.AbstractReloadableStorage; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import thebetweenlands.api.recipes.ISteepingPotRecipe; +import thebetweenlands.common.inventory.container.ContainerSilkBundle; +import thebetweenlands.common.recipe.misc.SteepingPotRecipes; +import thebetweenlands.common.registries.FluidRegistry; + +import java.util.Collection; +import java.util.List; + +/** + * While {@link SteepingPotRecipes} does implement the interface {@link ISteepingPotRecipe}, + * the place that stores recipes can only be of the type {@link SteepingPotRecipes}. + */ +@RegistryDescription +public class SteepingPot extends StandardListRegistry { + + private final AbstractReloadableStorage acceptedItemsStorage = new AbstractReloadableStorage<>(); + + private static boolean doesIIngredientContainMatch(IIngredient target, Object[] match) { + for (var o : match) { + if (o instanceof String s) { + return target instanceof IOreDicts ore && ore.getOreDicts().contains(s); + } + if (o instanceof ItemStack stack) { + return target.test(stack); + } + return false; + } + return false; + } + + @Override + @GroovyBlacklist + @ApiStatus.Internal + public void onReload() { + super.onReload(); + var acceptedItems = getAcceptedItems(); + acceptedItems.removeAll(acceptedItemsStorage.removeScripted()); + acceptedItems.addAll(acceptedItemsStorage.restoreFromBackup()); + } + + /** + * There is currently no support for item output recipes in JEI - they throw an NPE instead of appearing. + * As such, this functionality and corresponding examples of the RecipeBuilder is commented out. + */ + @RecipeBuilderDescription(example = { +// @Example(".input(item('minecraft:clay')).fluidInput(fluid('water')).output(item('minecraft:diamond'))"), + @Example(".input(item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay')).fluidInput(fluid('lava')).fluidOutput(fluid('water'))"), +// @Example(".input(item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:clay')).fluidInput(fluid('lava')).output(item('minecraft:diamond'))"), + @Example(".input(item('minecraft:diamond')).fluidInput(fluid('lava')).fluidOutput(fluid('dye_fluid')).meta(5)"), + @Example(".input(item('minecraft:emerald')).fluidInput(fluid('lava')).fluidOutput(fluid('water'))"), + }) + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return SteepingPotRecipesAccessor.getRecipes(); + } + + public Collection getAcceptedItems() { + return ContainerSilkBundle.acceptedItems; + } + + @MethodDescription(example = { + @Example("item('thebetweenlands:items_crushed:13')"), @Example("fluid('clean_water')") + }) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> (input.test(r.getInputFluidStack()) || doesIIngredientContainMatch(input, r.getInputs())) && doAddBackup(r)); + } + + @MethodDescription(example = { + @Example(value = "item('thebetweenlands:limestone')", commented = true), @Example("fluid('dye_fluid').withNbt(['type': 14])") + }) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> (output.test(r.getOutputItem()) || output.test(r.getOutputFluidStack())) && doAddBackup(r)); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION, priority = 500, example = @Example("item('minecraft:gold_block')")) + public boolean addAcceptedItem(ItemStack entry) { + return entry != null && getAcceptedItems().add(entry) && acceptedItemsStorage.addScripted(entry); + } + + @MethodDescription(priority = 500, example = @Example("item('thebetweenlands:items_crushed:5')")) + public boolean removeAcceptedItem(ItemStack entry) { + return entry != null && getAcceptedItems().removeIf(r -> r == entry) && acceptedItemsStorage.addBackup(entry); + } + + @MethodDescription(priority = 2000, example = @Example(commented = true)) + public void removeAllAcceptedItem() { + var acceptedItems = getAcceptedItems(); + acceptedItems.forEach(acceptedItemsStorage::addBackup); + acceptedItems.clear(); + } + + @Property(property = "input", comp = @Comp(gte = 1, lte = 4)) + @Property(property = "fluidInput", comp = @Comp(eq = 1)) + @Property(property = "fluidOutput", comp = @Comp(eq = 1)) +// @Property(property = "output", comp = @Comp(gte = 0, lte = 1)) +// @Property(property = "fluidOutput", comp = @Comp(gte = 0, lte = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + // Determines the color and state if relevant between two fluids. + // except one is an enum with 16 values and the other has 11. + // mods truly are amazing. + @Property(comp = @Comp(gte = 0, lte = 15)) + private int meta; + + @RecipeBuilderMethodDescription + public RecipeBuilder meta(int meta) { + this.meta = meta; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Betweenlands Steeping Pot recipe"; + } + + @Override + @GroovyBlacklist + protected int getMaxItemInput() { + return 1; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 4, 0, 0); + validateFluids(msg, 1, 1, 1, 1); +// validateItems(msg, 1, 4, 0, 1); +// validateFluids(msg, 1, 1, 0, 1); +// msg.add(output.isEmpty() && fluidOutput.isEmpty(), "either output or fluidOutput must contain an entry, but both were empty"); +// msg.add(!output.isEmpty() && !fluidOutput.isEmpty(), "either output or fluidOutput must have an entry, yet both had an entry"); + if (!fluidOutput.isEmpty()) { + var fluid = fluidOutput.get(0).getFluid(); + if (fluid != FluidRegistry.DYE_FLUID && fluid != FluidRegistry.DRINKABLE_BREW) { + msg.add(meta != 0, "meta has no effect if the fluid is not of type {} or {}, and meta was {} for the fluidOutput {}", FluidRegistry.DYE_FLUID.getName(), FluidRegistry.DRINKABLE_BREW.getName(), meta, fluid.getName()); + } else { + msg.add((meta <= 0 || meta >= 15), "meta must be greater than or equal to 0 and less than or equal to 15 if fluidOutput is of type {} or {}, yet it was {}", FluidRegistry.DYE_FLUID.getName(), FluidRegistry.DRINKABLE_BREW.getName(), meta); + } + } + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable SteepingPotRecipes register() { + if (!validate()) return null; + + for (var ingredient : input) { + for (var stack : ingredient.getMatchingStacks()) { + ModSupport.BETWEENLANDS.get().steepingPot.addAcceptedItem(stack); + } + } + + SteepingPotRecipes recipe = null; + List> inputs = IngredientHelper.cartesianProductOres(input); + for (var objects : inputs) { + recipe = new SteepingPotRecipes(fluidOutput.get(0), meta, fluidInput.get(0), objects.toArray()); + ModSupport.BETWEENLANDS.get().steepingPot.add(recipe); + } + +// if (output.isEmpty()) { +// for (var objects : inputs) { +// recipe = new SteepingPotRecipes(fluidOutput.get(0), meta, fluidInput.get(0), objects.toArray()); +// ModSupport.BETWEENLANDS.get().steepingPot.add(recipe); +// } +// } else { +// for (var objects : inputs) { +// recipe = new SteepingPotRecipes(output.get(0), fluidInput.get(0), objects.toArray()); +// ModSupport.BETWEENLANDS.get().steepingPot.add(recipe); +// } +// } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Hydrator.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Hydrator.java index 88019142e..36810c5e4 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Hydrator.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Hydrator.java @@ -5,18 +5,16 @@ 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 com.google.common.collect.Lists; import com.lothrazar.cyclicmagic.CyclicContent; import com.lothrazar.cyclicmagic.block.hydrator.RecipeHydrate; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; @RegistryDescription public class Hydrator extends StandardListRegistry { @@ -91,7 +89,7 @@ public void validate(GroovyLog.Msg msg) { public @Nullable RecipeHydrate register() { if (!validate()) return null; RecipeHydrate recipe = null; - List> cartesian = Lists.cartesianProduct(input.stream().map(x -> Arrays.asList(x.toMcIngredient().getMatchingStacks())).collect(Collectors.toList())); + List> cartesian = IngredientHelper.cartesianProductItemStacks(input); for (List stacks : cartesian) { recipe = new RecipeHydrate(stacks.toArray(new ItemStack[0]), output.get(0), water); ModSupport.CYCLIC.get().hydrator.add(recipe); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Melter.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Melter.java index 2f2cccd95..aa9dd2cb7 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Melter.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Melter.java @@ -4,18 +4,16 @@ 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 com.google.common.collect.Lists; import com.lothrazar.cyclicmagic.CyclicContent; import com.lothrazar.cyclicmagic.block.melter.RecipeMelter; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; @RegistryDescription public class Melter extends StandardListRegistry { @@ -80,7 +78,7 @@ public void validate(GroovyLog.Msg msg) { public @Nullable RecipeMelter register() { if (!validate()) return null; RecipeMelter recipe = null; - List> cartesian = Lists.cartesianProduct(input.stream().map(x -> Arrays.asList(x.toMcIngredient().getMatchingStacks())).collect(Collectors.toList())); + List> cartesian = IngredientHelper.cartesianProductItemStacks(input); for (List stacks : cartesian) { recipe = new RecipeMelter(stacks.toArray(new ItemStack[0]), fluidOutput.get(0).getFluid().getName(), fluidOutput.get(0).amount); ModSupport.CYCLIC.get().melter.add(recipe); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Packager.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Packager.java index c2612c9aa..7ce3e770e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Packager.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Packager.java @@ -4,18 +4,16 @@ 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 com.google.common.collect.Lists; import com.lothrazar.cyclicmagic.CyclicContent; import com.lothrazar.cyclicmagic.block.packager.RecipePackager; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; @RegistryDescription public class Packager extends StandardListRegistry { @@ -80,7 +78,7 @@ public void validate(GroovyLog.Msg msg) { public @Nullable RecipePackager register() { if (!validate()) return null; RecipePackager recipe = null; - List> cartesian = Lists.cartesianProduct(input.stream().map(x -> Arrays.asList(x.toMcIngredient().getMatchingStacks())).collect(Collectors.toList())); + List> cartesian = IngredientHelper.cartesianProductItemStacks(input); for (List stacks : cartesian) { recipe = new RecipePackager(output.get(0), stacks.toArray(new ItemStack[0])); ModSupport.CYCLIC.get().packager.add(recipe); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Solidifier.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Solidifier.java index 2a5e82eb7..78dcda1e3 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Solidifier.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/cyclic/Solidifier.java @@ -4,18 +4,16 @@ 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 com.google.common.collect.Lists; import com.lothrazar.cyclicmagic.CyclicContent; import com.lothrazar.cyclicmagic.block.solidifier.RecipeSolidifier; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; @RegistryDescription public class Solidifier extends StandardListRegistry { @@ -83,7 +81,7 @@ public void validate(GroovyLog.Msg msg) { public @Nullable RecipeSolidifier register() { if (!validate()) return null; RecipeSolidifier recipe = null; - List> cartesian = Lists.cartesianProduct(input.stream().map(x -> Arrays.asList(x.toMcIngredient().getMatchingStacks())).collect(Collectors.toList())); + List> cartesian = IngredientHelper.cartesianProductItemStacks(input); for (List stacks : cartesian) { recipe = new RecipeSolidifier(stacks.toArray(new ItemStack[0]), output.get(0), fluidInput.get(0).getFluid().getName(), fluidInput.get(0).amount); ModSupport.CYCLIC.get().solidifier.add(recipe); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/primaltech/WoodenBasin.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/primaltech/WoodenBasin.java index c9424c76d..ed4752de1 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/primaltech/WoodenBasin.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/primaltech/WoodenBasin.java @@ -5,10 +5,9 @@ import com.cleanroommc.groovyscript.api.documentation.annotations.*; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.core.mixin.primal_tech.WoodenBasinRecipesAccessor; -import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; +import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.StandardListRegistry; -import com.google.common.collect.Lists; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; @@ -16,9 +15,7 @@ import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.List; -import java.util.stream.Collectors; @RegistryDescription( admonition = @Admonition(type = Admonition.Type.WARNING, value = "groovyscript.wiki.primal_tech.wooden_basin.note0") @@ -96,13 +93,7 @@ public void validate(GroovyLog.Msg msg) { public @Nullable WoodenBasinRecipes register() { if (!validate()) return null; WoodenBasinRecipes recipe = null; - List> cartesian = Lists.cartesianProduct( - input.stream() - .map( - x -> x instanceof OreDictIngredient ore - ? Collections.singletonList(ore.getOreDict()) - : Arrays.asList(x.toMcIngredient().getMatchingStacks())) - .collect(Collectors.toList())); + List> cartesian = IngredientHelper.cartesianProductOres(input); for (List entry : cartesian) { recipe = WoodenBasinRecipesAccessor.createWoodenBasinRecipes(output.get(0), fluidInput.get(0), entry.toArray()); ModSupport.PRIMAL_TECH.get().woodenBasin.add(recipe); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/randomthings/Imbuing.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/randomthings/Imbuing.java index 90c112c08..739032a6b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/randomthings/Imbuing.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/randomthings/Imbuing.java @@ -4,18 +4,16 @@ 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 com.google.common.collect.Lists; import lumien.randomthings.recipes.imbuing.ImbuingRecipe; import lumien.randomthings.recipes.imbuing.ImbuingRecipeHandler; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.Ingredient; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.Collection; -import java.util.stream.Collectors; +import java.util.List; @RegistryDescription public class Imbuing extends StandardListRegistry { @@ -77,7 +75,7 @@ public void validate(GroovyLog.Msg msg) { public @Nullable ImbuingRecipe register() { if (!validate()) return null; ImbuingRecipe recipe = null; - var cartesian = Lists.cartesianProduct(input.stream().map(IIngredient::toMcIngredient).map(Ingredient::getMatchingStacks).map(Arrays::asList).collect(Collectors.toList())); + List> cartesian = IngredientHelper.cartesianProductItemStacks(input); for (var toImbue : mainInput.getMatchingStacks()) { for (var stacks : cartesian) { recipe = new ImbuingRecipe(toImbue, output.get(0), stacks.toArray(new ItemStack[0])); diff --git a/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java b/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java index 865ac9426..699f655b1 100644 --- a/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java +++ b/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java @@ -15,6 +15,7 @@ public class LateMixin implements ILateMixinLoader { "appliedenergistics2", "astralsorcery", "betterwithmods", + "thebetweenlands", "bloodmagic", "botania", "calculator", diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/CrabPotFilterRecipeBubblerAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/CrabPotFilterRecipeBubblerAccessor.java new file mode 100644 index 000000000..d4312f9f6 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/CrabPotFilterRecipeBubblerAccessor.java @@ -0,0 +1,17 @@ +package com.cleanroommc.groovyscript.core.mixin.thebetweenlands; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import thebetweenlands.api.recipes.ICrabPotFilterRecipeBubbler; +import thebetweenlands.common.recipe.misc.CrabPotFilterRecipeBubbler; + +import java.util.List; + +@Mixin(value = CrabPotFilterRecipeBubbler.class, remap = false) +public interface CrabPotFilterRecipeBubblerAccessor { + + @Accessor("RECIPES") + static List getRecipes() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/CrabPotFilterRecipeSiltAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/CrabPotFilterRecipeSiltAccessor.java new file mode 100644 index 000000000..cdd90e89b --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/CrabPotFilterRecipeSiltAccessor.java @@ -0,0 +1,17 @@ +package com.cleanroommc.groovyscript.core.mixin.thebetweenlands; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import thebetweenlands.api.recipes.ICrabPotFilterRecipeSilt; +import thebetweenlands.common.recipe.misc.CrabPotFilterRecipeSilt; + +import java.util.List; + +@Mixin(value = CrabPotFilterRecipeSilt.class, remap = false) +public interface CrabPotFilterRecipeSiltAccessor { + + @Accessor("RECIPES") + static List getRecipes() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/DruidAltarRecipeAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/DruidAltarRecipeAccessor.java new file mode 100644 index 000000000..2c6e43a39 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/DruidAltarRecipeAccessor.java @@ -0,0 +1,17 @@ +package com.cleanroommc.groovyscript.core.mixin.thebetweenlands; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import thebetweenlands.api.recipes.IDruidAltarRecipe; +import thebetweenlands.common.recipe.misc.DruidAltarRecipe; + +import java.util.ArrayList; + +@Mixin(value = DruidAltarRecipe.class, remap = false) +public interface DruidAltarRecipeAccessor { + + @Accessor("druidAltarRecipes") + static ArrayList getRecipes() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/PestleAndMortarRecipeAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/PestleAndMortarRecipeAccessor.java new file mode 100644 index 000000000..4db19f074 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/PestleAndMortarRecipeAccessor.java @@ -0,0 +1,17 @@ +package com.cleanroommc.groovyscript.core.mixin.thebetweenlands; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import thebetweenlands.api.recipes.IPestleAndMortarRecipe; +import thebetweenlands.common.recipe.mortar.PestleAndMortarRecipe; + +import java.util.List; + +@Mixin(value = PestleAndMortarRecipe.class, remap = false) +public interface PestleAndMortarRecipeAccessor { + + @Accessor("recipes") + static List getRecipes() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/PurifierRecipeAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/PurifierRecipeAccessor.java new file mode 100644 index 000000000..a7cd9fd5b --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/PurifierRecipeAccessor.java @@ -0,0 +1,17 @@ +package com.cleanroommc.groovyscript.core.mixin.thebetweenlands; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import thebetweenlands.api.recipes.IPurifierRecipe; +import thebetweenlands.common.recipe.purifier.PurifierRecipe; + +import java.util.List; + +@Mixin(value = PurifierRecipe.class, remap = false) +public interface PurifierRecipeAccessor { + + @Accessor("RECIPES") + static List getRecipes() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/SmokingRackRecipeAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/SmokingRackRecipeAccessor.java new file mode 100644 index 000000000..005e7ac07 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/SmokingRackRecipeAccessor.java @@ -0,0 +1,17 @@ +package com.cleanroommc.groovyscript.core.mixin.thebetweenlands; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import thebetweenlands.api.recipes.ISmokingRackRecipe; +import thebetweenlands.common.recipe.misc.SmokingRackRecipe; + +import java.util.List; + +@Mixin(value = SmokingRackRecipe.class, remap = false) +public interface SmokingRackRecipeAccessor { + + @Accessor("RECIPES") + static List getRecipes() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/SteepingPotRecipesAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/SteepingPotRecipesAccessor.java new file mode 100644 index 000000000..26349814b --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/thebetweenlands/SteepingPotRecipesAccessor.java @@ -0,0 +1,16 @@ +package com.cleanroommc.groovyscript.core.mixin.thebetweenlands; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import thebetweenlands.common.recipe.misc.SteepingPotRecipes; + +import java.util.List; + +@Mixin(value = SteepingPotRecipes.class, remap = false) +public interface SteepingPotRecipesAccessor { + + @Accessor("recipes") + static List getRecipes() { + 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 a2f32bbef..b1144566a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/IngredientHelper.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/IngredientHelper.java @@ -2,8 +2,10 @@ import com.cleanroommc.groovyscript.GroovyScriptConfig; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.IOreDicts; import com.cleanroommc.groovyscript.compat.vanilla.ItemStackMixinExpansion; import com.cleanroommc.groovyscript.sandbox.expand.LambdaClosure; +import com.google.common.collect.Lists; import groovy.lang.Closure; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Items; @@ -16,8 +18,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collection; -import java.util.Collections; +import java.util.*; public class IngredientHelper { @@ -77,6 +78,38 @@ public static IIngredient toIIngredient(FluidStack fluidStack) { return ingredients; } + /** + * Converts a List of IIngredients into every combination of oredict + * (if the IIngredient represents one or more oredicts) + * and matching ItemStacks + * + * @param inputs a list of IIngredients + * @return a list of cartesian product of the oredicts (if relevant) and matching stacks + */ + public static @NotNull List> cartesianProductOres(@NotNull List inputs) { + List> entries = new ArrayList<>(); + for (var input : inputs) { + if (input instanceof IOreDicts ore) entries.add(ore.getOreDicts()); + else entries.add(Arrays.asList(input.getMatchingStacks())); + } + return Lists.cartesianProduct(entries); + } + + /** + * Converts a List of IIngredients into every combination of matching ItemStacks + * + * @param inputs a list of IIngredients + * @return a list of cartesian product of the matching stacks + */ + public static @NotNull List> cartesianProductItemStacks(@NotNull List inputs) { + List> entries = new ArrayList<>(); + for (var input : inputs) { + entries.add(Arrays.asList(input.getMatchingStacks())); + } + return Lists.cartesianProduct(entries); + } + + public static boolean isEmpty(@Nullable IIngredient ingredient) { return ingredient == null || ingredient.isEmpty(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictIngredient.java b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictIngredient.java index 77ab97ab7..978b9acc5 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictIngredient.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictIngredient.java @@ -1,6 +1,8 @@ package com.cleanroommc.groovyscript.helper.ingredient; +import com.cleanroommc.groovyscript.api.IOreDicts; import com.cleanroommc.groovyscript.compat.vanilla.VanillaModule; +import com.google.common.collect.ImmutableList; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import net.minecraftforge.oredict.OreDictionary; @@ -10,7 +12,7 @@ import java.util.Iterator; import java.util.List; -public class OreDictIngredient extends IngredientBase implements Iterable { +public class OreDictIngredient extends IngredientBase implements Iterable, IOreDicts { private final String oreDict; private int count = 1; @@ -23,6 +25,11 @@ public String getOreDict() { return oreDict; } + @Override + public List getOreDicts() { + return ImmutableList.of(getOreDict()); + } + @Override public int getAmount() { return count; diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictWildcardIngredient.java b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictWildcardIngredient.java index ca7dd62e4..55b667ba0 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictWildcardIngredient.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictWildcardIngredient.java @@ -1,6 +1,7 @@ package com.cleanroommc.groovyscript.helper.ingredient; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.IOreDicts; import com.cleanroommc.groovyscript.core.mixin.OreDictionaryAccessor; import net.minecraft.item.ItemStack; import net.minecraftforge.oredict.OreDictionary; @@ -11,7 +12,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -public class OreDictWildcardIngredient extends ItemsIngredient { +public class OreDictWildcardIngredient extends ItemsIngredient implements IOreDicts { private final String oreDict; private final List matchingOreDictionaries = new ArrayList<>(); @@ -43,6 +44,11 @@ public String getOreDict() { return oreDict; } + @Override + public List getOreDicts() { + return getMatchingOreDictionaries(); + } + public List getMatchingOreDictionaries() { return ores; } diff --git a/src/main/resources/assets/groovyscript/lang/en_us.lang b/src/main/resources/assets/groovyscript/lang/en_us.lang index 48c5ee1cb..35e3c9967 100644 --- a/src/main/resources/assets/groovyscript/lang/en_us.lang +++ b/src/main/resources/assets/groovyscript/lang/en_us.lang @@ -563,6 +563,50 @@ groovyscript.wiki.betterwithmods.turntable.rotations.value=Sets the number of ro groovyscript.wiki.betterwithmods.turntable.outputBlock.value=Sets the blockstate that replaces the input block +# The Betweenlands +groovyscript.wiki.thebetweenlands.animator.title=Animator +groovyscript.wiki.thebetweenlands.animator.description=Converts an input item, Life amount from Life Crystals, and Fuel from Sulfur into an output itemstack, summoning an entity, a random item from a loottable, or summoning an entity and outputting an itemstack. +groovyscript.wiki.thebetweenlands.animator.fuel.value=Sets the fuel consumed +groovyscript.wiki.thebetweenlands.animator.life.value=Sets the life consumed from the life crystal +groovyscript.wiki.thebetweenlands.animator.entity.value=Sets the entity being spawned +groovyscript.wiki.thebetweenlands.animator.render.value=Sets the entity to render, typically the same as the entity to be spawned +groovyscript.wiki.thebetweenlands.animator.lootTable.value=Sets the LootTable used to generate outputs +groovyscript.wiki.thebetweenlands.animator.removeByEntity=Removes all entries that match the given entity +groovyscript.wiki.thebetweenlands.animator.removeByLootTable=Removes all entries that output the given Loot Table + +groovyscript.wiki.thebetweenlands.compost.title=Compost +groovyscript.wiki.thebetweenlands.compost.description=Converts an input itemstack into an amount of compost. +groovyscript.wiki.thebetweenlands.compost.time.value=Sets the time the recipe takes in ticks +groovyscript.wiki.thebetweenlands.compost.amount.value=Sets the amount of compost output + +groovyscript.wiki.thebetweenlands.crab_pot_filter_bubbler.title=Crab Pot Filter Bubbler +groovyscript.wiki.thebetweenlands.crab_pot_filter_bubbler.description=Converts an input item into an output itemstack when a Bubbler Crab is placed inside a Crab Pot Filter. + +groovyscript.wiki.thebetweenlands.crab_pot_filter_silt.title=Crab Pot Filter Silt +groovyscript.wiki.thebetweenlands.crab_pot_filter_silt.description=Converts an input item into an output itemstack when a Silt Crab is placed inside a Crab Pot Filter. + +groovyscript.wiki.thebetweenlands.druid_altar.title=Druid Altar +groovyscript.wiki.thebetweenlands.druid_altar.description=Converts 4 input items into an output itemstack. +groovyscript.wiki.thebetweenlands.druid_altar.note0=The 4 sapling recipe to reactivate the Druid Altar recipe will always appear in JEI, even if it has been removed. Additionally, this recipe cannot be removed via `removeByInput` or `removeByOutput` + +groovyscript.wiki.thebetweenlands.pestle_and_mortar.title=Pestle And Mortar +groovyscript.wiki.thebetweenlands.pestle_and_mortar.description=Converts an input item into an output itemstack in a Pestle and Mortar by using a Pestle tool in the Mortar. + +groovyscript.wiki.thebetweenlands.purifier.title=Purifier +groovyscript.wiki.thebetweenlands.purifier.description=Converts an input item into an output itemstack, consuming Sulfur and Swamp Water as fuel. + +groovyscript.wiki.thebetweenlands.smoking_rack.title=Smoking Rack +groovyscript.wiki.thebetweenlands.smoking_rack.description=Converts an input item into an output itemstack over a configurable period of time, consuming Fallen Leaves to do so. +groovyscript.wiki.thebetweenlands.smoking_rack.time.value=Sets the time the recipe takes times 10 in seconds (3 = 30 seconds) + +groovyscript.wiki.thebetweenlands.steeping_pot.title=Steeping Pot +groovyscript.wiki.thebetweenlands.steeping_pot.description=Converts a 1,000mb of fluid into either 1,000mb of a fluid, an output itemstack, or both, consuming up to 4 items from a Silk Bundle placed inside the Steeping Pot to do so. The Silk Bundle is converted into a Dirty Silk Bundle in the process. The Silk Bundle can only hold specific items, which are also configurable. +groovyscript.wiki.thebetweenlands.steeping_pot.meta.value=Sets the color of the output and the type of output if the fluidOutput is `dye_fluid` or `drinkable_brew` +groovyscript.wiki.thebetweenlands.steeping_pot.addAcceptedItem=Adds the given ItemStack to the accepted item list for the Silk Bundle +groovyscript.wiki.thebetweenlands.steeping_pot.removeAcceptedItem=Removes the given ItemStack from the accepted item list for the Silk Bundle +groovyscript.wiki.thebetweenlands.steeping_pot.removeAllAcceptedItem=Removes all entries from the accepted item list for the Silk Bundle + + # Blood Arsenal groovyscript.wiki.bloodarsenal.sanguine_infusion.title=Sanguine Infusion groovyscript.wiki.bloodarsenal.sanguine_infusion.description=Converts an input infusion itemstack and up to 8 input surrounding itemstacks into an output itemstack, consuming Life Essence from the network to do so when the Infusion de Sanguine Ritual is activated. Alternatively, instead of consuming an infusion item, adds or upgrades a modifier to the given stasis tool, with the ability to increase the quantity of inputs consumed based on level. @@ -2422,6 +2466,7 @@ groovyscript.wiki.thaumcraft.warp.description=Determines if holding an item or e groovyscript.wiki.thaumcraft.warp.addWarp=Adds Warp to the given item in the format `item`, `amount` groovyscript.wiki.thaumcraft.warp.removeWarp=Removes Warp from the given item + # The Aurorian groovyscript.wiki.theaurorian.moonlight_forge.title=Moonlight Forge groovyscript.wiki.theaurorian.moonlight_forge.description=Combines two items to get a third item. Only works at night, and works faster the higher it is placed in the world. @@ -2429,6 +2474,7 @@ groovyscript.wiki.theaurorian.moonlight_forge.removeByInput=Removes a recipe by groovyscript.wiki.theaurorian.scrapper.title=Scrapper groovyscript.wiki.theaurorian.scrapper.description=Turns an input item into an output item. Can be sped up by placing a Crystal on top of it. The crystal has a chance to break every time a recipe is executed. + # Thermal Expansion groovyscript.wiki.thermalexpansion.energy.value=Sets the energy cost of the recipe diff --git a/src/main/resources/mixin.groovyscript.thebetweenlands.json b/src/main/resources/mixin.groovyscript.thebetweenlands.json new file mode 100644 index 000000000..2f14d2423 --- /dev/null +++ b/src/main/resources/mixin.groovyscript.thebetweenlands.json @@ -0,0 +1,16 @@ +{ + "package": "com.cleanroommc.groovyscript.core.mixin.thebetweenlands", + "refmap": "mixins.groovyscript.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "CrabPotFilterRecipeBubblerAccessor", + "CrabPotFilterRecipeSiltAccessor", + "DruidAltarRecipeAccessor", + "PestleAndMortarRecipeAccessor", + "PurifierRecipeAccessor", + "SmokingRackRecipeAccessor", + "SteepingPotRecipesAccessor" + ] +} \ No newline at end of file