diff --git a/dependencies.gradle b/dependencies.gradle index 2cafb98a0..6ab3f9ef9 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -71,6 +71,7 @@ final def mod_dependencies = [ 'extra-utilities-2-225561:2678374' : [project.debug_extra_utilities_2], 'forestry-59751:2918418' : [project.debug_forestry], 'future-mc-310059:5626387' : [project.debug_future_mc], + 'horse-power-270466:2705433' : [project.debug_horse_power], 'immersive_engineering-231951:2974106' : [project.debug_immersive_engineering, project.debug_immersive_petroleum, project.debug_immersive_technology], 'immersive-petroleum-268250:3382321' : [project.debug_immersive_petroleum], 'mct-immersive-technology-359407:5108047' : [project.debug_immersive_technology], diff --git a/examples/postInit/horsepower.groovy b/examples/postInit/horsepower.groovy new file mode 100644 index 000000000..7713bf2ae --- /dev/null +++ b/examples/postInit/horsepower.groovy @@ -0,0 +1,133 @@ + +// Auto generated groovyscript example file +// MODS_LOADED: horsepower + +log.info 'mod \'horsepower\' detected, running script' + +// Horse Chopping Block: +// Converts an itemstack input into an itemstack output, with the chance of an additional output after a configurable +// amount of processing has been done. Depending on if the config option `Separate Chopping Recipes` is true, this may +// affect both Horse and Hand Chopping Blocks. Only the Horse Chopping Block can produce secondary outputs. + +mods.horsepower.chopping_block.removeByInput(item('minecraft:log:3')) +mods.horsepower.chopping_block.removeByOutput(item('minecraft:planks:4')) +// mods.horsepower.chopping_block.removeAll() + +mods.horsepower.chopping_block.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond') * 5) + .time(5) + .register() + +mods.horsepower.chopping_block.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:gold_ingot')) + .time(1) + .register() + +mods.horsepower.chopping_block.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay'), item('minecraft:diamond')) + .chance(50) + .time(2) + .register() + + +// Horse Grindstone: +// Converts an itemstack input into an itemstack output, with the chance of an additional output after a configurable +// amount of processing has been done. Depending on if the config option `Separate Grindstone Recipes` is true, this may +// affect both Horse and Hand Grindstones. + +mods.horsepower.grindstone.removeByInput(item('minecraft:double_plant:4')) +mods.horsepower.grindstone.removeByOutput(item('minecraft:sugar')) +// mods.horsepower.grindstone.removeAll() + +mods.horsepower.grindstone.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond') * 5) + .time(5) + .register() + +mods.horsepower.grindstone.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:gold_ingot')) + .time(1) + .register() + +mods.horsepower.grindstone.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay'), item('minecraft:diamond')) + .chance(50) + .time(2) + .register() + + +// Manual Chopping Block: +// Converts an itemstack input into an itemstack output after a configurable amount of processing has been done. Depending +// on if the config option `Separate Chopping Recipes` is true, this may affect both Horse and Hand Chopping Blocks. + +mods.horsepower.manual_chopping_block.removeByInput(item('minecraft:log:3')) +mods.horsepower.manual_chopping_block.removeByOutput(item('minecraft:planks:4')) +// mods.horsepower.manual_chopping_block.removeAll() + +mods.horsepower.manual_chopping_block.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond') * 5) + .time(5) + .register() + +mods.horsepower.manual_chopping_block.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:gold_ingot')) + .time(1) + .register() + + +// Manual Grindstone: +// Converts an itemstack input into an itemstack output, with the chance of an additional output after a configurable +// amount of processing has been done. Depending on if the config option `Separate Grindstone Recipes` is true, this may +// affect both Horse and Hand Grindstones. + +mods.horsepower.manual_grindstone.removeByInput(item('minecraft:double_plant:4')) +mods.horsepower.manual_grindstone.removeByOutput(item('minecraft:sugar')) +// mods.horsepower.manual_grindstone.removeAll() + +mods.horsepower.manual_grindstone.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond') * 5) + .time(5) + .register() + +mods.horsepower.manual_grindstone.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:gold_ingot')) + .time(1) + .register() + +mods.horsepower.manual_grindstone.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay'), item('minecraft:diamond')) + .chance(50) + .time(2) + .register() + + +// Horse Press: +// Converts an itemstack into another itemstack or a fluidstack by a horse running laps. + +mods.horsepower.press.removeByInput(item('minecraft:wheat_seeds')) +mods.horsepower.press.removeByOutput(fluid('water')) +// mods.horsepower.press.removeByOutput(item('minecraft:dirt')) +// mods.horsepower.press.removeAll() + +mods.horsepower.press.recipeBuilder() + .input(item('minecraft:clay')) + .output(item('minecraft:diamond') * 5) + .register() + +mods.horsepower.press.recipeBuilder() + .input(item('minecraft:diamond')) + .fluidOutput(fluid('lava') * 500) + .register() + + diff --git a/gradle.properties b/gradle.properties index 7bd9cb6ff..e52b240f2 100644 --- a/gradle.properties +++ b/gradle.properties @@ -47,6 +47,8 @@ debug_extra_utilities_2 = false debug_forestry = false debug_future_mc = false +debug_horse_power = false + debug_immersive_engineering = false debug_immersive_petroleum = false debug_immersive_technology = 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 38c1ab3ca..fd17502cc 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java @@ -31,6 +31,7 @@ import com.cleanroommc.groovyscript.compat.mods.extrautils2.ExtraUtils2; import com.cleanroommc.groovyscript.compat.mods.forestry.Forestry; import com.cleanroommc.groovyscript.compat.mods.futuremc.FutureMC; +import com.cleanroommc.groovyscript.compat.mods.horsepower.HorsePower; import com.cleanroommc.groovyscript.compat.mods.ic2.IC2; import com.cleanroommc.groovyscript.compat.mods.immersiveengineering.ImmersiveEngineering; import com.cleanroommc.groovyscript.compat.mods.immersivepetroleum.ImmersivePetroleum; @@ -106,6 +107,7 @@ public class ModSupport { public static final GroovyContainer EXTRA_UTILITIES_2 = new InternalModContainer<>("extrautils2", "Extra Utilities 2", ExtraUtils2::new, "extrautilities2"); public static final GroovyContainer FORESTRY = new InternalModContainer<>("forestry", "Forestry", Forestry::new); public static final GroovyContainer FUTURE_MC = new InternalModContainer<>("futuremc", "Future MC", FutureMC::new); + public static final GroovyContainer HORSE_POWER = new InternalModContainer<>("horsepower", "Horse Power", HorsePower::new); public static final GroovyContainer IMMERSIVE_ENGINEERING = new InternalModContainer<>("immersiveengineering", "Immersive Engineering", ImmersiveEngineering::new, "ie"); public static final GroovyContainer IMMERSIVE_PETROLEUM = new InternalModContainer<>("immersivepetroleum", "Immersive Petroleum", ImmersivePetroleum::new); public static final GroovyContainer IMMERSIVE_TECHNOLOGY = new InternalModContainer<>("immersivetech", "Immersive Technology", ImmersiveTechnology::new); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/ChoppingBlock.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/ChoppingBlock.java new file mode 100644 index 000000000..166f10f77 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/ChoppingBlock.java @@ -0,0 +1,133 @@ +package com.cleanroommc.groovyscript.compat.mods.horsepower; + +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.item.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import se.gory_moon.horsepower.recipes.ChoppingBlockRecipe; +import se.gory_moon.horsepower.recipes.HPRecipes; + +import java.util.Collection; + +@RegistryDescription +public class ChoppingBlock extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond') * 5).time(5)"), + @Example(".input(item('minecraft:diamond')).output(item('minecraft:gold_ingot')).time(1)"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay'), item('minecraft:diamond')).chance(50).time(2)") + }) + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + // have to override onReload and add to add recipes to the registry due to the actual setup being a map + @Override + public Collection getRecipes() { + return HPRecipes.instance().getChoppingRecipes(); + } + + @Override + @GroovyBlacklist + @ApiStatus.Internal + public void onReload() { + var recipes = getRecipes(); + recipes.removeAll(removeScripted()); + for (var recipe : restoreFromBackup()) { + HPRecipes.instance().addChoppingRecipe(recipe, false); + } + } + + @Override + @MethodDescription(type = MethodDescription.Type.ADDITION, description = "groovyscript.wiki.add_to_list", priority = 500) + public boolean add(ChoppingBlockRecipe recipe) { + HPRecipes.instance().addChoppingRecipe(recipe, false); + return recipe != null && doAddScripted(recipe); + } + + @MethodDescription(description = "groovyscript.wiki.horsepower.chopping_block.add0", type = MethodDescription.Type.ADDITION) + public ChoppingBlockRecipe add(IIngredient input, ItemStack output, int time) { + return recipeBuilder() + .time(time) + .output(output) + .input(input) + .register(); + } + + @MethodDescription(description = "groovyscript.wiki.horsepower.chopping_block.add1", type = MethodDescription.Type.ADDITION) + public ChoppingBlockRecipe add(IIngredient input, ItemStack output, ItemStack secondary, int chance, int time) { + return recipeBuilder() + .time(time) + .chance(chance) + .output(output, secondary) + .input(input) + .register(); + } + + @MethodDescription(example = @Example("item('minecraft:log:3')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(entry -> input.test(entry.getInput()) && doAddBackup(entry)); + } + + @MethodDescription(example = @Example("item('minecraft:planks:4')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(entry -> (output.test(entry.getOutput()) || output.test(entry.getSecondary())) && doAddBackup(entry)); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(gte = 1, lte = 2)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(gte = 0, lte = 100)) + private int chance; + @Property(comp = @Comp(gt = 0)) + private int time; + + @RecipeBuilderMethodDescription + public RecipeBuilder chance(int chance) { + this.chance = chance; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + + // todo this can only handle an input with a size of 1, should validate that here + + @Override + public String getErrorMsg() { + return "Error adding Horse Power Chopping Block recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 2); + validateFluids(msg); + msg.add(chance < 0 || chance > 100, "chance must be a non negative integer less than 100, yet it was {}", chance); + msg.add(time <= 0, "time must be greater than 0, yet it was {}", time); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable ChoppingBlockRecipe register() { + if (!validate()) return null; + ChoppingBlockRecipe recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new ChoppingBlockRecipe(stack, output.get(0), output.getOrEmpty(1), chance, time); + ModSupport.HORSE_POWER.get().choppingBlock.add(recipe); + } + return recipe; + } + + } + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/Grindstone.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/Grindstone.java new file mode 100644 index 000000000..cb473af6b --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/Grindstone.java @@ -0,0 +1,131 @@ +package com.cleanroommc.groovyscript.compat.mods.horsepower; + +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.item.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import se.gory_moon.horsepower.recipes.GrindstoneRecipe; +import se.gory_moon.horsepower.recipes.HPRecipes; + +import java.util.Collection; + +@RegistryDescription +public class Grindstone extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond') * 5).time(5)"), + @Example(".input(item('minecraft:diamond')).output(item('minecraft:gold_ingot')).time(1)"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay'), item('minecraft:diamond')).chance(50).time(2)") + }) + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + // have to override onReload and add to add recipes to the registry due to the actual setup being a map + @Override + public Collection getRecipes() { + return HPRecipes.instance().getGrindstoneRecipes(); + } + + @Override + @GroovyBlacklist + @ApiStatus.Internal + public void onReload() { + var recipes = getRecipes(); + recipes.removeAll(removeScripted()); + for (var recipe : restoreFromBackup()) { + HPRecipes.instance().addGrindstoneRecipe(recipe, false); + } + } + + @Override + @MethodDescription(type = MethodDescription.Type.ADDITION, description = "groovyscript.wiki.add_to_list", priority = 500) + public boolean add(GrindstoneRecipe recipe) { + HPRecipes.instance().addGrindstoneRecipe(recipe, false); + return recipe != null && doAddScripted(recipe); + } + + @MethodDescription(description = "groovyscript.wiki.horsepower.grindstone.add0", type = MethodDescription.Type.ADDITION) + public GrindstoneRecipe add(IIngredient input, ItemStack output, int time) { + return recipeBuilder() + .time(time) + .output(output) + .input(input) + .register(); + } + + @MethodDescription(description = "groovyscript.wiki.horsepower.grindstone.add1", type = MethodDescription.Type.ADDITION) + public GrindstoneRecipe add(IIngredient input, ItemStack output, ItemStack secondary, int chance, int time) { + return recipeBuilder() + .time(time) + .chance(chance) + .output(output, secondary) + .input(input) + .register(); + } + + @MethodDescription(example = @Example("item('minecraft:double_plant:4')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(entry -> input.test(entry.getInput()) && doAddBackup(entry)); + } + + @MethodDescription(example = @Example("item('minecraft:sugar')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(entry -> (output.test(entry.getOutput()) || output.test(entry.getSecondary())) && doAddBackup(entry)); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(gte = 1, lte = 2)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(gte = 0, lte = 100)) + private int chance; + @Property(comp = @Comp(gt = 0)) + private int time; + + @RecipeBuilderMethodDescription + public RecipeBuilder chance(int chance) { + this.chance = chance; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Horse Power Grindstone recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 2); + validateFluids(msg); + msg.add(chance < 0 || chance > 100, "chance must be a non negative integer less than 100, yet it was {}", chance); + msg.add(time <= 0, "time must be greater than 0, yet it was {}", time); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable GrindstoneRecipe register() { + if (!validate()) return null; + GrindstoneRecipe recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new GrindstoneRecipe(stack, output.get(0), output.getOrEmpty(1), chance, time); + ModSupport.HORSE_POWER.get().grindstone.add(recipe); + } + return recipe; + } + + } + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/HorsePower.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/HorsePower.java new file mode 100644 index 000000000..2f009efb9 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/HorsePower.java @@ -0,0 +1,13 @@ +package com.cleanroommc.groovyscript.compat.mods.horsepower; + +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; + +public class HorsePower extends GroovyPropertyContainer { + + public final ChoppingBlock choppingBlock = new ChoppingBlock(); + public final ManualChoppingBlock manualChoppingBlock = new ManualChoppingBlock(); + public final Grindstone grindstone = new Grindstone(); + public final ManualGrindstone manualGrindstone = new ManualGrindstone(); + public final Press press = new Press(); + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/ManualChoppingBlock.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/ManualChoppingBlock.java new file mode 100644 index 000000000..9fd3a21b4 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/ManualChoppingBlock.java @@ -0,0 +1,114 @@ +package com.cleanroommc.groovyscript.compat.mods.horsepower; + +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.item.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import se.gory_moon.horsepower.recipes.ChoppingBlockRecipe; +import se.gory_moon.horsepower.recipes.HPRecipes; +import se.gory_moon.horsepower.recipes.ManualChoppingBlockRecipe; + +import java.util.Collection; + +@RegistryDescription +public class ManualChoppingBlock extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond') * 5).time(5)"), + @Example(".input(item('minecraft:diamond')).output(item('minecraft:gold_ingot')).time(1)") + }) + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + // have to override onReload and add to add recipes to the registry due to the actual setup being a map + @Override + public Collection getRecipes() { + return HPRecipes.instance().getManualChoppingRecipes(); + } + + @Override + @GroovyBlacklist + @ApiStatus.Internal + public void onReload() { + var recipes = getRecipes(); + recipes.removeAll(removeScripted()); + for (var recipe : restoreFromBackup()) { + HPRecipes.instance().addChoppingRecipe(recipe, true); + } + } + + @Override + @MethodDescription(type = MethodDescription.Type.ADDITION, description = "groovyscript.wiki.add_to_list", priority = 500) + public boolean add(ChoppingBlockRecipe recipe) { + HPRecipes.instance().addChoppingRecipe(recipe, true); + return recipe != null && doAddScripted(recipe); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public ChoppingBlockRecipe add(IIngredient input, ItemStack output, int time) { + return recipeBuilder() + .time(time) + .output(output) + .input(input) + .register(); + } + + @MethodDescription(example = @Example("item('minecraft:log:3')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(entry -> input.test(entry.getInput()) && doAddBackup(entry)); + } + + @MethodDescription(example = @Example("item('minecraft:planks:4')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(entry -> output.test(entry.getOutput()) && doAddBackup(entry)); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(gt = 0)) + private int time; + + @RecipeBuilderMethodDescription + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + + // todo this can only handle an input with a size of 1, should validate that here + + @Override + public String getErrorMsg() { + return "Error adding Horse Power Manual Chopping Block recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 2); + validateFluids(msg); + msg.add(time <= 0, "time must be greater than 0, yet it was {}", time); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable ChoppingBlockRecipe register() { + if (!validate()) return null; + ChoppingBlockRecipe recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new ManualChoppingBlockRecipe(stack, output.get(0), ItemStack.EMPTY, 0, time); + ModSupport.HORSE_POWER.get().manualChoppingBlock.add(recipe); + } + return recipe; + } + + } + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/ManualGrindstone.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/ManualGrindstone.java new file mode 100644 index 000000000..7eeec6f96 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/ManualGrindstone.java @@ -0,0 +1,132 @@ +package com.cleanroommc.groovyscript.compat.mods.horsepower; + +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.item.ItemStack; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import se.gory_moon.horsepower.recipes.GrindstoneRecipe; +import se.gory_moon.horsepower.recipes.HPRecipes; +import se.gory_moon.horsepower.recipes.HandGrindstoneRecipe; + +import java.util.Collection; + +@RegistryDescription +public class ManualGrindstone extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond') * 5).time(5)"), + @Example(".input(item('minecraft:diamond')).output(item('minecraft:gold_ingot')).time(1)"), + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay'), item('minecraft:diamond')).chance(50).time(2)") + }) + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + // have to override onReload and add to add recipes to the registry due to the actual setup being a map + @Override + public Collection getRecipes() { + return HPRecipes.instance().getHandGrindstoneRecipes(); + } + + @Override + @GroovyBlacklist + @ApiStatus.Internal + public void onReload() { + var recipes = getRecipes(); + recipes.removeAll(removeScripted()); + for (var recipe : restoreFromBackup()) { + HPRecipes.instance().addGrindstoneRecipe(recipe, true); + } + } + + @Override + @MethodDescription(type = MethodDescription.Type.ADDITION, description = "groovyscript.wiki.add_to_list", priority = 500) + public boolean add(GrindstoneRecipe recipe) { + HPRecipes.instance().addGrindstoneRecipe(recipe, true); + return recipe != null && doAddScripted(recipe); + } + + @MethodDescription(description = "groovyscript.wiki.horsepower.manual_grindstone.add0", type = MethodDescription.Type.ADDITION) + public GrindstoneRecipe add(IIngredient input, ItemStack output, int time) { + return recipeBuilder() + .time(time) + .output(output) + .input(input) + .register(); + } + + @MethodDescription(description = "groovyscript.wiki.horsepower.manual_grindstone.add1", type = MethodDescription.Type.ADDITION) + public GrindstoneRecipe add(IIngredient input, ItemStack output, ItemStack secondary, int chance, int time) { + return recipeBuilder() + .time(time) + .chance(chance) + .output(output, secondary) + .input(input) + .register(); + } + + @MethodDescription(example = @Example("item('minecraft:double_plant:4')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(entry -> input.test(entry.getInput()) && doAddBackup(entry)); + } + + @MethodDescription(example = @Example("item('minecraft:sugar')")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(entry -> (output.test(entry.getOutput()) || output.test(entry.getSecondary())) && doAddBackup(entry)); + } + + @Property(property = "input", comp = @Comp(eq = 1)) + @Property(property = "output", comp = @Comp(gte = 1, lte = 2)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Property(comp = @Comp(gte = 0, lte = 100)) + private int chance; + @Property(comp = @Comp(gt = 0)) + private int time; + + @RecipeBuilderMethodDescription + public RecipeBuilder chance(int chance) { + this.chance = chance; + return this; + } + + @RecipeBuilderMethodDescription + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Horse Power Manual Grindstone recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 2); + validateFluids(msg); + msg.add(chance < 0 || chance > 100, "chance must be a non negative integer less than 100, yet it was {}", chance); + msg.add(time <= 0, "time must be greater than 0, yet it was {}", time); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable GrindstoneRecipe register() { + if (!validate()) return null; + GrindstoneRecipe recipe = null; + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new HandGrindstoneRecipe(stack, output.get(0), output.getOrEmpty(1), chance, time); + ModSupport.HORSE_POWER.get().manualGrindstone.add(recipe); + } + return recipe; + } + + } + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/Press.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/Press.java new file mode 100644 index 000000000..2963f3316 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/horsepower/Press.java @@ -0,0 +1,122 @@ +package com.cleanroommc.groovyscript.compat.mods.horsepower; + +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.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Nullable; +import se.gory_moon.horsepower.recipes.HPRecipes; +import se.gory_moon.horsepower.recipes.PressRecipe; + +import java.util.Collection; + +@RegistryDescription +public class Press extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:clay')).output(item('minecraft:diamond') * 5)"), + @Example(".input(item('minecraft:diamond')).fluidOutput(fluid('lava') * 500)") + }) + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + // have to override onReload and add to add recipes to the registry due to the actual setup being a map + @Override + public Collection getRecipes() { + return HPRecipes.instance().getPressRecipes(); + } + + @Override + @GroovyBlacklist + @ApiStatus.Internal + public void onReload() { + var recipes = getRecipes(); + recipes.removeAll(removeScripted()); + for (var recipe : restoreFromBackup()) { + HPRecipes.instance().addPressRecipe(recipe); + } + } + + @Override + @MethodDescription(type = MethodDescription.Type.ADDITION, description = "groovyscript.wiki.add_to_list", priority = 500) + public boolean add(PressRecipe recipe) { + HPRecipes.instance().addPressRecipe(recipe); + return recipe != null && doAddScripted(recipe); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public PressRecipe add(IIngredient input, ItemStack output) { + return recipeBuilder() + .output(output) + .input(input) + .register(); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION) + public PressRecipe add(IIngredient input, FluidStack output) { + return recipeBuilder() + .fluidOutput(output) + .input(input) + .register(); + } + + @MethodDescription(example = @Example("item('minecraft:wheat_seeds')")) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(entry -> input.test(entry.getInput()) && doAddBackup(entry)); + } + + @MethodDescription(example = { + @Example(value = "item('minecraft:dirt')", commented = true), + @Example("fluid('water')") + }) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(entry -> (output.test(entry.getOutput()) || output.test(entry.getOutputFluid())) && doAddBackup(entry)); + } + + @Property(property = "input", 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 { + + @Override + public String getErrorMsg() { + return "Error adding Horse Power Press recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 1); + validateFluids(msg, 0, 0, 0, 1); + msg.add(output.isEmpty() && fluidOutput.isEmpty(), "either output or fluidOutput must have have an entry, yet both were empty"); + msg.add(!output.isEmpty() && !fluidOutput.isEmpty(), "either output or fluidOutput must have have an entry, yet both had an entry"); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable PressRecipe register() { + if (!validate()) return null; + PressRecipe recipe = null; + if (fluidOutput.isEmpty()) { + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new PressRecipe(stack, output.get(0), ItemStack.EMPTY, 0, 0); + ModSupport.HORSE_POWER.get().press.add(recipe); + } + } else { + for (var stack : input.get(0).getMatchingStacks()) { + recipe = new PressRecipe(stack, fluidOutput.get(0)); + ModSupport.HORSE_POWER.get().press.add(recipe); + } + } + return recipe; + } + + } + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java b/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java index ef9b644a6..8afd78a49 100644 --- a/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java +++ b/src/main/java/com/cleanroommc/groovyscript/documentation/Registry.java @@ -45,6 +45,8 @@ public Registry(GroovyContainer mod, INamed r List imports = new ArrayList<>(); for (Method method : registryClass.getMethods()) { + // skip bridge methods as they are overridden by a child method. + if (method.isBridge()) continue; if (method.isAnnotationPresent(GroovyBlacklist.class)) continue; if (method.isAnnotationPresent(RecipeBuilderDescription.class)) { recipeBuilderMethods.add(method); diff --git a/src/main/resources/assets/groovyscript/lang/en_us.lang b/src/main/resources/assets/groovyscript/lang/en_us.lang index 7b6d13ccb..a67e0de42 100644 --- a/src/main/resources/assets/groovyscript/lang/en_us.lang +++ b/src/main/resources/assets/groovyscript/lang/en_us.lang @@ -1100,6 +1100,38 @@ groovyscript.wiki.futuremc.stonecutter.title=Stoenecutter groovyscript.wiki.futuremc.stonecutter.description=Converts an input itemstack into an output itemstack via selecting the desired output from the Stonecutter GUI. +# Horse Power +groovyscript.wiki.horsepower.chopping_block.title=Horse Chopping Block +groovyscript.wiki.horsepower.chopping_block.description=Converts an itemstack input into an itemstack output, with the chance of an additional output after a configurable amount of processing has been done. Depending on if the config option `Separate Chopping Recipes` is true, this may affect both Horse and Hand Chopping Blocks. Only the Horse Chopping Block can produce secondary outputs. +groovyscript.wiki.horsepower.chopping_block.add0=Adds recipes in the format `input`, `output`, `time` +groovyscript.wiki.horsepower.chopping_block.add1=Adds recipes in the format `input`, `output`, `secondary`, `chance`, `time` +groovyscript.wiki.horsepower.chopping_block.time.value=Sets the time in laps the horse has to take to complete the recipe +groovyscript.wiki.horsepower.chopping_block.chance.value=Sets the chance that the secondary output will be created if the secondary output exists + +groovyscript.wiki.horsepower.grindstone.title=Horse Grindstone +groovyscript.wiki.horsepower.grindstone.description=Converts an itemstack input into an itemstack output, with the chance of an additional output after a configurable amount of processing has been done. Depending on if the config option `Separate Grindstone Recipes` is true, this may affect both Horse and Hand Grindstones. +groovyscript.wiki.horsepower.grindstone.add0=Adds recipes in the format `input`, `output`, `time` +groovyscript.wiki.horsepower.grindstone.add1=Adds recipes in the format `input`, `output`, `secondary`, `chance`, `time` +groovyscript.wiki.horsepower.grindstone.time.value=Sets the time in laps the horse has to take to complete the recipe +groovyscript.wiki.horsepower.grindstone.chance.value=Sets the chance that the secondary output will be created if the secondary output exists + +groovyscript.wiki.horsepower.manual_chopping_block.title=Manual Chopping Block +groovyscript.wiki.horsepower.manual_chopping_block.description=Converts an itemstack input into an itemstack output after a configurable amount of processing has been done. Depending on if the config option `Separate Chopping Recipes` is true, this may affect both Horse and Hand Chopping Blocks. +groovyscript.wiki.horsepower.manual_chopping_block.add=Adds recipes in the format `input`, `output`, `time` +groovyscript.wiki.horsepower.manual_chopping_block.time.value=Sets the amount of chops the player has to make to complete the recipe + +groovyscript.wiki.horsepower.manual_grindstone.title=Manual Grindstone +groovyscript.wiki.horsepower.manual_grindstone.description=Converts an itemstack input into an itemstack output, with the chance of an additional output after a configurable amount of processing has been done. Depending on if the config option `Separate Grindstone Recipes` is true, this may affect both Horse and Hand Grindstones. +groovyscript.wiki.horsepower.manual_grindstone.add0=Adds recipes in the format `input`, `output`, `time` +groovyscript.wiki.horsepower.manual_grindstone.add1=Adds recipes in the format `input`, `output`, `secondary`, `chance`, `time` +groovyscript.wiki.horsepower.manual_grindstone.time.value=Sets the amount of chops the player has to make to complete the recipe +groovyscript.wiki.horsepower.manual_grindstone.chance.value=Sets the chance that the secondary output will be created if the secondary output exists + +groovyscript.wiki.horsepower.press.title=Horse Press +groovyscript.wiki.horsepower.press.description=Converts an itemstack into another itemstack or a fluidstack by a horse running laps +groovyscript.wiki.horsepower.press.add=Adds recipes in the format `input`, `output` + + # Immersive Engineering groovyscript.wiki.immersiveengineering.alloy_kiln.title=Alloy Kiln groovyscript.wiki.immersiveengineering.alloy_kiln.description=Converts two input itemstacks into an output itemstack, consuming fuel (based on burn time).