diff --git a/dependencies.gradle b/dependencies.gradle index f2e6b1f5a..90b1a93aa 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -67,6 +67,7 @@ final def mod_dependencies = [ 'brandons_core-231382:3408276' : [project.debug_draconic_evolution], 'draconic_evolution-223565:3431261' : [project.debug_draconic_evolution], 'redstone_flux-270789:2920436' : [project.debug_draconic_evolution, project.debug_thermal], + 'the-erebus-220698:3211974' : [project.debug_erebus], 'essentialcraft-4-unofficial-254817:5416404' : [project.debug_essentialcraft_4], 'dummycore-unofficial-266491:2611426' : [project.debug_essentialcraft_4], 'cyclops-core-232758:3159497' : [project.debug_evilcraft, project.debug_integrated_dynamics], @@ -131,7 +132,9 @@ final Map> runtime_dependencies = [ '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-magiculture-940521:5796192': [project.debug_erebus], 'curse.maven:just-enough-petroleum-291727:2549332' : [project.debug_immersive_petroleum], + 'curse.maven:just-enough-resources-240630:4440935' : [project.debug_erebus], '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], diff --git a/examples/postInit/erebus.groovy b/examples/postInit/erebus.groovy new file mode 100644 index 000000000..c34ca4bc3 --- /dev/null +++ b/examples/postInit/erebus.groovy @@ -0,0 +1,75 @@ + +// Auto generated groovyscript example file +// MODS_LOADED: erebus + +log.info 'mod \'erebus\' detected, running script' + +// Organic Composter: +// Converts valid items into compost. The Blacklist blocks all ItemStacks on it from being used, the Material list allows +// any Blocks using the valid Materials to be converted, and the Registry contains any valid ItemStacks. The conversion +// takes 10 seconds, and is fueled by erebus wall plants. + +// mods.erebus.composter.removeFromBlacklist(item('erebus:wall_plants', 1)) +mods.erebus.composter.removeFromMaterial(material('sponge')) +mods.erebus.composter.removeFromRegistry(item('minecraft:stick')) +// mods.erebus.composter.removeAllFromBlacklist() +// mods.erebus.composter.removeAllFromMaterial() +// mods.erebus.composter.removeAllFromRegistry() + +mods.erebus.composter.addBlacklist(item('erebus:wall_plants', 7)) +mods.erebus.composter.addBlacklist(item('erebus:wall_plants_cultivated', 7)) +mods.erebus.composter.addMaterial(material('tnt')) +mods.erebus.composter.addRegistry(item('minecraft:gold_ingot')) + +// Offering Altar: +// Converts up to 3 input itemstacks into an output itemstack. + +// mods.erebus.offering_altar.removeByInput(item('minecraft:emerald')) +mods.erebus.offering_altar.removeByOutput(item('erebus:materials', 38)) +// mods.erebus.offering_altar.removeAll() + +mods.erebus.offering_altar.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay')) + .register() + +mods.erebus.offering_altar.recipeBuilder() + .input(item('minecraft:stone'), ore('gemDiamond'), item('minecraft:clay')) + .output(item('minecraft:gold_ingot')) + .register() + + +// Smoothie-matic: +// Converts a container item, up to 4 input items, and up to 4 input fluidstacks into an output itemstack. + +mods.erebus.smoothie.removeByContainer(item('minecraft:bucket')) +mods.erebus.smoothie.removeByInput(fluid('honey')) +mods.erebus.smoothie.removeByInput(item('erebus:materials', 18)) +mods.erebus.smoothie.removeByOutput(item('erebus:materials', 21)) +// mods.erebus.smoothie.removeAll() + +mods.erebus.smoothie.recipeBuilder() + .container(item('minecraft:diamond')) + .output(item('minecraft:gold_ingot')) + .register() + +mods.erebus.smoothie.recipeBuilder() + .container(item('minecraft:clay')) + .input(item('minecraft:clay')) + .output(item('minecraft:gold_ingot')) + .register() + +mods.erebus.smoothie.recipeBuilder() + .container(item('minecraft:gold_block')) + .fluidInput(fluid('water') * 5000) + .output(item('minecraft:gold_ingot')) + .register() + +mods.erebus.smoothie.recipeBuilder() + .container(item('minecraft:stone')) + .input(item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot')) + .fluidInput(fluid('lava') * 500, fluid('formic_acid') * 500, fluid('honey') * 500, fluid('milk') * 500) + .output(item('minecraft:clay') * 5) + .register() + + diff --git a/gradle.properties b/gradle.properties index e966eab10..6eaf7741b 100644 --- a/gradle.properties +++ b/gradle.properties @@ -52,6 +52,7 @@ debug_cyclic = false debug_draconic_evolution = false debug_enderio = false +debug_erebus = false debug_essentialcraft_4 = false debug_evilcraft = false debug_extended_crafting = false diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java index e32c4df48..8c0361ddf 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java @@ -29,6 +29,7 @@ import com.cleanroommc.groovyscript.compat.mods.cyclic.Cyclic; import com.cleanroommc.groovyscript.compat.mods.draconicevolution.DraconicEvolution; import com.cleanroommc.groovyscript.compat.mods.enderio.EnderIO; +import com.cleanroommc.groovyscript.compat.mods.erebus.Erebus; import com.cleanroommc.groovyscript.compat.mods.essentialcraft.EssentialCraft; import com.cleanroommc.groovyscript.compat.mods.evilcraft.EvilCraft; import com.cleanroommc.groovyscript.compat.mods.extendedcrafting.ExtendedCrafting; @@ -118,6 +119,7 @@ public class ModSupport { public static final GroovyContainer CYCLIC = new InternalModContainer<>("cyclicmagic", "Cyclic", Cyclic::new, "cyclic"); public static final GroovyContainer DRACONIC_EVOLUTION = new InternalModContainer<>("draconicevolution", "Draconic Evolution", DraconicEvolution::new, "de"); public static final GroovyContainer ENDER_IO = new InternalModContainer<>("enderio", "Ender IO", EnderIO::new, "eio"); + public static final GroovyContainer EREBUS = new InternalModContainer<>("erebus", "The Erebus", Erebus::new); public static final GroovyContainer ESSENTIALCRAFT = new InternalModContainer<>("essentialcraft", "EssentialCraft 4", EssentialCraft::new, "ec4"); public static final GroovyContainer EVILCRAFT = new InternalModContainer<>("evilcraft", "EvilCraft", EvilCraft::new); public static final GroovyContainer EXTENDED_CRAFTING = new InternalModContainer<>("extendedcrafting", "Extended Crafting", ExtendedCrafting::new); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/Composter.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/Composter.java new file mode 100644 index 000000000..491653670 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/Composter.java @@ -0,0 +1,107 @@ +package com.cleanroommc.groovyscript.compat.mods.erebus; + +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.api.IScriptReloadable; +import com.cleanroommc.groovyscript.api.documentation.annotations.Admonition; +import com.cleanroommc.groovyscript.api.documentation.annotations.Example; +import com.cleanroommc.groovyscript.api.documentation.annotations.MethodDescription; +import com.cleanroommc.groovyscript.api.documentation.annotations.RegistryDescription; +import com.cleanroommc.groovyscript.core.mixin.erebus.ComposterRegistryAccessor; +import com.cleanroommc.groovyscript.registry.AbstractReloadableStorage; +import com.cleanroommc.groovyscript.registry.NamedRegistry; +import net.minecraft.block.material.Material; +import net.minecraft.item.ItemStack; + +import java.util.List; + +@RegistryDescription(category = RegistryDescription.Category.ENTRIES, admonition = { + @Admonition(value = "groovyscript.wiki.erebus.composter.note0", type = Admonition.Type.BUG), @Admonition("groovyscript.wiki.erebus.composter.note1") +}) +public class Composter extends NamedRegistry implements IScriptReloadable { + + private final AbstractReloadableStorage materialStorage = new AbstractReloadableStorage<>(); + private final AbstractReloadableStorage registryStorage = new AbstractReloadableStorage<>(); + private final AbstractReloadableStorage blacklistStorage = new AbstractReloadableStorage<>(); + + private static List getMaterial() { + return ComposterRegistryAccessor.getMaterial(); + } + + private static List getRegistry() { + return ComposterRegistryAccessor.getRegistry(); + } + + private static List getBlacklist() { + return ComposterRegistryAccessor.getBlacklist(); + } + + @Override + public void onReload() { + var material = getMaterial(); + var registry = getRegistry(); + var blacklist = getBlacklist(); + material.removeAll(materialStorage.removeScripted()); + material.addAll(materialStorage.restoreFromBackup()); + registry.removeAll(registryStorage.removeScripted()); + registry.addAll(registryStorage.restoreFromBackup()); + blacklist.removeAll(blacklistStorage.removeScripted()); + blacklist.addAll(blacklistStorage.restoreFromBackup()); + } + + @Override + public void afterScriptLoad() {} + + @MethodDescription(type = MethodDescription.Type.ADDITION, example = @Example("material('tnt')")) + public boolean addMaterial(Material material) { + return getMaterial().add(material) && materialStorage.addScripted(material); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION, example = @Example("item('minecraft:gold_ingot')")) + public boolean addRegistry(ItemStack stack) { + return getRegistry().add(stack) && registryStorage.addScripted(stack); + } + + @MethodDescription(type = MethodDescription.Type.ADDITION, example = { + @Example("item('erebus:wall_plants', 7)"), + @Example("item('erebus:wall_plants_cultivated', 7)") + }) + public boolean addBlacklist(ItemStack stack) { + return getBlacklist().add(stack) && blacklistStorage.addScripted(stack); + } + + @MethodDescription(example = @Example("material('sponge')")) + public boolean removeFromMaterial(Material material) { + return getMaterial().removeIf(r -> material == r && materialStorage.addBackup(r)); + } + + @MethodDescription(example = @Example("item('minecraft:stick')")) + public boolean removeFromRegistry(IIngredient ingredient) { + return getRegistry().removeIf(r -> ingredient.test(r) && registryStorage.addBackup(r)); + } + + @MethodDescription(example = @Example(value = "item('erebus:wall_plants', 1)", commented = true)) + public boolean removeFromBlacklist(IIngredient ingredient) { + return getBlacklist().removeIf(r -> ingredient.test(r) && blacklistStorage.addBackup(r)); + } + + @MethodDescription(priority = 2000, example = @Example(commented = true)) + public void removeAllFromMaterial() { + var entries = getMaterial(); + entries.forEach(materialStorage::addBackup); + entries.clear(); + } + + @MethodDescription(priority = 2000, example = @Example(commented = true)) + public void removeAllFromRegistry() { + var entries = getRegistry(); + entries.forEach(registryStorage::addBackup); + entries.clear(); + } + + @MethodDescription(priority = 2000, example = @Example(commented = true)) + public void removeAllFromBlacklist() { + var entries = getBlacklist(); + entries.forEach(blacklistStorage::addBackup); + entries.clear(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/Erebus.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/Erebus.java new file mode 100644 index 000000000..916bbb3b4 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/Erebus.java @@ -0,0 +1,10 @@ +package com.cleanroommc.groovyscript.compat.mods.erebus; + +import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; + +public class Erebus extends GroovyPropertyContainer { + + public final Composter composter = new Composter(); + public final Smoothie smoothie = new Smoothie(); + public final OfferingAltar offeringAltar = new OfferingAltar(); +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/OfferingAltar.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/OfferingAltar.java new file mode 100644 index 000000000..6c658d5ed --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/OfferingAltar.java @@ -0,0 +1,91 @@ +package com.cleanroommc.groovyscript.compat.mods.erebus; + +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.erebus.OfferingAltarRecipeAccessor; +import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import erebus.recipes.OfferingAltarRecipe; +import net.minecraft.item.ItemStack; +import net.minecraftforge.oredict.OreDictionary; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; + +@RegistryDescription +public class OfferingAltar extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".input(item('minecraft:gold_ingot')).output(item('minecraft:clay'))"), + @Example(".input(item('minecraft:stone'), ore('gemDiamond'), item('minecraft:clay')).output(item('minecraft:gold_ingot'))") + }) + public OfferingAltar.RecipeBuilder recipeBuilder() { + return new OfferingAltar.RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return OfferingAltarRecipeAccessor.getRecipes(); + } + + @MethodDescription(example = @Example(value = "item('minecraft:emerald')", commented = true)) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (Object object : r.getInputs()) { + if (object instanceof ItemStack stack && input.test(stack)) return doAddBackup(r); + else if (object instanceof String s) { + if (input instanceof IOreDicts d && d.getOreDicts().contains(s)) { + return true; + } else if (OreDictionary.getOres(s, false).stream().anyMatch(input)) { + return true; + } + } + } + return false; + }); + } + + @MethodDescription(example = @Example("item('erebus:materials', 38)")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> output.test(r.getOutput()) && doAddBackup(r)); + } + + @Property(property = "input", comp = @Comp(gte = 1, lte = 3)) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public String getErrorMsg() { + return "Error adding Erebus Offering Altar Recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 3, 1, 1); + validateFluids(msg); + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable OfferingAltarRecipe register() { + if (!validate()) return null; + OfferingAltarRecipe recipe = null; + var inputs = IngredientHelper.cartesianProductOres(input); + for (List objects : inputs) { + recipe = OfferingAltarRecipeAccessor.createOfferingAltarRecipe(output.get(0), objects.toArray()); + ModSupport.EREBUS.get().offeringAltar.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/Smoothie.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/Smoothie.java new file mode 100644 index 000000000..8ddaf3990 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/erebus/Smoothie.java @@ -0,0 +1,131 @@ +package com.cleanroommc.groovyscript.compat.mods.erebus; + +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.erebus.SmoothieMakerRecipeAccessor; +import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.StandardListRegistry; +import erebus.recipes.SmoothieMakerRecipe; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.Fluid; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.oredict.OreDictionary; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +@RegistryDescription +public class Smoothie extends StandardListRegistry { + + @RecipeBuilderDescription(example = { + @Example(".container(item('minecraft:diamond')).output(item('minecraft:gold_ingot'))"), + @Example(".container(item('minecraft:clay')).input(item('minecraft:clay')).output(item('minecraft:gold_ingot'))"), + @Example(".container(item('minecraft:gold_block')).fluidInput(fluid('water') * 5000).output(item('minecraft:gold_ingot'))"), + @Example(".container(item('minecraft:stone')).input(item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot')).fluidInput(fluid('lava') * 500, fluid('formic_acid') * 500, fluid('honey') * 500, fluid('milk') * 500).output(item('minecraft:clay') * 5)") + }) + public Smoothie.RecipeBuilder recipeBuilder() { + return new Smoothie.RecipeBuilder(); + } + + @Override + public Collection getRecipes() { + return SmoothieMakerRecipeAccessor.getRecipes(); + } + + @MethodDescription(example = { + @Example("item('erebus:materials', 18)"), @Example("fluid('honey')") + }) + public boolean removeByInput(IIngredient input) { + return getRecipes().removeIf(r -> { + for (FluidStack fluid : r.getFluids()) { + if (input.test(fluid)) return doAddBackup(r); + } + for (Object object : r.getInputs()) { + if (object instanceof ItemStack stack && input.test(stack)) return doAddBackup(r); + else if (object instanceof String s) { + if (input instanceof IOreDicts d && d.getOreDicts().contains(s)) { + return true; + } else if (OreDictionary.getOres(s, false).stream().anyMatch(input)) { + return true; + } + } + } + return false; + }); + } + + @MethodDescription(example = @Example("item('minecraft:bucket')")) + public boolean removeByContainer(IIngredient container) { + return getRecipes().removeIf(r -> container.test(r.getContainer()) && doAddBackup(r)); + } + + @MethodDescription(example = @Example("item('erebus:materials', 21)")) + public boolean removeByOutput(IIngredient output) { + return getRecipes().removeIf(r -> output.test(r.getOutput()) && doAddBackup(r)); + } + + @Property(property = "input", comp = @Comp(gte = 0, lte = 4)) + @Property(property = "fluidInput", comp = @Comp(gte = 0, lte = 4, unique = "groovyscript.wiki.erebus.smoothie.fluidInput.required")) + @Property(property = "output", comp = @Comp(eq = 1)) + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private static final int MAX_FLUID_CAPACITY = 16_000; + @Property(comp = @Comp(not = "null")) + private ItemStack container; + + @RecipeBuilderMethodDescription + public RecipeBuilder container(ItemStack container) { + this.container = container; + return this; + } + + @Override + protected int getMaxItemInput() { + return 1; + } + + @Override + public String getErrorMsg() { + return "Error adding Erebus Smoothie Recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 0, 4, 1, 1); + validateFluids(msg, 0, 4, 0, 0); + msg.add(IngredientHelper.isEmpty(container), "container must not be empty"); + validateStackSize(msg, getMaxItemInput(), "container", IngredientHelper.toIIngredient(container)); + validateStackSize(msg, getMaxItemInput(), "output", IngredientHelper.toIIngredient(output.getOrEmpty(0))); + validateStackSize(msg, MAX_FLUID_CAPACITY, "fluidInput", fluidInput.asIIngredientList()); + + // ensure no duplicate fluids + Set set = new ObjectOpenHashSet<>(); + for (var fluidStack : fluidInput) { + if (!set.add(fluidStack.getFluid())) { + msg.add("duplicate fluids cannot be handled correctly, and duplicate fluid {} was detected", fluidStack.getFluid()); + break; + } + } + } + + @Override + @RecipeBuilderRegistrationMethod + public @Nullable SmoothieMakerRecipe register() { + if (!validate()) return null; + SmoothieMakerRecipe recipe = null; + var inputs = IngredientHelper.cartesianProductOres(input); + for (List objects : inputs) { + recipe = SmoothieMakerRecipeAccessor.createSmoothieMakerRecipe(output.get(0), container, fluidInput.toArray(new FluidStack[0]), objects.toArray()); + ModSupport.EREBUS.get().smoothie.add(recipe); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java b/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java index 26c630fc2..194362903 100644 --- a/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java +++ b/src/main/java/com/cleanroommc/groovyscript/core/LateMixin.java @@ -18,6 +18,7 @@ public class LateMixin implements ILateMixinLoader { "betterwithmods", "thebetweenlands", "bloodmagic", + "erebus", "botania", "calculator", "draconicevolution", diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/ComposterRegistryAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/ComposterRegistryAccessor.java new file mode 100644 index 000000000..b8e350ba6 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/ComposterRegistryAccessor.java @@ -0,0 +1,28 @@ +package com.cleanroommc.groovyscript.core.mixin.erebus; + +import erebus.recipes.ComposterRegistry; +import net.minecraft.block.material.Material; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(value = ComposterRegistry.class, remap = false) +public interface ComposterRegistryAccessor { + + @Accessor("compostableMaterials") + static List getMaterial() { + throw new UnsupportedOperationException(); + } + + @Accessor("registry") + static List getRegistry() { + throw new UnsupportedOperationException(); + } + + @Accessor("blacklist") + static List getBlacklist() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/ComposterRegistryMixin.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/ComposterRegistryMixin.java new file mode 100644 index 000000000..0dcbfbbef --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/ComposterRegistryMixin.java @@ -0,0 +1,23 @@ +package com.cleanroommc.groovyscript.core.mixin.erebus; + +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import erebus.recipes.ComposterRegistry; +import net.minecraft.block.material.Material; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; + +import java.util.ArrayList; +import java.util.List; + +@Mixin(value = ComposterRegistry.class, remap = false) +public abstract class ComposterRegistryMixin { + + /** + * @reason ensure the list of valid materials is mutable for GroovyScript compat + * @author WaitingIdly + */ + @ModifyExpressionValue(method = "", at = @At(value = "INVOKE", target = "Ljava/util/Arrays;asList([Ljava/lang/Object;)Ljava/util/List;")) + private static List mutableMaterial(List original) { + return new ArrayList<>(original); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/OfferingAltarRecipeAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/OfferingAltarRecipeAccessor.java new file mode 100644 index 000000000..22ee91d43 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/OfferingAltarRecipeAccessor.java @@ -0,0 +1,23 @@ +package com.cleanroommc.groovyscript.core.mixin.erebus; + +import erebus.recipes.OfferingAltarRecipe; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +@Mixin(value = OfferingAltarRecipe.class, remap = false) +public interface OfferingAltarRecipeAccessor { + + @Invoker("") + static OfferingAltarRecipe createOfferingAltarRecipe(ItemStack output, Object... inputs) { + throw new UnsupportedOperationException(); + } + + @Accessor("list") + static List getRecipes() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/SmoothieMakerRecipeAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/SmoothieMakerRecipeAccessor.java new file mode 100644 index 000000000..1b47aacfe --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/erebus/SmoothieMakerRecipeAccessor.java @@ -0,0 +1,24 @@ +package com.cleanroommc.groovyscript.core.mixin.erebus; + +import erebus.recipes.SmoothieMakerRecipe; +import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +@Mixin(value = SmoothieMakerRecipe.class, remap = false) +public interface SmoothieMakerRecipeAccessor { + + @Invoker("") + static SmoothieMakerRecipe createSmoothieMakerRecipe(ItemStack output, ItemStack container, FluidStack[] fluids, Object... input) { + throw new UnsupportedOperationException(); + } + + @Accessor("recipes") + static List getRecipes() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/FluidStackList.java b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/FluidStackList.java index 47a9d34f6..9258e7ee5 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/FluidStackList.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/FluidStackList.java @@ -1,9 +1,11 @@ package com.cleanroommc.groovyscript.helper.ingredient; +import com.cleanroommc.groovyscript.api.IIngredient; import net.minecraftforge.fluids.FluidStack; import java.util.ArrayList; import java.util.Collection; +import java.util.List; public class FluidStackList extends ArrayList { @@ -43,4 +45,9 @@ public void copyElements() { } } } + + @SuppressWarnings("unchecked") + public List asIIngredientList() { + return (List) (Object) this; + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java index 1d69f5aec..9d013915c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java +++ b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java @@ -13,6 +13,7 @@ import groovy.lang.ExpandoMetaClass; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.block.Block; +import net.minecraft.block.material.Material; import net.minecraft.creativetab.CreativeTabs; import net.minecraft.enchantment.Enchantment; import net.minecraft.init.Blocks; @@ -38,13 +39,14 @@ public class ObjectMapperManager { - private static final Map> handlers = new Object2ObjectOpenHashMap<>(); - private static final Map>> handlerConflicts = new Object2ObjectOpenHashMap<>(); - private static final Map, Map>> modHandlers = new Object2ObjectOpenHashMap<>(); public static final String EMPTY = "empty"; public static final String WILDCARD = "*"; public static final String SPLITTER = ":"; + private static final Map> handlers = new Object2ObjectOpenHashMap<>(); + private static final Map>> handlerConflicts = new Object2ObjectOpenHashMap<>(); + private static final Map, Map>> modHandlers = new Object2ObjectOpenHashMap<>(); + public static void registerObjectMapper(AbstractObjectMapper mapper) { String key = mapper.getName(); if (mapper.getMod() != null) { @@ -73,6 +75,7 @@ public static void registerObjectMapper(AbstractObjectMapper mapper) { } public static void init() { + ObjectParserHelper.init(); registerObjectMapper(ItemStackMapper.INSTANCE); registerObjectMapper(BlockStateMapper.INSTANCE); ObjectMapper.builder("resource", ResourceLocation.class) @@ -116,6 +119,11 @@ public static void init() { .docOfType("block") .textureBinder(TextureBinder.of(ItemStack::new, TextureBinder.ofItem())) .register(); + ObjectMapper.builder("blockmaterial", Material.class) + .parser(IObjectParser.wrapStringGetter(ObjectParserHelper.materials::get)) + .completerOfNames(ObjectParserHelper.materials::keySet) + .docOfType("block material") + .register(); /*ObjectMapper.builder("blockstate", IBlockState.class) .parser(ObjectMappers::parseBlockState) .addSignature(String.class) @@ -166,20 +174,24 @@ public static void init() { .completer(ForgeRegistries.VILLAGER_PROFESSIONS) .docOfType("villager profession") .register(); - - final List careerList = new ArrayList<>(); - for (var profession : ForgeRegistries.VILLAGER_PROFESSIONS) { - if (profession != null) { - for (var career : ((VillagerProfessionAccessor) profession).getCareers()) { - if (career != null) { - careerList.add(career.getName()); - } - } - } - } ObjectMapper.builder("career", VillagerRegistry.VillagerCareer.class) - .parser(ObjectMappers::parseVillagerCareer) - .completerOfNames(() -> careerList) + .parser(IObjectParser.wrapStringGetter(x -> { + for (var profession : ForgeRegistries.VILLAGER_PROFESSIONS) { + for (var career : ((VillagerProfessionAccessor) profession).getCareers()) { + if (x.equals(career.getName())) return career; + } + } + return null; + })) + .completerOfNames(() -> { + List careers = new ArrayList<>(); + for (var profession : ForgeRegistries.VILLAGER_PROFESSIONS) { + for (var career : ((VillagerProfessionAccessor) profession).getCareers()) { + careers.add(career.getName()); + } + } + return careers; + }) .docOfType("villager career") .register(); ObjectMapper.builder("creativeTab", CreativeTabs.class) @@ -219,7 +231,7 @@ public static void init() { * @param name game object handler name (method name) * @param mainArg main argument * @param args extra arguments - * @param silent if error messages should be logged + * @param silent if error messages should be logged * @return game object or null */ diff --git a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMappers.java b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMappers.java index c64205624..82638d00e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMappers.java +++ b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMappers.java @@ -5,13 +5,10 @@ import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.api.Result; import com.cleanroommc.groovyscript.core.mixin.CreativeTabsAccessor; -import com.cleanroommc.groovyscript.core.mixin.VillagerProfessionAccessor; import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.google.common.base.Optional; import com.google.common.collect.Iterators; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.block.Block; -import net.minecraft.block.material.Material; import net.minecraft.block.properties.IProperty; import net.minecraft.block.state.IBlockState; import net.minecraft.creativetab.CreativeTabs; @@ -26,15 +23,10 @@ import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fml.common.registry.ForgeRegistries; -import net.minecraftforge.fml.common.registry.VillagerRegistry; import org.jetbrains.annotations.NotNull; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.Iterator; -import java.util.Locale; -import java.util.Map; import static com.cleanroommc.groovyscript.mapper.ObjectMapperManager.SPLITTER; import static com.cleanroommc.groovyscript.mapper.ObjectMapperManager.WILDCARD; @@ -189,19 +181,6 @@ private static Result parseBlockStates(IBlockState defaultState, It return Result.some(defaultState); } - public static Result parseVillagerCareer(String mainArg, Object... args) { - for (var profession : ForgeRegistries.VILLAGER_PROFESSIONS) { - if (profession != null) { - for (var career : ((VillagerProfessionAccessor) (profession)).getCareers()) { - if (career != null && mainArg.equals(career.getName())) { - return Result.some(career); - } - } - } - } - return Result.error(); - } - public static Result parseCreativeTab(String mainArg, Object... args) { for (CreativeTabs tab : CreativeTabs.CREATIVE_TAB_ARRAY) { if (tab != null && mainArg.equals(((CreativeTabsAccessor) tab).getTabLabel2())) { @@ -223,27 +202,6 @@ public static Result parseTextFormatting(String mainArg, Object. return textformat == null ? Result.error() : Result.some(textformat); } - private static Map materials; - - public static Result parseBlockMaterial(String mainArg, Object... args) { - if (materials == null) { - materials = new Object2ObjectOpenHashMap<>(); - for (Field field : Material.class.getFields()) { - if ((field.getModifiers() & Modifier.STATIC) != 0 && field.getType() == Material.class) { - try { - Material material = (Material) field.get(null); - materials.put(field.getName(), material); - materials.put(field.getName().toLowerCase(Locale.ROOT), material); - } catch (IllegalAccessException e) { - throw new RuntimeException(e); - } - } - } - } - Material material = materials.get(mainArg); - return material == null ? Result.error() : Result.some(material); - } - public static @NotNull Result parseNBT(String mainArg, Object... args) { try { return Result.some(JsonToNBT.getTagFromJson(mainArg)); diff --git a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectParserHelper.java b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectParserHelper.java new file mode 100644 index 000000000..28c8dc58f --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectParserHelper.java @@ -0,0 +1,33 @@ +package com.cleanroommc.groovyscript.mapper; + +import com.google.common.collect.ImmutableMap; +import net.minecraft.block.material.Material; + +import java.lang.reflect.Modifier; +import java.util.Locale; +import java.util.Map; + +public class ObjectParserHelper { + + public static Map materials; + + public static void init() { + materials = getMaterials(); + } + + private static ImmutableMap getMaterials() { + ImmutableMap.Builder materialBuilder = new ImmutableMap.Builder<>(); + for (var field : Material.class.getFields()) { + if (Modifier.isStatic(field.getModifiers()) && field.getType() == Material.class) { + try { + var material = (Material) field.get(null); + materialBuilder.put(field.getName(), material); + materialBuilder.put(field.getName().toLowerCase(Locale.ROOT), material); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + } + return materialBuilder.build(); + } +} diff --git a/src/main/resources/assets/groovyscript/lang/en_us.lang b/src/main/resources/assets/groovyscript/lang/en_us.lang index 2686c4778..023ee0820 100644 --- a/src/main/resources/assets/groovyscript/lang/en_us.lang +++ b/src/main/resources/assets/groovyscript/lang/en_us.lang @@ -1207,6 +1207,32 @@ groovyscript.wiki.enderio.vat.multipliers2.value=Sets the multiplier applied to groovyscript.wiki.enderio.vat.baseMultiplier.value=Sets the base amount of fluid output groovyscript.wiki.enderio.vat.energy.value=Sets the energy cost of the recipe + +# Erebus +groovyscript.wiki.erebus.composter.title=Organic Composter +groovyscript.wiki.erebus.composter.description=Converts valid items into compost. The Blacklist blocks all ItemStacks on it from being used, the Material list allows any Blocks using the valid Materials to be converted, and the Registry contains any valid ItemStacks. The conversion takes 10 seconds, and is fueled by erebus wall plants. +groovyscript.wiki.erebus.composter.note0=The Blacklist is supposed to have 2 entries by default - `erebus:wall_plants@1` and `erebus:wall_plants_cultivated@1` - however it is initialized prior to blocks or items being registered, and so contains two empty itemstacks instead. Furthermore, it is likely that using the metadata **1** is also a bug, as only metadata **7** is used as fuel. +groovyscript.wiki.erebus.composter.note1=Items extending `ItemFood` and `ItemSeed` will always be valid items unless added to the blacklist. +groovyscript.wiki.erebus.composter.addBlacklist=Add the given ItemStack to the Composter Blacklist +groovyscript.wiki.erebus.composter.addMaterial=Add the given Material to the Composter Material list +groovyscript.wiki.erebus.composter.addRegistry=Add the given ItemStack to the Composter Registry +groovyscript.wiki.erebus.composter.removeAllFromBlacklist=Removes all entries from the Blacklist +groovyscript.wiki.erebus.composter.removeAllFromMaterial=Removes all entries from the Material list +groovyscript.wiki.erebus.composter.removeAllFromRegistry=Removes all entries from the Registry +groovyscript.wiki.erebus.composter.removeFromBlacklist=Removes all matching ItemStacks from the Blacklist +groovyscript.wiki.erebus.composter.removeFromMaterial=Removes the provided Material from the Material list +groovyscript.wiki.erebus.composter.removeFromRegistry=Removes all matching ItemStacks from the Registry + +groovyscript.wiki.erebus.offering_altar.title=Offering Altar +groovyscript.wiki.erebus.offering_altar.description=Converts up to 3 input itemstacks into an output itemstack. + +groovyscript.wiki.erebus.smoothie.title=Smoothie-matic +groovyscript.wiki.erebus.smoothie.description=Converts a container item, up to 4 input items, and up to 4 input fluidstacks into an output itemstack. +groovyscript.wiki.erebus.smoothie.fluidInput.required=no fluid inputs can have a duplicate fluid type +groovyscript.wiki.erebus.smoothie.container.value=Sets the container itemstack required +groovyscript.wiki.erebus.smoothie.removeByContainer=Removes all recipes matching the provided container + + # EssentialCraft groovyscript.wiki.essentialcraft.demon_trade.title=Demon Trade groovyscript.wiki.essentialcraft.demon_trade.description=Adds an item that can be sold to Demons to obtain Ackronite. Note that each demon that spawns has a random item that it can accept, and will not accept any other item. diff --git a/src/main/resources/mixin.groovyscript.erebus.json b/src/main/resources/mixin.groovyscript.erebus.json new file mode 100644 index 000000000..cedf6f245 --- /dev/null +++ b/src/main/resources/mixin.groovyscript.erebus.json @@ -0,0 +1,13 @@ +{ + "package": "com.cleanroommc.groovyscript.core.mixin.erebus", + "refmap": "mixins.groovyscript.refmap.json", + "target": "@env(DEFAULT)", + "minVersion": "0.8", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "ComposterRegistryAccessor", + "ComposterRegistryMixin", + "OfferingAltarRecipeAccessor", + "SmoothieMakerRecipeAccessor" + ] +} \ No newline at end of file