From 7740c371c8f3eb755b24fd6162be6455bb6db70d Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Tue, 4 Jul 2023 04:47:12 -0700 Subject: [PATCH 01/28] botania examples and fixes --- examples/botania.groovy | 250 +++++++++++++----- .../compat/mods/botania/Apothecary.java | 6 +- .../compat/mods/botania/Botania.java | 2 + .../compat/mods/botania/Brew.java | 158 ++++------- .../compat/mods/botania/BrewRecipe.java | 124 +++++++++ .../compat/mods/botania/Lexicon.java | 93 ++++++- .../compat/mods/botania/ManaInfusion.java | 15 ++ .../compat/mods/botania/PureDaisy.java | 15 +- .../compat/mods/botania/RuneAltar.java | 6 +- 9 files changed, 490 insertions(+), 179 deletions(-) create mode 100644 src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/BrewRecipe.java diff --git a/examples/botania.groovy b/examples/botania.groovy index 39c7c367a..bd1d459ed 100644 --- a/examples/botania.groovy +++ b/examples/botania.groovy @@ -1,64 +1,190 @@ -import net.minecraft.util.ResourceLocation +import net.minecraft.potion.PotionEffect import net.minecraft.util.text.TextFormatting -def newType = mods.botania.Knowledge.add('newType', TextFormatting.RED, true) - -mods.botania.ElvenTrade.removeByInputs(ore('ingotManasteel')) -mods.botania.ElvenTrade.recipeBuilder() - .input(ore('ingotGold'), ore('ingotIron')) - .output(item('botania:manaresource', 7)) - .register() - -mods.botania.ManaInfusion.recipeBuilder() - .input(ore('ingotGold')) - .output(item('botania:manaresource', 1)) - .mana(500) - .catalyst(blockstate('minecraft:stone')) - .register() -mods.botania.ManaInfusion.removeByInput(item('minecraft:ender_pearl')) - -mods.botania.PureDaisy.add(blockstate('minecraft:iron_block'), blockstate('minecraft:gold_block'), 20) -mods.botania.PureDaisy.removeByInput(blockstate('minecraft:water')) -mods.botania.PureDaisy.removeByInput(ore('logWood')) - -mods.botania.Apothecary.removeByInput(ore('petalYellow'), ore('petalBrown')) -mods.botania.Apothecary.recipeBuilder() - .output(item('minecraft:golden_apple')) - .input(ore('blockGold')) - .input(ore('ingotIron')) - .input(item('minecraft:apple')) - .register() - -mods.botania.Orechid.removeByOutput(ore('oreEmerald')) -mods.botania.Orechid.add(ore('oreEmerald'), 1350) -mods.botania.OrechidIgnem.add(ore('blockGold'), 1800) - -mods.botania.Magnet.addToBlacklist(item('minecraft:diamond')) - -def myRecipe = mods.botania.Brew.recipeBuilder() - .input(ore('ingotIron')) - .input(ore('ingotGold')) - .input(ore('gemDiamond')) - .output(brew('absorption')) - .register() -mods.botania.Brew.removeByInput(item('minecraft:iron_ingot')) - -mods.botania.RuneAltar.removeByInput(ore('runeEarthB')) -mods.botania.RuneAltar.recipeBuilder() - .output(item('minecraft:diamond')) - .mana(500) - .input(ore('gemEmerald')) - .input(item('minecraft:apple')) - .register() - -mods.botania.Lexicon.Category.add('test', new ResourceLocation('minecraft', 'textures/items/apple.png')) -def myPage = mods.botania.Lexicon.Page.createTextPage('botania.testPage') -def rPage = mods.botania.Lexicon.Page.createBrewingPage('brewtest', 'bottomText', myRecipe) -mods.botania.Lexicon.Entry.entryBuilder() - .name('test_entry') - .icon(ore('blockIron')) - .category('test') - .page(myPage) - .page(rPage) - .knowledgeType(newType) - .register() \ No newline at end of file + +// Bracket Handlers +// Brew: +// Gets one of botania's unique brews. Default options: +brew('speed') +brew('strength') +brew('haste') +brew('healing') +brew('jumpBoost') +brew('regen') +brew('regenWeak') +brew('resistance') +brew('fireResistance') +brew('waterBreathing') +brew('invisibility') +brew('nightVision') +brew('absorption') + +brew('allure') +brew('soulCross') +brew('featherfeet') +brew('emptiness') +brew('bloodthirst') +brew('overload') +brew('clear') + +brew('warpWard') // Only if Thaumcraft is installed + + + +// Elven Trade: +// Convert in any number of item inputs into an item output. +def recipeElvenTrade = mods.botania.elventrade.recipeBuilder() + .input(ore('ingotGold'), ore('ingotIron')) + .output(item('botania:manaresource:7')) + .register() + +mods.botania.elventrade.removeByInputs(ore('ingotManasteel')) +mods.botania.elventrade.removeByOutputs(item('botania:dreamwood')) +//mods.botania.elventrade.removeAll() + +// Mana Infusion +// Toss an item into a mana pool with an optional catalyst blockstate below the pool. +def recipeInfusion = mods.botania.manainfusion.recipeBuilder() + .input(ore('ingotGold')) + .output(item('botania:manaresource', 1)) + .mana(500) + .catalyst(blockstate('minecraft:stone')) + .register() + +mods.botania.manainfusion.removeByInput(item('minecraft:ender_pearl')) +mods.botania.manainfusion.removeByCatalyst(blockstate('botania:alchemycatalyst')) +mods.botania.manainfusion.removeByOutput(item('botania:managlass')) +//mods.botania.manainfusion.removeAll() + +// Pure Daisy: +// Convert a given block to another blockstate after a period of time +mods.botania.puredaisy.recipeBuilder() + .input(ore('plankWood')) // input must be a Block, IBlockState, Oredict, or a String representing an oredict + .output(blockstate('minecraft:clay')) + .time(5) + .register() + +mods.botania.puredaisy.add(blockstate('minecraft:iron_block'), blockstate('minecraft:gold_block'), 20) + +mods.botania.puredaisy.removeByInput(blockstate('minecraft:water')) +mods.botania.puredaisy.removeByInput(ore('logWood')) +mods.botania.puredaisy.removeByOutput(blockstate('botania:livingrock')) +//mods.botania.puredaisy.removeAll() + + +// Petal Apothecary +// Converts item inputs into an item output consuming water and a seed. +def recipePetal = mods.botania.apothecary.recipeBuilder() + .input(ore('blockGold'), ore('ingotIron'), item('minecraft:apple')) + .output(item('minecraft:golden_apple')) + .register() + +mods.botania.apothecary.removeByInput(ore('runeFireB')) +mods.botania.apothecary.removeByInputs(ore('petalYellow'), ore('petalBrown')) +mods.botania.apothecary.removeByOutput(item('botania:specialflower').withNbt(["type": "puredaisy"])) +//mods.botania.apothecary.removeAll() + +// Orechid: +// Converts stone blocks into one of a few ore blocks at the cost of mana +mods.botania.orechid.add(ore('oreEmerald'), 1350) + +mods.botania.orechid.removeByOutput(ore('oreEmerald')) +mods.botania.orechid.removeByOutput('oreCoal') +//mods.botania.orechid.removeAll() + +// Orechid Ignem: +// Converts netherrack blocks into one of a few ore blocks at the cost of mana +mods.botania.orechidignem.add(ore('blockGold'), 1800) + +mods.botania.orechidignem.removeByOutput(ore('oreQuartz')) +//mods.botania.orechidignem.removeByOutput('oreQuartz') +//mods.botania.orechidignem.removeAll() + +// Magnet: +// Add or remove items from the magnet blacklist. +mods.botania.magnet.addToBlacklist(item('minecraft:diamond')) + +// Brew Effect: +// Creates a custom brew, but not a recipe for the brew. +mods.botania.brew.brewBuilder() + .key('groovy_example_brew') // Must be a unique key + .name('Groovy Brew') + .color(0x00FFFF) // Optional, default 0xFFFFFF + .cost(100) // Alias 'mana' + .effect(new PotionEffect(potion('strength'), 1800, 3), + new PotionEffect(potion('speed'), 1800, 2), + new PotionEffect(potion('weakness'), 3600, 1)) + .incense(true) // Optional, default true. Controls if the Incense Stick can be infused + .bloodPendant(true) // Optional, default true. Controls if the Tainted Blood Pendant can be infused + .register() + +// Brew Recipe: +// Converts a non-infused Managlass Vial, Alfglass Flask, Incense Stick, or Tainted Blood Pendant into one infused to hold the given brew at the cost of item inputs and mana. +def recipeBrewing = mods.botania.brewrecipe.recipeBuilder() + .input(item('minecraft:clay'), ore('ingotGold'), ore('gemDiamond')) + .brew(brew('absorption')) // Alias 'output' + .register() + +mods.botania.brewrecipe.removeByInput(item('minecraft:iron_ingot')) +mods.botania.brewrecipe.removeByOutput('speed') +mods.botania.brewrecipe.removeByOutput(brew('allure')) +//mods.botania.brewrecipe.removeAll() + +// Rune Altar: +// Converts a items inputs into an item ouput at the cost of mana when a Livingrock item is thrown atop the altar and right clicked with a Wand of the Forest +def recipeRune = mods.botania.runealtar.recipeBuilder() + .input(ore('gemEmerald'), item('minecraft:apple')) + .output(item('minecraft:diamond')) + .mana(500) + .register() + +mods.botania.runealtar.removeByInput(ore('runeEarthB')) +mods.botania.runealtar.removeByInputs(ore('feather'), ore('string')) +mods.botania.runealtar.removeByOutput(item('botania:rune:1')) +//mods.botania.runealtar.removeAll() + + +// Knowledge: +// Creates a new type of knowledge that Lexica Botania entries may be gated with. +// Can only be created, format id, color, autoUnlock +def newType = mods.botania.knowledge.add('newType', TextFormatting.RED, true) + +// Lexicon: +// Manipulate the Lexica Botania. + +// Category creates a new entry on the front page of the Lexica Botania. +mods.botania.lexicon.category.add('test', resource('minecraft:textures/items/apple.png')) +mods.botania.lexicon.category.add('first', resource('minecraft:textures/items/clay_ball.png'), 100) + +mods.botania.lexicon.category.remove('botania.category.alfhomancy') +mods.botania.lexicon.category.removeCategory('botania.category.misc') +//mods.botania.lexicon.category.removeAll() + +// Entry creates a new entry in a given category. +mods.botania.lexicon.entry.entryBuilder() + .name('test_entry') + .icon(ore('blockIron')) + .category('test') + .knowledgeType(newType) // Locks entry behind the given knowledge type. Also colors the entry name. + .page( + // Page creates a new page to be used in entries. + mods.botania.lexicon.page.createTextPage('groovy.exampleTextPage'), // looks for localization at "groovy.exampleTextPage" + mods.botania.lexicon.page.createLoreTextPage('groovy.exampleLoreTextPage'), + mods.botania.lexicon.page.createImagePage('groovy.exampleImagePage', 'minecraft:textures/items/apple.png'), + mods.botania.lexicon.page.createEntityPage('groovy.exampleEntityPage', 100, 'minecraft:wither_skeleton'), + mods.botania.lexicon.page.createEntityPage('groovy.exampleEntityPage', 5, entity('minecraft:wither_skeleton')), + mods.botania.lexicon.page.createCraftingPage('groovy.exampleCraftingPage', 'minecraft:clay'), + mods.botania.lexicon.page.createBrewingPage('groovy.exampleBrewingPage', 'bottomText', recipeBrewing), + mods.botania.lexicon.page.createInfusionPage('groovy.exampleInfusionPage', recipeInfusion), + mods.botania.lexicon.page.createRunePage('groovy.exampleRunePage', recipeRune), + mods.botania.lexicon.page.createPetalPage('groovy.examplePetalPage', recipePetal), + mods.botania.lexicon.page.createElvenTradePage('groovy.exampleElvenTradePage', recipeElvenTrade)) + .register() + +mods.botania.lexicon.entry.remove('botania.entry.flowers') +mods.botania.lexicon.entry.removeEntry('botania.entry.apothecary') +//mods.botania.lexicon.entry.removeAll() + +// cont. from Page +mods.botania.lexicon.page.removeByEntry('botania.entry.runeAltar') +//mods.botania.lexicon.page.removeAll() diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Apothecary.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Apothecary.java index d60440263..46443f986 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Apothecary.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Apothecary.java @@ -22,6 +22,10 @@ public RecipeBuilder recipeBuilder() { return new RecipeBuilder(); } + public Apothecary() { + super(VirtualizedRegistry.generateAliases("PetalApothecary")); + } + @Override @GroovyBlacklist public void onReload() { @@ -64,7 +68,7 @@ public boolean removeByOutput(IIngredient output) { public boolean removeByInput(IIngredient... inputs) { List converted = Arrays.stream(inputs).map(i -> i instanceof OreDictIngredient ? ((OreDictIngredient) i).getOreDict() : i.getMatchingStacks()[0]).collect(Collectors.toList()); if (BotaniaAPI.petalRecipes.removeIf(recipe -> { - boolean found = converted.stream().allMatch(o -> recipe.getInputs().stream().anyMatch(i -> o instanceof String ? o.equals(i) : ItemStack.areItemStacksEqual((ItemStack) i, (ItemStack) o))); + boolean found = converted.stream().allMatch(o -> recipe.getInputs().stream().anyMatch(i -> o instanceof String || i instanceof String ? o.equals(i) : ItemStack.areItemStacksEqual((ItemStack) i, (ItemStack) o))); if (found) addBackup(recipe); return found; })) return true; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Botania.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Botania.java index c591f526b..c390ee2e0 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Botania.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Botania.java @@ -16,6 +16,7 @@ public class Botania extends ModPropertyContainer { public final OrechidIgnem orechidIgnem = new OrechidIgnem(); public final RuneAltar runeAltar = new RuneAltar(); public final Brew brew = new Brew(); + public final BrewRecipe brewRecipe = new BrewRecipe(); public final Lexicon lexicon = new Lexicon(); public final Knowledge knowledge = new Knowledge(); public final Magnet magnet = new Magnet(); @@ -30,6 +31,7 @@ public Botania() { addRegistry(orechidIgnem); addRegistry(runeAltar); addRegistry(brew); + addRegistry(brewRecipe); addRegistry(lexicon.category); addRegistry(lexicon.entry); addRegistry(lexicon.page); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Brew.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Brew.java index 4d8384d5c..342b2d35c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Brew.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Brew.java @@ -2,129 +2,52 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; -import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; -import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; -import net.minecraft.item.ItemStack; import net.minecraft.potion.PotionEffect; import org.jetbrains.annotations.Nullable; import vazkii.botania.api.BotaniaAPI; -import vazkii.botania.api.recipe.RecipeBrew; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Collection; import java.util.List; -import java.util.stream.Collectors; -public class Brew extends VirtualizedRegistry { +public class Brew extends VirtualizedRegistry { public BrewBuilder brewBuilder() { return new BrewBuilder(); } - public RecipeBuilder recipeBuilder() { - return new RecipeBuilder(); - } - @Override @GroovyBlacklist public void onReload() { - removeScripted().forEach(BotaniaAPI.brewRecipes::remove); - BotaniaAPI.brewRecipes.addAll(restoreFromBackup()); - } - - public void add(RecipeBrew recipe) { - if (recipe == null) return; - addScripted(recipe); - BotaniaAPI.brewRecipes.add(recipe); - } - - public boolean remove(RecipeBrew recipe) { - if (recipe == null) return false; - addBackup(recipe); - return BotaniaAPI.brewRecipes.remove(recipe); + removeScripted().forEach(brew -> BotaniaAPI.brewMap.remove(brew.getKey())); + restoreFromBackup().forEach(brew -> BotaniaAPI.brewMap.put(brew.getKey(), brew)); } - public boolean removeByOutput(String brew) { - if (BotaniaAPI.brewRecipes.removeIf(recipe -> { - boolean found = recipe.getBrew().getKey().equals(brew); - if (found) addBackup(recipe); - return found; - })) return true; - - GroovyLog.msg("Error removing Botania Brew recipe") - .add("could not find recipe with input {}", brew) - .error() - .post(); - return false; + public void add(vazkii.botania.api.brew.Brew brew) { + if (brew == null) return; + addScripted(brew); + BotaniaAPI.brewMap.put(brew.getKey(), brew); } - public boolean removeByOutput(vazkii.botania.api.brew.Brew brew) { - return removeByOutput(brew.getKey()); + public boolean remove(vazkii.botania.api.brew.Brew brew) { + if (brew == null) return false; + addBackup(brew); + return BotaniaAPI.brewMap.remove(brew.getKey()) != null; } - public boolean removeByInput(IIngredient... inputs) { - List converted = Arrays.stream(inputs).map(i -> i instanceof OreDictIngredient ? ((OreDictIngredient) i).getOreDict() : i.getMatchingStacks()[0]).collect(Collectors.toList()); - if (BotaniaAPI.brewRecipes.removeIf(recipe -> { - boolean found = converted.stream().allMatch(o -> recipe.getInputs().stream().anyMatch(i -> (i instanceof String || o instanceof String) ? i.equals(o) : ItemStack.areItemStacksEqual((ItemStack) i, (ItemStack) o))); - if (found) addBackup(recipe); - return found; - })) return true; - - GroovyLog.msg("Error removing Botania Brew recipe") - .add("could not find recipe with inputs {}", converted) - .error() - .post(); - return false; - } - - public boolean removeByInputs(IIngredient... inputs) { - return removeByInput(inputs); + public boolean remove(String brew) { + if (brew == null) return false; + addBackup(BotaniaAPI.brewMap.get(brew)); + return BotaniaAPI.brewMap.remove(brew) != null; } public void removeAll() { - BotaniaAPI.brewRecipes.forEach(this::addBackup); - BotaniaAPI.brewRecipes.clear(); - } - - public SimpleObjectStream streamRecipes() { - return new SimpleObjectStream<>(BotaniaAPI.brewRecipes).setRemover(this::remove); - } - - public class RecipeBuilder extends AbstractRecipeBuilder { - - protected vazkii.botania.api.brew.Brew brew; - - public RecipeBuilder output(vazkii.botania.api.brew.Brew brew) { - this.brew = brew; - return this; - } - - public RecipeBuilder brew(vazkii.botania.api.brew.Brew brew) { - return output(brew); - } - - @Override - public String getErrorMsg() { - return "Error adding Botania Brew recipe"; - } - - @Override - public void validate(GroovyLog.Msg msg) { - validateFluids(msg, 0, 0, 0, 0); - validateItems(msg, 1, 20, 0, 0); - msg.add(brew == null, "Expected a valid output brew, got " + brew); - } - - @Override - public @Nullable RecipeBrew register() { - if (!validate()) return null; - RecipeBrew recipe = new RecipeBrew(brew, input.stream().map(i -> i instanceof OreDictIngredient ? ((OreDictIngredient) i).getOreDict() : i.getMatchingStacks()[0]).toArray()); - add(recipe); - return recipe; - } + BotaniaAPI.brewMap.forEach((l, r) -> this.addBackup(r)); + BotaniaAPI.brewMap.clear(); } public SimpleObjectStream streamBrews() { @@ -161,13 +84,27 @@ public BrewBuilder cost(int cost) { return this; } - public BrewBuilder noIncenseInfusion() { - this.canInfuseIncense = false; + public BrewBuilder mana(int mana) { + return cost(mana); + } + + public BrewBuilder incense(boolean incense) { + this.canInfuseIncense = incense; + return this; + } + + public BrewBuilder incense() { + this.canInfuseIncense = !canInfuseIncense; return this; } - public BrewBuilder noBloodPendantInfusion() { - this.canInfuseBloodPendant = false; + public BrewBuilder bloodPendant(boolean bloodPendant) { + this.canInfuseBloodPendant = bloodPendant; + return this; + } + + public BrewBuilder bloodPendant() { + this.canInfuseBloodPendant = !canInfuseBloodPendant; return this; } @@ -176,6 +113,20 @@ public BrewBuilder effect(PotionEffect effect) { return this; } + public BrewBuilder effect(PotionEffect... effects) { + for (PotionEffect effect : effects) { + effect(effect); + } + return this; + } + + public BrewBuilder effect(Collection effects) { + for (PotionEffect effect : effects) { + effect(effect); + } + return this; + } + @Override public String getErrorMsg() { return "Error adding Botania Brew"; @@ -185,7 +136,8 @@ public String getErrorMsg() { public void validate(GroovyLog.Msg msg) { validateItems(msg, 0, 0, 0, 0); validateFluids(msg, 0, 0, 0, 0); - msg.add(key == null, "must have a unique key for brew, got " + key); + msg.add(key == null, "key must be defined"); + msg.add(BotaniaAPI.brewMap.containsKey(key), "must have a unique key for brew, got " + key); msg.add(cost < 1, "cost must be at least 1, got " + cost); msg.add(effects.size() < 1, "must have at least 1 potion effect, got " + effects.size()); } @@ -198,8 +150,10 @@ public vazkii.botania.api.brew.Brew register() { vazkii.botania.api.brew.Brew brew = new vazkii.botania.api.brew.Brew(key, name, color, cost, effects.toArray(new PotionEffect[0])); if (!canInfuseBloodPendant) brew.setNotBloodPendantInfusable(); if (!canInfuseIncense) brew.setNotIncenseInfusable(); - BotaniaAPI.registerBrew(brew); + ModSupport.BOTANIA.get().brew.add(brew); return brew; } + } + } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/BrewRecipe.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/BrewRecipe.java new file mode 100644 index 000000000..1f6522df4 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/BrewRecipe.java @@ -0,0 +1,124 @@ +package com.cleanroommc.groovyscript.compat.mods.botania; + +import com.cleanroommc.groovyscript.api.GroovyBlacklist; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; +import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; +import vazkii.botania.api.BotaniaAPI; +import vazkii.botania.api.recipe.RecipeBrew; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class BrewRecipe extends VirtualizedRegistry { + + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + @GroovyBlacklist + public void onReload() { + removeScripted().forEach(BotaniaAPI.brewRecipes::remove); + BotaniaAPI.brewRecipes.addAll(restoreFromBackup()); + } + + public void add(RecipeBrew recipe) { + if (recipe == null) return; + addScripted(recipe); + BotaniaAPI.brewRecipes.add(recipe); + } + + public boolean remove(RecipeBrew recipe) { + if (recipe == null) return false; + addBackup(recipe); + return BotaniaAPI.brewRecipes.remove(recipe); + } + + public boolean removeByOutput(String brew) { + if (BotaniaAPI.brewRecipes.removeIf(recipe -> { + boolean found = recipe.getBrew().getKey().equals(brew); + if (found) addBackup(recipe); + return found; + })) return true; + + GroovyLog.msg("Error removing Botania Brew recipe") + .add("could not find recipe with input {}", brew) + .error() + .post(); + return false; + } + + public boolean removeByOutput(vazkii.botania.api.brew.Brew brew) { + return removeByOutput(brew.getKey()); + } + + public boolean removeByInput(IIngredient... inputs) { + List converted = Arrays.stream(inputs).map(i -> i instanceof OreDictIngredient ? ((OreDictIngredient) i).getOreDict() : i.getMatchingStacks()[0]).collect(Collectors.toList()); + if (BotaniaAPI.brewRecipes.removeIf(recipe -> { + boolean found = converted.stream().allMatch(o -> recipe.getInputs().stream().anyMatch(i -> (i instanceof String || o instanceof String) ? i.equals(o) : ItemStack.areItemStacksEqual((ItemStack) i, (ItemStack) o))); + if (found) addBackup(recipe); + return found; + })) return true; + + GroovyLog.msg("Error removing Botania Brew recipe") + .add("could not find recipe with inputs {}", converted) + .error() + .post(); + return false; + } + + public boolean removeByInputs(IIngredient... inputs) { + return removeByInput(inputs); + } + + public void removeAll() { + BotaniaAPI.brewRecipes.forEach(this::addBackup); + BotaniaAPI.brewRecipes.clear(); + } + + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(BotaniaAPI.brewRecipes).setRemover(this::remove); + } + + public class RecipeBuilder extends AbstractRecipeBuilder { + + protected vazkii.botania.api.brew.Brew brew; + + public RecipeBuilder output(vazkii.botania.api.brew.Brew brew) { + this.brew = brew; + return this; + } + + public RecipeBuilder brew(vazkii.botania.api.brew.Brew brew) { + return output(brew); + } + + @Override + public String getErrorMsg() { + return "Error adding Botania Brew recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateFluids(msg); + validateItems(msg, 1, 6, 0, 0); + msg.add(brew == null, "Expected a valid output brew, got " + brew); + } + + @Override + public @Nullable RecipeBrew register() { + if (!validate()) return null; + RecipeBrew recipe = new RecipeBrew(brew, input.stream().map(i -> i instanceof OreDictIngredient ? ((OreDictIngredient) i).getOreDict() : i.getMatchingStacks()[0]).toArray()); + add(recipe); + return recipe; + } + } + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Lexicon.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Lexicon.java index e46bed8c0..3a8d1689c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Lexicon.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/Lexicon.java @@ -19,10 +19,7 @@ import vazkii.botania.api.recipe.*; import vazkii.botania.common.lexicon.page.*; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; public class Lexicon { @@ -64,15 +61,30 @@ public boolean remove(LexiconCategory category) { return true; } - public boolean removeCategory(String name) { + public boolean remove(String name) { LexiconCategory category = Botania.getCategory(name); if (category != null) return remove(category); + + GroovyLog.msg("Error removing Botania Lexica Botania Category") + .add("could not find category with name {}", name) + .error() + .post(); return false; } + public boolean removeCategory(String name) { + return remove(name); + } + public SimpleObjectStream streamCategories() { return new SimpleObjectStream<>(BotaniaAPI.getAllCategories()).setRemover(this::remove); } + + public void removeAll() { + BotaniaAPI.getAllCategories().forEach(this::addBackup); + BotaniaAPI.getAllCategories().clear(); + } + } public static class Page extends VirtualizedRegistry { @@ -109,12 +121,30 @@ public boolean remove(LexiconEntry entry, int index) { return remove(entry, page); } - public void removeAll(LexiconEntry entry) { - for (int i = 0; i < entry.pages.size(); i++) - addBackup(new PageChange(entry.pages.get(i), entry, i)); + public void removeByEntry(LexiconEntry entry) { + entry.pages.forEach(x -> addBackup(new PageChange(x, entry, entry.pages.indexOf(x)))); entry.pages.clear(); } + public void removeByEntry(String name) { + LexiconEntry entry = Botania.getEntry(name); + if (entry == null) { + GroovyLog.msg("Error removing Botania Lexica Botania Pages by Entry") + .add("could not find entry with name {}", name) + .error() + .post(); + return; + } + removeByEntry(entry); + } + + public void removeAll() { + for (LexiconEntry entry : BotaniaAPI.getAllEntries()) { + entry.pages.forEach(x -> addBackup(new PageChange(x, entry, entry.pages.indexOf(x)))); + entry.pages.clear(); + } + } + public SimpleObjectStream streamPages(LexiconEntry entry) { return new SimpleObjectStream<>(entry.pages).setRemover(page -> remove(entry, page)); } @@ -204,12 +234,21 @@ public boolean remove(LexiconEntry entry) { return true; } - public boolean removeEntry(String name) { + public boolean remove(String name) { LexiconEntry entry = Botania.getEntry(name); if (entry != null) return remove(entry); + + GroovyLog.msg("Error removing Botania Lexica Botania Entry") + .add("could not find entry with name {}", name) + .error() + .post(); return false; } + public boolean removeEntry(String name) { + return remove(name); + } + public void setKnowledgeType(String entry, KnowledgeType type) { Objects.requireNonNull(Botania.getEntry(entry)).setKnowledgeType(type); } @@ -218,6 +257,28 @@ public void setKnowledgeType(String entry, String type) { setKnowledgeType(entry, BotaniaAPI.knowledgeTypes.get(type)); } + public void removeByCategory(LexiconCategory category) { + category.entries.forEach(this::addBackup); + category.entries.clear(); + } + + public void removeByCategory(String name) { + LexiconCategory category = Botania.getCategory(name); + if (category == null) { + GroovyLog.msg("Error removing Botania Lexica Botania Entries by Category") + .add("could not find category with name {}", name) + .error() + .post(); + return; + } + removeByCategory(category); + } + + public void removeAll() { + BotaniaAPI.getAllEntries().forEach(this::addBackup); + BotaniaAPI.getAllEntries().clear(); + } + public SimpleObjectStream streamEntries() { return new SimpleObjectStream<>(BotaniaAPI.getAllEntries()).setRemover(this::remove); } @@ -266,6 +327,20 @@ public EntryBuilder page(LexiconPage page) { return this; } + public EntryBuilder page(LexiconPage... pages) { + for (LexiconPage page : pages) { + page(page); + } + return this; + } + + public EntryBuilder page(Collection pages) { + for (LexiconPage page : pages) { + page(page); + } + return this; + } + public EntryBuilder extraRecipe(IIngredient stack) { this.extraRecipes.add(stack.getMatchingStacks()[0]); return this; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/ManaInfusion.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/ManaInfusion.java index 605db69f4..c762764bd 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/ManaInfusion.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/ManaInfusion.java @@ -72,6 +72,21 @@ public boolean removeByInput(IIngredient input) { return false; } + public boolean removeByCatalyst(IBlockState catalyst) { + if (BotaniaAPI.manaInfusionRecipes.removeIf(recipe -> { + if (recipe.getCatalyst() == null) return false; + boolean found = recipe.getCatalyst().equals(catalyst); + if (found) addBackup(recipe); + return found; + })) return true; + + GroovyLog.msg("Error removing Botania Mana Infusion recipe") + .add("could not find recipe with catalyst {}", catalyst) + .error() + .post(); + return false; + } + public void removeAll() { BotaniaAPI.manaInfusionRecipes.forEach(this::addBackup); BotaniaAPI.manaInfusionRecipes.clear(); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/PureDaisy.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/PureDaisy.java index 3db5c93b4..8dddc4fc0 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/PureDaisy.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/PureDaisy.java @@ -2,13 +2,12 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; -import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; +import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; -import net.minecraft.init.Blocks; import org.jetbrains.annotations.Nullable; import vazkii.botania.api.BotaniaAPI; import vazkii.botania.api.recipe.RecipePureDaisy; @@ -76,6 +75,10 @@ public boolean removeByInput(String input) { return false; } + public boolean removeByInput(OreDictIngredient input) { + return removeByInput(input.getOreDict()); + } + public boolean removeByInput(IBlockState input) { if (BotaniaAPI.pureDaisyRecipes.removeIf(recipe -> { boolean found = (recipe.getInput() instanceof IBlockState && recipe.getInput().equals(input)) || (recipe.getInput() instanceof Block && recipe.getInput() == input.getBlock()); @@ -133,6 +136,10 @@ public RecipeBuilder input(String input) { return this; } + public RecipeBuilder input(OreDictIngredient input) { + return input(input.getOreDict()); + } + @Override public String getErrorMsg() { return "Error adding Botania Pure Daisy recipe"; @@ -143,8 +150,8 @@ public void validate(GroovyLog.Msg msg) { validateItems(msg, 0, 0, 0, 0); validateFluids(msg, 0, 0, 0, 0); msg.add(time < 0, "time must be at least 1, got " + time); - msg.add(output != null, "expected IBlockState output, got " + output); - msg.add(input != null, "expected IBlockState or String input, got " + input); + msg.add(output == null, "output must be defined"); + msg.add(input == null || !(input instanceof String || input instanceof IBlockState), "expected IBlockState or String input, got {}", input); } @Override diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/RuneAltar.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/RuneAltar.java index 3c245dffd..b077b931e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/RuneAltar.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/RuneAltar.java @@ -7,10 +7,12 @@ import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.Nullable; import vazkii.botania.api.BotaniaAPI; import vazkii.botania.api.recipe.RecipeRuneAltar; +import vazkii.botania.common.block.ModBlocks; import java.util.Arrays; import java.util.List; @@ -64,7 +66,7 @@ public boolean removeByOutput(IIngredient output) { public boolean removeByInput(IIngredient... inputs) { List converted = Arrays.stream(inputs).map(i -> i instanceof OreDictIngredient ? ((OreDictIngredient) i).getOreDict() : i.getMatchingStacks()[0]).collect(Collectors.toList()); if (BotaniaAPI.runeAltarRecipes.removeIf(recipe -> { - boolean found = converted.stream().allMatch(o -> recipe.getInputs().stream().anyMatch(i -> (i instanceof String || o instanceof String)? i.equals(o) : ItemStack.areItemStacksEqual((ItemStack) i, (ItemStack) o)));; + boolean found = converted.stream().allMatch(o -> recipe.getInputs().stream().anyMatch(i -> (i instanceof String || o instanceof String)? i.equals(o) : ItemStack.areItemStacksEqual((ItemStack) i, (ItemStack) o))); if (found) addBackup(recipe); return found; })) return true; @@ -107,6 +109,8 @@ public String getErrorMsg() { public void validate(GroovyLog.Msg msg) { validateFluids(msg, 0, 0, 0, 0); validateItems(msg, 1, 20, 1, 1); + msg.add(input.stream().anyMatch(x -> x.test(new ItemStack(Item.getItemFromBlock(ModBlocks.livingrock), 1, 0))), + "input cannot contain a livingrock item"); msg.add(mana < 1, "mana must be at least 1, got " + mana); } From 6e67b02092d71e85727a0bb8f895ebcc321ea1a2 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Tue, 4 Jul 2023 05:47:19 -0700 Subject: [PATCH 02/28] draconic evolution examples and fixes --- build.gradle | 4 +- examples/de.groovy | 15 ------ examples/draconicevolution.groovy | 25 ++++++++++ gradle.properties | 2 +- .../groovyscript/compat/mods/ModSupport.java | 2 +- .../compat/mods/draconicevolution/Fusion.java | 50 ++++++++++--------- 6 files changed, 55 insertions(+), 43 deletions(-) delete mode 100644 examples/de.groovy create mode 100644 examples/draconicevolution.groovy diff --git a/build.gradle b/build.gradle index 5073ba274..c8185ac47 100644 --- a/build.gradle +++ b/build.gradle @@ -119,7 +119,7 @@ dependencies { } compileOnly rfg.deobf('curse.maven:redstone_flux-270789:2920436') - if (project.debug_thermal.toBoolean() || project.debug_de.toBoolean()) { + if (project.debug_thermal.toBoolean() || project.debug_draconic_evolution.toBoolean()) { runtimeOnly rfg.deobf('curse.maven:redstone_flux-270789:2920436') } @@ -166,7 +166,7 @@ dependencies { compileOnly rfg.deobf('curse.maven:codechicken_lib_1_8-242818:2779848') compileOnly rfg.deobf('curse.maven:draconic_evolution-223565:3431261') compileOnly rfg.deobf('curse.maven:brandons_core-231382:3408276') - if (project.debug_de.toBoolean()) { + if (project.debug_draconic_evolution.toBoolean()) { runtimeOnly rfg.deobf('curse.maven:codechicken_lib_1_8-242818:2779848') runtimeOnly rfg.deobf('curse.maven:draconic_evolution-223565:3431261') runtimeOnly rfg.deobf('curse.maven:brandons_core-231382:3408276') diff --git a/examples/de.groovy b/examples/de.groovy deleted file mode 100644 index c0976f05b..000000000 --- a/examples/de.groovy +++ /dev/null @@ -1,15 +0,0 @@ - -mods.de.Fusion.recipeBuilder() - .catalyst(item('minecraft:diamond')) - .input(ore('ingotIron')) - .input(ore('ingotIron')) - .input(item('minecraft:dirt')) - .input(item('minecraft:grass')) - .input(item('minecraft:grass')) - .input(item('minecraft:dirt')) - .input(ore('ingotGold')) - .input(ore('ingotGold')) - .output(item('minecraft:nether_star')) - .energy(100000) - .tierWyvern() - .register() \ No newline at end of file diff --git a/examples/draconicevolution.groovy b/examples/draconicevolution.groovy new file mode 100644 index 000000000..22f10f2c1 --- /dev/null +++ b/examples/draconicevolution.groovy @@ -0,0 +1,25 @@ + +// Fusion: +// Consumes items and power from up to 54 pedestals of at least a given tier pointing towards a Fusion Crafting Core containing a catalyst to produce an output item. +mods.draconicevolution.fusion.recipeBuilder() + .catalyst(item('minecraft:diamond')) + .input(ore('ingotIron'), ore('ingotIron'), item('minecraft:dirt'), item('minecraft:grass'), item('minecraft:grass'), item('minecraft:dirt'), ore('ingotGold'), ore('ingotGold')) + .output(item('minecraft:nether_star')) + .energy(10) // Energy cost per item. Optional, default 1000000 (1 million) + .tier(1) // Optional, default 0 (basic) + .register() + +mods.draconicevolution.fusion.recipeBuilder() + .catalyst(item('minecraft:diamond')) + .input(item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay')) + .output(item('minecraft:nether_star')) + .energy(100000) + //.tierNormal() // Alias for tier(0) + //.tierBasic() // Alias for tier(0) + //.tierWyvern() // Alias for tier(1) + //.tierDraconic() // Alias for tier(2) + .tierChaotic() // Alias for tier(3) + .register() + +mods.draconicevolution.fusion.removeByCatalyst(item('draconicevolution:chaos_shard')) +//mods.draconicevolution.fusion.removeAll() diff --git a/gradle.properties b/gradle.properties index adffc65fb..45b8d1e12 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,7 +23,7 @@ debug_evilcraft = false debug_thermal = false debug_thaum = false debug_ic2 = false -debug_de = false +debug_draconic_evolution = false debug_ie = false debug_enderio = false debug_astral = 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 c22b71d2c..6242b880c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java @@ -51,7 +51,7 @@ public class ModSupport implements IDynamicGroovyProperty { public static final Container THERMAL_EXPANSION = new Container<>("thermalexpansion", "Thermal Expansion", ThermalExpansion::new, "te", "thermal"); public static final Container TINKERS_CONSTRUCT = new Container<>("tconstruct", "Tinkers' Construct", TinkersConstruct::new, "ticon", "tinkersconstruct"); public static final Container TINKERS_COMPLEMENT = new Container<>("tcomplement", "Tinkers Complement", TinkersComplement::new, "tcomp", "tinkerscomplement"); - public static final Container DRACONIC_EVO = new Container<>("draconicevolution", "Draconic Evolution", DraconicEvolution::new, "de"); + public static final Container DRACONIC_EVOLUTION = new Container<>("draconicevolution", "Draconic Evolution", DraconicEvolution::new, "de"); public static final Container ROOTS = new Container<>("roots", "Roots 3", Roots::new); public static final Container BLOOD_MAGIC = new Container<>("bloodmagic", "Blood Magic: Alchemical Wizardry", BloodMagic::new, "bm"); public static final Container EVILCRAFT = new Container<>("evilcraft", "EvilCraft", EvilCraft::new); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/Fusion.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/Fusion.java index 88b6f8c4f..c951b9117 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/Fusion.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/draconicevolution/Fusion.java @@ -12,6 +12,8 @@ import net.minecraft.item.ItemStack; import org.jetbrains.annotations.Nullable; +import java.util.stream.Collectors; + public class Fusion extends VirtualizedRegistry { public Fusion() { @@ -28,32 +30,29 @@ public RecipeBuilder recipeBuilder() { return new RecipeBuilder(); } + public void add(IFusionRecipe recipe) { + addScripted(recipe); + RecipeManager.FUSION_REGISTRY.add(recipe); + } + public boolean remove(IFusionRecipe recipe) { - int oldSize = ((FusionRegistryAccessor) RecipeManager.FUSION_REGISTRY).getREGISTRY().size(); - RecipeManager.FUSION_REGISTRY.remove(recipe); - if (oldSize != ((FusionRegistryAccessor) RecipeManager.FUSION_REGISTRY).getREGISTRY().size()) { + if (RecipeManager.FUSION_REGISTRY.getRecipes().contains(recipe)) { addBackup(recipe); + RecipeManager.FUSION_REGISTRY.remove(recipe); return true; } return false; } - public void removeByCatalyst(ItemStack item) { - if (IngredientHelper.isEmpty(item)) { - GroovyLog.msg("Error removing Draconic Evo. Fusion recipe") - .add("catalyst must not be empty") - .error() - .post(); - } - IFusionRecipe recipe = RecipeManager.FUSION_REGISTRY.findRecipeForCatalyst(item); - if (recipe == null) { - GroovyLog.msg("Error removing Draconic Evo. Fusion recipe") - .add("can't find recipe for %s", item) - .error() - .post(); + for (IFusionRecipe recipe : RecipeManager.FUSION_REGISTRY.getRecipes().stream().filter(x -> x.getRecipeCatalyst().isItemEqual(item)).collect(Collectors.toList())) { + remove(recipe); } - remove(recipe); + } + + public void removeAll() { + ((FusionRegistryAccessor) RecipeManager.FUSION_REGISTRY).getREGISTRY().forEach(this::addBackup); + ((FusionRegistryAccessor) RecipeManager.FUSION_REGISTRY).getREGISTRY().clear(); } public SimpleObjectStream streamRecipes() { @@ -64,7 +63,7 @@ public SimpleObjectStream streamRecipes() { public static class RecipeBuilder extends AbstractRecipeBuilder { private ItemStack catalyst; - private long energy; + private long energy = 1000000; private int tier; public RecipeBuilder energy(long energy) { @@ -86,6 +85,10 @@ public RecipeBuilder tierNormal() { return tier(0); } + public RecipeBuilder tierBasic() { + return tier(0); + } + public RecipeBuilder tierWyvern() { return tier(1); } @@ -105,19 +108,18 @@ public String getErrorMsg() { @Override public void validate(GroovyLog.Msg msg) { - validateItems(msg, 1, 20, 1, 1); + validateItems(msg, 1, 54, 1, 1); validateFluids(msg); - msg.add(IngredientHelper.isEmpty(catalyst), () -> "catalyst must not be empty"); - msg.add(tier < 0 || tier > 3, () -> "tier must be between 0 (normal) and 3 (chaotic)"); - if (energy <= 0) energy = 1000000; + msg.add(IngredientHelper.isEmpty(catalyst), "catalyst must not be empty"); + msg.add(tier < 0 || tier > 3, "tier must be between 0 (basic) and 3 (chaotic), yet it was {}", tier); + msg.add(energy <= 0 , "energy must be greater than 0, yet it was {}", energy); } @Override public @Nullable IFusionRecipe register() { if (!validate()) return null; GroovyFusionRecipe recipe = new GroovyFusionRecipe(output.get(0), catalyst, input, energy, tier); - ModSupport.DRACONIC_EVO.get().fusion.addScripted(recipe); - RecipeManager.FUSION_REGISTRY.add(recipe); + ModSupport.DRACONIC_EVOLUTION.get().fusion.add(recipe); return recipe; } } From d73a360b4cbf093ee91ad9576274d3ba4a52d99c Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Wed, 5 Jul 2023 20:42:28 -0700 Subject: [PATCH 03/28] mekanism examples and went overboard --- examples/mekanism.groovy | 346 ++++++++++++++---- .../compat/mods/mekanism/ChemicalInfuser.java | 31 ++ .../mods/mekanism/ChemicalOxidizer.java | 34 ++ .../compat/mods/mekanism/Combiner.java | 41 +++ .../compat/mods/mekanism/Crusher.java | 33 ++ .../compat/mods/mekanism/Crystallizer.java | 30 ++ .../mods/mekanism/DissolutionChamber.java | 34 ++ ...arator.java => ElectrolyticSeparator.java} | 44 ++- .../mods/mekanism/EnrichmentChamber.java | 33 ++ .../compat/mods/mekanism/Infusion.java | 201 ++++++++++ .../mods/mekanism/InjectionChamber.java | 34 ++ .../compat/mods/mekanism/Mekanism.java | 18 +- .../mods/mekanism/MetallurgicInfuser.java | 73 +++- .../mods/mekanism/OsmiumCompressor.java | 37 ++ .../mekanism/PressurizedReactionChamber.java | 80 +--- .../mods/mekanism/PurificationChamber.java | 34 ++ .../compat/mods/mekanism/Sawmill.java | 50 +++ .../compat/mods/mekanism/Smelting.java | 87 +++++ .../mods/mekanism/SolarNeutronActivator.java | 32 +- ...tion.java => ThermalEvaporationPlant.java} | 38 +- .../compat/mods/mekanism/Washer.java | 30 ++ .../mekanism/recipe/GasRecipeBuilder.java | 66 ++++ .../mods/mekanism/recipe/GasStackList.java | 49 +++ .../recipe/VirtualizedMekanismRegistry.java | 10 + 24 files changed, 1312 insertions(+), 153 deletions(-) rename src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/{Separator.java => ElectrolyticSeparator.java} (56%) create mode 100644 src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Infusion.java create mode 100644 src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Smelting.java rename src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/{ThermalEvaporation.java => ThermalEvaporationPlant.java} (56%) create mode 100644 src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/GasRecipeBuilder.java create mode 100644 src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/GasStackList.java diff --git a/examples/mekanism.groovy b/examples/mekanism.groovy index a71b4a964..a94b7b8e9 100644 --- a/examples/mekanism.groovy +++ b/examples/mekanism.groovy @@ -1,73 +1,273 @@ -// crusher -mods.mekanism.Crusher.add(item('minecraft:clay_ball'), item('minecraft:gold_ingot')) -mods.mekanism.Crusher.removeByInput(ore('ingotSilver')) - -// chemical infuser -mods.mekanism.ChemicalInfuser.add(gas('copper'), gas('iron'), gas('gold')) -mods.mekanism.ChemicalInfuser.removeByInput(gas('hydrogen'), gas('chlorine')) - -// chemical oxidizer -mods.mekanism.ChemicalOxidizer.add(ore('dustGold'), gas('gold')) -mods.mekanism.ChemicalOxidizer.removeByInput(ore('dustSulfur')) - -// combiner -mods.mekanism.Combiner.add(ore('gemQuartz') * 8, item('minecraft:netherrack'), item('minecraft:quartz_ore')) -mods.mekanism.Combiner.removeByInput(ore('gemQuartz') * 8, item('minecraft:cobblestone')) - -// crystallizer -mods.mekanism.Crystallizer.removeByInput(gas('cleanGold')) // either remove first or don't remove at all. the recipe below should overwrite the original recipe -mods.mekanism.Crystallizer.add(gas('cleanGold'), item('minecraft:gold_ingot')) - -// dissolution chamber -mods.mekanism.DissolutionChamber.add(item('minecraft:packed_ice'), gas('water')) -mods.mekanism.DissolutionChamber.removeByInput(item('mekanism:oreblock:0')) - -// enrichment chamber -mods.mekanism.EnrichmentChamber.add(item('minecraft:clay_ball'), item('minecraft:nether_star')) -mods.mekanism.EnrichmentChamber.removeByInput(item('minecraft:diamond')) - -// injection chamber -mods.mekanism.InjectionChamber.add(item('minecraft:diamond'), gas('water'), item('minecraft:nether_star')) -mods.mekanism.InjectionChamber.removeByInput(item('minecraft:hardened_clay'), gas('water')) - -// metallurgic infuser -mods.mekanism.MetallurgicInfuser.add(item('minecraft:clay_ball'), 'DIAMOND', 200, item('minecraft:nether_star')) -mods.mekanism.MetallurgicInfuser.removeByInput(ore('dustObsidian'), 'DIAMOND') - -// osmium compressor -mods.mekanism.OsmiumCompressor.add(item('minecraft:diamond'), gas('liquidosmium'), item('minecraft:nether_star')) -mods.mekanism.OsmiumCompressor.removeByInput(ore('dustRefinedObsidian'), gas('liquidosmium')) - -// prc -mods.mekanism.PRC.recipeBuilder() - .fluidInput(fluid('water')) - .gasInput(gas('water')) - .input(item('minecraft:clay_ball')) - .output(item('minecraft:diamond')) - .gasOutput(gas('ethene')) - .register() -mods.mekanism.PRC.removeByInput(ore('dustCoal'), fluid('water'), gas('oxygen')) - -// purification chamber -mods.mekanism.PurificationChamber.add(item('minecraft:diamond'), gas('oxygen'), item('minecraft:nether_star')) -mods.mekanism.PurificationChamber.removeByInput(item('mekanism:oreblock:0'), gas('oxygen')) - -// sawmill -mods.mekanism.Sawmill.add(item('minecraft:diamond_block'), item('minecraft:diamond') * 9) -mods.mekanism.Sawmill.removeByInput(item('minecraft:ladder')) - -// separator -mods.mekanism.ElectrolyticSeparator.add(fluid('lava'), gas('cleanGold'), gas('cleanCopper'), 3000) -mods.mekanism.ElectrolyticSeparator.removeByInput(fluid('water')) - -// solar neutron activator -mods.mekanism.SolarNeutronActivator.add(gas('water'), gas('hydrogen')) -mods.mekanism.SolarNeutronActivator.removeByInput(gas('lithium')) - -// thermal evaporation plant -mods.mekanism.ThermalEvaporationPlant.removeByInput(fluid('water')) -mods.mekanism.ThermalEvaporationPlant.add(fluid('water'), fluid('steam')) - -// washer -mods.mekanism.Washer.add(gas('water'), gas('hydrogen')) -mods.mekanism.Washer.removeByInput(gas('iron')) + +// Bracket Handlers +// Gas +gas('gold') +gas('liquidosmium') + +// Infusion +infusion('carbon') +infusion('redstone') +infusion('diamond') +infusion('obsidian') +infusion('fungi') +infusion('bio') +infusion('tin') + + +// Infusion: +// Add new infusion types and itemstacks to those types + +mods.mekanism.infusion.infusion(infusion('diamond')) + .add(100, item('minecraft:clay')) + .remove(ore('dustDiamond')) + +mods.mekanism.infusion.infusion(infusion('carbon')) + .removeAll() // Must occur before anything is added + .add(100, ore('ingotGold')) + +// NOTE: +// To register the texture used, you have to add the following event listen to a PreInit file. +// event_manager.listen { TextureStitchEvent.Pre event -> event.getMap().registerSprite(resource('groovytest:blocks/example')) } +// Where 'assets/groovytest/textures/blocks/example.png' is the location of the desired texture. +mods.mekanism.infusion.infusion('groovy_example', resource('groovytest:blocks/example')) + .add(10, item('minecraft:ice')) + .add(20, item('minecraft:packed_ice')) + + +//mods.mekanism.infusion.removeByType(infusion('diamond')) +//mods.mekanism.infusion.removeAll() + + +// Chemical Infuser: +// Combines two input gas stacks into a output gas stack +mods.mekanism.chemicalinfuser.recipeBuilder() + .gasInput(gas('copper') * 10, gas('iron')) + .gasOutput(gas('gold') * 15) + .register() +//mods.mekanism.chemicalinfuser.add(gas('copper') * 10, gas('iron'), gas('gold') * 15) + +mods.mekanism.chemicalinfuser.removeByInput(gas('hydrogen'), gas('chlorine')) +//mods.mekanism.chemicalinfuser.removeAll() + + +// Chemical Oxidizer (Oxidizer): +// Converts an input itemstack into an output gasstack +mods.mekanism.chemicaloxidizer.recipeBuilder() + .input(ore('dustGold')) + .gasOutput(gas('gold')) + .register() +//mods.mekanism.chemicaloxidizer.add(ore('dustGold'), gas('gold')) + +mods.mekanism.chemicaloxidizer.removeByInput(ore('dustSulfur')) +//mods.mekanism.chemicaloxidizer.removeAll() + +// Combiner: +// Combines an input itemstack with an extra itemstack to create an output itemstack +mods.mekanism.combiner.recipeBuilder() + .input(ore('gemQuartz') * 8) + .extra(item('minecraft:netherrack')) + .output(item('minecraft:quartz_ore')) + .register() +//mods.mekanism.combiner.add(ore('gemQuartz') * 8, item('minecraft:netherrack'), item('minecraft:quartz_ore')) + +mods.mekanism.combiner.removeByInput(ore('gemQuartz') * 8, item('minecraft:cobblestone')) +//mods.mekanism.combiner.removeAll() + + +// Crusher: +// Converts an input itemstack into an output itemstack. +mods.mekanism.crusher.recipeBuilder() + .input(item('minecraft:clay_ball')) + .output(item('minecraft:gold_ingot')) + .register() +//mods.mekanism.crusher.add(item('minecraft:clay_ball'), item('minecraft:gold_ingot')) + +mods.mekanism.crusher.removeByInput(ore('ingotTin')) +//mods.mekanism.crusher.removeAll() + + +// Crystallizer: +// Converts an input gasstack into an output itemstack. +mods.mekanism.crystallizer.recipeBuilder() + .gasInput(gas('cleanGold')) + .output(item('minecraft:gold_ingot')) + .register() +//mods.mekanism.crystallizer.add(gas('cleanGold'), item('minecraft:gold_ingot')) + +mods.mekanism.crystallizer.removeByInput(gas('cleanGold')) // either remove first or don't remove at all. the recipe below should overwrite the original recipe +//mods.mekanism.crystallizer.removeAll() + + +// Dissolution Chamber (Dissolver): +// Converts an input itemstack into an output gasstack at the cost of 100mb of Sulfuric Acid +mods.mekanism.dissolutionchamber.recipeBuilder() + .input(item('minecraft:packed_ice')) + .gasOutput(gas('water') * 2000) + .register() +//mods.mekanism.dissolutionchamber.add(item('minecraft:packed_ice'), gas('water')) + +mods.mekanism.dissolutionchamber.removeByInput(item('mekanism:oreblock:0')) +//mods.mekanism.dissolutionchamber.removeAll() + + +// Enrichment Chamber (Enricher): +// Converts an input itemstack into an output itemstack. +mods.mekanism.enrichmentchamber.recipeBuilder() + .input(item('minecraft:clay_ball')) + .output(item('minecraft:nether_star')) + .register() +//mods.mekanism.enrichmentchamber.add(item('minecraft:clay_ball'), item('minecraft:nether_star')) + +mods.mekanism.enrichmentchamber.removeByInput(item('minecraft:diamond')) +//mods.mekanism.enrichmentchamber.removeAll() + + +// Electrolytic Separator (Separator): +// Converts an input fluid into two output gasstacks at the cost of power. +mods.mekanism.electrolyticseparator.recipeBuilder() + .fluidInput(fluid('lava') * 10) + .gasOutput(gas('cleanGold') * 5, gas('cleanCopper') * 3) + .energy(3000) + .register() +//mods.mekanism.electrolyticseparator.add(fluid('lava') * 10, gas('cleanGold') * 5, gas('cleanCopper') * 3, 3000) + +mods.mekanism.electrolyticseparator.removeByInput(fluid('water')) +//mods.mekanism.electrolyticseparator.removeAll() + + +// Injection Chamber (Injector): +// Converts an input itemstack and 200 of a gasstack into an output itemstack. +mods.mekanism.injectionchamber.recipeBuilder() + .input(item('minecraft:diamond')) + .gasInput(gas('water')) // Always uses 200 + .output(item('minecraft:nether_star')) + .register() +//mods.mekanism.injectionchamber.add(item('minecraft:diamond'), gas('water'), item('minecraft:nether_star')) + +mods.mekanism.injectionchamber.removeByInput(item('minecraft:hardened_clay'), gas('water')) +//mods.mekanism.injectionchamber.removeAll() + + +// Metallurgic Infuser: +// Converts and input itemstack and a varible amount of an infusion type into an output itemstack. +mods.mekanism.metallurgicinfuser.recipeBuilder() + .input(item('minecraft:nether_star')) + .infuse(infusion('groovy_example')) + .amount(50) + .output(item('minecraft:clay')) + .register() +//mods.mekanism.metallurgicinfuser.add(item('minecraft:nether_star'), infusion('groovy_example'), 50, item('minecraft:clay')) + +mods.mekanism.metallurgicinfuser.removeByInput(ore('dustObsidian'), 'DIAMOND') +//mods.mekanism.metallurgicinfuser.removeAll() + + +// Osmium Compressor: +// Converts an input itemstack and 200 of a gasstack into an output itemstack. By default, will use Liquid Osmium as the gasstack +mods.mekanism.osmiumcompressor.recipeBuilder() + .input(item('minecraft:diamond')) + .gasInput(gas('hydrogen')) // Optional GasStack, default liquidosmium. Always uses 200 + .output(item('minecraft:nether_star')) + .register() + +//mods.mekanism.osmiumcompressor.add(item('minecraft:diamond'), gas('hydrogen'), item('minecraft:nether_star')) + +mods.mekanism.osmiumcompressor.removeByInput(ore('dustRefinedObsidian'), gas('liquidosmium')) +//mods.mekanism.osmiumcompressor.removeAll() + + +// Pressurized Reaction Chamber (PRC): +// Converts an input fluidstack, gasstack, and optional itemstack into an output gasstack and optional itemstack. +mods.mekanism.pressurizedreactionchamber.recipeBuilder() + .fluidInput(fluid('water')) + .gasInput(gas('water')) + .input(item('minecraft:clay_ball')) // Optional IIngredient + .output(item('minecraft:diamond')) // Optional ItemStack + .gasOutput(gas('ethene')) + .register() + +mods.mekanism.pressurizedreactionchamber.recipeBuilder() + .fluidInput(fluid('lava')) + .gasInput(gas('water') * 100) + .gasOutput(gas('sulfuricacid') * 5) + .register() + +mods.mekanism.pressurizedreactionchamber.removeByInput(ore('logWood'), fluid('water'), gas('oxygen')) +//mods.mekanism.pressurizedreactionchamber.removeAll() + + +// Purification Chamber (Purifier): +// Converts an input itemstack and gasstack into an output itemstack. +mods.mekanism.purificationchamber.recipeBuilder() + .input(item('minecraft:diamond')) + .gasInput(gas('deuterium')) + .output(item('minecraft:nether_star')) + .register() +//mods.mekanism.purificationchamber.add(item('minecraft:diamond'), gas('oxygen'), item('minecraft:nether_star')) + +mods.mekanism.purificationchamber.removeByInput(item('mekanism:oreblock:0'), gas('oxygen')) +//mods.mekanism.purificationchamber.removeAll() + + +// Sawmill: +// Converts an input itemstack into an output itemstack, with an optional additional output. +mods.mekanism.sawmill.recipeBuilder() + .input(item('minecraft:diamond_block')) + .output(item('minecraft:diamond') * 9) + .extra(item('minecraft:clay_ball')) // Optional ItemStack, adds an extra chanced output + .chance(0.7) // Optional double, defaults to 1.0 + .register() +//mods.mekanism.sawmill.add(item('minecraft:diamond_block'), item('minecraft:diamond') * 9, item('minecraft:clay_ball'), 0.7) + +mods.mekanism.sawmill.removeByInput(item('minecraft:ladder')) +//mods.mekanism.sawmill.removeAll() + + +// Smelting (Smelter): +// Converts an input itemstack into an output itemstack in a recipe exclusive to the Smelter. Overrides the default furnace recipe, if applicable. +// WARNING: Exclusive recipes are not displayed in JEI. +mods.mekanism.smelting.recipeBuilder() + .input(item('minecraft:clay_ball')) + .output(item('minecraft:clay')) + .register() +//mods.mekanism.smelting.add(item('minecraft:diamond_block'), item('minecraft:clay')) + +// No recipes are exclusive to the Energised Smelter by default +//mods.mekanism.smelting.removeByInput(item('minecraft:clay')) +//mods.mekanism.smelting.removeAll() + + +// Solar Neutron Activator (SNA): +// Converts an input gasstack into an output gasstack while exposed to the sun. +mods.mekanism.solarneutronactivator.recipeBuilder() + .gasInput(gas('water')) + .gasOutput(gas('hydrogen')) + .register() +//mods.mekanism.solarneutronactivator.add(gas('water'), gas('hydrogen')) + +mods.mekanism.solarneutronactivator.removeByInput(gas('lithium')) +//mods.mekanism.solarneutronactivator.removeAll() + + +// Thermal Evaporation Plant (Thermal Evaporation, TEP): +// Converts an input fluidstack into an output fluidstack over time based on multiblock temperature. +mods.mekanism.thermalevaporationplant.recipeBuilder() + .fluidInput(fluid('water')) + .fluidOutput(fluid('steam')) + .register() +//mods.mekanism.thermalevaporationplant.add(fluid('water'), fluid('steam')) + +mods.mekanism.thermalevaporationplant.removeByInput(fluid('water')) +//mods.mekanism.thermalevaporationplant.removeAll() + + +// Washer: +// Converts an input gasstack into an output gasstack at the cost of 5mb of water. +mods.mekanism.washer.recipeBuilder() + .gasInput(gas('water') * 10) + .gasOutput(gas('hydrogen') * 20) + .register() +//mods.mekanism.washer.add(gas('water'), gas('hydrogen')) + +mods.mekanism.washer.removeByInput(gas('iron')) +//mods.mekanism.washer.removeAll() diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalInfuser.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalInfuser.java index 6753c4d5a..eab2642c1 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalInfuser.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalInfuser.java @@ -1,11 +1,14 @@ package com.cleanroommc.groovyscript.compat.mods.mekanism; import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import mekanism.api.gas.GasStack; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.ChemicalPairInput; import mekanism.common.recipe.machines.ChemicalInfuserRecipe; +import org.jetbrains.annotations.Nullable; public class ChemicalInfuser extends VirtualizedMekanismRegistry { @@ -13,6 +16,10 @@ public ChemicalInfuser() { super(RecipeHandler.Recipe.CHEMICAL_INFUSER); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public ChemicalInfuserRecipe add(GasStack leftInput, GasStack rightInput, GasStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Chemical Infuser recipe").error(); msg.add(Mekanism.isEmpty(leftInput), () -> "left gas input must not be empty"); @@ -21,6 +28,7 @@ public ChemicalInfuserRecipe add(GasStack leftInput, GasStack rightInput, GasSta if (msg.postIfNotEmpty()) return null; ChemicalInfuserRecipe recipe = new ChemicalInfuserRecipe(leftInput.copy(), rightInput.copy(), output.copy()); + addScripted(recipe); recipeRegistry.put(recipe); return recipe; } @@ -39,4 +47,27 @@ public boolean removeByInput(GasStack leftInput, GasStack rightInput) { removeError("could not find recipe for %s and %s", leftInput, rightInput); return false; } + + public static class RecipeBuilder extends GasRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Chemical Infuser recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg); + validateFluids(msg); + validateGases(msg, 2, 2, 1, 1); + } + + @Override + public @Nullable ChemicalInfuserRecipe register() { + if (!validate()) return null; + ChemicalInfuserRecipe recipe = new ChemicalInfuserRecipe(gasInput.get(0), gasInput.get(1), gasOutput.get(0)); + ModSupport.MEKANISM.get().chemicalInfuser.add(recipe); + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalOxidizer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalOxidizer.java index 2f0604e25..d32364385 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalOxidizer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalOxidizer.java @@ -2,6 +2,8 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; @@ -10,6 +12,7 @@ import mekanism.common.recipe.inputs.ItemStackInput; import mekanism.common.recipe.machines.OxidationRecipe; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class ChemicalOxidizer extends VirtualizedMekanismRegistry { @@ -17,6 +20,10 @@ public ChemicalOxidizer() { super(RecipeHandler.Recipe.CHEMICAL_OXIDIZER, VirtualizedRegistry.generateAliases("Oxidizer")); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public OxidationRecipe add(IIngredient ingredient, GasStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Oxidizer recipe").error(); msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); @@ -52,4 +59,31 @@ public boolean removeByInput(IIngredient ingredient) { } return found; } + + public static class RecipeBuilder extends GasRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Chemical Oxidizer recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 0); + validateFluids(msg); + validateGases(msg, 0, 0, 1, 1); + } + + @Override + public @Nullable OxidationRecipe register() { + if (!validate()) return null; + OxidationRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + OxidationRecipe r = new OxidationRecipe(itemStack.copy(), gasOutput.get(0)); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().chemicalOxidizer.add(r); + } + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Combiner.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Combiner.java index c6be963c5..afabd4c9b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Combiner.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Combiner.java @@ -2,12 +2,15 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.DoubleMachineInput; import mekanism.common.recipe.machines.CombinerRecipe; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class Combiner extends VirtualizedMekanismRegistry { @@ -15,6 +18,10 @@ public Combiner() { super(RecipeHandler.Recipe.COMBINER); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public CombinerRecipe add(IIngredient ingredient, ItemStack extra, ItemStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Crusher recipe").error(); msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); @@ -53,4 +60,38 @@ public boolean removeByInput(IIngredient ingredient, ItemStack extra) { } return found; } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private ItemStack extra; + + public RecipeBuilder extra(ItemStack extra) { + this.extra = extra; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Combiner recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + public @Nullable CombinerRecipe register() { + if (!validate()) return null; + CombinerRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + CombinerRecipe r = new CombinerRecipe(itemStack.copy(), extra, output.get(0)); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().combiner.add(r); + } + return recipe; + } + } + } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crusher.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crusher.java index fc7ee47f2..d9131ffa3 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crusher.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crusher.java @@ -2,12 +2,15 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.ItemStackInput; import mekanism.common.recipe.machines.CrusherRecipe; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class Crusher extends VirtualizedMekanismRegistry { @@ -15,6 +18,10 @@ public Crusher() { super(RecipeHandler.Recipe.CRUSHER); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public CrusherRecipe add(IIngredient ingredient, ItemStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Crusher recipe").error(); msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); @@ -50,4 +57,30 @@ public boolean removeByInput(IIngredient ingredient) { } return found; } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Crusher recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + public @Nullable CrusherRecipe register() { + if (!validate()) return null; + CrusherRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + CrusherRecipe r = new CrusherRecipe(itemStack.copy(), output.get(0)); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().crusher.add(r); + } + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crystallizer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crystallizer.java index ff6772fbc..a49f0bf73 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crystallizer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crystallizer.java @@ -1,6 +1,8 @@ package com.cleanroommc.groovyscript.compat.mods.mekanism; import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import mekanism.api.gas.GasStack; @@ -8,6 +10,7 @@ import mekanism.common.recipe.inputs.GasInput; import mekanism.common.recipe.machines.CrystallizerRecipe; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class Crystallizer extends VirtualizedMekanismRegistry { @@ -15,6 +18,10 @@ public Crystallizer() { super(RecipeHandler.Recipe.CHEMICAL_CRYSTALLIZER); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public CrystallizerRecipe add(GasStack input, ItemStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Crystallizer recipe").error(); msg.add(Mekanism.isEmpty(input), () -> "input must not be empty"); @@ -40,4 +47,27 @@ public boolean removeByInput(GasStack input) { removeError("could not find recipe for %", input); return false; } + + public static class RecipeBuilder extends GasRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Crystallizer recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 0, 0, 1, 1); + validateFluids(msg); + validateGases(msg, 1, 1, 0, 0); + } + + @Override + public @Nullable CrystallizerRecipe register() { + if (!validate()) return null; + CrystallizerRecipe recipe = new CrystallizerRecipe(gasInput.get(0), output.get(0)); + ModSupport.MEKANISM.get().crystallizer.add(recipe); + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/DissolutionChamber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/DissolutionChamber.java index a874e39cf..993eb609c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/DissolutionChamber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/DissolutionChamber.java @@ -2,6 +2,8 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; @@ -10,6 +12,7 @@ import mekanism.common.recipe.inputs.ItemStackInput; import mekanism.common.recipe.machines.DissolutionRecipe; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class DissolutionChamber extends VirtualizedMekanismRegistry { @@ -17,6 +20,10 @@ public DissolutionChamber() { super(RecipeHandler.Recipe.CHEMICAL_DISSOLUTION_CHAMBER, VirtualizedRegistry.generateAliases("Dissolver")); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public DissolutionRecipe add(IIngredient ingredient, GasStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Dissolution Chamber recipe").error(); msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); @@ -52,4 +59,31 @@ public boolean removeByInput(IIngredient ingredient) { } return found; } + + public static class RecipeBuilder extends GasRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Dissolution Chamber recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 0); + validateFluids(msg); + validateGases(msg, 0, 0, 1, 1); + } + + @Override + public @Nullable DissolutionRecipe register() { + if (!validate()) return null; + DissolutionRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + DissolutionRecipe r = new DissolutionRecipe(itemStack.copy(), gasOutput.get(0)); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().dissolutionChamber.add(r); + } + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Separator.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ElectrolyticSeparator.java similarity index 56% rename from src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Separator.java rename to src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ElectrolyticSeparator.java index 5b1710a50..0a7b484a7 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Separator.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ElectrolyticSeparator.java @@ -1,6 +1,8 @@ package com.cleanroommc.groovyscript.compat.mods.mekanism; import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; @@ -9,11 +11,16 @@ import mekanism.common.recipe.inputs.FluidInput; import mekanism.common.recipe.machines.SeparatorRecipe; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.Nullable; -public class Separator extends VirtualizedMekanismRegistry { +public class ElectrolyticSeparator extends VirtualizedMekanismRegistry { - public Separator() { - super(RecipeHandler.Recipe.ELECTROLYTIC_SEPARATOR, VirtualizedRegistry.generateAliases("ElectrolyticSeparator")); + public ElectrolyticSeparator() { + super(RecipeHandler.Recipe.ELECTROLYTIC_SEPARATOR, VirtualizedRegistry.generateAliases("Separator")); + } + + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); } public SeparatorRecipe add(FluidStack input, GasStack leftOutput, GasStack rightOutput, double energy) { @@ -24,6 +31,7 @@ public SeparatorRecipe add(FluidStack input, GasStack leftOutput, GasStack right if (msg.postIfNotEmpty()) return null; SeparatorRecipe recipe = new SeparatorRecipe(input.copy(), energy, leftOutput.copy(), rightOutput.copy()); + addScripted(recipe); recipeRegistry.put(recipe); return recipe; } @@ -41,4 +49,34 @@ public boolean removeByInput(FluidStack input) { removeError("could not find recipe for %s", input); return false; } + + public static class RecipeBuilder extends GasRecipeBuilder { + + private double energy; + + public RecipeBuilder energy(double energy) { + this.energy = energy; + return this; + } + @Override + public String getErrorMsg() { + return "Error adding Mekanism Electrolytic Separator recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg); + validateFluids(msg, 1, 1, 0, 0); + validateGases(msg, 0, 0, 2, 2); + msg.add(energy <= 0, "energy must be a nonnegative integer, yet it was {}", energy); + } + + @Override + public @Nullable SeparatorRecipe register() { + if (!validate()) return null; + SeparatorRecipe recipe = new SeparatorRecipe(fluidInput.get(0), energy, gasOutput.get(0), gasOutput.get(1)); + ModSupport.MEKANISM.get().electrolyticSeparator.add(recipe); + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/EnrichmentChamber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/EnrichmentChamber.java index e933ef150..103076900 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/EnrichmentChamber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/EnrichmentChamber.java @@ -2,13 +2,16 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.ItemStackInput; import mekanism.common.recipe.machines.EnrichmentRecipe; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class EnrichmentChamber extends VirtualizedMekanismRegistry { @@ -16,6 +19,10 @@ public EnrichmentChamber() { super(RecipeHandler.Recipe.ENRICHMENT_CHAMBER, VirtualizedRegistry.generateAliases("Enricher")); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public EnrichmentRecipe add(IIngredient ingredient, ItemStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Enrichment Chamber recipe").error(); msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); @@ -51,4 +58,30 @@ public boolean removeByInput(IIngredient ingredient) { } return found; } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Enrichment Chamber recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + public @Nullable EnrichmentRecipe register() { + if (!validate()) return null; + EnrichmentRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + EnrichmentRecipe r = new EnrichmentRecipe(itemStack.copy(), output.get(0)); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().enrichmentChamber.add(r); + } + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Infusion.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Infusion.java new file mode 100644 index 000000000..d3ebf957b --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Infusion.java @@ -0,0 +1,201 @@ +package com.cleanroommc.groovyscript.compat.mods.mekanism; + +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import mekanism.api.infuse.InfuseObject; +import mekanism.api.infuse.InfuseRegistry; +import mekanism.api.infuse.InfuseType; +import net.minecraft.client.Minecraft; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ResourceLocation; +import org.apache.commons.lang3.tuple.Pair; + +import java.util.*; +import java.util.stream.Collectors; + +public class Infusion extends VirtualizedRegistry> { + + private List> objectBackup; + private List> objectScripted; + + public Infusion() { + super(); + this.objectBackup = new ArrayList<>(); + this.objectScripted = new ArrayList<>(); + } + + public static InfusionItems infusion(InfuseType type) { + return new InfusionItems(type); + } + + + public static InfusionItems infusion(String type, ResourceLocation resource) { + return new InfusionItems(type, resource); + } + + public static InfusionItems infusion(String type, String resource) { + return new InfusionItems(type, resource); + } + + public static InfusionItems infusion(String type) { + return new InfusionItems(type); + } + + @Override + public void onReload() { + removeScripted().forEach(pair -> InfuseRegistry.getInfuseMap().put(pair.getKey(), pair.getValue())); + restoreFromBackup().forEach(pair -> InfuseRegistry.getInfuseMap().remove(pair.getKey())); + + this.objectBackup.forEach(pair -> InfuseRegistry.getObjectMap().put(pair.getKey(), pair.getValue())); + this.objectScripted.forEach(pair -> InfuseRegistry.getObjectMap().remove(pair.getKey())); + + this.objectBackup = new ArrayList<>(); + this.objectScripted = new ArrayList<>(); + } + + public void addType(String name, ResourceLocation resource) { + InfuseType infuse = new InfuseType(name.toUpperCase(Locale.ROOT), resource); + infuse.unlocalizedName = name.toLowerCase(Locale.ROOT); + infuse.setIcon(Minecraft.getMinecraft().getTextureMapBlocks().registerSprite(infuse.iconResource)); + addScripted(Pair.of(name.toUpperCase(Locale.ROOT), infuse)); + InfuseRegistry.registerInfuseType(infuse); + } + + public void addType(String name, String resource) { + addType(name, new ResourceLocation(resource)); + } + + public boolean removeType(String name) { + addBackup(Pair.of(name.toUpperCase(Locale.ROOT), InfuseRegistry.get(name))); + InfuseRegistry.getInfuseMap().remove(name.toUpperCase(Locale.ROOT)); + return true; + } + + public void add(InfuseType type, int amount, ItemStack item) { + InfuseObject object = new InfuseObject(type, amount); + this.objectScripted.add(Pair.of(item, object)); + InfuseRegistry.registerInfuseObject(item, object); + } + + public void add(InfuseType type, int amount, IIngredient... ingredients) { + for (ItemStack item : Arrays.stream(ingredients).flatMap(g -> Arrays.stream(g.getMatchingStacks())).collect(Collectors.toList())) { + add(type, amount, item); + } + } + + public void add(String type, int amount, IIngredient... ingredients) { + add(InfuseRegistry.get(type.toUpperCase(Locale.ROOT)), amount, ingredients); + } + + public void add(InfuseType type, int amount, Collection ingredients) { + for (ItemStack item : ingredients.stream().flatMap(g -> Arrays.stream(g.getMatchingStacks())).collect(Collectors.toList())) { + add(type, amount, item); + } + } + + public void add(String type, int amount, Collection ingredients) { + add(InfuseRegistry.get(type.toUpperCase(Locale.ROOT)), amount, ingredients); + } + + public void remove(IIngredient item) { + for (Map.Entry entry : InfuseRegistry.getObjectMap().entrySet().stream().filter(x -> item.test(x.getKey())).collect(Collectors.toList())) { + objectBackup.add(Pair.of(entry.getKey(), entry.getValue())); + InfuseRegistry.getObjectMap().remove(entry.getKey()); + } + } + + public void remove(IIngredient... ingredients) { + for (IIngredient item : ingredients) { + remove(item); + } + } + + public void remove(Collection ingredients) { + for (IIngredient item : ingredients) { + remove(item); + } + } + + public void removeByType(InfuseType type) { + for (Map.Entry entry : InfuseRegistry.getObjectMap().entrySet().stream().filter(x -> x.getValue().type == type).collect(Collectors.toList())) { + objectBackup.add(Pair.of(entry.getKey(), entry.getValue())); + InfuseRegistry.getObjectMap().remove(entry.getKey()); + } + } + + public void removeByType(String type) { + removeByType(InfuseRegistry.get(type.toUpperCase(Locale.ROOT))); + } + + public void removeAll() { + InfuseRegistry.getInfuseMap().forEach((l, r) -> addBackup(Pair.of(l, r))); + InfuseRegistry.getInfuseMap().clear(); + InfuseRegistry.getObjectMap().forEach((l, r) -> objectBackup.add(Pair.of(l, r))); + InfuseRegistry.getObjectMap().clear(); + } + + public static class InfusionItems { + + private InfuseType type; + + public InfusionItems(InfuseType type) { + this.type = type; + } + + public InfusionItems(String type, ResourceLocation resource) { + if (!InfuseRegistry.contains(type.toUpperCase(Locale.ROOT))) ModSupport.MEKANISM.get().infusion.addType(type, resource); + this.type = InfuseRegistry.get(type.toUpperCase(Locale.ROOT)); + } + + public InfusionItems(String type, String resource) { + this(type, new ResourceLocation(resource)); + } + + public InfusionItems(String type) { + if (InfuseRegistry.contains(type.toUpperCase(Locale.ROOT))) this.type = InfuseRegistry.get(type.toUpperCase(Locale.ROOT)); + else GroovyLog.msg("Error creating Mekansim Infusion type") + .add("No ResourceLocation was defined for requested infusion type {}", type) + .error() + .post(); + } + + public InfusionItems add(int amount, IIngredient item) { + ModSupport.MEKANISM.get().infusion.add(type, amount, item); + return this; + } + + public InfusionItems add(int amount, IIngredient... item) { + ModSupport.MEKANISM.get().infusion.add(type, amount, item); + return this; + } + + public InfusionItems add(int amount, Collection item) { + ModSupport.MEKANISM.get().infusion.add(type, amount, item); + return this; + } + + public InfusionItems remove(IIngredient item) { + ModSupport.MEKANISM.get().infusion.remove(item); + return this; + } + + public InfusionItems remove(IIngredient... item) { + ModSupport.MEKANISM.get().infusion.remove(item); + return this; + } + + public InfusionItems remove(Collection item) { + ModSupport.MEKANISM.get().infusion.remove(item); + return this; + } + + public InfusionItems removeAll() { + ModSupport.MEKANISM.get().infusion.removeByType(type); + return this; + } + + } + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/InjectionChamber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/InjectionChamber.java index 43e15cf3c..79f58b4a5 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/InjectionChamber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/InjectionChamber.java @@ -2,6 +2,8 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; @@ -10,6 +12,7 @@ import mekanism.common.recipe.inputs.AdvancedMachineInput; import mekanism.common.recipe.machines.InjectionRecipe; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class InjectionChamber extends VirtualizedMekanismRegistry { @@ -17,6 +20,10 @@ public InjectionChamber() { super(RecipeHandler.Recipe.CHEMICAL_INJECTION_CHAMBER, VirtualizedRegistry.generateAliases("Injector")); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public InjectionRecipe add(IIngredient ingredient, GasStack gasInput, ItemStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Injection Chamber recipe").error(); msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); @@ -54,4 +61,31 @@ public boolean removeByInput(IIngredient ingredient, GasStack gasInput) { } return found; } + + public static class RecipeBuilder extends GasRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Injection Chamber recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + validateGases(msg, 1, 1, 0, 0); + } + + @Override + public @Nullable InjectionRecipe register() { + if (!validate()) return null; + InjectionRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + InjectionRecipe r = new InjectionRecipe(itemStack.copy(), gasInput.get(0).getGas(), output.get(0)); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().injectionChamber.add(r); + } + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Mekanism.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Mekanism.java index 825f6bd0e..91b119704 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Mekanism.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Mekanism.java @@ -6,18 +6,24 @@ import mekanism.api.gas.Gas; import mekanism.api.gas.GasRegistry; import mekanism.api.gas.GasStack; +import mekanism.api.infuse.InfuseRegistry; import net.minecraft.util.text.TextFormatting; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Optional; import org.jetbrains.annotations.Nullable; +import java.util.Locale; + public class Mekanism extends ModPropertyContainer { + public final Infusion infusion = new Infusion(); + public final ChemicalInfuser chemicalInfuser = new ChemicalInfuser(); public final Combiner combiner = new Combiner(); public final Crusher crusher = new Crusher(); public final Crystallizer crystallizer = new Crystallizer(); public final DissolutionChamber dissolutionChamber = new DissolutionChamber(); + public final ElectrolyticSeparator electrolyticSeparator = new ElectrolyticSeparator(); public final EnrichmentChamber enrichmentChamber = new EnrichmentChamber(); public final InjectionChamber injectionChamber = new InjectionChamber(); public final MetallurgicInfuser metallurgicInfuser = new MetallurgicInfuser(); @@ -26,17 +32,20 @@ public class Mekanism extends ModPropertyContainer { public final PressurizedReactionChamber pressurizedReactionChamber = new PressurizedReactionChamber(); public final PurificationChamber purificationChamber = new PurificationChamber(); public final Sawmill sawmill = new Sawmill(); - public final Separator separator = new Separator(); + public final Smelting smelting = new Smelting(); public final SolarNeutronActivator solarNeutronActivator = new SolarNeutronActivator(); - public final ThermalEvaporation thermalEvaporation = new ThermalEvaporation(); + public final ThermalEvaporationPlant thermalEvaporationPlant = new ThermalEvaporationPlant(); public final Washer washer = new Washer(); public Mekanism() { + addRegistry(infusion); + addRegistry(chemicalInfuser); addRegistry(combiner); addRegistry(crusher); addRegistry(crystallizer); addRegistry(dissolutionChamber); + addRegistry(electrolyticSeparator); addRegistry(enrichmentChamber); addRegistry(injectionChamber); addRegistry(metallurgicInfuser); @@ -45,9 +54,9 @@ public Mekanism() { addRegistry(pressurizedReactionChamber); addRegistry(purificationChamber); addRegistry(sawmill); - addRegistry(separator); + addRegistry(smelting); addRegistry(solarNeutronActivator); - addRegistry(thermalEvaporation); + addRegistry(thermalEvaporationPlant); addRegistry(washer); } @@ -57,6 +66,7 @@ public void initialize() { Gas gas = GasRegistry.getGas(s); return gas == null ? null : new GasStack(gas, 1); }); + BracketHandlerManager.registerBracketHandler("infusion", s -> InfuseRegistry.get(s.toUpperCase(Locale.ROOT))); } @Optional.Method(modid = "mekanism") diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/MetallurgicInfuser.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/MetallurgicInfuser.java index 541a9cf61..d0b34754e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/MetallurgicInfuser.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/MetallurgicInfuser.java @@ -2,14 +2,17 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import mekanism.api.infuse.InfuseRegistry; import mekanism.api.infuse.InfuseType; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.InfusionInput; import mekanism.common.recipe.machines.MetallurgicInfuserRecipe; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class MetallurgicInfuser extends VirtualizedMekanismRegistry { @@ -17,37 +20,42 @@ public MetallurgicInfuser() { super(RecipeHandler.Recipe.METALLURGIC_INFUSER); } - public MetallurgicInfuserRecipe add(IIngredient ingredient, String infuseType, int infuseAmount, ItemStack output) { - InfuseType infuseType1 = InfuseRegistry.get(infuseType); + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + public MetallurgicInfuserRecipe add(IIngredient ingredient, InfuseType infuseType, int infuseAmount, ItemStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Metallurgic Infuser recipe").error(); msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); msg.add(IngredientHelper.isEmpty(output), () -> "output must not be empty"); - msg.add(infuseType1 == null, () -> infuseType + " is not a valid infuse type"); + msg.add(infuseType == null, () -> "invalid infusion type"); if (infuseAmount <= 0) infuseAmount = 40; if (msg.postIfNotEmpty()) return null; output = output.copy(); MetallurgicInfuserRecipe recipe1 = null; for (ItemStack itemStack : ingredient.getMatchingStacks()) { - MetallurgicInfuserRecipe recipe = new MetallurgicInfuserRecipe(new InfusionInput(infuseType1, infuseAmount, itemStack.copy()), output); + MetallurgicInfuserRecipe recipe = new MetallurgicInfuserRecipe(new InfusionInput(infuseType, infuseAmount, itemStack.copy()), output); if (recipe1 == null) recipe1 = recipe; recipeRegistry.put(recipe); addScripted(recipe); } return recipe1; } + public MetallurgicInfuserRecipe add(IIngredient ingredient, String infuseType, int infuseAmount, ItemStack output) { + return add(ingredient, InfuseRegistry.get(infuseType), infuseAmount, output); + } - public boolean removeByInput(IIngredient ingredient, String infuseType) { - InfuseType infuseType1 = InfuseRegistry.get(infuseType); + public boolean removeByInput(IIngredient ingredient, InfuseType infuseType) { GroovyLog.Msg msg = GroovyLog.msg("Error removing Mekanism Metallurgic Infuser recipe").error(); msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); - msg.add(infuseType1 == null, () -> infuseType + " is not a valid infuse type"); + msg.add(infuseType == null, () -> "invalid infusion type"); if (msg.postIfNotEmpty()) return false; boolean found = false; for (ItemStack itemStack : ingredient.getMatchingStacks()) { // infuse amount is not hashed so we don't need it - MetallurgicInfuserRecipe recipe = recipeRegistry.get().remove(new InfusionInput(infuseType1, 1, itemStack)); + MetallurgicInfuserRecipe recipe = recipeRegistry.get().remove(new InfusionInput(infuseType, 1, itemStack)); if (recipe != null) { addBackup(recipe); found = true; @@ -58,4 +66,53 @@ public boolean removeByInput(IIngredient ingredient, String infuseType) { } return found; } + + public boolean removeByInput(IIngredient ingredient, String infuseType) { + return removeByInput(ingredient, InfuseRegistry.get(infuseType)); + } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private InfuseType infuse; + private int amount; + + public RecipeBuilder infuse(InfuseType infuse) { + this.infuse = infuse; + return this; + } + + public RecipeBuilder infuse(String infuse) { + return infuse(InfuseRegistry.get(infuse)); + } + + public RecipeBuilder amount(int amount) { + this.amount = amount; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Metallurgic Infuser recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + msg.add(infuse == null, "infuse must be defined"); + msg.add(amount <= 0, "amount must be an integer greater than 0, yet it was {}", amount); + } + + @Override + public @Nullable MetallurgicInfuserRecipe register() { + if (!validate()) return null; + MetallurgicInfuserRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + MetallurgicInfuserRecipe r = new MetallurgicInfuserRecipe(new InfusionInput(infuse, amount, itemStack.copy()), output.get(0)); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().metallurgicInfuser.add(r); + } + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/OsmiumCompressor.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/OsmiumCompressor.java index aace586c6..91ce56e43 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/OsmiumCompressor.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/OsmiumCompressor.java @@ -2,14 +2,19 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import mekanism.api.gas.Gas; import mekanism.api.gas.GasStack; +import mekanism.common.MekanismFluids; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.AdvancedMachineInput; import mekanism.common.recipe.machines.OsmiumCompressorRecipe; import mekanism.common.recipe.outputs.ItemStackOutput; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class OsmiumCompressor extends VirtualizedMekanismRegistry { @@ -17,6 +22,10 @@ public OsmiumCompressor() { super(RecipeHandler.Recipe.OSMIUM_COMPRESSOR); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public OsmiumCompressorRecipe add(IIngredient ingredient, GasStack gasInput, ItemStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Osmium Compressor recipe").error(); msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); @@ -53,4 +62,32 @@ public boolean removeByInput(IIngredient ingredient, GasStack gasInput) { } return found; } + + public static class RecipeBuilder extends GasRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Osmium Compressor recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + validateGases(msg, 0, 1, 0, 0); + } + + @Override + public @Nullable OsmiumCompressorRecipe register() { + if (!validate()) return null; + Gas gas = gasInput.isEmpty() ? MekanismFluids.LiquidOsmium : gasInput.get(0).getGas(); + OsmiumCompressorRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + OsmiumCompressorRecipe r = new OsmiumCompressorRecipe(new AdvancedMachineInput(itemStack.copy(), gas), new ItemStackOutput(output.get(0))); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().osmiumCompressor.add(r); + } + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PressurizedReactionChamber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PressurizedReactionChamber.java index a71759c08..c3061dd93 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PressurizedReactionChamber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PressurizedReactionChamber.java @@ -3,25 +3,22 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; -import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import mekanism.api.gas.GasStack; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.PressurizedInput; import mekanism.common.recipe.machines.PressurizedRecipe; +import mekanism.common.recipe.outputs.PressurizedOutput; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - public class PressurizedReactionChamber extends VirtualizedMekanismRegistry { public PressurizedReactionChamber() { - super(RecipeHandler.Recipe.PRESSURIZED_REACTION_CHAMBER, "PRC"); + super(RecipeHandler.Recipe.PRESSURIZED_REACTION_CHAMBER, "PRC", "prc"); } public RecipeBuilder recipeBuilder() { @@ -62,59 +59,11 @@ public boolean removeByInput(IIngredient inputSolid, FluidStack inputFluid, GasS return found; } - public static class RecipeBuilder extends AbstractRecipeBuilder { + public static class RecipeBuilder extends GasRecipeBuilder { - private final List gasInput = new ArrayList<>(); - private final List gasOutput = new ArrayList<>(); private int duration; private double energy; - public RecipeBuilder gasInput(GasStack gas) { - this.gasInput.add(gas); - return this; - } - - public RecipeBuilder gasInput(Collection gases) { - if (gases != null && !gases.isEmpty()) { - for (GasStack gas : gasInput) { - gasInput(gas); - } - } - return this; - } - - public RecipeBuilder gasInput(GasStack... gases) { - if (gases != null && gases.length > 0) { - for (GasStack gas : gasInput) { - gasInput(gas); - } - } - return this; - } - - public RecipeBuilder gasOutput(GasStack gas) { - this.gasOutput.add(gas); - return this; - } - - public RecipeBuilder gasOutput(Collection gases) { - if (gases != null && !gases.isEmpty()) { - for (GasStack gas : gasOutput) { - gasOutput(gas); - } - } - return this; - } - - public RecipeBuilder gasOutput(GasStack... gases) { - if (gases != null && gases.length > 0) { - for (GasStack gas : gasOutput) { - gasOutput(gas); - } - } - return this; - } - public RecipeBuilder duration(int duration) { this.duration = duration; return this; @@ -132,12 +81,9 @@ public String getErrorMsg() { @Override public void validate(GroovyLog.Msg msg) { - validateItems(msg, 1, 1, 1, 1); + validateItems(msg, 0, 1, 0, 1); validateFluids(msg, 1, 1, 0, 0); - this.gasInput.removeIf(Mekanism::isEmpty); - this.gasOutput.removeIf(Mekanism::isEmpty); - msg.add(this.gasInput.size() != 1, () -> getRequiredString(1, 1, " gas input") + ", but found " + this.gasInput.size()); - msg.add(this.gasOutput.size() != 1, () -> getRequiredString(1, 1, " gas output") + ", but found " + this.gasOutput.size()); + validateGases(msg, 1, 1, 1, 1); if (duration <= 0) duration = 100; if (energy <= 0) energy = 8000; } @@ -145,7 +91,19 @@ public void validate(GroovyLog.Msg msg) { @Override public @Nullable PressurizedRecipe register() { if (!validate()) return null; - return ModSupport.MEKANISM.get().pressurizedReactionChamber.add(input.get(0), fluidInput.get(0), gasInput.get(0), output.get(0), gasOutput.get(0), energy, duration); + PressurizedOutput pressurizedOutput = new PressurizedOutput(output.getOrEmpty(0), gasOutput.get(0)); + PressurizedRecipe recipe = null; + if (input.isEmpty()) { + recipe = new PressurizedRecipe(new PressurizedInput(ItemStack.EMPTY, fluidInput.get(0), gasInput.get(0)), pressurizedOutput, energy, duration); + ModSupport.MEKANISM.get().pressurizedReactionChamber.add(recipe); + } else { + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + PressurizedRecipe r = new PressurizedRecipe(new PressurizedInput(itemStack.copy(), fluidInput.get(0), gasInput.get(0)), pressurizedOutput, energy, duration); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().pressurizedReactionChamber.add(r); + } + } + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PurificationChamber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PurificationChamber.java index 00892834c..108318b83 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PurificationChamber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PurificationChamber.java @@ -2,6 +2,8 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; @@ -11,6 +13,7 @@ import mekanism.common.recipe.machines.PurificationRecipe; import mekanism.common.recipe.outputs.ItemStackOutput; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class PurificationChamber extends VirtualizedMekanismRegistry { @@ -18,6 +21,10 @@ public PurificationChamber() { super(RecipeHandler.Recipe.PURIFICATION_CHAMBER, VirtualizedRegistry.generateAliases("Purifier")); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public PurificationRecipe add(IIngredient ingredient, GasStack gasInput, ItemStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Purification Chamber recipe").error(); msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); @@ -54,4 +61,31 @@ public boolean removeByInput(IIngredient ingredient, GasStack gasInput) { } return found; } + + public static class RecipeBuilder extends GasRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Purification Chamber recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + validateGases(msg, 1, 1, 0, 0); + } + + @Override + public @Nullable PurificationRecipe register() { + if (!validate()) return null; + PurificationRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + PurificationRecipe r = new PurificationRecipe(new AdvancedMachineInput(itemStack.copy(), gasInput.get(0).getGas()), new ItemStackOutput(output.get(0))); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().purificationChamber.add(r); + } + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Sawmill.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Sawmill.java index a58486f29..4eabbb26a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Sawmill.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Sawmill.java @@ -2,13 +2,16 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.ItemStackInput; import mekanism.common.recipe.machines.SawmillRecipe; import mekanism.common.recipe.outputs.ChanceOutput; import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; public class Sawmill extends VirtualizedMekanismRegistry { @@ -16,6 +19,10 @@ public Sawmill() { super(RecipeHandler.Recipe.PRECISION_SAWMILL); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public SawmillRecipe add(IIngredient ingredient, ItemStack output) { return add(ingredient, output, null, 0.0); } @@ -67,4 +74,47 @@ public boolean removeByInput(IIngredient ingredient) { } return found; } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private ItemStack extra = ItemStack.EMPTY; + private double chance = 1.0; + + public RecipeBuilder extra(ItemStack extra) { + this.extra = extra; + return this; + } + + public RecipeBuilder chance(double chance) { + this.chance = chance; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Sawmill recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + msg.add(chance < 0 || chance > 1, "chance must be between 0 and 1.0, yet it was {}", chance); + } + + @Override + public @Nullable SawmillRecipe register() { + if (!validate()) return null; + ChanceOutput chanceOutput = extra.isEmpty() + ? new ChanceOutput(output.get(0)) + : new ChanceOutput(output.get(0), extra, chance); + SawmillRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + SawmillRecipe r = new SawmillRecipe(new ItemStackInput(itemStack.copy()), chanceOutput); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().sawmill.add(r); + } + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Smelting.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Smelting.java new file mode 100644 index 000000000..77a57ad55 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Smelting.java @@ -0,0 +1,87 @@ +package com.cleanroommc.groovyscript.compat.mods.mekanism; + +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; +import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import mekanism.common.recipe.RecipeHandler; +import mekanism.common.recipe.inputs.ItemStackInput; +import mekanism.common.recipe.machines.SmeltingRecipe; +import mekanism.common.recipe.outputs.ItemStackOutput; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +public class Smelting extends VirtualizedMekanismRegistry { + + public Smelting() { + super(RecipeHandler.Recipe.ENERGIZED_SMELTER, VirtualizedMekanismRegistry.generateAliases("Smelter")); + } + + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + public SmeltingRecipe add(IIngredient ingredient, ItemStack output) { + GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Smelter recipe").error(); + msg.add(IngredientHelper.isEmpty(ingredient), () -> "input must not be empty"); + msg.add(IngredientHelper.isEmpty(output), () -> "output must not be empty"); + if (msg.postIfNotEmpty()) return null; + + output = output.copy(); + SmeltingRecipe recipe1 = null; + for (ItemStack itemStack : ingredient.getMatchingStacks()) { + SmeltingRecipe recipe = new SmeltingRecipe(new ItemStackInput(itemStack.copy()), new ItemStackOutput(output)); + if (recipe1 == null) recipe1 = recipe; + recipeRegistry.put(recipe); + addScripted(recipe); + } + return recipe1; + } + + public boolean removeByInput(IIngredient ingredient) { + if (IngredientHelper.isEmpty(ingredient)) { + removeError("input must not be empty"); + return false; + } + boolean found = false; + for (ItemStack itemStack : ingredient.getMatchingStacks()) { + SmeltingRecipe recipe = recipeRegistry.get().remove(new ItemStackInput(itemStack)); + if (recipe != null) { + addBackup(recipe); + found = true; + } + } + if (!found) { + removeError("could not find recipe for %s", ingredient); + } + return found; + } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Smelting recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 1, 1); + validateFluids(msg); + } + + @Override + public @Nullable SmeltingRecipe register() { + if (!validate()) return null; + SmeltingRecipe recipe = null; + for (ItemStack itemStack : input.get(0).getMatchingStacks()) { + SmeltingRecipe r = new SmeltingRecipe(itemStack.copy(), output.get(0)); + if (recipe == null) recipe = r; + ModSupport.MEKANISM.get().smelting.add(r); + } + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/SolarNeutronActivator.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/SolarNeutronActivator.java index a82ff13fb..359b986a2 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/SolarNeutronActivator.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/SolarNeutronActivator.java @@ -1,16 +1,23 @@ package com.cleanroommc.groovyscript.compat.mods.mekanism; import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import mekanism.api.gas.GasStack; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.GasInput; import mekanism.common.recipe.machines.SolarNeutronRecipe; +import org.jetbrains.annotations.Nullable; public class SolarNeutronActivator extends VirtualizedMekanismRegistry { public SolarNeutronActivator() { - super(RecipeHandler.Recipe.SOLAR_NEUTRON_ACTIVATOR, "SNA"); + super(RecipeHandler.Recipe.SOLAR_NEUTRON_ACTIVATOR, "SNA", "sna"); + } + + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); } public SolarNeutronRecipe add(GasStack input, GasStack output) { @@ -38,4 +45,27 @@ public boolean removeByInput(GasStack input) { removeError("could not find recipe for %", input); return false; } + + public static class RecipeBuilder extends GasRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Solar Neutron Activator recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg); + validateFluids(msg); + validateGases(msg, 1, 1, 1, 1); + } + + @Override + public @Nullable SolarNeutronRecipe register() { + if (!validate()) return null; + SolarNeutronRecipe recipe = new SolarNeutronRecipe(gasInput.get(0), gasOutput.get(0)); + ModSupport.MEKANISM.get().solarNeutronActivator.add(recipe); + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ThermalEvaporation.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ThermalEvaporationPlant.java similarity index 56% rename from src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ThermalEvaporation.java rename to src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ThermalEvaporationPlant.java index e633081c8..e86945f89 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ThermalEvaporation.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ThermalEvaporationPlant.java @@ -1,17 +1,27 @@ package com.cleanroommc.groovyscript.compat.mods.mekanism; import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.FluidInput; import mekanism.common.recipe.machines.ThermalEvaporationRecipe; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.Nullable; -public class ThermalEvaporation extends VirtualizedMekanismRegistry { +import java.util.Arrays; - public ThermalEvaporation() { - super(RecipeHandler.Recipe.THERMAL_EVAPORATION_PLANT, "TEP"); +public class ThermalEvaporationPlant extends VirtualizedMekanismRegistry { + + public ThermalEvaporationPlant() { + super(RecipeHandler.Recipe.THERMAL_EVAPORATION_PLANT, "TEP", "tep"); + aliases.addAll(Arrays.asList(VirtualizedMekanismRegistry.generateAliases("ThermalEvaporation"))); + } + + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); } public ThermalEvaporationRecipe add(FluidStack input, FluidStack output) { @@ -39,4 +49,26 @@ public boolean removeByInput(FluidStack input) { removeError("could not find recipe for %", input); return false; } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Thermal Evaporation Plant recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg); + validateFluids(msg, 1, 1, 1, 1); + } + + @Override + public @Nullable ThermalEvaporationRecipe register() { + if (!validate()) return null; + ThermalEvaporationRecipe recipe = new ThermalEvaporationRecipe(fluidInput.get(0), fluidOutput.get(0)); + ModSupport.MEKANISM.get().thermalEvaporationPlant.add(recipe); + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Washer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Washer.java index 8ec160b7b..32124458b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Washer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Washer.java @@ -1,11 +1,14 @@ package com.cleanroommc.groovyscript.compat.mods.mekanism; import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.GasRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.mekanism.recipe.VirtualizedMekanismRegistry; import mekanism.api.gas.GasStack; import mekanism.common.recipe.RecipeHandler; import mekanism.common.recipe.inputs.GasInput; import mekanism.common.recipe.machines.WasherRecipe; +import org.jetbrains.annotations.Nullable; public class Washer extends VirtualizedMekanismRegistry { @@ -13,6 +16,10 @@ public Washer() { super(RecipeHandler.Recipe.CHEMICAL_WASHER); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public WasherRecipe add(GasStack input, GasStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error adding Mekanism Washer recipe").error(); msg.add(Mekanism.isEmpty(input), () -> "input must not be empty"); @@ -38,4 +45,27 @@ public boolean removeByInput(GasStack input) { removeError("could not find recipe for %", input); return false; } + + public static class RecipeBuilder extends GasRecipeBuilder { + + @Override + public String getErrorMsg() { + return "Error adding Mekanism Washer recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg); + validateFluids(msg); + validateGases(msg, 1, 1, 1, 1); + } + + @Override + public @Nullable WasherRecipe register() { + if (!validate()) return null; + WasherRecipe recipe = new WasherRecipe(gasInput.get(0), gasOutput.get(0)); + ModSupport.MEKANISM.get().washer.add(recipe); + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/GasRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/GasRecipeBuilder.java new file mode 100644 index 000000000..ca3bafd94 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/GasRecipeBuilder.java @@ -0,0 +1,66 @@ +package com.cleanroommc.groovyscript.compat.mods.mekanism.recipe; + +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import mekanism.api.gas.GasStack; + +import java.util.Collection; + +public abstract class GasRecipeBuilder extends AbstractRecipeBuilder { + + protected final GasStackList gasInput = new GasStackList(); + protected final GasStackList gasOutput = new GasStackList(); + + public GasRecipeBuilder gasInput(GasStack gas) { + this.gasInput.add(gas); + return this; + } + + public GasRecipeBuilder gasInput(Collection gases) { + for (GasStack gas : gases) { + gasInput(gas); + } + return this; + } + + public GasRecipeBuilder gasInput(GasStack... gases) { + for (GasStack gas : gases) { + gasInput(gas); + } + return this; + } + + public GasRecipeBuilder gasOutput(GasStack gas) { + this.gasOutput.add(gas); + return this; + } + + public GasRecipeBuilder gasOutput(Collection gases) { + for (GasStack gas : gases) { + gasOutput(gas); + } + return this; + } + + public GasRecipeBuilder gasOutput(GasStack... gases) { + for (GasStack gas : gases) { + gasOutput(gas); + } + return this; + } + + + public void validateGases(GroovyLog.Msg msg, int minInput, int maxInput, int minOutput, int maxOutput) { + gasInput.trim(); + gasOutput.trim(); + msg.add(gasInput.size() < minInput || gasInput.size() > maxInput, () -> getRequiredString(minInput, maxInput, "gas input") + ", but found " + gasInput.size()); + msg.add(gasOutput.size() < minOutput || gasOutput.size() > maxOutput, () -> getRequiredString(minOutput, maxOutput, "gas output") + ", but found " + gasOutput.size()); + } + + public void validateGases(GroovyLog.Msg msg) { + validateItems(msg, 0, 0, 0, 0); + } + + + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/GasStackList.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/GasStackList.java new file mode 100644 index 000000000..8c9779007 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/GasStackList.java @@ -0,0 +1,49 @@ +package com.cleanroommc.groovyscript.compat.mods.mekanism.recipe; + +import com.cleanroommc.groovyscript.compat.mods.mekanism.Mekanism; +import mekanism.api.gas.GasStack; + +import java.util.ArrayList; +import java.util.Collection; + +public class GasStackList extends ArrayList { + + public GasStackList() { + } + + public GasStackList(Collection collection) { + super(collection); + } + + public GasStack getOrEmpty(int i) { + if (i < 0 || i >= size()) { + return null; + } + return get(i); + } + + public int getRealSize() { + if (isEmpty()) return 0; + int realSize = 0; + for (GasStack t : this) { + if (!Mekanism.isEmpty(t)) realSize++; + } + return realSize; + } + + public void trim() { + if (!isEmpty()) { + removeIf(Mekanism::isEmpty); + } + } + + public void copyElements() { + for (int i = 0; i < size(); i++) { + GasStack gasStack = get(i); + if (!Mekanism.isEmpty(gasStack)) { + set(i, gasStack.copy()); + } + } + } + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/VirtualizedMekanismRegistry.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/VirtualizedMekanismRegistry.java index a26bad84c..da88bef4c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/VirtualizedMekanismRegistry.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/recipe/VirtualizedMekanismRegistry.java @@ -25,6 +25,11 @@ public void onReload() { restoreFromBackup().forEach(recipeRegistry::put); } + public void add(R recipe) { + recipeRegistry.put(recipe); + addScripted(recipe); + } + public boolean remove(R recipe) { if (recipeRegistry.get().remove(recipe) != null) { addBackup(recipe); @@ -38,6 +43,11 @@ public SimpleObjectStream streamRecipes() { .setRemover(this::remove); } + public void removeAll() { + recipeRegistry.get().values().forEach(this::addBackup); + recipeRegistry.get().clear(); + } + @GroovyBlacklist public void removeError(String reason, Object... data) { GroovyLog.msg("Error removing Mekanism " + getAliases().get(0) + " recipe") From 1941705349dac66ca5f11385985e0620fde4de94 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Fri, 7 Jul 2023 07:30:50 -0700 Subject: [PATCH 04/28] immersive engineering examples and also overboard --- build.gradle | 4 +- examples/immersiveengineering.groovy | 220 +++++++++++++++++ gradle.properties | 2 +- .../mods/immersiveengineering/AlloyKiln.java | 18 +- .../mods/immersiveengineering/ArcFurnace.java | 121 +++++++--- .../immersiveengineering/BlastFurnace.java | 15 +- .../BlastFurnaceFuel.java | 109 +++++++++ .../BlueprintCrafting.java | 17 +- .../immersiveengineering/BottlingMachine.java | 21 +- .../mods/immersiveengineering/CokeOven.java | 19 +- .../mods/immersiveengineering/Crusher.java | 8 +- .../mods/immersiveengineering/Excavator.java | 222 ++++++++++++++++++ .../mods/immersiveengineering/Fermenter.java | 8 +- .../ImmersiveEngineering.java | 12 + .../mods/immersiveengineering/MetalPress.java | 36 +-- .../mods/immersiveengineering/Mixer.java | 58 +++-- .../mods/immersiveengineering/Refinery.java | 23 +- .../mods/immersiveengineering/Squeezer.java | 47 +++- 18 files changed, 827 insertions(+), 133 deletions(-) create mode 100644 examples/immersiveengineering.groovy create mode 100644 src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlastFurnaceFuel.java create mode 100644 src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Excavator.java diff --git a/build.gradle b/build.gradle index c8185ac47..dd8a1c14e 100644 --- a/build.gradle +++ b/build.gradle @@ -201,7 +201,7 @@ dependencies { } compileOnly rfg.deobf('curse.maven:immersive_engineering-231951:2974106') - if (project.debug_ie.toBoolean()) { + if (project.debug_immersive_engineering.toBoolean()) { runtimeOnly rfg.deobf('curse.maven:immersive_engineering-231951:2974106') } @@ -229,7 +229,7 @@ dependencies { } compileOnly rfg.deobf('curse.maven:immersive_engineering-231951:2974106') - if (project.debug_ie.toBoolean()) { + if (project.debug_immersive_engineering.toBoolean()) { runtimeOnly rfg.deobf('curse.maven:immersive_engineering-231951:2974106') } diff --git a/examples/immersiveengineering.groovy b/examples/immersiveengineering.groovy new file mode 100644 index 000000000..23d756ea0 --- /dev/null +++ b/examples/immersiveengineering.groovy @@ -0,0 +1,220 @@ + +// Alloy Kiln: +// Converts two input itemstacks into an output itemstack, consuming fuel (based on burn time). +mods.immersiveengineering.alloykiln.recipeBuilder() + .input(item('minecraft:diamond'), ore('ingotGold')) + .output(item('minecraft:clay')) + .register() + +mods.immersiveengineering.alloykiln.removeByInput(item('minecraft:gold_ingot'), item('immersiveengineering:metal:3')) +mods.immersiveengineering.alloykiln.removeByOutput(item('immersiveengineering:metal:6')) +//mods.immersiveengineering.alloykiln.removeAll() + + +// Arc Furnace: +// Converts 1 input itemstack with up to 4 additional inputs into an output itemstack and an optional 'slag' itemstack, taking time and using rf power. +mods.immersiveengineering.arcfurnace.recipeBuilder() + .mainInput(item('minecraft:diamond')) + .input(item('minecraft:diamond'), ore('ingotGold')) + .output(item('minecraft:clay')) + .time(100) + .energyPerTick(100) + .slag(item('minecraft:gold_nugget')) + .register() + +mods.immersiveengineering.arcfurnace.removeByInput(item('immersiveengineering:metal:18'), item('immersiveengineering:material:17')) +mods.immersiveengineering.arcfurnace.removeByOutput(item('immersiveengineering:metal:7')) +//mods.immersiveengineering.arcfurnace.removeAll() + + +// Blast Furnace: +// Converts an input itemstack into an output itemstack and an optional 'slag' itemstack, taking time and consuming fuel (based on Blast Furnace Fuels). +mods.immersiveengineering.blastfurnace.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .time(100) + .slag(item('minecraft:gold_nugget')) + .register() + +mods.immersiveengineering.blastfurnace.removeByInput(item('minecraft:iron_block')) +mods.immersiveengineering.blastfurnace.removeByOutput(item('immersiveengineering:metal:8')) +//mods.immersiveengineering.blastfurnace.removeAll() + + +// Blast Furnace Fuel: +// Allows an item to be used in the Blast Furnace as a fuel for the given number of ticks. +mods.immersiveengineering.blastfurnacefuel.recipeBuilder() + .input(item('minecraft:clay')) + .time(100) + .register() + +mods.immersiveengineering.blastfurnacefuel.removeByInput(item('immersiveengineering:material:6')) +//mods.immersiveengineering.blastfurnacefuel.removeAll() + + +// Blueprint Crafting (Blueprint): +// Converts any number of input itemstacks into an output itemstack, using a blueprint with the category nbt tag as a catalyst. +mods.immersiveengineering.blueprint.recipeBuilder() + .input(item('minecraft:diamond'), ore('ingotGold')) + .output(item('minecraft:clay')) + .category('groovy') // Default blueprint options: components, molds, bullet, specialBullet, electrode. + .register() + +mods.immersiveengineering.blueprint.removeByCategory('electrode') +mods.immersiveengineering.blueprint.removeByInput('components', item('immersiveengineering:metal:38'), item('immersiveengineering:metal:38'), item('immersiveengineering:metal')) +mods.immersiveengineering.blueprint.removeByOutput('components', item('immersiveengineering:material:8')) +//mods.immersiveengineering.blueprint.removeAll() + + +// Bottling Machine (Bottling): +// Converts an input itemstack and fluidstack into an output itemstack. +mods.immersiveengineering.bottling.recipeBuilder() + .input(item('minecraft:diamond')) + .fluidInput(fluid('water')) + .output(item('minecraft:clay')) + .register() + +mods.immersiveengineering.bottling.removeByInput(item('minecraft:sponge'), fluid('water') * 1000) +mods.immersiveengineering.bottling.removeByOutput(item('minecraft:potion').withNbt([Potion:'minecraft:mundane'])) +//mods.immersiveengineering.bottling.removeAll() + + +// Coke Oven: +// Converts an input itemstack into an output itemstack over time, producing a given amount of creosote oil. +mods.immersiveengineering.cokeoven.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .time(100) + .creosote(50) + .register() + +mods.immersiveengineering.cokeoven.removeByInput(item('minecraft:log')) +mods.immersiveengineering.cokeoven.removeByOutput(item('immersiveengineering:material:6')) +//mods.immersiveengineering.cokeoven.removeAll() + + +// Crusher: +// Converts an input itemstack into an output itemstack, consuming energy. +mods.immersiveengineering.crusher.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .energy(100) + .register() + +mods.immersiveengineering.crusher.removeByInput(item('immersiveengineering:material:7')) +mods.immersiveengineering.crusher.removeByOutput(item('minecraft:sand')) +//mods.immersiveengineering.crusher.removeAll() + + +// Excavator: +// Adds a Mineral Mix with the given name, weight, fail chance, ores, and allowed dimensions. A Mineral Mix can be mined +// by an Excavator Multiblock. +// WARNING: reloading will not change chunks already 'discovered' +mods.immersiveengineering.excavator.recipeBuilder() + .name('demo') + .weight(20000) + .fail(0.5) + .ore(ore('blockDiamond'), 50) + .ore('blockGold', 10) + .dimension(0, 1) + .register() + +mods.immersiveengineering.excavator.recipeBuilder() + .name('demo') + .weight(2000) + .fail(0.1) + .ore(ore('blockDiamond'), 50) + .dimension(-1, 1) + .blacklist() + .register() + +mods.immersiveengineering.excavator.removeByOres(ore('oreAluminum')) +mods.immersiveengineering.excavator.removeByMineral('silt') +//mods.immersiveengineering.excavator.removeAll() + + +// Fermenter: +// Converts an input itemstack into an output fluidstack with an optional output itemstack, consuming power. +mods.immersiveengineering.fermenter.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) // Optional + .fluidOutput(fluid('water')) + .energy(100) + .register() + +mods.immersiveengineering.fermenter.removeByInput(item('minecraft:reeds')) +mods.immersiveengineering.fermenter.removeByOutput(fluid('ethanol')) +//mods.immersiveengineering.fermenter.removeAll() + + +// Metal Press: +// Converts an input itemstack into an output itemstack, with a mold catalyst, consuming power. +mods.immersiveengineering.metalpress.recipeBuilder() + .mold(item('minecraft:diamond')) + .input(ore('ingotGold')) + .output(item('minecraft:clay')) + .energy(100) + .register() + +mods.immersiveengineering.metalpress.removeByInput(item('minecraft:iron_ingot')) +mods.immersiveengineering.metalpress.removeByInput(item('immersiveengineering:mold'), item('immersiveengineering:metal:8')) +mods.immersiveengineering.metalpress.removeByOutput(item('immersiveengineering:material:23')) +mods.immersiveengineering.metalpress.removeByOutput(item('immersiveengineering:mold'), item('immersiveengineering:metal:31')) +mods.immersiveengineering.metalpress.removeByMold(item('immersiveengineering:mold:4')) +//mods.immersiveengineering.metalpress.removeAll() + + +// Mixer: +// Converts any number of input itemstacks and a fluidstack into an output fluidstack, consuming power. +mods.immersiveengineering.mixer.recipeBuilder() + .input(item('minecraft:diamond'), ore('ingotGold'), ore('ingotGold'), ore('ingotGold')) + .fluidInput(fluid('water')) + .fluidOutput(fluid('lava')) + .energy(100) + .register() + +mods.immersiveengineering.mixer.removeByInput(item('minecraft:sand'), item('minecraft:sand'), item('minecraft:clay_ball'), item('minecraft:gravel')) +mods.immersiveengineering.mixer.removeByInput(fluid('water'), item('minecraft:speckled_melon')) +mods.immersiveengineering.mixer.removeByOutput(fluid('potion').withNbt([Potion:'minecraft:night_vision'])) +//mods.immersiveengineering.mixer.removeAll() + + +// Refinery: +// Converts 2 input fluidstacks into an output fluidstack, consuming power. +mods.immersiveengineering.refinery.recipeBuilder() + .fluidInput(fluid('water'), fluid('water')) + .fluidOutput(fluid('lava')) + .energy(100) + .register() + +mods.immersiveengineering.refinery.removeByInput(fluid('plantoil'), fluid('ethanol')) +//mods.immersiveengineering.refinery.removeByOutput(fluid('biodiesel')) // <- already removed by 'removeByInput' line +//mods.immersiveengineering.refinery.removeAll() + + +// Squeezer: +// Converts an input itemstack into either an output itemstack, fluidstack, or both, using energy. +mods.immersiveengineering.squeezer.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) // Either an output itemstack or output fluidstack must be defined + .fluidOutput(fluid('lava')) // Either an output itemstack or output fluidstack must be defined + .energy(100) + .register() + +// WARNING: If only an output itemstack is defined, the itemstack will not display in JEI. +mods.immersiveengineering.squeezer.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay')) // Either an output itemstack or output fluidstack must be defined + .energy(100) + .register() + +mods.immersiveengineering.squeezer.recipeBuilder() + .input(item('minecraft:clay')) + .fluidOutput(fluid('water')) // Either an output itemstack or output fluidstack must be defined + .energy(100) + .register() + +mods.immersiveengineering.squeezer.removeByInput(item('minecraft:wheat_seeds')) +mods.immersiveengineering.squeezer.removeByOutput(fluid('plantoil')) +mods.immersiveengineering.squeezer.removeByOutput(item('immersiveengineering:material:18')) +//mods.immersiveengineering.squeezer.removeAll() diff --git a/gradle.properties b/gradle.properties index 45b8d1e12..a0ed5a55d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -24,7 +24,7 @@ debug_thermal = false debug_thaum = false debug_ic2 = false debug_draconic_evolution = false -debug_ie = false +debug_immersive_engineering = false debug_enderio = false debug_astral = false debug_roots = false diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/AlloyKiln.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/AlloyKiln.java index d2c1ffb1e..905148647 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/AlloyKiln.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/AlloyKiln.java @@ -7,6 +7,7 @@ import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.ApiStatus; @@ -63,7 +64,7 @@ public void removeByOutput(ItemStack output) { List recipes = AlloyRecipe.removeRecipes(output); if (recipes.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Alloy Kiln recipe") - .add("no recipes found for %s", output) + .add("no recipes found for {}", output) .error() .post(); return; @@ -84,7 +85,7 @@ public void removeByInput(ItemStack input, ItemStack input1) { remove(recipe); } else { GroovyLog.msg("Error removing Immersive Engineering Alloy Kiln recipe") - .add("no recipes found for %s and %s", input, input1) + .add("no recipes found for {} and {}", input, input1) .error() .post(); } @@ -99,7 +100,14 @@ public void removeAll() { AlloyRecipe.recipeList.clear(); } - public static class RecipeBuilder extends TimeRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private int time; + + public RecipeBuilder time(int time) { + this.time = time; + return this; + } @Override public String getErrorMsg() { @@ -116,7 +124,9 @@ public void validate(GroovyLog.Msg msg) { @Override public @Nullable AlloyRecipe register() { if (!validate()) return null; - return ModSupport.IMMERSIVE_ENGINEERING.get().alloyKiln.add(output.get(0), input.get(0), input.get(1), time); + AlloyRecipe recipe = new AlloyRecipe(output.get(0), ImmersiveEngineering.toIngredientStack(input.get(0)), ImmersiveEngineering.toIngredientStack(input.get(1)), time); + ModSupport.IMMERSIVE_ENGINEERING.get().alloyKiln.add(recipe); + return recipe; } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ArcFurnace.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ArcFurnace.java index e5cf12145..926b2c7b2 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ArcFurnace.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ArcFurnace.java @@ -1,7 +1,6 @@ package com.cleanroommc.groovyscript.compat.mods.immersiveengineering; import blusunrize.immersiveengineering.api.crafting.ArcFurnaceRecipe; -import blusunrize.immersiveengineering.api.crafting.IngredientStack; import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; @@ -9,14 +8,17 @@ import com.cleanroommc.groovyscript.helper.ArrayUtils; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; -import net.minecraft.util.NonNullList; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import javax.annotation.Nonnull; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; public class ArcFurnace extends VirtualizedRegistry { @@ -44,8 +46,8 @@ public void add(ArcFurnaceRecipe recipe) { } public ArcFurnaceRecipe add(ItemStack output, IIngredient input, List additives, @Nonnull ItemStack slag, int time, int energyPerTick) { - IngredientStack[] inputs = ArrayUtils.mapToArray(additives, ImmersiveEngineering::toIngredientStack); - ArcFurnaceRecipe recipe = ArcFurnaceRecipe.addRecipe(output, ImmersiveEngineering.toIngredientStack(input), slag, time, energyPerTick, (Object[]) inputs); + Object[] inputs = ArrayUtils.mapToArray(additives, ImmersiveEngineering::toIngredientStack); + ArcFurnaceRecipe recipe = ArcFurnaceRecipe.addRecipe(output, ImmersiveEngineering.toIngredientStack(input), slag, time, energyPerTick, inputs); addScripted(recipe); return recipe; } @@ -66,40 +68,55 @@ public void removeByOutput(ItemStack output) { .post(); return; } - List list = ArcFurnaceRecipe.removeRecipes(output); - if (list.isEmpty()) { + List recipes = ArcFurnaceRecipe.recipeList.stream().filter(r -> r.output != null && r.output.isItemEqual(output)).collect(Collectors.toList()); + for (ArcFurnaceRecipe recipe : recipes) { + remove(recipe); + } + if (recipes.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Arc Furnace recipe") - .add("no recipes found for %s", output) + .add("no recipes found for {}", output) .error() .post(); - return; } - list.forEach(this::addBackup); } - public void removeByInput(List inputAndAdditives) { - if (inputAndAdditives == null || inputAndAdditives.isEmpty()) { + public void removeByInput(IIngredient main, List inputAndAdditives) { + if (main == null || main.isEmpty() || inputAndAdditives == null || inputAndAdditives.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Arc Furnace recipe") .add("inputs must not be empty") .error() .post(); return; } - - NonNullList list = NonNullList.create(); - ItemStack main = inputAndAdditives.get(0); - inputAndAdditives.remove(0); - list.addAll(inputAndAdditives); - ArcFurnaceRecipe recipe = ArcFurnaceRecipe.findRecipe(main, list); - if (recipe != null) { + List recipes = ArcFurnaceRecipe.recipeList.stream() + .filter(r -> ImmersiveEngineering.areIngredientsEquals(r.input, main) && + (inputAndAdditives.stream().anyMatch(check -> Arrays.stream(r.additives).anyMatch(target -> ImmersiveEngineering.areIngredientsEquals(target, check))))) + .collect(Collectors.toList()); + for (ArcFurnaceRecipe recipe : recipes) { remove(recipe); - } else { - inputAndAdditives.add(0, main); - GroovyLog.msg("Error removing Immersive Engineering Alloy Kiln recipe") - .add("no recipes found for %s", inputAndAdditives) + } + if (recipes.isEmpty()) { + GroovyLog.msg("Error removing Immersive Engineering Arc Furnace recipe") + .add("no recipes found with a main ingredient of {}, and additives of {}", main, inputAndAdditives) + .error() + .post(); + } + } + + + public void removeByInput(List inputAndAdditives) { + if (inputAndAdditives == null || inputAndAdditives.isEmpty()) { + GroovyLog.msg("Error removing Immersive Engineering Arc Furnace recipe") + .add("inputs must not be empty") .error() .post(); + return; } + removeByInput(inputAndAdditives.remove(0), inputAndAdditives); + } + + public void removeByInput(IIngredient... inputAndAdditives) { + removeByInput(new ArrayList<>(Arrays.asList(inputAndAdditives))); } public SimpleObjectStream streamRecipes() { @@ -111,10 +128,24 @@ public void removeAll() { ArcFurnaceRecipe.recipeList.clear(); } - public static class RecipeBuilder extends TimeRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { - protected int energyPerTick; - protected ItemStack slag; + private int time; + private IIngredient mainInput; + private int energyPerTick; + private ItemStack slag = ItemStack.EMPTY; + private String specialRecipeType; + + + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + + public RecipeBuilder mainInput(IIngredient mainInput) { + this.mainInput = mainInput; + return this; + } public RecipeBuilder energyPerTick(int energy) { this.energyPerTick = energy; @@ -126,6 +157,26 @@ public RecipeBuilder slag(ItemStack slag) { return this; } + public RecipeBuilder specialRecipeType(String specialRecipeType) { + this.specialRecipeType = specialRecipeType; + return this; + } + + public RecipeBuilder alloying() { + this.specialRecipeType = "Alloying"; + return this; + } + + public RecipeBuilder ores() { + this.specialRecipeType = "Ores"; + return this; + } + + public RecipeBuilder recycling() { + this.specialRecipeType = "Recycling"; + return this; + } + @Override public String getErrorMsg() { return "Error adding Immersive Engineering Arc Furnace recipe"; @@ -133,19 +184,25 @@ public String getErrorMsg() { @Override public void validate(GroovyLog.Msg msg) { - validateItems(msg, 1, 5, 1, 1); + if (input.size() >= 2 && mainInput == null) { + mainInput = input.remove(0); + } + validateItems(msg, 0, 4, 1, 1); validateFluids(msg); - if (time < 0) time = 200; - if (energyPerTick < 0) energyPerTick = 100; - if (slag == null) slag = ItemStack.EMPTY; + msg.add(mainInput == null, "mainInput must be defined"); + msg.add(time <= 0, "time must be greater than 0, yet it was {}", time); + msg.add(energyPerTick <= 0, "energyPerTick must be greater than 0, yet it was {}", energyPerTick); + msg.add(slag == null, "slag must be defined"); } @Override public @Nullable ArcFurnaceRecipe register() { if (!validate()) return null; - IIngredient mainInput = input.get(0); - input.remove(0); - return ModSupport.IMMERSIVE_ENGINEERING.get().arcFurnace.add(output.get(0), mainInput, input, slag, time, energyPerTick); + Object[] additives = ArrayUtils.mapToArray(input, ImmersiveEngineering::toIngredientStack); + ArcFurnaceRecipe recipe = new ArcFurnaceRecipe(output.get(0), mainInput, slag, time, energyPerTick, additives); + if (specialRecipeType != null) recipe.setSpecialRecipeType(specialRecipeType); + ModSupport.IMMERSIVE_ENGINEERING.get().arcFurnace.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlastFurnace.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlastFurnace.java index 1a676976a..7839ce992 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlastFurnace.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlastFurnace.java @@ -6,6 +6,7 @@ import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.Nullable; @@ -61,7 +62,7 @@ public void removeByOutput(ItemStack output) { List list = BlastFurnaceRecipe.removeRecipes(output); if (list.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Blast Furnace recipe") - .add("no recipes found for %s", output) + .add("no recipes found for {}", output) .error() .post(); return; @@ -82,7 +83,7 @@ public void removeByInput(ItemStack input) { remove(recipe); } else { GroovyLog.msg("Error removing Immersive Engineering Blast Furnace recipe") - .add("no recipes found for %s", input) + .add("no recipes found for {}", input) .error() .post(); } @@ -97,9 +98,15 @@ public void removeAll() { BlastFurnaceRecipe.recipeList.clear(); } - public static class RecipeBuilder extends TimeRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { - protected ItemStack slag; + private int time; + private ItemStack slag; + + public RecipeBuilder time(int time) { + this.time = time; + return this; + } public RecipeBuilder slag(ItemStack slag) { this.slag = slag; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlastFurnaceFuel.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlastFurnaceFuel.java new file mode 100644 index 000000000..0b4ab7caf --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlastFurnaceFuel.java @@ -0,0 +1,109 @@ +package com.cleanroommc.groovyscript.compat.mods.immersiveengineering; + +import blusunrize.immersiveengineering.api.crafting.BlastFurnaceRecipe; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; +import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +import java.util.List; +import java.util.stream.Collectors; + +public class BlastFurnaceFuel extends VirtualizedRegistry { + + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public void onReload() { + removeScripted().forEach(recipe -> BlastFurnaceRecipe.blastFuels.removeIf(r -> r == recipe)); + BlastFurnaceRecipe.blastFuels.addAll(restoreFromBackup()); + } + + public void add(BlastFurnaceRecipe.BlastFurnaceFuel recipe) { + if (recipe != null) { + addScripted(recipe); + BlastFurnaceRecipe.blastFuels.add(recipe); + } + } + + public BlastFurnaceRecipe.BlastFurnaceFuel add(IIngredient input, int time) { + BlastFurnaceRecipe.BlastFurnaceFuel recipe = new BlastFurnaceRecipe.BlastFurnaceFuel(ImmersiveEngineering.toIngredientStack(input), time); + add(recipe); + return recipe; + } + + public boolean remove(BlastFurnaceRecipe.BlastFurnaceFuel recipe) { + if (BlastFurnaceRecipe.blastFuels.removeIf(r -> r == recipe)) { + addBackup(recipe); + return true; + } + return false; + } + + public void removeByInput(ItemStack input) { + if (IngredientHelper.isEmpty(input)) { + GroovyLog.msg("Error removing Immersive Engineering Blast Furnace recipe") + .add("input must not be empty") + .error() + .post(); + return; + } + List recipes = BlastFurnaceRecipe.blastFuels.stream().filter(r -> r.input.matches(input)).collect(Collectors.toList()); + for (BlastFurnaceRecipe.BlastFurnaceFuel recipe : recipes) { + remove(recipe); + } + if (recipes.isEmpty()) { + GroovyLog.msg("Error removing Immersive Engineering Blast Furnace recipe") + .add("no recipes found for {}", input) + .error() + .post(); + } + } + + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(BlastFurnaceRecipe.blastFuels).setRemover(this::remove); + } + + public void removeAll() { + BlastFurnaceRecipe.blastFuels.forEach(this::addBackup); + BlastFurnaceRecipe.blastFuels.clear(); + } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private int time; + + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Immersive Engineering Blast Furnace Fuel"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 0); + validateFluids(msg); + if (time < 0) time = 200; + } + + @Override + public @Nullable BlastFurnaceRecipe.BlastFurnaceFuel register() { + if (!validate()) return null; + BlastFurnaceRecipe.BlastFurnaceFuel recipe = new BlastFurnaceRecipe.BlastFurnaceFuel(ImmersiveEngineering.toIngredientStack(input.get(0)), time); + ModSupport.IMMERSIVE_ENGINEERING.get().blastFurnaceFuel.add(recipe); + return recipe; + } + } + +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlueprintCrafting.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlueprintCrafting.java index 8a5a0fd51..b1d5eece1 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlueprintCrafting.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BlueprintCrafting.java @@ -50,7 +50,7 @@ public void add(BlueprintCraftingRecipe recipe) { } public BlueprintCraftingRecipe add(String blueprintCategory, ItemStack output, List inputs) { - IngredientStack[] inputs1 = ArrayUtils.mapToArray(inputs, ImmersiveEngineering::toIngredientStack); + Object[] inputs1 = ArrayUtils.mapToArray(inputs, ImmersiveEngineering::toIngredientStack); BlueprintCraftingRecipe recipe = new BlueprintCraftingRecipe(blueprintCategory, output.copy(), inputs1); add(recipe); return recipe; @@ -67,7 +67,7 @@ public boolean remove(BlueprintCraftingRecipe recipe) { public void removeByCategory(String blueprintCategory) { if (!BlueprintCraftingRecipe.recipeList.containsKey(blueprintCategory)) { GroovyLog.msg("Error removing Immersive Engineering Blueprint Crafting recipe") - .add("category %s does not exist", blueprintCategory) + .add("category {} does not exist", blueprintCategory) .error() .post(); return; @@ -94,7 +94,7 @@ public void removeByOutput(String blueprintCategory, ItemStack output) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Blueprint Crafting recipe") - .add("no recipes found for %s", output) + .add("no recipes found for {}", output) .error() .post(); } @@ -126,7 +126,7 @@ public void removeByInput(String blueprintCategory, ItemStack... inputs) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Blueprint Crafting recipe") - .add("no recipes found for %s", Arrays.toString(inputs)) + .add("no recipes found for {}", Arrays.toString(inputs)) .error() .post(); } @@ -154,7 +154,7 @@ public void removeAll() { public static class RecipeBuilder extends AbstractRecipeBuilder { - protected String category; + private String category; public RecipeBuilder category(String category) { this.category = category; @@ -168,7 +168,7 @@ public String getErrorMsg() { @Override public void validate(GroovyLog.Msg msg) { - validateItems(msg, 1, 6, 1, 1); + validateItems(msg, 1, Integer.MAX_VALUE, 1, 1); validateFluids(msg); if (this.category == null) this.category = BlueprintCraftingRecipe.blueprintCategories.get(0); } @@ -176,7 +176,10 @@ public void validate(GroovyLog.Msg msg) { @Override public @Nullable BlueprintCraftingRecipe register() { if (!validate()) return null; - return ModSupport.IMMERSIVE_ENGINEERING.get().blueprint.add(category, output.get(0), input); + Object[] inputs = ArrayUtils.mapToArray(input, ImmersiveEngineering::toIngredientStack); + BlueprintCraftingRecipe recipe = new BlueprintCraftingRecipe(category, output.get(0), inputs); + ModSupport.IMMERSIVE_ENGINEERING.get().blueprint.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BottlingMachine.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BottlingMachine.java index 08f66bfe4..a06d0ef0f 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BottlingMachine.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/BottlingMachine.java @@ -13,6 +13,9 @@ import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; +import java.util.List; +import java.util.stream.Collectors; + public class BottlingMachine extends VirtualizedRegistry { public BottlingMachine() { @@ -66,7 +69,7 @@ public void removeByOutput(ItemStack output) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Bottling Machine recipe") - .add("no recipes found for %s", output) + .add("no recipes found for {}", output) .error() .post(); } @@ -80,13 +83,13 @@ public void removeByInput(ItemStack input, FluidStack inputFluid) { .postIfNotEmpty()) { return; } - BottlingMachineRecipe recipe = BottlingMachineRecipe.findRecipe(input, inputFluid); - if (recipe != null) { - addBackup(recipe); - BottlingMachineRecipe.recipeList.remove(recipe); - } else { + List recipes = BottlingMachineRecipe.recipeList.stream().filter(r -> ApiUtils.stackMatchesObject(input, r.input) && inputFluid.isFluidEqual(r.fluidInput)).collect(Collectors.toList()); + for (BottlingMachineRecipe recipe : recipes) { + remove(recipe); + } + if (recipes.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Bottling Machine recipe") - .add("no recipes found for %s and %s", input, inputFluid) + .add("no recipes found for {} and {}", input, inputFluid) .error() .post(); } @@ -117,7 +120,9 @@ public void validate(GroovyLog.Msg msg) { @Override public @Nullable BottlingMachineRecipe register() { if (!validate()) return null; - return ModSupport.IMMERSIVE_ENGINEERING.get().bottlingMachine.add(output.get(0), input.get(0), fluidInput.get(0)); + BottlingMachineRecipe recipe = new BottlingMachineRecipe(output.get(0), ImmersiveEngineering.toIngredientStack(input.get(0)), fluidInput.get(0)); + ModSupport.IMMERSIVE_ENGINEERING.get().bottlingMachine.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/CokeOven.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/CokeOven.java index cfc45209c..7c1ec89e9 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/CokeOven.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/CokeOven.java @@ -7,6 +7,7 @@ import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.Nullable; @@ -61,7 +62,7 @@ public void removeByOutput(ItemStack output) { List list = CokeOvenRecipe.removeRecipes(output); if (list.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Crusher recipe") - .add("no recipes found for %s", output) + .add("no recipes found for {}", output) .error() .post(); return; @@ -85,7 +86,7 @@ public void removeByInput(ItemStack input) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Crusher recipe") - .add("no recipes found for %s", input) + .add("no recipes found for {}", input) .error() .post(); } @@ -100,9 +101,15 @@ public void removeAll() { CokeOvenRecipe.recipeList.clear(); } - public static class RecipeBuilder extends TimeRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { - protected int creosote; + private int time; + private int creosote; + + public RecipeBuilder time(int time) { + this.time = time; + return this; + } public RecipeBuilder creosote(int creosote) { this.creosote = creosote; @@ -125,7 +132,9 @@ public void validate(GroovyLog.Msg msg) { @Override public @Nullable CokeOvenRecipe register() { if (!validate()) return null; - return ModSupport.IMMERSIVE_ENGINEERING.get().cokeOven.add(output.get(0), input.get(0), time, creosote); + CokeOvenRecipe recipe = new CokeOvenRecipe(output.get(0), ImmersiveEngineering.toIEInput(input.get(0)), time, creosote); + ModSupport.IMMERSIVE_ENGINEERING.get().cokeOven.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Crusher.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Crusher.java index 0092c1ee0..26d2a9c9f 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Crusher.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Crusher.java @@ -60,7 +60,7 @@ public void removeByOutput(ItemStack output) { List list = CrusherRecipe.removeRecipesForOutput(output); if (list.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Crusher recipe") - .add("no recipes found for %s", output) + .add("no recipes found for {}", output) .error() .post(); return; @@ -78,7 +78,7 @@ public void removeByInput(ItemStack input) { List list = CrusherRecipe.removeRecipesForInput(input); if (list.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Crusher recipe") - .add("no recipes found for %s", input) + .add("no recipes found for {}", input) .error() .post(); return; @@ -112,7 +112,9 @@ public void validate(GroovyLog.Msg msg) { @Override public @Nullable CrusherRecipe register() { if (!validate()) return null; - return ModSupport.IMMERSIVE_ENGINEERING.get().crusher.add(output.get(0), input.get(0), energy); + CrusherRecipe recipe = new CrusherRecipe(output.get(0), input.get(0), energy); + ModSupport.IMMERSIVE_ENGINEERING.get().crusher.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Excavator.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Excavator.java new file mode 100644 index 000000000..92f35b482 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Excavator.java @@ -0,0 +1,222 @@ +package com.cleanroommc.groovyscript.compat.mods.immersiveengineering; + +import blusunrize.immersiveengineering.api.tool.ExcavatorHandler; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; +import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import org.apache.commons.lang3.tuple.Pair; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.stream.Collectors; + +public class Excavator extends VirtualizedRegistry> { + + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @Override + public void onReload() { + removeScripted().forEach(recipe -> ExcavatorHandler.mineralList.entrySet().removeIf(r -> r.getKey() == recipe.getKey())); + restoreFromBackup().forEach(recipe -> ExcavatorHandler.mineralList.put(recipe.getKey(), recipe.getValue())); + } + + public void add(ExcavatorHandler.MineralMix recipe, Integer weight) { + if (recipe != null) { + addScripted(Pair.of(recipe, weight)); + ExcavatorHandler.mineralList.put(recipe, weight); + } + } + + public ExcavatorHandler.MineralMix add(String name, int mineralWeight, float failChance, String[] ores, float[] chances) { + ExcavatorHandler.MineralMix recipe = new ExcavatorHandler.MineralMix(name, failChance, ores, chances); + add(recipe, mineralWeight); + return recipe; + } + + public boolean remove(ExcavatorHandler.MineralMix recipe) { + int weight = ExcavatorHandler.mineralList.get(recipe); + if (weight > 0) { + ExcavatorHandler.mineralList.entrySet().removeIf(r -> r.getKey() == recipe); + addBackup(Pair.of(recipe, weight)); + return true; + } + return false; + } + + public boolean removeByMineral(String key) { + List entries = ExcavatorHandler.mineralList.keySet().stream() + .filter(r -> r.name.equalsIgnoreCase(key)) + .collect(Collectors.toList()); + for (ExcavatorHandler.MineralMix recipe : entries) { + remove(recipe); + } + if (entries.isEmpty()) { + GroovyLog.msg("Error removing Immersive Engineering Excavator entry") + .add("no entries found for {}", key) + .error() + .post(); + return false; + } + return true; + } + + public void removeByOres(String... ores) { + if (ores == null || ores.length == 0) { + GroovyLog.msg("Error removing Immersive Engineering Excavator entry") + .add("ores must not be empty") + .error() + .post(); + return; + } + List entries = ExcavatorHandler.mineralList.keySet().stream() + .filter(r -> Arrays.stream(ores).anyMatch(check -> Arrays.stream(r.ores).anyMatch(target -> target.matches(check)))) + .collect(Collectors.toList()); + for (ExcavatorHandler.MineralMix recipe : entries) { + remove(recipe); + } + if (entries.isEmpty()) { + GroovyLog.msg("Error removing Immersive Engineering Excavator entry") + .add("no entries found for {}", Arrays.toString(ores)) + .error() + .post(); + } + } + + public void removeByOres(OreDictIngredient... ores) { + if (IngredientHelper.isEmpty(ores)) { + GroovyLog.msg("Error removing Immersive Engineering Excavator entry") + .add("ores must not be empty") + .error() + .post(); + return; + } + List entries = ExcavatorHandler.mineralList.keySet().stream() + .filter(r -> Arrays.stream(ores).anyMatch(check -> Arrays.stream(r.ores).anyMatch(target -> target.matches(check.getOreDict())))) + .collect(Collectors.toList()); + for (ExcavatorHandler.MineralMix recipe : entries) { + remove(recipe); + } + if (entries.isEmpty()) { + GroovyLog.msg("Error removing Immersive Engineering Excavator entry") + .add("no entries found for {}", Arrays.toString(ores)) + .error() + .post(); + } + } + + public SimpleObjectStream> streamRecipes() { + return new SimpleObjectStream<>(ExcavatorHandler.mineralList.entrySet()).setRemover(r -> this.remove(r.getKey())); + } + + public void removeAll() { + ExcavatorHandler.mineralList.forEach((r, l) -> addBackup(Pair.of(r, l))); + ExcavatorHandler.mineralList.clear(); + } + + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private String name; + private int weight; + private float fail; + private final List ores = new ArrayList<>(); + private final List chances = new ArrayList<>(); + private final List dimensions = new ArrayList<>(); + private boolean blacklist = true; + + public RecipeBuilder name(String name) { + this.name = name; + return this; + } + + public RecipeBuilder weight(int weight) { + this.weight = weight; + return this; + } + + public RecipeBuilder fail(float fail) { + this.fail = fail; + return this; + } + + public RecipeBuilder ore(String ore, float chance) { + this.ores.add(ore); + this.chances.add(chance); + return this; + } + + public RecipeBuilder ore(OreDictIngredient ore, float chance) { + this.ores.add(ore.getOreDict()); + this.chances.add(chance); + return this; + } + + public RecipeBuilder dimension(int dimension) { + this.dimensions.add(dimension); + return this; + } + + public RecipeBuilder dimension(int... dimensions) { + for (int dimension : dimensions) { + dimension(dimension); + } + return this; + } + + public RecipeBuilder dimension(Collection dimensions) { + for (int dimension : dimensions) { + dimension(dimension); + } + return this; + } + + public RecipeBuilder blacklist(boolean blacklist) { + this.blacklist = blacklist; + return this; + } + + public RecipeBuilder blacklist() { + this.blacklist = !blacklist; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Immersive Engineering Excavator entry"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg); + validateFluids(msg); + msg.add(fail < 0 || fail > 1, "fail must be a float between 0 and 1, yet it was {}", fail); + msg.add(ores.size() != chances.size(), "ores and chances must be of equal length, yet ores was {} and chances was {}", ores.size(), chances.size()); + } + + @Override + public @Nullable ExcavatorHandler.MineralMix register() { + if (!validate()) return null; + float[] chanceArray = new float[chances.size()]; + for (int i = 0; i < chances.size(); i++) { + chanceArray[i] = chances.get(i); + } + ExcavatorHandler.MineralMix recipe = new ExcavatorHandler.MineralMix(name, fail, ores.toArray(new String[0]), chanceArray); + + int[] dims = dimensions.stream().mapToInt(Integer::intValue).toArray(); + if (dims != null) { + if (blacklist) recipe.dimensionBlacklist = dims; + else recipe.dimensionWhitelist = dims; + } + recipe.recalculateChances(); + + ModSupport.IMMERSIVE_ENGINEERING.get().excavator.add(recipe, weight); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Fermenter.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Fermenter.java index 4319945a9..816c352cd 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Fermenter.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Fermenter.java @@ -66,7 +66,7 @@ public void removeByOutput(FluidStack fluidOutput) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Fermenter recipe") - .add("no recipes found for %s", fluidOutput) + .add("no recipes found for {}", fluidOutput) .error() .post(); } @@ -85,7 +85,7 @@ public void removeByInput(ItemStack input) { addBackup(recipe); } else { GroovyLog.msg("Error removing Immersive Engineering Fermenter recipe") - .add("no recipes found for %s", input) + .add("no recipes found for {}", input) .error() .post(); } @@ -116,7 +116,9 @@ public void validate(GroovyLog.Msg msg) { @Override public @Nullable FermenterRecipe register() { if (!validate()) return null; - return ModSupport.IMMERSIVE_ENGINEERING.get().fermenter.add(fluidOutput.get(0), output.getOrEmpty(0), input.get(0), energy); + FermenterRecipe recipe = new FermenterRecipe(fluidOutput.get(0), output.getOrEmpty(0), input.get(0), energy); + ModSupport.IMMERSIVE_ENGINEERING.get().fermenter.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ImmersiveEngineering.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ImmersiveEngineering.java index d1b49a33f..256fb1794 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ImmersiveEngineering.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/ImmersiveEngineering.java @@ -15,10 +15,12 @@ public class ImmersiveEngineering extends ModPropertyContainer { public final AlloyKiln alloyKiln = new AlloyKiln(); public final ArcFurnace arcFurnace = new ArcFurnace(); public final BlastFurnace blastFurnace = new BlastFurnace(); + public final BlastFurnaceFuel blastFurnaceFuel = new BlastFurnaceFuel(); public final BlueprintCrafting blueprint = new BlueprintCrafting(); public final BottlingMachine bottlingMachine = new BottlingMachine(); public final CokeOven cokeOven = new CokeOven(); public final Crusher crusher = new Crusher(); + public final Excavator excavator = new Excavator(); public final Fermenter fermenter = new Fermenter(); public final MetalPress metalPress = new MetalPress(); public final Mixer mixer = new Mixer(); @@ -29,10 +31,12 @@ public ImmersiveEngineering() { addRegistry(alloyKiln); addRegistry(arcFurnace); addRegistry(blastFurnace); + addRegistry(blastFurnaceFuel); addRegistry(blueprint); addRegistry(bottlingMachine); addRegistry(cokeOven); addRegistry(crusher); + addRegistry(excavator); addRegistry(fermenter); addRegistry(metalPress); addRegistry(mixer); @@ -53,6 +57,14 @@ public static IngredientStack toIngredientStack(IIngredient ingredient) { return new IngredientStack(Arrays.asList(ingredient.getMatchingStacks())); } + public static boolean areIngredientsEquals(IngredientStack target, IIngredient other) { + return other instanceof OreDictIngredient ? target.matches(((OreDictIngredient) other).getOreDict()) : target.matches(other.getMatchingStacks()); + } + + public static boolean areIngredientsEquals(IIngredient target, IngredientStack other) { + return areIngredientsEquals(other, target); + } + public static Object toIEInput(IIngredient ingredient) { if (ingredient instanceof OreDictIngredient) { return ((OreDictIngredient) ingredient).getOreDict(); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/MetalPress.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/MetalPress.java index 7282d608c..0665d9c7a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/MetalPress.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/MetalPress.java @@ -22,12 +22,13 @@ public MetalPress() { super(); } + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + @Override public void onReload() { - removeScripted().forEach(recipe -> { - if (MetalPressRecipe.recipeList.containsValue(recipe)) - MetalPressRecipe.recipeList.remove(recipe.mold, recipe); - }); + removeScripted().forEach(recipe -> MetalPressRecipe.recipeList.get(recipe.mold).removeIf(r -> r == recipe)); restoreFromBackup().forEach(recipe -> MetalPressRecipe.recipeList.put(recipe.mold, recipe)); } @@ -39,7 +40,7 @@ public void add(MetalPressRecipe recipe) { } public MetalPressRecipe add(ItemStack output, IIngredient input, ItemStack mold, int energy) { - MetalPressRecipe recipe = MetalPressRecipe.addRecipe(output.copy(), ImmersiveEngineering.toIngredientStack(input), mold, energy); + MetalPressRecipe recipe = new MetalPressRecipe(output.copy(), ImmersiveEngineering.toIngredientStack(input), ApiUtils.createComparableItemStack(mold, true), energy); add(recipe); return recipe; } @@ -62,7 +63,7 @@ public void removeByOutput(ItemStack output) { List list = MetalPressRecipe.removeRecipes(output); if (list.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Metal Press recipe") - .add("no recipes found for %s", output) + .add("no recipes found for {}", output) .error() .post(); return; @@ -91,7 +92,7 @@ public void removeByOutput(ItemStack mold, ItemStack output) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Metal Press recipe") - .add("no recipes found for %s and %s", mold, output) + .add("no recipes found for {} and {}", mold, output) .error() .post(); } @@ -119,7 +120,7 @@ public void removeByInput(ItemStack mold, ItemStack input) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Metal Press recipe") - .add("no recipes found for %s and %s", mold, input) + .add("no recipes found for {} and {}", mold, input) .error() .post(); } @@ -140,7 +141,7 @@ public void removeByInput(ItemStack input) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Metal Press recipe") - .add("no recipes found for %s", input) + .add("no recipes found for {}", input) .error() .post(); } @@ -174,6 +175,13 @@ public SimpleObjectStream streamRecipes() { public static class RecipeBuilder extends EnergyRecipeBuilder { + private ItemStack mold = ItemStack.EMPTY; + + public RecipeBuilder mold(ItemStack mold) { + this.mold = mold; + return this; + } + @Override public String getErrorMsg() { return "Error adding Immersive Engineering Metal Press recipe"; @@ -181,17 +189,17 @@ public String getErrorMsg() { @Override public void validate(GroovyLog.Msg msg) { - validateItems(msg, 2, 2, 1, 1); + validateItems(msg, 1, 1, 1, 1); validateFluids(msg); + msg.add(mold.isEmpty(), "mold must be defined"); } @Override public @Nullable MetalPressRecipe register() { if (!validate()) return null; - for (ItemStack stack : input.get(1).getMatchingStacks()) { - return ModSupport.IMMERSIVE_ENGINEERING.get().metalPress.add(output.get(0), input.get(0), stack, energy); - } - return null; + MetalPressRecipe recipe = new MetalPressRecipe(output.get(0), ImmersiveEngineering.toIngredientStack(input.get(0)), ApiUtils.createComparableItemStack(mold, true), energy); + ModSupport.IMMERSIVE_ENGINEERING.get().metalPress.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Mixer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Mixer.java index 290874716..d05dc60cb 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Mixer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Mixer.java @@ -1,6 +1,5 @@ package com.cleanroommc.groovyscript.compat.mods.immersiveengineering; -import blusunrize.immersiveengineering.api.crafting.IngredientStack; import blusunrize.immersiveengineering.api.crafting.MixerRecipe; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; @@ -10,14 +9,12 @@ import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; -import net.minecraft.item.ItemStack; -import net.minecraft.util.NonNullList; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; import java.util.Arrays; -import java.util.Collections; import java.util.List; +import java.util.stream.Collectors; public class Mixer extends VirtualizedRegistry { @@ -43,7 +40,7 @@ public void add(MixerRecipe recipe) { } public MixerRecipe add(FluidStack fluidOutput, FluidStack fluidInput, int energy, List itemInput) { - IngredientStack[] inputs = ArrayUtils.mapToArray(itemInput, ImmersiveEngineering::toIngredientStack); + Object[] inputs = ArrayUtils.mapToArray(itemInput, ImmersiveEngineering::toIngredientStack); MixerRecipe recipe = new MixerRecipe(fluidOutput, fluidInput, inputs, energy); add(recipe); return recipe; @@ -72,41 +69,34 @@ public void removeByOutput(FluidStack fluidOutput) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Mixer recipe") - .add("no recipes found for %s", fluidOutput) + .add("no recipes found for {}", fluidOutput) .error() .post(); } } - public void removeByInput(ItemStack... itemInputs) { + public void removeByInput(IIngredient... itemInputs) { if (GroovyLog.msg("Error removing Immersive Engineering Mixer recipe") .add(itemInputs == null || itemInputs.length == 0, () -> "item input must not be empty") .error() .postIfNotEmpty()) { return; } - if (!MixerRecipe.recipeList.removeIf(recipe -> { - if (recipe.itemInputs.length != itemInputs.length) return false; - - int i; - for (i = 0; i < itemInputs.length; i++) { - if (!recipe.itemInputs[i].matches(itemInputs[i])) break; - } - - if (i == itemInputs.length) { - addBackup(recipe); - return true; - } - return false; - })) { + List recipes = MixerRecipe.recipeList.stream().filter(r -> r.itemInputs.length == itemInputs.length && + Arrays.stream(itemInputs).anyMatch(check -> Arrays.stream(r.itemInputs).anyMatch(target -> ImmersiveEngineering.areIngredientsEquals(target, check)))) + .collect(Collectors.toList()); + for (MixerRecipe recipe : recipes) { + remove(recipe); + } + if (recipes.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Mixer recipe") - .add("no recipes found for %s and %s", Arrays.toString(itemInputs)) + .add("no recipes found for {}", Arrays.toString(itemInputs)) .error() .post(); } } - public void removeByInput(FluidStack fluidInput, ItemStack... itemInput) { + public void removeByInput(FluidStack fluidInput, IIngredient... itemInput) { if (GroovyLog.msg("Error removing Immersive Engineering Mixer recipe") .add(IngredientHelper.isEmpty(fluidInput), () -> "fluid input must not be empty") .add(itemInput == null || itemInput.length == 0, () -> "item input must not be empty") @@ -114,13 +104,16 @@ public void removeByInput(FluidStack fluidInput, ItemStack... itemInput) { .postIfNotEmpty()) { return; } - NonNullList inputs = NonNullList.create(); - Collections.addAll(inputs, itemInput); - - MixerRecipe recipe = MixerRecipe.findRecipe(fluidInput, inputs); - if (recipe == null || !remove(recipe)) { + List recipes = MixerRecipe.recipeList.stream().filter(r -> fluidInput.isFluidEqual(r.fluidInput) && + r.itemInputs.length == itemInput.length && + Arrays.stream(itemInput).anyMatch(check -> Arrays.stream(r.itemInputs).anyMatch(target -> ImmersiveEngineering.areIngredientsEquals(target, check)))) + .collect(Collectors.toList()); + for (MixerRecipe recipe : recipes) { + remove(recipe); + } + if (recipes.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Mixer recipe") - .add("no recipes found for %s and %s", fluidInput, Arrays.toString(itemInput)) + .add("no recipes found for {} and {}", fluidInput, Arrays.toString(itemInput)) .error() .post(); } @@ -144,14 +137,17 @@ public String getErrorMsg() { @Override public void validate(GroovyLog.Msg msg) { - validateItems(msg, 1, 8, 0, 0); + validateItems(msg, 1, Integer.MAX_VALUE, 0, 0); validateFluids(msg, 1, 1, 1, 1); } @Override public @Nullable MixerRecipe register() { if (!validate()) return null; - return ModSupport.IMMERSIVE_ENGINEERING.get().mixer.add(fluidOutput.get(0), fluidInput.get(0), energy, input); + Object[] inputs = ArrayUtils.mapToArray(input, ImmersiveEngineering::toIngredientStack); + MixerRecipe recipe = new MixerRecipe(fluidOutput.get(0), fluidInput.get(0), inputs, energy); + ModSupport.IMMERSIVE_ENGINEERING.get().mixer.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Refinery.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Refinery.java index 266c14374..2d603669e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Refinery.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Refinery.java @@ -10,6 +10,9 @@ import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; +import java.util.List; +import java.util.stream.Collectors; + public class Refinery extends VirtualizedRegistry { public Refinery() { @@ -34,8 +37,8 @@ public void add(RefineryRecipe recipe) { } public RefineryRecipe add(FluidStack output, FluidStack input0, FluidStack input1, int energy) { - RefineryRecipe recipe = RefineryRecipe.addRecipe(output, input0, input1, energy); - addScripted(recipe); + RefineryRecipe recipe = new RefineryRecipe(output, input0, input1, energy); + add(recipe); return recipe; } @@ -63,7 +66,7 @@ public void removeByOutput(FluidStack fluidOutput) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Refinery recipe") - .add("no recipes found for %s", fluidOutput) + .add("no recipes found for {}", fluidOutput) .error() .post(); } @@ -77,10 +80,13 @@ public void removeByInput(FluidStack input0, FluidStack input1) { .postIfNotEmpty()) { return; } - RefineryRecipe recipe = RefineryRecipe.findRecipe(input0, input1); - if (recipe == null || !remove(recipe)) { + List recipes = RefineryRecipe.recipeList.stream().filter(r -> (r.input0.isFluidEqual(input0) && r.input1.isFluidEqual(input1)) || (r.input0.isFluidEqual(input1) && r.input1.isFluidEqual(input0))).collect(Collectors.toList()); + for (RefineryRecipe recipe : recipes) { + remove(recipe); + } + if (recipes.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Refinery recipe") - .add("no recipes found for %s and %s", input0, input1) + .add("no recipes found for {} and {}", input0, input1) .error() .post(); } @@ -110,7 +116,10 @@ public void validate(GroovyLog.Msg msg) { @Override public @Nullable RefineryRecipe register() { - return ModSupport.IMMERSIVE_ENGINEERING.get().refinery.add(fluidOutput.get(0), fluidInput.get(0), fluidInput.get(1), energy); + if (!validate()) return null; + RefineryRecipe recipe = new RefineryRecipe(fluidOutput.get(0), fluidInput.get(0), fluidInput.get(1), energy); + ModSupport.IMMERSIVE_ENGINEERING.get().refinery.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java index 3eaf53096..6ce991d3a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java @@ -13,6 +13,8 @@ import org.jetbrains.annotations.Nullable; import javax.annotation.Nonnull; +import java.util.List; +import java.util.stream.Collectors; public class Squeezer extends VirtualizedRegistry { @@ -39,7 +41,7 @@ public void add(SqueezerRecipe recipe) { public SqueezerRecipe add(FluidStack fluidOutput, @Nonnull ItemStack itemOutput, IIngredient input, int energy) { SqueezerRecipe recipe = new SqueezerRecipe(fluidOutput, itemOutput, ImmersiveEngineering.toIngredientStack(input), energy); - addScripted(recipe); + add(recipe); return recipe; } @@ -67,7 +69,7 @@ public void removeByOutput(FluidStack fluidOutput) { return false; })) { GroovyLog.msg("Error removing Immersive Engineering Squeezer recipe") - .add("no recipes found for %s", fluidOutput) + .add("no recipes found for {}", fluidOutput) .error() .post(); } @@ -81,15 +83,32 @@ public void removeByOutput(FluidStack fluidOutput, ItemStack itemOutput) { .postIfNotEmpty()) { return; } - if (!SqueezerRecipe.recipeList.removeIf(recipe -> { - if (fluidOutput.isFluidEqual(recipe.fluidOutput) && recipe.input.matches(itemOutput)) { - addBackup(recipe); - return true; - } - return false; - })) { + List recipes = SqueezerRecipe.recipeList.stream().filter(r -> fluidOutput.isFluidEqual(r.fluidOutput) && r.itemOutput.isItemEqual(itemOutput)).collect(Collectors.toList()); + for (SqueezerRecipe recipe : recipes) { + remove(recipe); + } + if (recipes.isEmpty()) { + GroovyLog.msg("Error removing Immersive Engineering Squeezer recipe") + .add("no recipes found for {} and {}", fluidOutput, itemOutput) + .error() + .post(); + } + } + + public void removeByOutput(ItemStack itemOutput) { + if (GroovyLog.msg("Error removing Immersive Engineering Squeezer recipe") + .add(IngredientHelper.isEmpty(itemOutput), () -> "item input must not be empty") + .error() + .postIfNotEmpty()) { + return; + } + List recipes = SqueezerRecipe.recipeList.stream().filter(r -> r.itemOutput.isItemEqual(itemOutput)).collect(Collectors.toList()); + for (SqueezerRecipe recipe : recipes) { + remove(recipe); + } + if (recipes.isEmpty()) { GroovyLog.msg("Error removing Immersive Engineering Squeezer recipe") - .add("no recipes found for %s and %s", fluidOutput, itemOutput) + .add("no recipes found for {}", itemOutput) .error() .post(); } @@ -106,7 +125,7 @@ public void removeByInput(ItemStack input) { SqueezerRecipe recipe = SqueezerRecipe.findRecipe(input); if (recipe == null || !remove(recipe)) { GroovyLog.msg("Error removing Immersive Engineering Squeezer recipe") - .add("no recipes found for %s", input) + .add("no recipes found for {}", input) .error() .post(); } @@ -132,11 +151,15 @@ public String getErrorMsg() { public void validate(GroovyLog.Msg msg) { validateItems(msg, 1, 1, 0, 1); validateFluids(msg, 0, 0, 0, 1); + msg.add(fluidOutput.size() == 0 && output.size() == 0, "Either a fluid output or an item output must be defined"); } @Override public @Nullable SqueezerRecipe register() { - return ModSupport.IMMERSIVE_ENGINEERING.get().squeezer.add(fluidOutput.getOrEmpty(0), output.getOrEmpty(0), input.get(0), energy); + if (!validate()) return null; + SqueezerRecipe recipe = new SqueezerRecipe(fluidOutput.getOrEmpty(0), output.getOrEmpty(0), ImmersiveEngineering.toIngredientStack(input.get(0)), energy); + ModSupport.IMMERSIVE_ENGINEERING.get().squeezer.add(recipe); + return recipe; } } } From bf0ffff6906a69c4d89ea334391b66fcae48c9db Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Tue, 18 Jul 2023 11:21:55 -0700 Subject: [PATCH 05/28] enderio examples and fixes --- examples/enderio.groovy | 294 ++++++++++++++---- .../compat/mods/enderio/AlloySmelter.java | 82 +++-- .../compat/mods/enderio/Enchanter.java | 32 +- .../compat/mods/enderio/EnderIO.java | 2 + .../compat/mods/enderio/FluidCoolant.java | 42 ++- .../compat/mods/enderio/FluidFuel.java | 25 ++ .../compat/mods/enderio/SagMill.java | 18 ++ .../compat/mods/enderio/SagMillGrinding.java | 113 +++++++ .../compat/mods/enderio/SliceNSplice.java | 29 +- .../compat/mods/enderio/SoulBinder.java | 52 +++- .../compat/mods/enderio/Tank.java | 134 +++++++- .../groovyscript/compat/mods/enderio/Vat.java | 20 ++ .../SimpleRecipeGroupHolderAccessor.java | 14 + .../resources/mixin.groovyscript.enderio.json | 1 + 14 files changed, 748 insertions(+), 110 deletions(-) create mode 100644 src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SagMillGrinding.java create mode 100644 src/main/java/com/cleanroommc/groovyscript/core/mixin/enderio/SimpleRecipeGroupHolderAccessor.java diff --git a/examples/enderio.groovy b/examples/enderio.groovy index efb9e1445..55fba1a77 100644 --- a/examples/enderio.groovy +++ b/examples/enderio.groovy @@ -1,64 +1,232 @@ -// enderio -//mods.enderio.alloySmelter.add(item('minecraft:nether_star'), [item('minecraft:clay_ball'), item('minecraft:gold_ingot'), item('minecraft:dirt')], 9999) -//mods.enderio.alloySmelter.remove(item('enderio:item_alloy_ingot0)>') - -mods.enderio.AlloySmelter.recipeBuilder() - .input(item('minecraft:clay_ball'), item('minecraft:gold_ingot'), item('minecraft:dirt')) - .output(item('minecraft:nether_star')) - .energy(9999) - .register() - -mods.enderio.SoulBinder.recipeBuilder() - .input(item('minecraft:clay_ball')) - .output(item('minecraft:nether_star')) - .entitySoul('minecraft:zombie') - .xp(20) - .energy(9999) - .register() - -//mods.enderio.soulBinder.add('balanceness', item('minecraft:nether_star'), item('minecraft:clay'), ['minecraft:wither'], 9999, 20) -mods.enderio.SoulBinder.remove(item('enderio:item_material:16')) - -mods.enderio.SagMill.recipeBuilder() - .input(item('minecraft:clay_ball')) - .output(item('minecraft:iron_ingot'), 0.3f) - .output(item('minecraft:gold_ingot'), 0.15f) - .output(item('minecraft:diamond'), 0.05f) - .output(item('minecraft:diamond'), 0.05f) - .bonusTypeMultiply() - .energy(6000) - .tierSimple() - .register() - -//mods.enderio.sagMill.removeByInput item('minecraft:wheat') - -mods.enderio.SliceNSplice.add(item('minecraft:totem_of_undying'), [item('minecraft:diamond'), item('minecraft:gold_ingot'), item('minecraft:diamond'), null, item('minecraft:nether_star'), null], 9999) -//mods.enderio.SliceNSplice.remove(item('enderio:block_enderman_skull2)>') -//mods.enderio.SliceNSplice.removeByInput([item('enderio:item_alloy_ingot7)>', item('enderio:block_enderman_skull'), item('enderio:item_alloy_ingot7)>', item('minecraft:potion'), item('enderio:item_basic_capacitor'), item('minecraft:potion')]) - -//mods.enderio.FluidFuel.addFuel(fluid('water'), 1000, 100) -//mods.enderio.FluidFuel.addCoolant(fluid('water'), 10f) - -mods.enderio.Enchanter.remove(item('enchantment:efficiency')) -mods.enderio.Enchanter.recipeBuilder() - .enchantment(item('enchantment:efficiency')) - .input(item('minecraft:nether_star') * 2) - .xpCostMultiplier(3f) - .customBook(item('enderio:item_dark_steel_upgrade:0')) - .customLapis(item('minecraft:poisonous_potato')) - .register() - -mods.enderio.Vat.recipeBuilder() - .input(fluid('water') * 500) - .output(fluid('lava') * 500) - .itemInputLeft(item('minecraft:diamond'), 1.5) - .itemInputRight(item('minecraft:iron_ingot'), 0.7) - .itemInputRight(item('minecraft:gold_ingot'), 7) - .baseMultiplier(1) - .register() - -mods.enderio.Vat.remove(fluid('nutrient_distillation')) - -mods.enderio.Tank.removeDrain(fluid('water'), item('minecraft:sponge:0')) -mods.enderio.Tank.addFill(item('minecraft:clay_ball'), fluid('lava') * 10000, item('minecraft:nether_star')) +// Alloy Smelter (Alloying): +// Convert up to 3 itemstack inputs into an itemstack output, using energy and giving XP. Can be restricted to require a given tier of machine. +// Can be set to require at least SIMPLE, NORMAL, or ENHANCED tiers, or to IGNORE the tier. SIMPLE and IGNORE are effectively the same. +mods.enderio.alloysmelter.recipeBuilder() + .input(item('minecraft:diamond') * 4, item('minecraft:clay') * 32) + .output(item('minecraft:nether_star')) + .energy(100000) // Optional int, how much energy is required for the recipe. Default of 5000. + .xp(500) // Optional int, how much xp is output when the recipe is finished. Default of 0. + .tierEnhanced() // Optional, sets the minimum tier of machine recipe for recipe to ENHANCED. Default IGNORE + .register() + +mods.enderio.alloysmelter.recipeBuilder() + .input(item('minecraft:clay') * 4, item('minecraft:diamond')) + .output(item('minecraft:obsidian')) + .tierNormal() // Optional, sets the minimum tier of machine recipe for recipe to NORMAL. Default IGNORE + .register() + +mods.enderio.alloysmelter.recipeBuilder() + .input(item('minecraft:diamond') * 4, item('minecraft:gold_ingot') * 2) + .output(item('minecraft:clay') * 4) + .tierSimple() // Optional, sets the minimum tier of machine recipe for recipe to SIMPLE. Default IGNORE + .register() + +mods.enderio.alloysmelter.recipeBuilder() + .input(item('minecraft:diamond') * 2, item('minecraft:gold_nugget') * 2) + .output(item('minecraft:clay') * 4) + .tierAny() // Optional, sets the minimum tier of machine recipe for recipe to IGNORE. Default IGNORE + .register() + +mods.enderio.alloysmelter.remove(item('enderio:item_material:70')) // Remove by ItemStack output +//mods.enderio.alloysmelter.removeAll() + + +// Enchanter: +// Convert an input itemstack, player xp, and either a written book and lapis or a custom alternative into an enchanted book. +mods.enderio.enchanter.recipeBuilder() + .enchantment(enchantment('sharpness')) + .input(item('minecraft:clay')) + .amountPerLevel(3) // Optional int, multiplier per enchantment level. Defaults to amount of the input ItemStack + .xpCostMultiplier(2) // Optional double, base XP multiplier. Default 1. + .customBook(item('minecraft:book')) // Optional ItemStack, item that would otherwise be a written book. Default item('minecraft:writable_book') + .customLapis(item('minecraft:diamond')) // Optional OreDict, item that would otherwise be lapis, consumes 3 per output enchantment level. Default ore('gemLapis') + .register() + +mods.enderio.enchanter.recipeBuilder() + .enchantment(enchantment('unbreaking')) + .input(item('minecraft:diamond')) + .register() + +mods.enderio.enchanter.remove(enchantment('mending')) +mods.enderio.enchanter.removeAll() + + +// Fluid Coolant (Combustion Coolant): +// Create a Coolant with a given coolant rate that produces power with a Fuel while in a Combustion Generator. +mods.enderio.fluidcoolant.addCoolant(fluid('xpjuice'), 1000) + +mods.enderio.fluidcoolant.remove(fluid('water')) +//mods.enderio.fluidcoolant.removeAll() + + +// Fluid Fuel (Combustion Fuel): +// Create a Fuel with a given power per tick and total burn time that produces power with a Coolant while in a Combustion Generator. +mods.enderio.fluidfuel.addFuel(fluid('lava'), 500, 1000) + +mods.enderio.fluidfuel.remove(fluid('fire_water')) +//mods.enderio.fluidfuel.removeAll() + + +// Sag Mill (SAGMill, Sag): +// Convert an input itemstack into up to 4 output itemstacks with chances, using energy. Output can be boosted by Grinding Balls based on set bonusType. +// Can be set to require at least SIMPLE, NORMAL, or ENHANCED tiers, or to IGNORE the tier. SIMPLE and IGNORE are effectively the same. +mods.enderio.sagmill.recipeBuilder() + .input(item('minecraft:diamond_block')) + .output(item('minecraft:diamond') * 4) // Has an 100% chance. + .output(item('minecraft:clay_ball') * 2, 0.7) + .output(item('minecraft:gold_ingot'), 0.1) + .output(item('minecraft:gold_ingot'), 0.1) // Between 1 and 4 outputs. + .bonusTypeMultiply() // Optional, controls the effect Grinding Balls have on outputs. Default bonusTypeNone. + .energy(1000) // Optional int, how much energy is required for the recipe. Default of 5000. + .tierEnhanced() // Optional, sets the minimum tier of machine recipe for recipe to ENHANCED. Default IGNORE + .register() + +mods.enderio.sagmill.recipeBuilder() + .input(item('minecraft:clay_ball')) + .output(item('minecraft:diamond') * 4) + .output(item('minecraft:gold_ingot'), 0.1) + .bonusTypeChance() // Optional, controls the effect Grinding Balls have on outputs. Default bonusTypeNone. + .tierNormal() // Optional, sets the minimum tier of machine recipe for recipe to NORMAL. Default IGNORE + .register() + +mods.enderio.sagmill.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:gold_ingot'), 0.1) + .bonusTypeNone() // Optional, controls the effect Grinding Balls have on outputs. Default bonusTypeNone. + .tierSimple() // Optional, sets the minimum tier of machine recipe for recipe to SIMPLE. Default IGNORE + .register() + +mods.enderio.sagmill.recipeBuilder() + .input(item('minecraft:nether_star')) + .output(item('minecraft:clay_ball') * 2, 0.7) + .output(item('minecraft:gold_ingot'), 0.1) + .tierAny() // Optional, sets the minimum tier of machine recipe for recipe to IGNORE. Default IGNORE + .register() + +mods.enderio.sagmill.removeByInput(item('minecraft:wheat')) +//mods.enderio.sagmill.removeAll() + + +// Sag Mill Grinding (Grinding): +// Add a new Griding Ball for use in a Sag Mill with the given output multiplier, power multiplier, chance multiplier, and duration (in base power used). +mods.enderio.sagmillgrinding.recipeBuilder() + .input(item('minecraft:clay_ball')) + .chance(6.66) // Optional int, chance to double all outputs. Default 1. + .power(0.001) // Optional int, multiplier to required power for recipes. Default 1. + .grinding(3.33) // Optional int, increases the chances of outputs up to 100%. Default 1. + .duration(10000) // Amount of power used in recipes before it is consumed. + .register() + +mods.enderio.sagmillgrinding.remove(item('minecraft:flint')) +//mods.enderio.sagmillgrinding.removeAll() + + +// Slice N Splice (SliceAndSplice): +// Convert up to 6 input itemstacks into an output itemstack, using energy and giving XP. +mods.enderio.slicensplice.recipeBuilder() + .input(item('minecraft:clay'), null, item('minecraft:clay')) + .input(null, item('minecraft:clay'), null) + .output(item('minecraft:gold_ingot')) + .energy(1000) // Optional int, how much energy is required for the recipe. Default of 5000. + .xp(5) // Optional int, how much xp is output when the recipe is finished. Default of 0. + .register() + +mods.enderio.slicensplice.remove(item('enderio:item_material:40')) // Remove by ItemStack output +mods.enderio.slicensplice.removeByInput( // Remove by List input + [item('enderio:item_alloy_ingot:7'), item('enderio:block_enderman_skull'), item('enderio:item_alloy_ingot:7'), + item('minecraft:potion').withNbt(["Potion": "minecraft:water"]), item('enderio:item_basic_capacitor'), item('minecraft:potion').withNbt(["Potion": "minecraft:water"])] +) +//mods.enderio.slicensplice.removeAll() + + +// Soulbinder: +// Converts an input itemstack into an output itemstack, requiring one of several entities in soul vials, using energy and giving XP. Must have a unique name. +// To function properly, the input entities must be allowed in Soul Vials. +mods.enderio.soulbinder.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .entity(entity('minecraft:zombie'), entity('minecraft:enderman')) + .name('groovy_example') + .energy(1000) // Optional int, how much energy is required for the recipe. Default of 5000. + .xp(5) // Optional int, how much xp is output when the recipe is finished. Default of 0. + .register() + +mods.enderio.soulbinder.remove(item('enderio:item_material:17')) // Remove by ItemStack output +//mods.enderio.soulbinder.removeAll() + + +// Tank: +// Converts an input itemstack into an output fluidstack with an optional output itemstack in drain mode, +// or converts an input itemstack and fluidstack into an output itemstack in fill mode. +mods.enderio.tank.recipeBuilder() + .drain() // puts fluid into tank + .input(item('minecraft:clay')) + .output(item('minecraft:diamond')) // Optional ItemStack. + .fluidInput(fluid('water') * 500) + .register() + +mods.enderio.tank.recipeBuilder() + .fill() // takes fluid out of tank + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) // Optional ItemStack. + .fluidOutput(fluid('water') * 500) + .register() + +mods.enderio.tank.recipeBuilder() + .drain() + .input(item('minecraft:diamond')) + .fluidInput(fluid('fire_water') * 8000) + .register() + +mods.enderio.tank.recipeBuilder() + .fill() + .input(item('minecraft:diamond')) + .fluidOutput(fluid('fire_water') * 8000) + .register() + +mods.enderio.tank.removeDrain(item('minecraft:experience_bottle'), fluid('xpjuice')) +mods.enderio.tank.removeFill(item('minecraft:glass_bottle'), fluid('xpjuice')) +//mods.enderio.tank.removeAll() + + +// Vat: +// Converts an input fluidstack into an output itemstack at a rate based on up 2 itemstack inputs, and using power. +// Can be set to require at least NORMAL or ENHANCED tiers, or to IGNORE the tier. NORMAL and IGNORE are effectively the same. +mods.enderio.vat.recipeBuilder() + .input(fluid('lava')) + .output(fluid('hootch')) + .baseMultiplier(2) // Optional int, determines the base fluid output relative to fluid input + .itemInputLeft(item('minecraft:clay'), 2) + .itemInputLeft(item('minecraft:clay_ball'), 0.5) + .itemInputRight(item('minecraft:diamond'), 5) + .itemInputRight(item('minecraft:diamond_block'), 50) + .itemInputRight(item('minecraft:gold_block'), 10) + .itemInputRight(item('minecraft:gold_ingot'), 1) + .itemInputRight(item('minecraft:gold_nugget'), 0.1) + .energy(1000) + .tierEnhanced() // Optional, sets the minimum tier of machine recipe for recipe to ENHANCED (the higher of the two tiers). Default IGNORE + .register() + +mods.enderio.vat.recipeBuilder() + .input(fluid('hootch') * 100) + .output(fluid('water') * 50) + .itemInputLeft(item('minecraft:clay_ball'), 1) + .itemInputRight(item('minecraft:diamond'), 1) + .energy(1000) + .tierNormal() // Optional, sets the minimum tier of machine recipe for recipe to NORMAL (the lower of the two tiers). Default IGNORE + .register() + +mods.enderio.vat.recipeBuilder() + .input(fluid('water')) + .output(fluid('hootch')) + .itemInputLeft(item('minecraft:clay'), 2) + .itemInputLeft(item('minecraft:clay_ball'), 0.5) + .itemInputRight(item('minecraft:diamond'), 5) + .itemInputRight(item('minecraft:gold_ingot'), 1) + .energy(1000) + .tierAny() // Optional, sets the minimum tier of machine recipe for recipe to IGNORE. Default IGNORE + .register() + +mods.enderio.vat.remove(fluid('nutrient_distillation')) +//mods.enderio.vat.removeAll() diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/AlloySmelter.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/AlloySmelter.java index a2fb9e596..157fc4ebd 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/AlloySmelter.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/AlloySmelter.java @@ -10,9 +10,11 @@ import com.cleanroommc.groovyscript.core.mixin.enderio.ItemRecipeNodeAccessor; import com.cleanroommc.groovyscript.core.mixin.enderio.TriItemLookupAccessor; import com.cleanroommc.groovyscript.helper.ArrayUtils; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import com.enderio.core.common.util.NNList; import crazypants.enderio.base.recipe.IManyToOneRecipe; +import crazypants.enderio.base.recipe.MachineRecipeRegistry; import crazypants.enderio.base.recipe.alloysmelter.AlloyRecipeManager; import crazypants.enderio.base.recipe.lookup.ItemRecipeLeafNode; import crazypants.enderio.base.recipe.lookup.ItemRecipeNode; @@ -26,6 +28,7 @@ import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.stream.Collectors; public class AlloySmelter extends VirtualizedRegistry { @@ -40,29 +43,6 @@ public RecipeBuilder recipeBuilder() { return new RecipeBuilder(); } - public void remove(ItemStack output) { - List recipes = find(output); - if (!recipes.isEmpty()) { - if (this.removalQueue == null) { - this.removalQueue = new ObjectOpenHashSet<>(recipes.size()); - } - for (IManyToOneRecipe r : recipes) { - addBackup(r); - this.removalQueue.add(r); - } - } - } - - public List find(ItemStack output) { - List recipes = new ArrayList<>(); - for (IManyToOneRecipe recipe : ((AlloyRecipeManagerAccessor) AlloyRecipeManager.getInstance()).getLookup()) { - if (OreDictionary.itemMatches(output, recipe.getOutput(), false)) { - recipes.add(recipe); - } - } - return recipes; - } - @GroovyBlacklist public void onReload() { AlloyRecipeManagerAccessor accessor = (AlloyRecipeManagerAccessor) AlloyRecipeManager.getInstance(); @@ -91,6 +71,36 @@ public void afterScriptLoad() { } } + public void remove(ItemStack output) { + List recipes = find(output); + if (!recipes.isEmpty()) { + if (this.removalQueue == null) { + this.removalQueue = new ObjectOpenHashSet<>(recipes.size()); + } + for (IManyToOneRecipe r : recipes) { + addBackup(r); + this.removalQueue.add(r); + } + } + } + + public boolean remove(IManyToOneRecipe recipe) { + if (recipe == null) return false; + addBackup(recipe); + this.removalQueue.add(recipe); + return true; + } + + public List find(ItemStack output) { + List recipes = new ArrayList<>(); + for (IManyToOneRecipe recipe : ((AlloyRecipeManagerAccessor) AlloyRecipeManager.getInstance()).getLookup()) { + if (OreDictionary.itemMatches(output, recipe.getOutput(), false)) { + recipes.add(recipe); + } + } + return recipes; + } + @GroovyBlacklist @ApiStatus.Internal private void removeInternal(Collection recipes) { @@ -125,11 +135,35 @@ private void removeInternal(Collection recipes) { } } + public SimpleObjectStream streamRecipes() { + List list = MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.ALLOYSMELTER).values().stream() + .filter(r -> r instanceof IManyToOneRecipe) + .map(r -> (IManyToOneRecipe) r).collect(Collectors.toList()); + return new SimpleObjectStream<>(list) + .setRemover(this::remove); + } + + public void removeAll() { + AlloyRecipeManagerAccessor accessor = (AlloyRecipeManagerAccessor) AlloyRecipeManager.getInstance(); + @SuppressWarnings("unchecked") + Int2ObjectOpenHashMap, ItemRecipeNode>>> map = + ((ItemRecipeNodeAccessor>>) + ((TriItemLookupAccessor) accessor.getLookup()).getRoot()).getMap(); + for (NNPair, ItemRecipeNode>> pair : map.values()) { + Iterator listIter = pair.left.iterator(); + while (listIter.hasNext()) { + addBackup(listIter.next()); + listIter.remove(); + } + } + } + + public static class RecipeBuilder extends EnderIORecipeBuilder { private float xp; - public RecipeBuilder xpChance(float xp) { + public RecipeBuilder xp(float xp) { this.xp = xp; return this; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Enchanter.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Enchanter.java index bde03dd80..a5a0c5771 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Enchanter.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Enchanter.java @@ -5,6 +5,8 @@ import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.CustomEnchanterRecipe; +import com.cleanroommc.groovyscript.core.mixin.enderio.SimpleRecipeGroupHolderAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.cleanroommc.groovyscript.helper.recipe.IRecipeBuilder; @@ -18,6 +20,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collection; import java.util.List; public class Enchanter extends VirtualizedRegistry { @@ -26,6 +29,16 @@ public Enchanter() { super(); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + @GroovyBlacklist + public void onReload() { + removeScripted().forEach(MachineRecipeRegistry.instance::removeRecipe); + restoreFromBackup().forEach(MachineRecipeRegistry.instance::registerRecipe); + } + public void add(EnchanterRecipe recipe) { MachineRecipeRegistry.instance.registerRecipe(recipe); addScripted(recipe); @@ -38,8 +51,11 @@ public void add(Enchantment enchantment, IIngredient input) { .register(); } - public RecipeBuilder recipeBuilder() { - return new RecipeBuilder(); + public boolean remove(EnchanterRecipe recipe) { + if (recipe == null) return false; + MachineRecipeRegistry.instance.removeRecipe(recipe); + addBackup(recipe); + return true; } public void remove(Enchantment enchantment) { @@ -63,10 +79,14 @@ public void remove(Enchantment enchantment) { } } - @GroovyBlacklist - public void onReload() { - removeScripted().forEach(MachineRecipeRegistry.instance::removeRecipe); - restoreFromBackup().forEach(MachineRecipeRegistry.instance::registerRecipe); + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>((Collection) MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.ENCHANTER).values()) + .setRemover(this::remove); + } + + public void removeAll() { + MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.ENCHANTER).forEach((r, l) -> addBackup((EnchanterRecipe) l)); + ((SimpleRecipeGroupHolderAccessor) MachineRecipeRegistry.instance.getRecipeHolderssForMachine(MachineRecipeRegistry.ENCHANTER)).getRecipes().clear(); } public static class RecipeBuilder implements IRecipeBuilder { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/EnderIO.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/EnderIO.java index 84bb4d68e..f423d193d 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/EnderIO.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/EnderIO.java @@ -9,6 +9,7 @@ public class EnderIO extends ModPropertyContainer { public final FluidCoolant fluidCoolant = new FluidCoolant(); public final Enchanter enchanter = new Enchanter(); public final SagMill sagMill = new SagMill(); + public final SagMillGrinding sagMillGrinding = new SagMillGrinding(); public final SliceNSplice sliceNSplice = new SliceNSplice(); public final SoulBinder soulBinder = new SoulBinder(); public final Tank tank = new Tank(); @@ -20,6 +21,7 @@ public EnderIO() { addRegistry(fluidCoolant); addRegistry(enchanter); addRegistry(sagMill); + addRegistry(sagMillGrinding); addRegistry(sliceNSplice); addRegistry(soulBinder); addRegistry(tank); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidCoolant.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidCoolant.java index 76e3a0925..d8e3d3125 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidCoolant.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidCoolant.java @@ -3,6 +3,7 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.core.mixin.enderio.FluidFuelRegisterAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import crazypants.enderio.base.fluid.FluidFuelRegister; import crazypants.enderio.base.fluid.IFluidCoolant; @@ -10,6 +11,8 @@ import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; +import java.util.Map; + public class FluidCoolant extends VirtualizedRegistry { public FluidCoolant() { @@ -29,12 +32,26 @@ public void addCoolant(Fluid fluid, float degreesPerMb) { GroovyLog.get().error("Error adding EnderIO coolant for null fluid!"); return; } - IFluidCoolant existingCoolant = find(fluid); - if (existingCoolant != null) { - addBackup(existingCoolant); + IFluidCoolant coolant = new FluidFuelRegister.CoolantImpl(fluid, degreesPerMb); + addCoolant(coolant); + } + + public void addCoolant(IFluidCoolant fluidCoolant) { + if (fluidCoolant == null) { + GroovyLog.get().error("Error adding EnderIO coolant for null fluidCoolant!"); + return; } - FluidFuelRegister.instance.addCoolant(fluid, degreesPerMb); - addScripted(find(fluid)); + ((FluidFuelRegisterAccessor) FluidFuelRegister.instance).getCoolants().put(fluidCoolant.getFluid().getName(), fluidCoolant); + addScripted(fluidCoolant); + } + + public boolean remove(IFluidCoolant fluidCoolant) { + if (fluidCoolant == null) { + GroovyLog.get().error("Error removing EnderIO coolant for null fluidCoolant!"); + return false; + } + remove(fluidCoolant.getFluid()); + return true; } public void remove(FluidStack fluidStack) { @@ -61,7 +78,7 @@ public void remove(Fluid fluid) { @Nullable public IFluidCoolant find(Fluid fluid) { - return FluidFuelRegister.instance.getCoolant(fluid); + return ((FluidFuelRegisterAccessor) FluidFuelRegister.instance).getCoolants().get(fluid.getName()); //FluidFuelRegister.instance.getCoolant(fluid); } @GroovyBlacklist @@ -71,4 +88,17 @@ public void onReload() { restoreFromBackup().forEach(c -> accessor.getCoolants().put(c.getFluid().getName(), c)); } + public SimpleObjectStream> streamRecipes() { + return new SimpleObjectStream<>(((FluidFuelRegisterAccessor) FluidFuelRegister.instance).getCoolants().entrySet()) + .setRemover(r -> remove(r.getValue())); + } + + public void removeAll() { + ((FluidFuelRegisterAccessor) FluidFuelRegister.instance).getCoolants().forEach((r, l) -> { + if (l == null) return; + addBackup(l); + }); + ((FluidFuelRegisterAccessor) FluidFuelRegister.instance).getCoolants().clear(); + } + } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidFuel.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidFuel.java index fd8e5f62a..692e9d81b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidFuel.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidFuel.java @@ -3,6 +3,7 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.core.mixin.enderio.FluidFuelRegisterAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import crazypants.enderio.base.fluid.FluidFuelRegister; import crazypants.enderio.base.fluid.IFluidFuel; @@ -10,6 +11,8 @@ import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; +import java.util.Map; + public class FluidFuel extends VirtualizedRegistry { public FluidFuel() { @@ -37,6 +40,15 @@ public void addFuel(Fluid fluid, int rfPerCycle, int totalBurnTime) { addScripted(find(fluid)); } + public boolean remove(IFluidFuel fluidFuel) { + if (fluidFuel == null) { + GroovyLog.get().error("Error removing EnderIO coolant for null fluidFuel!"); + return false; + } + remove(fluidFuel.getFluid()); + return true; + } + public void remove(FluidStack fluidStack) { if (fluidStack == null) { GroovyLog.get().error("Error removing EnderIO fuel for null fluidstack!"); @@ -71,4 +83,17 @@ public void onReload() { restoreFromBackup().forEach(c -> accessor.getFuels().put(c.getFluid().getName(), c)); } + public SimpleObjectStream> streamRecipes() { + return new SimpleObjectStream<>(((FluidFuelRegisterAccessor) FluidFuelRegister.instance).getFuels().entrySet()) + .setRemover(r -> remove(r.getValue())); + } + + public void removeAll() { + ((FluidFuelRegisterAccessor) FluidFuelRegister.instance).getFuels().forEach((r, l) -> { + if (l == null) return; + addBackup(l); + }); + ((FluidFuelRegisterAccessor) FluidFuelRegister.instance).getFuels().clear(); + } + } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SagMill.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SagMill.java index 5da169a6f..74d9b7159 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SagMill.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SagMill.java @@ -6,6 +6,7 @@ import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.EnderIORecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.RecipeInput; import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.SagRecipe; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import crazypants.enderio.base.recipe.Recipe; @@ -33,6 +34,13 @@ public void add(Recipe recipe) { addScripted(recipe); } + public boolean remove(Recipe recipe) { + if (recipe == null) return false; + SagMillRecipeManager.getInstance().getRecipes().remove(recipe); + addBackup(recipe); + return true; + } + public void removeByInput(ItemStack input) { Recipe recipe = (Recipe) SagMillRecipeManager.getInstance().getRecipeForInput(RecipeLevel.IGNORE, input); if (recipe == null) { @@ -49,6 +57,16 @@ public void onReload() { restoreFromBackup().forEach(SagMillRecipeManager.getInstance().getRecipes()::add); } + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(SagMillRecipeManager.getInstance().getRecipes()) + .setRemover(this::remove); + } + + public void removeAll() { + SagMillRecipeManager.getInstance().getRecipes().forEach(this::addBackup); + SagMillRecipeManager.getInstance().getRecipes().clear(); + } + public static class RecipeBuilder extends EnderIORecipeBuilder { private final FloatList chances = new FloatArrayList(); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SagMillGrinding.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SagMillGrinding.java new file mode 100644 index 000000000..3a7ca9827 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SagMillGrinding.java @@ -0,0 +1,113 @@ +package com.cleanroommc.groovyscript.compat.mods.enderio; + +import com.cleanroommc.groovyscript.api.GroovyBlacklist; +import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.RecipeInput; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import crazypants.enderio.base.recipe.sagmill.GrindingBall; +import crazypants.enderio.base.recipe.sagmill.SagMillRecipeManager; +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.Nullable; + +public class SagMillGrinding extends VirtualizedRegistry { + + public SagMillGrinding() { + super(VirtualizedRegistry.generateAliases("Grinding")); + } + + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + public void add(GrindingBall recipe) { + SagMillRecipeManager.getInstance().addBall(recipe); + addScripted(recipe); + } + + public boolean remove(GrindingBall recipe) { + if (recipe == null) return false; + SagMillRecipeManager.getInstance().getBalls().remove(recipe); + addBackup(recipe); + return true; + } + + public boolean remove(ItemStack grindingBall) { + for (GrindingBall ball : SagMillRecipeManager.getInstance().getBalls()) { + if (ball.isInput(grindingBall)) { + remove(ball); + return true; + } + } + return false; + } + + @GroovyBlacklist + public void onReload() { + removeScripted().forEach(SagMillRecipeManager.getInstance().getBalls()::remove); + restoreFromBackup().forEach(SagMillRecipeManager.getInstance().getBalls()::add); + } + + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(SagMillRecipeManager.getInstance().getBalls()) + .setRemover(this::remove); + } + + public void removeAll() { + SagMillRecipeManager.getInstance().getBalls().forEach(this::addBackup); + SagMillRecipeManager.getInstance().getBalls().clear(); + } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private float chance = 1; + private float power = 1; + private float grinding = 1; + private int duration; + + public RecipeBuilder chance(float chance) { + this.chance = chance; + return this; + } + + public RecipeBuilder power(float power) { + this.power = power; + return this; + } + + public RecipeBuilder grinding(float grinding) { + this.grinding = grinding; + return this; + } + + public RecipeBuilder duration(int duration) { + this.duration = duration; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding EnderIO Sag Mill Grinding Ball entry"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateItems(msg, 1, 1, 0, 0); + validateFluids(msg); + msg.add(chance <= 0, "chance must be an integer greater than 0, yet it was {}", chance); + msg.add(power <= 0, "power must be an integer greater than 0, yet it was {}", power); + msg.add(grinding <= 0, "grinding must be an integer greater than 0, yet it was {}", grinding); + msg.add(duration <= 0, "duration must be an integer greater than 0, yet it was {}", duration); + } + + @Override + public @Nullable GrindingBall register() { + if (!validate()) return null; + GrindingBall recipe = new GrindingBall(new RecipeInput(input.get(0)), grinding, chance, power, duration); + ModSupport.ENDER_IO.get().sagMillGrinding.add(recipe); + return recipe; + } + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SliceNSplice.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SliceNSplice.java index fcf596eeb..165118b05 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SliceNSplice.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SliceNSplice.java @@ -4,13 +4,15 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.compat.mods.ModSupport; -import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.EnderIORecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.ManyToOneRecipe; import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.RecipeInput; import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.RecipeUtils; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import crazypants.enderio.base.recipe.*; +import crazypants.enderio.base.recipe.sagmill.SagMillRecipeManager; import crazypants.enderio.base.recipe.slicensplice.SliceAndSpliceRecipeManager; import net.minecraft.item.ItemStack; import net.minecraftforge.oredict.OreDictionary; @@ -49,6 +51,13 @@ public void add(Recipe recipe) { addScripted(r); } + public boolean remove(IManyToOneRecipe recipe) { + if (recipe == null) return false; + SagMillRecipeManager.getInstance().getRecipes().remove((Recipe) recipe); + addBackup(recipe); + return true; + } + public void remove(ItemStack output) { int count = 0; Iterator iter = SliceAndSpliceRecipeManager.getInstance().getRecipes().iterator(); @@ -81,15 +90,31 @@ public void onReload() { restoreFromBackup().forEach(SliceAndSpliceRecipeManager.getInstance().getRecipes()::add); } - public static class RecipeBuilder extends EnderIORecipeBuilder { + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(SliceAndSpliceRecipeManager.getInstance().getRecipes()) + .setRemover(this::remove); + } + + public void removeAll() { + SliceAndSpliceRecipeManager.getInstance().getRecipes().forEach(this::addBackup); + SliceAndSpliceRecipeManager.getInstance().getRecipes().clear(); + } + + public static class RecipeBuilder extends AbstractRecipeBuilder { private float xp; + private int energy; public RecipeBuilder xp(float xp) { this.xp = xp; return this; } + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } + @Override public String getErrorMsg() { return "Error adding EnderIO Slice'n'Splice recipe"; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SoulBinder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SoulBinder.java index 68b3a66be..f39a316e2 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SoulBinder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SoulBinder.java @@ -3,17 +3,21 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.compat.mods.ModSupport; -import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.EnderIORecipeBuilder; +import com.cleanroommc.groovyscript.core.mixin.enderio.SimpleRecipeGroupHolderAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.helper.recipe.RecipeName; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import com.enderio.core.common.util.NNList; import crazypants.enderio.base.recipe.IMachineRecipe; import crazypants.enderio.base.recipe.MachineRecipeRegistry; +import crazypants.enderio.base.recipe.RecipeLevel; import crazypants.enderio.base.recipe.soul.BasicSoulBinderRecipe; import crazypants.enderio.base.recipe.soul.ISoulBinderRecipe; import net.minecraft.entity.EntityList; import net.minecraft.item.ItemStack; import net.minecraft.util.ResourceLocation; +import net.minecraftforge.fml.common.registry.EntityEntry; import net.minecraftforge.oredict.OreDictionary; import org.jetbrains.annotations.Nullable; @@ -36,6 +40,13 @@ public void add(ISoulBinderRecipe recipe) { addScripted(recipe); } + public boolean remove(ISoulBinderRecipe recipe) { + if (recipe == null) return false; + MachineRecipeRegistry.instance.removeRecipe(recipe); + addBackup(recipe); + return true; + } + public void remove(ItemStack output) { List recipes = new ArrayList<>(); for (IMachineRecipe recipe : MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.SOULBINDER).values()) { @@ -59,10 +70,21 @@ public void onReload() { restoreFromBackup().forEach(MachineRecipeRegistry.instance::registerRecipe); } - public static class RecipeBuilder extends EnderIORecipeBuilder { + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>((Collection) MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.SOULBINDER).values()) + .setRemover(this::remove); + } + + public void removeAll() { + MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.SOULBINDER).forEach((r, l) -> addBackup((ISoulBinderRecipe) l)); + ((SimpleRecipeGroupHolderAccessor) MachineRecipeRegistry.instance.getRecipeHolderssForMachine(MachineRecipeRegistry.SOULBINDER)).getRecipes().clear(); + } + + public static class RecipeBuilder extends AbstractRecipeBuilder { private String name; private int xp; + private int energy; private final NNList entities = new NNList<>(); private final List entityErrors = new ArrayList<>(); @@ -95,11 +117,35 @@ public RecipeBuilder entitySoul(Collection entities) { return this; } + public RecipeBuilder entity(EntityEntry entity) { + entities.add(entity.getRegistryName()); + return this; + } + + public RecipeBuilder entity(EntityEntry... entities) { + for (EntityEntry entity : entities) { + entity(entity); + } + return this; + } + + public RecipeBuilder entity(Collection entities) { + for (EntityEntry entity : entities) { + entity(entity); + } + return this; + } + public RecipeBuilder xp(int xp) { this.xp = xp; return this; } + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } + @Override public String getErrorMsg() { return "Error adding EnderIO Soul Binder recipe"; @@ -128,7 +174,7 @@ public void validate(GroovyLog.Msg msg) { energy, xp, name, - level, + RecipeLevel.IGNORE, entities, new BasicSoulBinderRecipe.OutputFilter() { }); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Tank.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Tank.java index ea5039d6b..bbfdf2ffd 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Tank.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Tank.java @@ -1,10 +1,15 @@ package com.cleanroommc.groovyscript.compat.mods.enderio; +import com.cleanroommc.groovyscript.GroovyScript; import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; +import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.RecipeUtils; +import com.cleanroommc.groovyscript.core.mixin.enderio.SimpleRecipeGroupHolderAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.helper.recipe.RecipeName; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import com.enderio.core.common.util.stackable.Things; @@ -14,8 +19,10 @@ import crazypants.enderio.base.recipe.tank.TankMachineRecipe; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; +import java.util.Collection; import java.util.List; public class Tank extends VirtualizedRegistry { @@ -24,8 +31,17 @@ public Tank() { super(); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + + public void add(TankMachineRecipe recipe) { + MachineRecipeRegistry.instance.registerRecipe(recipe); + addScripted(recipe); + } + public void addFill(IIngredient input, FluidStack inputFluid, ItemStack output) { - addFill(RecipeName.generate(), input, inputFluid, output); + addFill(GroovyScript.getRunConfig().getPackId() + ":" + RecipeName.generate("groovyscript_enderio_tank_"), input, inputFluid, output); } public void addFill(String recipeName, IIngredient input, FluidStack inputFluid, ItemStack output) { @@ -38,12 +54,11 @@ public void addFill(String recipeName, IIngredient input, FluidStack inputFluid, Things in = RecipeUtils.toThings(input); Things out = new Things().add(output); TankMachineRecipe rec = new TankMachineRecipe(recipeName, true, in, inputFluid, out, TankMachineRecipe.Logic.NONE, RecipeLevel.IGNORE); - MachineRecipeRegistry.instance.registerRecipe(rec); - addScripted(rec); + add(rec); } public void addDrain(IIngredient input, FluidStack outputFluid, ItemStack output) { - addDrain(RecipeName.generate(), input, outputFluid, output); + addDrain(GroovyScript.getRunConfig().getPackId() + ":" + RecipeName.generate("groovyscript_enderio_tank_"), input, outputFluid, output); } public void addDrain(String recipeName, IIngredient input, FluidStack outputFluid, ItemStack output) { @@ -56,8 +71,35 @@ public void addDrain(String recipeName, IIngredient input, FluidStack outputFlui Things in = RecipeUtils.toThings(input); Things out = new Things().add(output); TankMachineRecipe rec = new TankMachineRecipe(recipeName, false, in, outputFluid, out, TankMachineRecipe.Logic.NONE, RecipeLevel.IGNORE); - MachineRecipeRegistry.instance.registerRecipe(rec); - addScripted(rec); + add(rec); + } + + public boolean remove(TankMachineRecipe recipe) { + if (recipe == null) return false; + addBackup(recipe); + MachineRecipeRegistry.instance.removeRecipe(recipe); + return true; + } + + public void removeFill(ItemStack input, FluidStack fluid) { + GroovyLog.Msg msg = GroovyLog.msg("Error removing EnderIO Tank filling recipe").error(); + msg.add(IngredientHelper.isEmpty(fluid), () -> "fluid must not be empty"); + msg.add(IngredientHelper.isEmpty(input), () -> "input must not be empty"); + if (msg.postIfNotEmpty()) return; + + List recipes = new ArrayList<>(); + for (IMachineRecipe recipe : MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.TANK_FILLING).values()) { + TankMachineRecipe tankMachineRecipe = (TankMachineRecipe) recipe; + if (tankMachineRecipe.getFluid().isFluidEqual(fluid) && tankMachineRecipe.getInput().contains(input)) { + recipes.add(tankMachineRecipe); + } + } + if (recipes.isEmpty()) { + GroovyLog.get().error("Could not find EnderIO Tank filling recipes for fluid {} and input {}", fluid.getFluid().getName(), input); + } else { + recipes.forEach(this::addBackup); + recipes.forEach(MachineRecipeRegistry.instance::removeRecipe); + } } public void removeFill(FluidStack fluid, ItemStack output) { @@ -81,6 +123,27 @@ public void removeFill(FluidStack fluid, ItemStack output) { } } + public void removeDrain(ItemStack input, FluidStack fluid) { + GroovyLog.Msg msg = GroovyLog.msg("Error removing EnderIO Tank draining recipe").error(); + msg.add(IngredientHelper.isEmpty(fluid), () -> "fluid must not be empty"); + msg.add(IngredientHelper.isEmpty(input), () -> "input must not be empty"); + if (msg.postIfNotEmpty()) return; + + List recipes = new ArrayList<>(); + for (IMachineRecipe recipe : MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.TANK_EMPTYING).values()) { + TankMachineRecipe tankMachineRecipe = (TankMachineRecipe) recipe; + if (tankMachineRecipe.getFluid().isFluidEqual(fluid) && tankMachineRecipe.getInput().contains(input)) { + recipes.add(tankMachineRecipe); + } + } + if (recipes.isEmpty()) { + GroovyLog.get().error("Could not find EnderIO Tank draining recipes for fluid {} and input {}", fluid.getFluid().getName(), input); + } else { + recipes.forEach(this::addBackup); + recipes.forEach(MachineRecipeRegistry.instance::removeRecipe); + } + } + public void removeDrain(FluidStack fluid, ItemStack output) { GroovyLog.Msg msg = GroovyLog.msg("Error removing EnderIO Tank draining recipe").error(); msg.add(IngredientHelper.isEmpty(fluid), () -> "fluid must not be empty"); @@ -107,4 +170,63 @@ public void onReload() { removeScripted().forEach(MachineRecipeRegistry.instance::removeRecipe); restoreFromBackup().forEach(MachineRecipeRegistry.instance::registerRecipe); } + + public SimpleObjectStream streamRecipes() { + List list = new ArrayList<>(); + list.addAll((Collection) MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.TANK_FILLING).values()); + list.addAll((Collection) MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.TANK_EMPTYING).values()); + return new SimpleObjectStream<>(list).setRemover(this::remove); + } + + public void removeAll() { + MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.TANK_FILLING).forEach((r, l) -> addBackup((TankMachineRecipe) l)); + ((SimpleRecipeGroupHolderAccessor) MachineRecipeRegistry.instance.getRecipeHolderssForMachine(MachineRecipeRegistry.TANK_FILLING)).getRecipes().clear(); + MachineRecipeRegistry.instance.getRecipesForMachine(MachineRecipeRegistry.TANK_EMPTYING).forEach((r, l) -> addBackup((TankMachineRecipe) l)); + ((SimpleRecipeGroupHolderAccessor) MachineRecipeRegistry.instance.getRecipeHolderssForMachine(MachineRecipeRegistry.TANK_EMPTYING)).getRecipes().clear(); + } + + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private boolean isFilling; + + public RecipeBuilder fill() { + this.isFilling = true; + return this; + } + + public RecipeBuilder drain() { + this.isFilling = false; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding EnderIO Tank recipe"; + } + + public String getRecipeNamePrefix() { + return "groovyscript_enderio_tank_"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + validateName(); + validateItems(msg, 1, 1, 0, 1); + if (isFilling) validateFluids(msg, 0, 0, 1, 1); + else validateFluids(msg, 1, 1, 0, 0); + msg.add(msg.hasSubMessages(), "The Tank Recipe Builder requires an input fluid stack if it is draining and " + + "an output fluid stack if it is filling. This recipe was {}.", isFilling ? "filling" : "draining"); + } + + @Override + public @Nullable TankMachineRecipe register() { + if (!validate()) return null; + Things in = RecipeUtils.toThings(input.get(0)); + Things out = new Things().add(output.getOrEmpty(0)); + TankMachineRecipe recipe = new TankMachineRecipe(name.toString(), isFilling, in, isFilling ? fluidOutput.get(0) : fluidInput.get(0), out, TankMachineRecipe.Logic.NONE, RecipeLevel.IGNORE); + + ModSupport.ENDER_IO.get().tank.add(recipe); + return recipe; + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Vat.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Vat.java index c1ef96a9b..1f08079f9 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Vat.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/Vat.java @@ -5,6 +5,7 @@ import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.enderio.recipe.RecipeInput; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; import com.cleanroommc.groovyscript.helper.ingredient.IngredientList; import com.cleanroommc.groovyscript.helper.recipe.IRecipeBuilder; @@ -20,6 +21,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; public class Vat extends VirtualizedRegistry { @@ -37,6 +39,13 @@ public void add(Recipe recipe) { addScripted((VatRecipe) instance.getRecipes().get(instance.getRecipes().size() - 1)); } + public boolean remove(VatRecipe recipe) { + if (recipe == null) return false; + VatRecipeManager.getInstance().getRecipes().remove(recipe); + addBackup(recipe); + return true; + } + public void remove(FluidStack output) { if (IngredientHelper.isEmpty(output)) { GroovyLog.get().error("Error removing EnderIO Vat recipe for empty output!"); @@ -45,6 +54,7 @@ public void remove(FluidStack output) { int oldSize = VatRecipeManager.getInstance().getRecipes().size(); VatRecipeManager.getInstance().getRecipes().removeIf(recipe -> { FluidStack recipeOutput = recipe.getOutputs()[0].getFluidOutput(); + if (output.isFluidEqual(recipeOutput)) addBackup((VatRecipe) recipe); return output.isFluidEqual(recipeOutput); }); if (oldSize == VatRecipeManager.getInstance().getRecipes().size()) { @@ -59,6 +69,16 @@ public void onReload() { recipes.addAll(restoreFromBackup()); } + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(VatRecipeManager.getInstance().getRecipes().stream().map(r -> (VatRecipe) r).collect(Collectors.toList())) + .setRemover(this::remove); + } + + public void removeAll() { + VatRecipeManager.getInstance().getRecipes().forEach(r -> addBackup((VatRecipe) r)); + VatRecipeManager.getInstance().getRecipes().clear(); + } + public static class RecipeBuilder implements IRecipeBuilder { private FluidStack output; diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/enderio/SimpleRecipeGroupHolderAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/enderio/SimpleRecipeGroupHolderAccessor.java new file mode 100644 index 000000000..361ab3337 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/enderio/SimpleRecipeGroupHolderAccessor.java @@ -0,0 +1,14 @@ +package com.cleanroommc.groovyscript.core.mixin.enderio; + +import crazypants.enderio.base.recipe.IMachineRecipe; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.Map; + +@Mixin(targets = "crazypants.enderio.base.recipe.MachineRecipeRegistry$SimpleRecipeGroupHolder") +public interface SimpleRecipeGroupHolderAccessor { + + @Accessor + Map getRecipes(); +} diff --git a/src/main/resources/mixin.groovyscript.enderio.json b/src/main/resources/mixin.groovyscript.enderio.json index 6da1e0b53..90755ac7a 100644 --- a/src/main/resources/mixin.groovyscript.enderio.json +++ b/src/main/resources/mixin.groovyscript.enderio.json @@ -10,6 +10,7 @@ "FluidFuelRegisterAccessor", "ItemRecipeLeafNodeAccessor", "ItemRecipeNodeAccessor", + "SimpleRecipeGroupHolderAccessor", "TriItemLookupAccessor" ] } \ No newline at end of file From a45bb59552de4241b28d426495684829ec46de9d Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Thu, 20 Jul 2023 14:35:56 -0700 Subject: [PATCH 06/28] make condition/transformer return a new object --- .../core/mixin/FluidStackMixin.java | 10 ++++++---- .../core/mixin/ItemStackMixin.java | 18 ++++++++++-------- .../helper/ingredient/IngredientBase.java | 12 +++++++----- .../helper/ingredient/OrIngredient.java | 4 ++-- .../helper/ingredient/OreDictIngredient.java | 4 ++-- .../ingredient/OreDictWildcardIngredient.java | 6 +++--- 6 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/FluidStackMixin.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/FluidStackMixin.java index b293753c9..02c79898b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/core/mixin/FluidStackMixin.java +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/FluidStackMixin.java @@ -90,13 +90,15 @@ public ItemStack applyTransform(ItemStack matchedInput) { } public FluidStack when(Closure matchCondition) { - this.matchCondition = matchCondition; - return (FluidStack) (Object) this; + FluidStackMixin fresh = (FluidStackMixin) exactCopy(); + fresh.matchCondition = matchCondition; + return (FluidStack) (Object) fresh; } public FluidStack transform(Closure transformer) { - this.transformer = transformer; - return (FluidStack) (Object) this; + FluidStackMixin fresh = (FluidStackMixin) exactCopy(); + fresh.transformer = transformer; + return (FluidStack) (Object) fresh; } @Override diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/ItemStackMixin.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/ItemStackMixin.java index dfebaccb1..dc796da3a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/core/mixin/ItemStackMixin.java +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/ItemStackMixin.java @@ -60,8 +60,8 @@ public void setNbt(NBTTagCompound nbt) { public IIngredient exactCopy() { ItemStackMixin copy = (ItemStackMixin) (Object) groovyscript$getThis().copy(); copy.setMark(getMark()); - copy.transform(transformer); - copy.when(matchCondition); + copy.transformer = transformer; + copy.matchCondition = matchCondition; copy.nbtMatcher = nbtMatcher; return copy; } @@ -90,13 +90,15 @@ public boolean test(ItemStack stack) { } public ItemStack when(Closure matchCondition) { - this.matchCondition = matchCondition; - return groovyscript$getThis(); + ItemStackMixin fresh = (ItemStackMixin) exactCopy(); + fresh.matchCondition = matchCondition; + return (ItemStack) (Object) fresh; } public ItemStack transform(Closure transformer) { - this.transformer = transformer; - return groovyscript$getThis(); + ItemStackMixin fresh = (ItemStackMixin) exactCopy(); + fresh.transformer = transformer; + return (ItemStack) (Object) fresh; } public ItemStack reuse() { @@ -171,8 +173,8 @@ public IIngredient withMeta(int meta) { ItemStack t = groovyscript$getThis(); ItemStackMixin itemStack = (ItemStackMixin) (Object) new ItemStack(t.getItem(), t.getCount(), meta); itemStack.setMark(getMark()); - itemStack.transform(transformer); - itemStack.when(matchCondition); + itemStack.transformer = transformer; + itemStack.matchCondition = matchCondition; itemStack.nbtMatcher = nbtMatcher; return itemStack; } diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/IngredientBase.java b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/IngredientBase.java index db45c25bf..b6aade381 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/IngredientBase.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/IngredientBase.java @@ -12,20 +12,22 @@ public abstract class IngredientBase implements IIngredient { protected Closure transformer; public IngredientBase when(Closure matchCondition) { - this.matchCondition = matchCondition; - return this; + IngredientBase fresh = (IngredientBase) this.exactCopy(); + fresh.matchCondition = matchCondition; + return fresh; } public IngredientBase transform(Closure transformer) { - this.transformer = transformer; - return this; + IngredientBase fresh = (IngredientBase) this.exactCopy(); + fresh.transformer = transformer; + return fresh; } public IngredientBase reuse() { return transform(IngredientHelper.REUSE); } - public IngredientBase noreturn() { + public IngredientBase noReturn() { return transform(IngredientHelper.NO_RETURN); } diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OrIngredient.java b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OrIngredient.java index c4946f8d8..7fbb71308 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OrIngredient.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OrIngredient.java @@ -28,8 +28,8 @@ public IIngredient exactCopy() { OrIngredient orIngredient = new OrIngredient(); orIngredient.ingredients.addAll(this.ingredients); orIngredient.setAmount(getAmount()); - orIngredient.when(this.matchCondition); - orIngredient.transform(orIngredient.transformer); + orIngredient.transformer = transformer; + orIngredient.matchCondition = matchCondition; return orIngredient; } 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 cd639de11..860657368 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictIngredient.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictIngredient.java @@ -39,8 +39,8 @@ public void setAmount(int amount) { public OreDictIngredient exactCopy() { OreDictIngredient oreDictIngredient = new OreDictIngredient(this.oreDict); oreDictIngredient.setAmount(this.count); - oreDictIngredient.transform(this.transformer); - oreDictIngredient.when(this.matchCondition); + oreDictIngredient.transformer = transformer; + oreDictIngredient.matchCondition = matchCondition; return oreDictIngredient; } 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 966a7055c..ca7dd62e4 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictWildcardIngredient.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictWildcardIngredient.java @@ -15,7 +15,7 @@ public class OreDictWildcardIngredient extends ItemsIngredient { private final String oreDict; private final List matchingOreDictionaries = new ArrayList<>(); - public final List ores = Collections.unmodifiableList(this.matchingOreDictionaries);; + public final List ores = Collections.unmodifiableList(this.matchingOreDictionaries); public static OreDictWildcardIngredient of(String oreDict) { List matchingOreDictionaries = new ArrayList<>(); @@ -55,8 +55,8 @@ public List getOres() { public IIngredient exactCopy() { OreDictWildcardIngredient odwi = new OreDictWildcardIngredient(this.oreDict, this.matchingOreDictionaries, getItemStacks()); odwi.setAmount(getAmount()); - odwi.transform(transformer); - odwi.when(matchCondition); + odwi.transformer = transformer; + odwi.matchCondition = matchCondition; return odwi; } } From 47aec20900c48152aabc8de45a9a38234dc8e372 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Thu, 20 Jul 2023 15:23:02 -0700 Subject: [PATCH 07/28] vanilla --- examples/main.groovy | 50 ---- examples/vanilla.groovy | 229 ++++++++++++++++++ .../starlightaltar/AltarRecipeBuilder.java | 9 - .../extendedcrafting/EnderRecipeBuilder.java | 5 + .../extendedcrafting/TableRecipeBuilder.java | 5 + .../arcane/ArcaneRecipeBuilder.java | 28 ++- .../groovyscript/compat/vanilla/Crafting.java | 74 +++++- .../compat/vanilla/CraftingRecipeBuilder.java | 61 +++-- .../groovyscript/compat/vanilla/Furnace.java | 68 ++++++ .../groovyscript/compat/vanilla/OreDict.java | 12 + .../groovyscript/compat/vanilla/Player.java | 78 ++++-- .../vanilla/RarityItemStackExpansion.java | 12 + .../compat/vanilla/VanillaModule.java | 4 + .../groovyscript/helper/GroovyHelper.java | 4 + .../helper/recipe/AbstractRecipeBuilder.java | 6 +- 15 files changed, 535 insertions(+), 110 deletions(-) delete mode 100644 examples/main.groovy create mode 100644 examples/vanilla.groovy create mode 100644 src/main/java/com/cleanroommc/groovyscript/compat/vanilla/RarityItemStackExpansion.java diff --git a/examples/main.groovy b/examples/main.groovy deleted file mode 100644 index 54621648f..000000000 --- a/examples/main.groovy +++ /dev/null @@ -1,50 +0,0 @@ -//println("Hello from groovy") - -def map = [test: 2, test2: 3] - -println map -println map.getClass() - -/*recipes.addShaped("test", '', [ - [null, null, null], - [null, ''.withNbt([Energy: 1000000]), null], - [null, null, null] -]) - -recipes.remove('thermalexpansion:capacitor_10') -recipes.remove('thermalexpansion:capacitor_11')*/ - -//ItemStack item = '' -//println("Count: " + item.getCount().toString()) -//println("Meta: " + item.getMetadata().toString()) - -/*def netherStarTransformer = { netherStar -> - return '' -} - -recipes.addShaped("test_name", '' * 3, [ - [''.transform(netherStarTransformer), '' * 1000, ''.transform(netherStarTransformer)], - [null, '', null], - [item('minecraft:nether_star').transform(netherStarTransformer), null, ''.transform(netherStarTransformer)] -]) - -//recipes.addShapeless('test_shapeless', '' * 2, ['', '']) -//recipes.addShapeless('test_shapeless2', '' * 2, ['', '']) - -//recipes.remove('minecraft:clay') - -// mekanism -//mods.mekanism.crusher.add '', '' -//mods.mekanism.crusher.remove '', "" - - - -events.world.onBlockBreak { world, blockState, pos, player -> - player.sendMessage(new TextComponentString("Block broken")) - false -} - -events.entity.onEnderTeleport { event -> - event.setAttackDamage 19.5f -}*/ - diff --git a/examples/vanilla.groovy b/examples/vanilla.groovy new file mode 100644 index 000000000..1bfeb7165 --- /dev/null +++ b/examples/vanilla.groovy @@ -0,0 +1,229 @@ + +// Imports must happen above all other code. + +import net.minecraftforge.event.entity.living.EnderTeleportEvent +import net.minecraftforge.event.world.BlockEvent +import net.minecraft.util.text.TextComponentString + +// Crafting recipes are typically created via recipe builder, but also have shorthand versions for some common uses. +// Here are a series of examples, with the shorthand and corresponding recipe builder: + +//crafting.addShaped(item('minecraft:gold_block'), [[item('minecraft:gold_ingot'),item('minecraft:gold_ingot'),item('minecraft:gold_ingot')],[null, null, null],[item('minecraft:gold_ingot'),item('minecraft:gold_ingot'),item('minecraft:gold_ingot')]]) +crafting.shapedBuilder() + .output(item('minecraft:gold_block')) + .shape([[item('minecraft:gold_ingot'),item('minecraft:gold_ingot'),item('minecraft:gold_ingot')],[null, null, null],[item('minecraft:gold_ingot'),item('minecraft:gold_ingot'),item('minecraft:gold_ingot')]]) + .register() + +//crafting.addShaped('gold_v_to_clay', item('minecraft:clay'), [[item('minecraft:gold_ingot'),null,item('minecraft:gold_ingot')],[null,item('minecraft:gold_ingot'),null]]) +crafting.shapedBuilder() + .name('gold_v_to_clay') + .output(item('minecraft:clay')) + .shape([[item('minecraft:gold_ingot'),null,item('minecraft:gold_ingot')],[null,item('minecraft:gold_ingot'),null]]) + .register() + +//crafting.addShaped(resource('example:resource_location'), item('minecraft:clay'), [[item('minecraft:cobblestone')],[item('minecraft:nether_star')],[item('minecraft:cobblestone')]]) +crafting.shapedBuilder() + .name(resource('example:resource_location')) + .output(item('minecraft:clay')) + .shape([[item('minecraft:cobblestone')],[item('minecraft:nether_star')],[item('minecraft:cobblestone')]]) + .register() + +//crafting.addShapeless(item('minecraft:clay'), [item('minecraft:cobblestone'),item('minecraft:nether_star'),item('minecraft:gold_ingot')]) +crafting.shapelessBuilder() + .output(item('minecraft:clay')) + .input([item('minecraft:cobblestone'),item('minecraft:nether_star'),item('minecraft:gold_ingot')]) + .register() + +//crafting.addShapeless('precious_to_clay', item('minecraft:clay'), [item('minecraft:diamond'),item('minecraft:gold_ingot'),item('minecraft:gold_ingot')]) +crafting.shapelessBuilder() + .name('precious_to_clay') + .output(item('minecraft:clay')) + .input([item('minecraft:diamond'),item('minecraft:gold_ingot'),item('minecraft:gold_ingot')]) + .register() + +//crafting.addShapeless(resource('example:resource_location2'), item('minecraft:clay'), [item('minecraft:cobblestone'), item('minecraft:gold_ingot')]) +crafting.shapelessBuilder() + .name(resource('example:resource_location2')) + .output(item('minecraft:clay')) + .input([item('minecraft:cobblestone'), item('minecraft:gold_ingot')]) + .register() + +//crafting.replaceShapeless(item('minecraft:ender_eye'), [item('minecraft:ender_pearl'),item('minecraft:nether_star')]) +crafting.shapelessBuilder() + .output(item('minecraft:ender_eye')) + .input([item('minecraft:ender_pearl'),item('minecraft:nether_star')]) + .replace() + .register() + +//crafting.replaceShapeless('minecraft:pink_dye_from_pink_tulp', item('minecraft:clay'), [item('minecraft:nether_star')]) +crafting.shapelessBuilder() + .name('minecraft:pink_dye_from_pink_tulp') + .output(item('minecraft:clay')) + .input([item('minecraft:nether_star')]) + .replaceByName() + .register() + +//crafting.replaceShapeless(resource('minecraft:pink_dye_from_peony'), item('minecraft:clay'), [item('minecraft:cobblestone'), item('minecraft:gold_ingot')]) +crafting.shapelessBuilder() + .name(resource('minecraft:pink_dye_from_peony')) + .output(item('minecraft:clay')) + .input([item('minecraft:cobblestone'), item('minecraft:gold_ingot')]) + .replaceByName() + .register() + +//crafting.replaceShaped(item('minecraft:chest'), [[ore('logWood'),ore('logWood'),ore('logWood')],[ore('logWood'),null,ore('logWood')],[ore('logWood'),ore('logWood'),ore('logWood')]]) +crafting.shapedBuilder() + .output(item('minecraft:chest')) + .shape([[ore('logWood'),ore('logWood'),ore('logWood')],[ore('logWood'),null,ore('logWood')],[ore('logWood'),ore('logWood'),ore('logWood')]]) + .replace() + .register() + +//crafting.replaceShaped('gold_to_diamonds', item('minecraft:diamond') * 8, [[item('minecraft:gold_ingot'),item('minecraft:gold_ingot'),item('minecraft:gold_ingot')],[item('minecraft:gold_ingot'),null,item('minecraft:gold_ingot')],[item('minecraft:gold_ingot'),item('minecraft:gold_ingot'),item('minecraft:gold_ingot')]]) +crafting.shapedBuilder() + .name('gold_to_diamonds') + .output(item('minecraft:diamond') * 8) + .shape([[item('minecraft:gold_ingot'),item('minecraft:gold_ingot'),item('minecraft:gold_ingot')],[item('minecraft:gold_ingot'),null,item('minecraft:gold_ingot')],[item('minecraft:gold_ingot'),item('minecraft:gold_ingot'),item('minecraft:gold_ingot')]]) + .replaceByName() + .register() + +//crafting.replaceShaped(resource('minecraft:sea_lantern'), item('minecraft:clay'), [[item('minecraft:glowstone')],[item('minecraft:glowstone')],[item('minecraft:glowstone')]]) +crafting.shapedBuilder() + .name(resource('minecraft:sea_lantern')) + .output(item('minecraft:clay')) + .shape([[item('minecraft:glowstone')],[item('minecraft:glowstone')],[item('minecraft:glowstone')]]) + .replaceByName() + .register() + + +// The recipe builder also has some additional features, including +// The abilty to input a string and a set of keys, significantly improving readability. + +crafting.shapedBuilder() + .name('nether_star_from_clay_and_tnt') + .output(item('minecraft:nether_star')) + .row('TXT') + .row('X X') // The key space (' ') is set to Ingredient.EMPTY (and cannot be changed) + .row('!X!') // WARNING: All rows must be the same length. + .key('T', item('minecraft:tnt')) // Keys are case sensitive + .key('X', item('minecraft:clay').reuse()) // Reuse returns the item instead of consuming it + .key('!', item('minecraft:tnt').transform({ _ -> item('minecraft:diamond') })) // Transforms the item into a diamond + .register() + +// A map of keys can also be passed in. The map can contain any IIngredient, including those with transforms or otherwise +def presetKeys = [ + X: item('minecraft:clay'), + T: item('minecraft:tnt'), + D: item('minecraft:diamond'), + S: ore('netherStar').reuse(), + '!': item('minecraft:tnt').transform({ _ -> item('minecraft:diamond') }), + G: ore('ingotGold'), + W: fluid('water') * 1000, // Any tank that contains >= 1000 mb and can be reduced by 1000. + '0': item('minecraft:diamond_sword').withNbt([display:[Name:'Sword with Specific NBT data']]) +] + +crafting.shapedBuilder() + .output(item('minecraft:clay_ball') * 3) + .shape('S S', // Shape allows a series of either comma separated strings or an array of strings + ' G ', + 'SWS') + .key(presetKeys) + .register() + +crafting.shapedBuilder() + .name('nether_star_duplication_with_tnt') + .output(item('minecraft:nether_star')) + .row('!!!') + .row('!S!') + .row('!!!') + .key(presetKeys) + .register() + +crafting.shapedBuilder() + .output(item('minecraft:clay')) + .row(' ') + .row(' 0 ') // Requires the item be in exactly the center of the 3x3 grid. + .row(' ') + .key(presetKeys) + .register() + + +crafting.remove('minecraft:mossy_stonebrick') // Remove the entry with the recipe ID +crafting.remove(resource('minecraft:stonebrick')) +crafting.removeByOutput(item('minecraft:gold_ingot')) // Remove all recipes with the output +crafting.removeByInput(item('minecraft:iron_ingot')) // Remove all recipes containing the ingredient as an input +//crafting.removeAll() + + +// Furnace +furnace.add(ore('ingotIron'), item('minecraft:diamond')) // exp has a default value of 0.1 +furnace.add(item('minecraft:nether_star'), item('minecraft:clay') * 64, 13) + +furnace.recipeBuilder() + .input(ore('ingotGold')) + .output(item('minecraft:nether_star')) + .exp(0.5) // Optional float, xp gained per recipe completion. Default 0.1f + .register() + +furnace.removeByInput(item('minecraft:clay')) +furnace.removeByOutput(item('minecraft:brick')) +//furnace.removeAll() + + +// OreDictionary (OreDict) +oredict.add('ingotGold', item('minecraft:nether_star')) +oredict.add('netherStar', item('minecraft:gold_ingot')) +oredict.remove('netherStar', item('minecraft:nether_star')) + +oredict.clear('plankWood') // Note that any recipes using this oredict will silently die +oredict.removeAll('ingotIron') +//oredict.removeAll() + + +// Starting inventory +player.testingStartingItems = false // Enable this to have the items be given every time you join the world. Use in testing only. +player.replaceDefaultInventory = true // Enable this to replace any existing items with GroovyScript's starting inventory items. +player.setStartingItems(true, // Boolean determines if items are added to specific slots, with true meaning the items are slot specific. + item('minecraft:clay').withNbt([display:[Name:'Hotbar']]), null, null, null, null, null, null, null, null, + item('minecraft:clay').withNbt([display:[Name:'Top row of inventory']]), null, null, null, null, null, null, null, null, + item('minecraft:clay').withNbt([display:[Name:'Middle row of inventory']]), null, null, null, null, null, null, null, null, + item('minecraft:clay').withNbt([display:[Name:'Bottom row of inventory']]), null, null, null, null, null, null, null, null, + item('minecraft:diamond_boots'), item('minecraft:diamond_leggings'), item('minecraft:diamond_chestplate'), item('minecraft:diamond_helmet'), + item('minecraft:clay').withNbt([display:[Name:'Offhand']]) +) + +// Items can also be added to specific slots individually +//player.addStartingItem(item('minecraft:diamond_boots'), 36) // Note that this will error if the slot has already been set to an item +// 0-8 is hotbar, 9-17 is top row, 18-26 is middle row, 26-35 is bottom row, 36 is boots, 37 is leggings, 38 is chestplate, 39 is helmet, and 40 is offhand. + +// Or added to any slot in the inventory +player.addStartingItem(item('minecraft:clay_ball')) +player.addStartingItem(item('minecraft:gold_ingot')) +player.addStartingItem(item('minecraft:diamond')) +player.addStartingItem(item('minecraft:nether_star')) +player.addStartingItem(item('minecraft:water_bucket')) + +// Text formatting bracket handler +// Colors: BLACK (0), DARK_BLUE (1), DARK_GREEN (2), DARK_AQUA (3), DARK_RED (4), DARK_PURPLE (5), GOLD (6), GRAY (7), DARK_GRAY (8),BLUE (9), GREEN (10), AQUA (11), RED (12), LIGHT_PURPLE (13), YELLOW (14), WHITE (15) +// Emphasis: OBFUSCATED, BOLD, STRIKETHROUGH, UNDERLINE, ITALIC +// Clears formatting: RESET (-1) + +// Note: only one text format can be set at a time. To have multiple, use a different way. +rarity.set(textformat('AQUA'), item('minecraft:diamond')) +// And item mixin +item('minecraft:clay').setRarity(textformat('BOLD')) + +// Removes text formatting from the name. +rarity.set(textformat('RESET'), item('minecraft:enchanted_book')) +item('minecraft:golden_apple').setRarity(textformat('-1')) + + +// Use eventManager.listen and listen to the desired event. +eventManager.listen({ BlockEvent.BreakEvent event -> { + event.setCanceled(true) // Many events can be canceled. + event.player.sendMessage(new TextComponentString("${event.getState().getBlock().getLocalizedName()} Block was prevent from being broken")) +}}) + +// The outer parentheses and inner curly braces are optional. +eventManager.listen { EnderTeleportEvent event -> + event.setAttackDamage 19.5f +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java index a0557a7c5..9e1838518 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java @@ -80,15 +80,6 @@ public AltarRecipeBuilder shape(String... matrix) { return this; } - public AltarRecipeBuilder key(String c, IIngredient item) { - if (c == null || c.length() != 1) { - errors.add("key must be a single char but found '" + c + "'"); - return this; - } - this.keyMap.put(c.charAt(0), item); - return this; - } - public AltarRecipeBuilder starlight(int starlight) { this.starlightRequired = starlight; return this; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/EnderRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/EnderRecipeBuilder.java index 37ff1d8b5..02efafa8c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/EnderRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/EnderRecipeBuilder.java @@ -83,6 +83,11 @@ public EnderRecipeBuilder.Shaped row(String row) { return this; } + public EnderRecipeBuilder.Shaped key(char c, IIngredient ingredient) { + this.keyMap.put(c, ingredient); + return this; + } + public EnderRecipeBuilder.Shaped key(String c, IIngredient ingredient) { if (c == null || c.length() != 1) { errors.add("key must be a single char, but found '" + c + "'"); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/TableRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/TableRecipeBuilder.java index a60e17a05..f19d6efa4 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/TableRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/TableRecipeBuilder.java @@ -91,6 +91,11 @@ public TableRecipeBuilder.Shaped row(String row) { return this; } + public TableRecipeBuilder.Shaped key(char c, IIngredient ingredient) { + this.keyMap.put(c, ingredient); + return this; + } + public TableRecipeBuilder.Shaped key(String c, IIngredient ingredient) { if (c == null || c.length() != 1) { errors.add("key must be a single char, but found '" + c + "'"); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/arcane/ArcaneRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/arcane/ArcaneRecipeBuilder.java index 0a1a652b5..8d606cbce 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/arcane/ArcaneRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/arcane/ArcaneRecipeBuilder.java @@ -9,7 +9,6 @@ import com.cleanroommc.groovyscript.registry.ReloadableRegistryManager; import it.unimi.dsi.fastutil.chars.Char2ObjectOpenHashMap; import net.minecraft.item.crafting.IRecipe; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.common.registry.ForgeRegistries; import org.apache.commons.lang3.ArrayUtils; import thaumcraft.api.aspects.Aspect; @@ -56,8 +55,6 @@ protected void validateArcane(GroovyLog.Msg msg) { public static class Shaped extends ArcaneRecipeBuilder { - private static final String ID_PREFIX = "shaped_arcane_"; - protected boolean mirrored = false; private String[] keyBasedMatrix; private final Char2ObjectOpenHashMap keyMap = new Char2ObjectOpenHashMap<>(); @@ -98,6 +95,11 @@ public ArcaneRecipeBuilder.Shaped row(String row) { return this; } + public ArcaneRecipeBuilder.Shaped key(char c, IIngredient ingredient) { + this.keyMap.put(c, ingredient); + return this; + } + // groovy doesn't have char literals public ArcaneRecipeBuilder.Shaped key(String c, IIngredient ingredient) { if (c == null || c.length() != 1) { @@ -118,6 +120,11 @@ public ArcaneRecipeBuilder.Shaped shape(List> matrix) { return this; } + @Override + public String getRecipeNamePrefix() { + return "groovyscript_shaped_arcane_"; + } + @Override public IRecipe register() { GroovyLog.Msg msg = GroovyLog.msg("Error creating Thaumcraft Arcane Workbench recipe").error() @@ -136,8 +143,8 @@ public IRecipe register() { if (recipe != null) { handleReplace(); - ResourceLocation rl = createName(name, ID_PREFIX); - ReloadableRegistryManager.addRegistryEntry(ForgeRegistries.RECIPES, rl, recipe); + validateName(); + ReloadableRegistryManager.addRegistryEntry(ForgeRegistries.RECIPES, name, recipe); } return recipe; @@ -146,8 +153,6 @@ public IRecipe register() { public static class Shapeless extends ArcaneRecipeBuilder { - private static final String ID_PREFIX = "shapeless_arcane_"; - private final List ingredients = new ArrayList<>(); public ArcaneRecipeBuilder.Shapeless input(IIngredient ingredient) { @@ -169,6 +174,11 @@ public ArcaneRecipeBuilder.Shapeless input(Collection ingredients) return this; } + @Override + public String getRecipeNamePrefix() { + return "groovyscript_shapeless_arcane_"; + } + @Override public IRecipe register() { IngredientHelper.trim(ingredients); @@ -183,8 +193,8 @@ public IRecipe register() { } handleReplace(); ShapelessArcaneCR recipe = new ShapelessArcaneCR(output.copy(), ingredients, recipeFunction, recipeAction, researchKey, vis, aspects); - ResourceLocation rl = createName(name, ID_PREFIX); - ReloadableRegistryManager.addRegistryEntry(ForgeRegistries.RECIPES, rl, recipe); + validateName(); + ReloadableRegistryManager.addRegistryEntry(ForgeRegistries.RECIPES, name, recipe); return recipe; } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Crafting.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Crafting.java index 5d2da7285..fb929a5e7 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Crafting.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Crafting.java @@ -24,6 +24,10 @@ public static IIngredient getFallback(char c) { return fallbackChars.get(c); } + public void setFallback(char key, IIngredient ingredient) { + fallbackChars.put(key, ingredient); + } + public void setFallback(String key, IIngredient ingredient) { if (key == null || key.length() != 1) { GroovyLog.get().error("Fallback key must be a single character"); @@ -33,7 +37,10 @@ public void setFallback(String key, IIngredient ingredient) { } public void addShaped(ItemStack output, List> input) { - addShaped(null, output, input); + shapedBuilder() + .matrix(input) + .output(output) + .register(); } public void addShaped(String name, ItemStack output, List> input) { @@ -44,8 +51,19 @@ public void addShaped(String name, ItemStack output, List> inp .register(); } + public void addShaped(ResourceLocation name, ItemStack output, List> input) { + shapedBuilder() + .matrix(input) + .output(output) + .name(name) + .register(); + } + public void addShapeless(ItemStack output, List input) { - addShapeless(null, output, input); + shapelessBuilder() + .input(input) + .output(output) + .register(); } public void addShapeless(String name, ItemStack output, List input) { @@ -56,8 +74,20 @@ public void addShapeless(String name, ItemStack output, List input) .register(); } + public void addShapeless(ResourceLocation name, ItemStack output, List input) { + shapelessBuilder() + .input(input) + .output(output) + .name(name) + .register(); + } + public void replaceShapeless(ItemStack output, List input) { - replaceShapeless(null, output, input); + shapelessBuilder() + .input(input) + .output(output) + .replace() + .register(); } public void replaceShapeless(String name, ItemStack output, List input) { @@ -65,12 +95,25 @@ public void replaceShapeless(String name, ItemStack output, List in .input(input) .output(output) .name(name) - .replace() + .replaceByName() + .register(); + } + + public void replaceShapeless(ResourceLocation name, ItemStack output, List input) { + shapelessBuilder() + .input(input) + .output(output) + .name(name) + .replaceByName() .register(); } public void replaceShaped(ItemStack output, List> input) { - replaceShaped(null, output, input); + shapedBuilder() + .matrix(input) + .output(output) + .replace() + .register(); } public void replaceShaped(String name, ItemStack output, List> input) { @@ -82,10 +125,23 @@ public void replaceShaped(String name, ItemStack output, List> .register(); } + public void replaceShaped(ResourceLocation name, ItemStack output, List> input) { + shapedBuilder() + .matrix(input) + .output(output) + .name(name) + .replaceByName() + .register(); + } + public void remove(String name) { ReloadableRegistryManager.removeRegistryEntry(ForgeRegistries.RECIPES, name); } + public void remove(ResourceLocation name) { + ReloadableRegistryManager.removeRegistryEntry(ForgeRegistries.RECIPES, name); + } + public void removeByOutput(IIngredient output) { removeByOutput(output, true); } @@ -136,7 +192,7 @@ public void removeByInput(IIngredient input, boolean log) { } List recipesToRemove = new ArrayList<>(); for (IRecipe recipe : ForgeRegistries.RECIPES) { - if (recipe.getRegistryName() != null && !recipe.getIngredients().isEmpty() && recipe.getIngredients().stream().anyMatch(i -> i.getMatchingStacks().length > 0 && input.test(i.getMatchingStacks()[0]))){ + if (recipe.getRegistryName() != null && !recipe.getIngredients().isEmpty() && recipe.getIngredients().stream().anyMatch(i -> i.getMatchingStacks().length > 0 && input.test(i.getMatchingStacks()[0]))) { recipesToRemove.add(recipe.getRegistryName()); } } @@ -162,6 +218,12 @@ public SimpleObjectStream streamRecipes() { }); } + public void removeAll() { + for (IRecipe recipe : ForgeRegistries.RECIPES) { + ReloadableRegistryManager.removeRegistryEntry(ForgeRegistries.RECIPES, recipe.getRegistryName()); + } + } + public CraftingRecipeBuilder.Shaped shapedBuilder() { return new CraftingRecipeBuilder.Shaped(3, 3); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/CraftingRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/CraftingRecipeBuilder.java index 638316057..3b5d1fe69 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/CraftingRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/CraftingRecipeBuilder.java @@ -21,11 +21,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; public abstract class CraftingRecipeBuilder { protected ItemStack output; - protected String name; + protected ResourceLocation name; protected Closure recipeFunction; protected Closure recipeAction; protected byte replace = 0; @@ -38,6 +39,15 @@ public CraftingRecipeBuilder(int width, int height) { } public CraftingRecipeBuilder name(String name) { + if (name.contains(":")) { + this.name = new ResourceLocation(name); + } else { + this.name = new ResourceLocation(GroovyScript.getRunConfig().getPackId(), name); + } + return this; + } + + public CraftingRecipeBuilder name(ResourceLocation name) { this.name = name; return this; } @@ -86,20 +96,19 @@ protected void handleReplace() { } @GroovyBlacklist - protected ResourceLocation createName(@Nullable String name, @Nullable String prefix) { + public String getRecipeNamePrefix() { + return "groovyscript_"; + } + + @GroovyBlacklist + public void validateName() { if (name == null) { - return new ResourceLocation(GroovyScript.getRunConfig().getPackId(), prefix == null ? RecipeName.generate() : RecipeName.generate(prefix)); - } - if (name.contains(":")) { - return new ResourceLocation(name); + name = new ResourceLocation(GroovyScript.getRunConfig().getPackId(), RecipeName.generate(getRecipeNamePrefix())); } - return new ResourceLocation(GroovyScript.getRunConfig().getPackId(), name); } public static class Shaped extends CraftingRecipeBuilder { - private static final String ID_PREFIX = "shaped_"; - protected boolean mirrored = false; private String[] keyBasedMatrix; private final Char2ObjectOpenHashMap keyMap = new Char2ObjectOpenHashMap<>(); @@ -141,6 +150,11 @@ public Shaped row(String row) { return this; } + public Shaped key(char c, IIngredient ingredient) { + this.keyMap.put(c, ingredient); + return this; + } + // groovy doesn't have char literals public Shaped key(String c, IIngredient ingredient) { if (c == null || c.length() != 1) { @@ -151,6 +165,13 @@ public Shaped key(String c, IIngredient ingredient) { return this; } + public Shaped key(Map map) { + for (Map.Entry x : map.entrySet()) { + key(x.getKey(), x.getValue()); + } + return this; + } + public Shaped matrix(List> matrix) { this.ingredientMatrix = matrix; return this; @@ -161,9 +182,14 @@ public Shaped shape(List> matrix) { return this; } + @Override + public String getRecipeNamePrefix() { + return "groovyscript_shaped_"; + } + @Override public IRecipe register() { - GroovyLog.Msg msg = GroovyLog.msg("Error adding Minecraft Shapeless Crafting recipe").error() + GroovyLog.Msg msg = GroovyLog.msg("Error adding Minecraft Shaped Crafting recipe").error() .add((keyBasedMatrix == null || keyBasedMatrix.length == 0) && (ingredientMatrix == null || ingredientMatrix.isEmpty()), () -> "No matrix was defined") .add(keyBasedMatrix != null && ingredientMatrix != null, () -> "A key based matrix AND a ingredient based matrix was defined. This is not allowed!"); if (msg.postIfNotEmpty()) return null; @@ -178,8 +204,8 @@ public IRecipe register() { if (recipe != null) { handleReplace(); - ResourceLocation rl = createName(name, ID_PREFIX); - ReloadableRegistryManager.addRegistryEntry(ForgeRegistries.RECIPES, rl, recipe); + validateName(); + ReloadableRegistryManager.addRegistryEntry(ForgeRegistries.RECIPES, name, recipe); } return recipe; @@ -188,8 +214,6 @@ public IRecipe register() { public static class Shapeless extends CraftingRecipeBuilder { - private static final String ID_PREFIX = "shapeless_"; - private final List ingredients = new ArrayList<>(); public Shapeless(int width, int height) { @@ -215,6 +239,11 @@ public Shapeless input(Collection ingredients) { return this; } + @Override + public String getRecipeNamePrefix() { + return "groovyscript_shapeless_"; + } + @Override public IRecipe register() { IngredientHelper.trim(ingredients); @@ -228,8 +257,8 @@ public IRecipe register() { } handleReplace(); ShapelessCraftingRecipe recipe = new ShapelessCraftingRecipe(output.copy(), ingredients, recipeFunction, recipeAction); - ResourceLocation rl = createName(name, ID_PREFIX); - ReloadableRegistryManager.addRegistryEntry(ForgeRegistries.RECIPES, rl, recipe); + validateName(); + ReloadableRegistryManager.addRegistryEntry(ForgeRegistries.RECIPES, name, recipe); return recipe; } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Furnace.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Furnace.java index 3509e09f2..6e90154e5 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Furnace.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Furnace.java @@ -5,9 +5,11 @@ import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.FurnaceRecipes; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; @@ -19,6 +21,10 @@ public Furnace() { super(); } + public RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + public void add(IIngredient input, ItemStack output) { add(input, output, 0.1f); } @@ -164,6 +170,21 @@ public SimpleObjectStream streamRecipes() { return new SimpleObjectStream<>(recipes, false).setRemover(recipe -> remove(recipe, true)); } + public void removeAll() { + FurnaceRecipes.instance().getSmeltingList().entrySet().removeIf(entry -> { + float exp = FurnaceRecipes.instance().getSmeltingExperience(entry.getValue()); + Recipe recipe = new Recipe(entry.getKey(), entry.getValue(), exp); + addBackup(recipe); + return true; + }); + /*for (Map.Entry entry : FurnaceRecipes.instance().getSmeltingList().entrySet()) { + float exp = FurnaceRecipes.instance().getSmeltingExperience(entry.getValue()); + Recipe recipe = new Recipe(entry.getKey(), entry.getValue(), exp); + addBackup(recipe); + FurnaceRecipes.instance().getSmeltingList().remove(recipe.input); + }*/ + } + @GroovyBlacklist @Override public void onReload() { @@ -171,6 +192,53 @@ public void onReload() { getBackupRecipes().forEach(recipe -> FurnaceRecipes.instance().addSmeltingRecipe(recipe.input, recipe.output, recipe.exp)); } + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private IIngredient input; + private ItemStack output; + private float exp = 0.1f; + + public RecipeBuilder input(IIngredient input) { + this.input = input; + return this; + } + + public RecipeBuilder output(ItemStack output) { + this.output = output; + return this; + } + + public RecipeBuilder exp(float exp) { + this.exp = exp; + return this; + } + + @Override + public String getErrorMsg() { + return "Error adding Minecraft Furnace recipe"; + } + + @Override + public void validate(GroovyLog.Msg msg) { + msg.add(IngredientHelper.isEmpty(input), () -> "Input must not be empty"); + msg.add(IngredientHelper.isEmpty(output), () -> "Output must not be empty"); + if (exp < 0) { + exp = 0.1f; + } + } + + @Override + public @Nullable Recipe register() { + if (!validate()) return null; + Recipe recipe = null; + for (ItemStack itemStack : input.getMatchingStacks()) { + recipe = new Recipe(itemStack, output, exp); + VanillaModule.furnace.add(recipe); + } + return recipe; + } + } + public static class Recipe { private final ItemStack input; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/OreDict.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/OreDict.java index cffa387ca..503aa84fe 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/OreDict.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/OreDict.java @@ -111,6 +111,10 @@ private boolean remove(String oreDict, ItemStack ore, boolean scripted) { } public boolean clear(String name) { + return removeAll(name); + } + + public boolean removeAll(String name) { List list = getItems(name); if (GroovyLog.msg("Error removing from OreDictionary entry") .add(list.isEmpty(), "OreDictionary Entry was empty") @@ -121,4 +125,12 @@ public boolean clear(String name) { list.forEach(stack -> remove(name, stack)); return true; } + + public void removeAll() { + for (String name : OreDictionary.getOreNames()) { + for (ItemStack stack : getItems(name)) { + remove(name, stack); + } + } + } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Player.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Player.java index 6ce32e366..d8795d1fb 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Player.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Player.java @@ -3,29 +3,39 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IScriptReloadable; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.item.ItemStack; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; public class Player implements IScriptReloadable { public static final String GIVEN_ITEMS = "GroovyScript:GivenItems"; public boolean testingStartingItems = false; + public boolean replaceDefaultInventory = false; private final List givenItemsAnySlot = new ArrayList<>(); - private ItemStack[] givenItemsSlots = new ItemStack[36]; + private final Map givenItemsSlots = new Int2ObjectOpenHashMap<>(); @GroovyBlacklist public void addToInventory(InventoryPlayer playerInv) { - for (int i = 0; i < givenItemsSlots.length; i++) { - ItemStack stack = givenItemsSlots[i]; - if (stack != null && !stack.isEmpty()) { - playerInv.add(i, stack.copy()); + if (replaceDefaultInventory) playerInv.clear(); + + for (Map.Entry entry : givenItemsSlots.entrySet()) { + if (replaceDefaultInventory) { + playerInv.setInventorySlotContents(entry.getKey(), entry.getValue().copy()); + } else { + if (entry.getValue().isEmpty()) continue; + + if (playerInv.getStackInSlot(entry.getKey()).isEmpty() || playerInv.getStackInSlot(entry.getKey()).equals(entry.getValue())) { + playerInv.add(entry.getKey(), entry.getValue().copy()); + } else { + GroovyLog.msg("Could not set inventory slot {} to itemstack {}", entry.getKey(), entry.getValue()).error().post(); + } } } givenItemsAnySlot.stream().map(ItemStack::copy).forEach(playerInv::addItemStackToInventory); @@ -36,29 +46,59 @@ public void addStartingItem(ItemStack item) { } public void addStartingItem(ItemStack item, int slot) { - if (slot >= 36) { - GroovyLog.msg("Warning: assigning items to a player's inventory slot greater than 36 may cause some items to not be received by the player.") + if (slot >= 41) { + GroovyLog.msg("Warning: assigning items to a player's inventory slot greater than 41 may cause some items to not be received by the player.") .warn().post(); } if (slot <= -1) { - this.givenItemsAnySlot.add(item); + givenItemsAnySlot.add(item == null ? ItemStack.EMPTY : item); } else { - if (slot >= givenItemsSlots.length) { - ItemStack[] oldGivenItemsSlots = givenItemsSlots; - givenItemsSlots = Arrays.copyOf(oldGivenItemsSlots, slot + 1); - } - if (givenItemsSlots[slot] != null) { - GroovyLog.msg("Error: slot {} has already been occupied by another item.", slot) + if (givenItemsSlots.get(slot) != null) { + GroovyLog.msg("Warning: slot {} has already been occupied by another item.", slot) .error().post(); + return; + } + givenItemsSlots.put(slot, item == null ? ItemStack.EMPTY : item); + } + } + + public void setStartingItems(boolean isSlotSpecific, ItemStack... items) { + if (items.length >= 41) { + GroovyLog.msg("Warning: assigning items to a player's inventory slot greater than 41 may cause some items to not be received by the player.") + .warn().post(); + } + if (isSlotSpecific) { + givenItemsSlots.clear(); + for (int i = 0; i < items.length; i++) { + givenItemsSlots.put(i, items[i] == null ? ItemStack.EMPTY : items[i]); } + } else { + givenItemsAnySlot.clear(); + givenItemsAnySlot.addAll(Arrays.stream(items).filter(Objects::nonNull).collect(Collectors.toList())); + } + } + + public void setStartingItems(boolean isSlotSpecific, List items) { + if (items.size() >= 41) { + GroovyLog.msg("Warning: assigning items to a player's inventory slot greater than 41 may cause some items to not be received by the player.") + .warn().post(); + } + if (isSlotSpecific) { + givenItemsSlots.clear(); + for (int i = 0; i < items.size(); i++) { + givenItemsSlots.put(i, items.get(0) == null ? ItemStack.EMPTY : items.get(0)); + } + } else { + givenItemsAnySlot.clear(); + givenItemsAnySlot.addAll(items.stream().filter(Objects::nonNull).collect(Collectors.toList())); } } @Override @GroovyBlacklist public void onReload() { - this.givenItemsAnySlot.clear(); - this.givenItemsSlots = new ItemStack[36]; + givenItemsAnySlot.clear(); + givenItemsSlots.clear(); } @Override diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/RarityItemStackExpansion.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/RarityItemStackExpansion.java new file mode 100644 index 000000000..0a39d7d47 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/RarityItemStackExpansion.java @@ -0,0 +1,12 @@ +package com.cleanroommc.groovyscript.compat.vanilla; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.text.TextFormatting; + +public class RarityItemStackExpansion { + + public static ItemStack setRarity(ItemStack item, TextFormatting color) { + VanillaModule.rarity.set(color, item); + return item; + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java index 1371ccc29..9f4963b7d 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java @@ -5,6 +5,8 @@ import com.cleanroommc.groovyscript.api.IScriptReloadable; import com.cleanroommc.groovyscript.compat.content.Content; import com.cleanroommc.groovyscript.compat.loot.Loot; +import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper; +import net.minecraft.item.ItemStack; public class VanillaModule implements IScriptReloadable { @@ -25,6 +27,8 @@ public static void initializeBinding() { GroovyScript.getSandbox().registerBinding("Player", player); GroovyScript.getSandbox().registerBinding("Content", content); GroovyScript.getSandbox().registerBinding("Rarity", rarity); + + ExpansionHelper.mixinClass(ItemStack.class, RarityItemStackExpansion.class); } @Override diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/GroovyHelper.java b/src/main/java/com/cleanroommc/groovyscript/helper/GroovyHelper.java index 8496a0748..9c5b43069 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/GroovyHelper.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/GroovyHelper.java @@ -47,6 +47,10 @@ public static String getPackName() { return GroovyScript.getRunConfig().getPackName(); } + public static String getPackId() { + return GroovyScript.getRunConfig().getPackId(); + } + public static String getPackVersion() { return GroovyScript.getRunConfig().getVersion(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/recipe/AbstractRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/helper/recipe/AbstractRecipeBuilder.java index 84b5a158a..345dcd842 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/recipe/AbstractRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/recipe/AbstractRecipeBuilder.java @@ -25,7 +25,11 @@ public String getRecipeNamePrefix() { } public AbstractRecipeBuilder name(String name) { - this.name = new ResourceLocation(GroovyScript.getRunConfig().getPackId(), name); + if (name.contains(":")) { + this.name = new ResourceLocation(name); + } else { + this.name = new ResourceLocation(GroovyScript.getRunConfig().getPackId(), name); + } return this; } From add96c6b1eebd4e5aa0a20b859455b0576baed2f Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Thu, 20 Jul 2023 15:41:43 -0700 Subject: [PATCH 08/28] split examples into preInit and postInit, update runConfig --- .../{ => postInit}/actuallyadditions.groovy | 0 examples/{ => postInit}/astral.groovy | 0 examples/{ => postInit}/bloodmagic.groovy | 0 examples/{ => postInit}/botania.groovy | 0 examples/{ => postInit}/chisel.groovy | 0 .../{ => postInit}/draconicevolution.groovy | 0 examples/{ => postInit}/enderio.groovy | 0 examples/{ => postInit}/evilcraft.groovy | 0 .../{ => postInit}/extendedcrafting.groovy | 0 examples/{ => postInit}/forestry.groovy | 0 .../immersiveengineering.groovy | 0 examples/{ => postInit}/loot.groovy | 0 examples/{ => postInit}/mekanism.groovy | 0 examples/{ => postInit}/roots.groovy | 0 examples/{ => postInit}/thaumcraft.groovy | 0 examples/{ => postInit}/thermal.groovy | 0 examples/{ => postInit}/vanilla.groovy | 0 examples/preInit/mekanism.groovy | 5 +++++ examples/runConfig.json | 22 ++++++++----------- 19 files changed, 14 insertions(+), 13 deletions(-) rename examples/{ => postInit}/actuallyadditions.groovy (100%) rename examples/{ => postInit}/astral.groovy (100%) rename examples/{ => postInit}/bloodmagic.groovy (100%) rename examples/{ => postInit}/botania.groovy (100%) rename examples/{ => postInit}/chisel.groovy (100%) rename examples/{ => postInit}/draconicevolution.groovy (100%) rename examples/{ => postInit}/enderio.groovy (100%) rename examples/{ => postInit}/evilcraft.groovy (100%) rename examples/{ => postInit}/extendedcrafting.groovy (100%) rename examples/{ => postInit}/forestry.groovy (100%) rename examples/{ => postInit}/immersiveengineering.groovy (100%) rename examples/{ => postInit}/loot.groovy (100%) rename examples/{ => postInit}/mekanism.groovy (100%) rename examples/{ => postInit}/roots.groovy (100%) rename examples/{ => postInit}/thaumcraft.groovy (100%) rename examples/{ => postInit}/thermal.groovy (100%) rename examples/{ => postInit}/vanilla.groovy (100%) create mode 100644 examples/preInit/mekanism.groovy diff --git a/examples/actuallyadditions.groovy b/examples/postInit/actuallyadditions.groovy similarity index 100% rename from examples/actuallyadditions.groovy rename to examples/postInit/actuallyadditions.groovy diff --git a/examples/astral.groovy b/examples/postInit/astral.groovy similarity index 100% rename from examples/astral.groovy rename to examples/postInit/astral.groovy diff --git a/examples/bloodmagic.groovy b/examples/postInit/bloodmagic.groovy similarity index 100% rename from examples/bloodmagic.groovy rename to examples/postInit/bloodmagic.groovy diff --git a/examples/botania.groovy b/examples/postInit/botania.groovy similarity index 100% rename from examples/botania.groovy rename to examples/postInit/botania.groovy diff --git a/examples/chisel.groovy b/examples/postInit/chisel.groovy similarity index 100% rename from examples/chisel.groovy rename to examples/postInit/chisel.groovy diff --git a/examples/draconicevolution.groovy b/examples/postInit/draconicevolution.groovy similarity index 100% rename from examples/draconicevolution.groovy rename to examples/postInit/draconicevolution.groovy diff --git a/examples/enderio.groovy b/examples/postInit/enderio.groovy similarity index 100% rename from examples/enderio.groovy rename to examples/postInit/enderio.groovy diff --git a/examples/evilcraft.groovy b/examples/postInit/evilcraft.groovy similarity index 100% rename from examples/evilcraft.groovy rename to examples/postInit/evilcraft.groovy diff --git a/examples/extendedcrafting.groovy b/examples/postInit/extendedcrafting.groovy similarity index 100% rename from examples/extendedcrafting.groovy rename to examples/postInit/extendedcrafting.groovy diff --git a/examples/forestry.groovy b/examples/postInit/forestry.groovy similarity index 100% rename from examples/forestry.groovy rename to examples/postInit/forestry.groovy diff --git a/examples/immersiveengineering.groovy b/examples/postInit/immersiveengineering.groovy similarity index 100% rename from examples/immersiveengineering.groovy rename to examples/postInit/immersiveengineering.groovy diff --git a/examples/loot.groovy b/examples/postInit/loot.groovy similarity index 100% rename from examples/loot.groovy rename to examples/postInit/loot.groovy diff --git a/examples/mekanism.groovy b/examples/postInit/mekanism.groovy similarity index 100% rename from examples/mekanism.groovy rename to examples/postInit/mekanism.groovy diff --git a/examples/roots.groovy b/examples/postInit/roots.groovy similarity index 100% rename from examples/roots.groovy rename to examples/postInit/roots.groovy diff --git a/examples/thaumcraft.groovy b/examples/postInit/thaumcraft.groovy similarity index 100% rename from examples/thaumcraft.groovy rename to examples/postInit/thaumcraft.groovy diff --git a/examples/thermal.groovy b/examples/postInit/thermal.groovy similarity index 100% rename from examples/thermal.groovy rename to examples/postInit/thermal.groovy diff --git a/examples/vanilla.groovy b/examples/postInit/vanilla.groovy similarity index 100% rename from examples/vanilla.groovy rename to examples/postInit/vanilla.groovy diff --git a/examples/preInit/mekanism.groovy b/examples/preInit/mekanism.groovy new file mode 100644 index 000000000..62530d18b --- /dev/null +++ b/examples/preInit/mekanism.groovy @@ -0,0 +1,5 @@ + + +eventManager.listen { TextureStitchEvent.Pre event -> + event.getMap().registerSprite(resource('groovytest:blocks/example')) +} diff --git a/examples/runConfig.json b/examples/runConfig.json index 76a0287df..c2d9401ef 100644 --- a/examples/runConfig.json +++ b/examples/runConfig.json @@ -1,6 +1,11 @@ { - "packName": "", - "version": "0.0.1", + "packName": "PlaceHolder name", + "packId": "placeholdername", + "version": "1.0.0", + "debug": true, + "classes": [ + "classes/" + ], "loaders": { "preInit": [ "preInit/" @@ -8,16 +13,7 @@ "init": [ ], "postInit": [ - "startup/" + "postInit/" ] - }, - "packmodes": { - "normal": [ - "normal/" - ], - "expert": [ - "expert" - ] - }, - "asm": null + } } \ No newline at end of file From 8abb13f3031ee4c1006a6025c1e63325232656f3 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Fri, 21 Jul 2023 17:03:21 -0700 Subject: [PATCH 09/28] replace %s with {} --- .../compat/mods/bloodmagic/AlchemyArray.java | 8 ++++---- .../compat/mods/bloodmagic/AlchemyTable.java | 4 ++-- .../compat/mods/bloodmagic/BloodAltar.java | 4 ++-- .../compat/mods/bloodmagic/TartaricForge.java | 4 ++-- .../compat/mods/bloodmagic/Tranquility.java | 8 ++++---- .../groovyscript/compat/mods/enderio/SoulBinder.java | 2 +- .../groovyscript/compat/mods/ic2/classic/Canner.java | 4 ++-- .../compat/mods/ic2/classic/ClassicElectrolyzer.java | 10 +++++----- .../compat/mods/ic2/classic/ClassicScrapbox.java | 2 +- .../compat/mods/ic2/classic/LiquidFuelGenerator.java | 2 +- .../compat/mods/ic2/classic/RareEarthExtractor.java | 2 +- .../groovyscript/compat/mods/ic2/exp/Fermenter.java | 2 +- .../compat/mods/mekanism/ChemicalInfuser.java | 2 +- .../compat/mods/mekanism/ChemicalOxidizer.java | 2 +- .../groovyscript/compat/mods/mekanism/Combiner.java | 2 +- .../groovyscript/compat/mods/mekanism/Crusher.java | 2 +- .../compat/mods/mekanism/DissolutionChamber.java | 2 +- .../compat/mods/mekanism/ElectrolyticSeparator.java | 2 +- .../compat/mods/mekanism/EnrichmentChamber.java | 2 +- .../compat/mods/mekanism/InjectionChamber.java | 2 +- .../compat/mods/mekanism/MetallurgicInfuser.java | 2 +- .../compat/mods/mekanism/OsmiumCompressor.java | 2 +- .../mods/mekanism/PressurizedReactionChamber.java | 2 +- .../compat/mods/mekanism/PurificationChamber.java | 2 +- .../groovyscript/compat/mods/mekanism/Sawmill.java | 2 +- .../groovyscript/compat/mods/mekanism/Smelting.java | 2 +- .../groovyscript/compat/mods/tcomplement/HighOven.java | 8 ++++---- .../groovyscript/compat/mods/thaumcraft/Crucible.java | 2 +- .../compat/mods/thaumcraft/InfusionCrafting.java | 2 +- .../compat/mods/thermalexpansion/Brewer.java | 2 +- .../compat/mods/thermalexpansion/Crucible.java | 2 +- .../compat/mods/thermalexpansion/Pulverizer.java | 2 +- .../compat/mods/tinkersconstruct/Alloying.java | 2 +- .../compat/mods/tinkersconstruct/Casting.java | 7 +++---- .../compat/mods/tinkersconstruct/Materials.java | 4 ++-- .../compat/mods/tinkersconstruct/Melting.java | 5 ++--- 36 files changed, 57 insertions(+), 59 deletions(-) diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java index 2ffc35b53..56a32d606 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java @@ -74,7 +74,7 @@ public boolean removeByInput(IIngredient input) { } GroovyLog.msg("Error removing Blood Magic Alchemy Array recipe") - .add("could not find recipe with input %s", input) + .add("could not find recipe with input {}", input) .error() .post(); return false; @@ -92,7 +92,7 @@ public boolean removeByCatalyst(IIngredient catalyst) { } GroovyLog.msg("Error removing Blood Magic Alchemy Array recipe") - .add("could not find recipe with catalyst %s", catalyst) + .add("could not find recipe with catalyst {}", catalyst) .error() .post(); return false; @@ -110,7 +110,7 @@ public boolean removeByInputAndCatalyst(IIngredient input, IIngredient catalyst) } GroovyLog.msg("Error removing Blood Magic Alchemy Array recipe") - .add("could not find recipe with input %s and catalyst %s", input, catalyst) + .add("could not find recipe with input {} and catalyst {}", input, catalyst) .error() .post(); return false; @@ -128,7 +128,7 @@ public boolean removeByOutput(ItemStack output) { } GroovyLog.msg("Error removing Blood Magic Alchemy Array recipe") - .add("could not find recipe with output %s", output) + .add("could not find recipe with output {}", output) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyTable.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyTable.java index b00141729..e34edd3d2 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyTable.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyTable.java @@ -80,7 +80,7 @@ public boolean removeByInput(NonNullList input) { } GroovyLog.msg("Error removing Blood Magic Alchemy Table recipe") - .add("could not find recipe with inputs including all of %s", input) + .add("could not find recipe with inputs including all of {}", input) .error() .post(); return false; @@ -97,7 +97,7 @@ public boolean removeByOutput(ItemStack output) { return true; } GroovyLog.msg("Error removing Blood Magic Alchemy Table recipe") - .add("could not find recipe with output %s", output) + .add("could not find recipe with output {}", output) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/BloodAltar.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/BloodAltar.java index 0110b2765..d5994e262 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/BloodAltar.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/BloodAltar.java @@ -64,7 +64,7 @@ public boolean removeByInput(IIngredient input) { } GroovyLog.msg("Error removing Blood Magic Blood Altar recipe") - .add("could not find recipe with input %s", input) + .add("could not find recipe with input {}", input) .error() .post(); return false; @@ -82,7 +82,7 @@ public boolean removeByOutput(ItemStack output) { } GroovyLog.msg("Error removing Blood Magic Blood Altar recipe") - .add("could not find recipe with output %s", output) + .add("could not find recipe with output {}", output) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/TartaricForge.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/TartaricForge.java index fcb1b045d..871b13112 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/TartaricForge.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/TartaricForge.java @@ -91,7 +91,7 @@ public boolean removeByInput(NonNullList input) { } GroovyLog.msg("Error removing Blood Magic Tartaric Forge recipe") - .add("could not find recipe with inputs including all of %s", input) + .add("could not find recipe with inputs including all of {}", input) .error() .post(); return false; @@ -108,7 +108,7 @@ public boolean removeByOutput(ItemStack output) { return true; } GroovyLog.msg("Error removing Blood Magic Tartaric Forge recipe") - .add("could not find recipe with output %s", output) + .add("could not find recipe with output {}", output) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/Tranquility.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/Tranquility.java index d68457d07..ed90aec72 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/Tranquility.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/Tranquility.java @@ -54,7 +54,7 @@ public void add(IBlockState blockstate, String tranquility, double value) { } } GroovyLog.msg("Error adding or adjusting Blood Magic Tranquility") - .add("could not find tranquility type with string %s", tranquility) + .add("could not find tranquility type with string {}", tranquility) .error() .post(); } @@ -84,7 +84,7 @@ public void remove(IBlockState blockstate, String tranquility) { } } GroovyLog.msg("Error removing Blood Magic Tranquility") - .add("could not find tranquility type with string %s", tranquility) + .add("could not find tranquility type with string {}", tranquility) .error() .post(); } @@ -99,7 +99,7 @@ public boolean remove(IBlockState blockstate, EnumTranquilityType tranquility) { } } GroovyLog.msg("Error removing Blood Magic Tranquility") - .add("could not find tranquility entry with blockstate %s and enum %s", blockstate, tranquility.name()) + .add("could not find tranquility entry with blockstate {} and enum {}", blockstate, tranquility.name()) .error() .post(); return false; @@ -159,7 +159,7 @@ public RecipeBuilder tranquility(String tranquility) { return this; } } - GroovyLog.msg("Tranquility string not found. The options are: %s, yet found %s", names.deleteCharAt(names.length() - 1).toString(), tranquility) + GroovyLog.msg("Tranquility string not found. The options are: {}, yet found {}", names.deleteCharAt(names.length() - 1).toString(), tranquility) .warn() .post(); return this; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SoulBinder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SoulBinder.java index f39a316e2..2b1490d44 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SoulBinder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/SoulBinder.java @@ -157,7 +157,7 @@ public void validate(GroovyLog.Msg msg) { validateFluids(msg); if (!entityErrors.isEmpty()) { for (String error : entityErrors) { - msg.add("could not find entity with name %s", error); + msg.add("could not find entity with name {}", error); } } if (energy <= 0) energy = 5000; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/Canner.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/Canner.java index fed711df4..faeb2f26d 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/Canner.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/Canner.java @@ -124,7 +124,7 @@ public boolean removeFuelValue(IIngredient fuel) { ICannerRegistry.FuelInfo info = ClassicRecipes.canningMachine.getFuelInfo(fuel.getMatchingStacks()[0]); if (info == null) { GroovyLog.msg("Error removing Industrialcraft 2 Canner recipe") - .add("no recipes found for %s", fuel) + .add("no recipes found for {}", fuel) .error() .post(); return false; @@ -197,7 +197,7 @@ public boolean removeCanning(ItemStack container) { } } GroovyLog.msg("Error removing Industrialcraft 2 Canning Machine recipe") - .add("no recipes found for %s", container) + .add("no recipes found for {}", container) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/ClassicElectrolyzer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/ClassicElectrolyzer.java index 45cd1e858..a235ae9f8 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/ClassicElectrolyzer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/ClassicElectrolyzer.java @@ -87,7 +87,7 @@ public boolean removeByOutput(ItemStack output) { } } GroovyLog.msg("Error removing Industrialcraft 2 Electrolyzer recipe") - .add("no recipes found for %s", output) + .add("no recipes found for {}", output) .error() .post(); return false; @@ -110,7 +110,7 @@ public boolean removeByInput(ItemStack input) { } } GroovyLog.msg("Error removing Industrialcraft 2 Electrolyzer recipe") - .add("no recipes found for %s", input) + .add("no recipes found for {}", input) .error() .post(); return false; @@ -128,17 +128,17 @@ private void add(ElectrolyzerRecipe recipe) { switch (recipe.type) { case CHARGE: for (ItemStack stack : recipe.input.getMatchingStacks()) { - ClassicRecipes.electrolyzer.addChargeRecipe(stack, recipe.output, recipe.energy, "" + recipe.hashCode()); + ClassicRecipes.electrolyzer.addChargeRecipe(stack, recipe.output, recipe.energy, String.valueOf(recipe.hashCode())); } break; case DISCHARGE: for (ItemStack stack : recipe.input.getMatchingStacks()) { - ClassicRecipes.electrolyzer.addDischargeRecipe(stack, recipe.output, recipe.energy, "" + recipe.hashCode()); + ClassicRecipes.electrolyzer.addDischargeRecipe(stack, recipe.output, recipe.energy, String.valueOf(recipe.hashCode())); } break; case BOTH: for (ItemStack stack : recipe.input.getMatchingStacks()) { - ClassicRecipes.electrolyzer.addBothRecipe(stack, recipe.output, recipe.energy, "" + recipe.hashCode()); + ClassicRecipes.electrolyzer.addBothRecipe(stack, recipe.output, recipe.energy, String.valueOf(recipe.hashCode())); } break; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/ClassicScrapbox.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/ClassicScrapbox.java index 68da24f22..7d39656c7 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/ClassicScrapbox.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/ClassicScrapbox.java @@ -61,7 +61,7 @@ public boolean remove(ItemStack stack) { } } GroovyLog.msg("Error removing Industrialcraft 2 Scrapbox recipe") - .add("no recipes found for %s", stack) + .add("no recipes found for {}", stack) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/LiquidFuelGenerator.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/LiquidFuelGenerator.java index b820b7c78..1b5d3a38a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/LiquidFuelGenerator.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/LiquidFuelGenerator.java @@ -64,7 +64,7 @@ public boolean remove(Fluid fluid) { ILiquidFuelGeneratorRegistry.BurnEntry entry = ClassicRecipes.fluidGenerator.getBurnEntry(fluid); if (entry == null) { GroovyLog.msg("Error removing Liquid Fuel Generator recipe") - .add("no recipes found for %s", fluid) + .add("no recipes found for {}", fluid) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/RareEarthExtractor.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/RareEarthExtractor.java index 9117931c3..6ab82102d 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/RareEarthExtractor.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/classic/RareEarthExtractor.java @@ -59,7 +59,7 @@ public boolean remove(ItemStack input) { } } GroovyLog.msg("Error removing Rare Earth Extractor recipe") - .add("no recipes found for %s", input) + .add("no recipes found for {}", input) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/exp/Fermenter.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/exp/Fermenter.java index 1ecd6d3f4..f1f20f42a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/exp/Fermenter.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ic2/exp/Fermenter.java @@ -102,7 +102,7 @@ public boolean remove(String input) { return true; } GroovyLog.msg("Error removing Industrialcraft 2 Fermenter recipe") - .add("no recipes found for %s", input) + .add("no recipes found for {}", input) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalInfuser.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalInfuser.java index eab2642c1..c8ef06763 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalInfuser.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalInfuser.java @@ -44,7 +44,7 @@ public boolean removeByInput(GasStack leftInput, GasStack rightInput) { addBackup(recipe); return true; } - removeError("could not find recipe for %s and %s", leftInput, rightInput); + removeError("could not find recipe for {} and {}", leftInput, rightInput); return false; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalOxidizer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalOxidizer.java index d32364385..97f8547a7 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalOxidizer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ChemicalOxidizer.java @@ -55,7 +55,7 @@ public boolean removeByInput(IIngredient ingredient) { } } if (!found) { - removeError("could not find recipe for %s", ingredient); + removeError("could not find recipe for {}", ingredient); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Combiner.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Combiner.java index afabd4c9b..d7aecced7 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Combiner.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Combiner.java @@ -56,7 +56,7 @@ public boolean removeByInput(IIngredient ingredient, ItemStack extra) { } } if (!found) { - removeError("could not find recipe for %s and %s", ingredient, extra); + removeError("could not find recipe for {} and {}", ingredient, extra); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crusher.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crusher.java index d9131ffa3..e573f4c9c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crusher.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Crusher.java @@ -53,7 +53,7 @@ public boolean removeByInput(IIngredient ingredient) { } } if (!found) { - removeError("could not find recipe for %s", ingredient); + removeError("could not find recipe for {}", ingredient); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/DissolutionChamber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/DissolutionChamber.java index 993eb609c..023f49c8e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/DissolutionChamber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/DissolutionChamber.java @@ -55,7 +55,7 @@ public boolean removeByInput(IIngredient ingredient) { } } if (!found) { - removeError("could not find recipe for %s", ingredient); + removeError("could not find recipe for {}", ingredient); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ElectrolyticSeparator.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ElectrolyticSeparator.java index 0a7b484a7..a9782b57f 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ElectrolyticSeparator.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/ElectrolyticSeparator.java @@ -46,7 +46,7 @@ public boolean removeByInput(FluidStack input) { addBackup(recipe); return true; } - removeError("could not find recipe for %s", input); + removeError("could not find recipe for {}", input); return false; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/EnrichmentChamber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/EnrichmentChamber.java index 103076900..57fedd52c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/EnrichmentChamber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/EnrichmentChamber.java @@ -54,7 +54,7 @@ public boolean removeByInput(IIngredient ingredient) { } } if (!found) { - removeError("could not find recipe for %s", ingredient); + removeError("could not find recipe for {}", ingredient); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/InjectionChamber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/InjectionChamber.java index 79f58b4a5..9549e5e6c 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/InjectionChamber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/InjectionChamber.java @@ -57,7 +57,7 @@ public boolean removeByInput(IIngredient ingredient, GasStack gasInput) { } } if (!found) { - removeError("could not find recipe for %s and %s", ingredient, gasInput); + removeError("could not find recipe for {} and {}", ingredient, gasInput); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/MetallurgicInfuser.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/MetallurgicInfuser.java index d0b34754e..e16d1b268 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/MetallurgicInfuser.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/MetallurgicInfuser.java @@ -62,7 +62,7 @@ public boolean removeByInput(IIngredient ingredient, InfuseType infuseType) { } } if (!found) { - removeError("could not find recipe for %s", ingredient); + removeError("could not find recipe for {}", ingredient); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/OsmiumCompressor.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/OsmiumCompressor.java index 91ce56e43..33f7c5e47 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/OsmiumCompressor.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/OsmiumCompressor.java @@ -58,7 +58,7 @@ public boolean removeByInput(IIngredient ingredient, GasStack gasInput) { } } if (!found) { - removeError("could not find recipe for %s and %s", ingredient, gasInput); + removeError("could not find recipe for {} and {}", ingredient, gasInput); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PressurizedReactionChamber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PressurizedReactionChamber.java index c3061dd93..f06cce7c6 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PressurizedReactionChamber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PressurizedReactionChamber.java @@ -54,7 +54,7 @@ public boolean removeByInput(IIngredient inputSolid, FluidStack inputFluid, GasS } } if (!found) { - removeError("could not find recipe for %s, %s and %s", inputSolid, inputFluid, inputGas); + removeError("could not find recipe for {}, {}, and {}", inputSolid, inputFluid, inputGas); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PurificationChamber.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PurificationChamber.java index 108318b83..11926c3f9 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PurificationChamber.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/PurificationChamber.java @@ -57,7 +57,7 @@ public boolean removeByInput(IIngredient ingredient, GasStack gasInput) { } } if (!found) { - removeError("could not find recipe for %s and %s", ingredient, gasInput); + removeError("could not find recipe for {} and {}", ingredient, gasInput); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Sawmill.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Sawmill.java index 4eabbb26a..f9a29af42 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Sawmill.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Sawmill.java @@ -70,7 +70,7 @@ public boolean removeByInput(IIngredient ingredient) { } } if (!found) { - removeError("could not find recipe for %s", ingredient); + removeError("could not find recipe for {}", ingredient); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Smelting.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Smelting.java index 77a57ad55..90cfd2478 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Smelting.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/mekanism/Smelting.java @@ -54,7 +54,7 @@ public boolean removeByInput(IIngredient ingredient) { } } if (!found) { - removeError("could not find recipe for %s", ingredient); + removeError("could not find recipe for {}", ingredient); } return found; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tcomplement/HighOven.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tcomplement/HighOven.java index 32295af49..98b44b806 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tcomplement/HighOven.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tcomplement/HighOven.java @@ -329,7 +329,7 @@ public boolean removeByInput(FluidStack input) { })) return true; GroovyLog.msg("Error removing Tinkers Complement High Oven Heating recipe") - .add("could not find recipe with input %s", input) + .add("could not find recipe with input {}", input) .error() .post(); return false; @@ -343,7 +343,7 @@ public boolean removeByOutput(FluidStack output) { })) return true; GroovyLog.msg("Error removing Tinkers Complement High Oven Heating recipe") - .add("could not find recipe with output %s", output) + .add("could not find recipe with output {}", output) .error() .post(); return false; @@ -357,7 +357,7 @@ public boolean removeByInputAndOutput(FluidStack input, FluidStack output) { })) return true; GroovyLog.msg("Error removing Tinkers Complement High Oven Heating recipe") - .add("could not find recipe with input %s and output %s", input, output) + .add("could not find recipe with input {} and output {}", input, output) .error() .post(); return false; @@ -447,7 +447,7 @@ public boolean removeByItem(IIngredient item) { })) return true; GroovyLog.msg("Error removing Tinkers Complement High Oven fuel") - .add("could not find override with item %s", item) + .add("could not find override with item {}", item) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Crucible.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Crucible.java index bd274f49f..b42cab2f2 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Crucible.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/Crucible.java @@ -97,7 +97,7 @@ public void removeByOutput(IIngredient output) { } if (recipes.isEmpty()) { GroovyLog.msg("Error removing Thaumcraft Crucible recipe") - .add("no recipes found for %s", output) + .add("no recipes found for {}", output) .error() .post(); return; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/InfusionCrafting.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/InfusionCrafting.java index 22d95c8e7..88f2f5808 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/InfusionCrafting.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/InfusionCrafting.java @@ -107,7 +107,7 @@ public void removeByOutput(IIngredient output) { } if (recipes.isEmpty()) { GroovyLog.msg("Error removing Thaumcraft Infusion Crafting recipe") - .add("no recipes found for %s", output.toString()) + .add("no recipes found for {}", output.toString()) .error() .post(); return; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Brewer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Brewer.java index 2fced8dae..e58c1afc3 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Brewer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Brewer.java @@ -53,7 +53,7 @@ public void removeByInput(IIngredient ingredient, FluidStack input) { } if (!found) { GroovyLog.msg("Error removing Thermal Expansion Brewer recipe") - .add("could not find recipe for %s and %s", ingredient, input) + .add("could not find recipe for {} and {}", ingredient, input) .error() .post(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Crucible.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Crucible.java index 2dfa9cbbd..12657c6d6 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Crucible.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Crucible.java @@ -67,7 +67,7 @@ public void removeByInput(IIngredient input) { } if (!found) { GroovyLog.msg("Error removing Thermal Expansion Brewer recipe") - .add("could not find recipe for %s", input) + .add("could not find recipe for {}", input) .error() .post(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java index e9c34fa82..dfba9a4a9 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java @@ -78,7 +78,7 @@ public void removeByInput(IIngredient input) { } if (!found) { GroovyLog.msg("Error removing Thermal Expansion Pulverizer recipe") - .add("could not find recipe for %s", input) + .add("could not find recipe for {}", input) .error() .post(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Alloying.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Alloying.java index 04c64d6b6..00a8b95e9 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Alloying.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Alloying.java @@ -80,7 +80,7 @@ public boolean removeByInputsAndOutput(FluidStack output, FluidStack... inputs) })) return true; GroovyLog.msg("Error removing Tinkers Construct Alloying recipe") - .add("could not find recipe with inputs %s and output {}", Arrays.asList(inputs), output) + .add("could not find recipe with inputs {} and output {}", Arrays.asList(inputs), output) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Casting.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Casting.java index 3e3a9c609..11c5c7bb3 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Casting.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Casting.java @@ -12,7 +12,6 @@ import net.minecraftforge.fluids.FluidRegistry; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; -import slimeknights.mantle.util.RecipeMatch; import slimeknights.tconstruct.library.smeltery.CastingRecipe; import slimeknights.tconstruct.library.smeltery.ICastingRecipe; @@ -54,7 +53,7 @@ public boolean removeByOutput(ItemStack output){ })) return true; GroovyLog.msg("Error removing Tinkers Construct Casting Table recipe") - .add("could not find recipe with output %s", output) + .add("could not find recipe with output {}", output) .error() .post(); return false; @@ -68,7 +67,7 @@ public boolean removeByInput(FluidStack input) { })) return true; GroovyLog.msg("Error removing Tinkers Construct Casting Table recipe") - .add("could not find recipe with input %s", input) + .add("could not find recipe with input {}", input) .error() .post(); return false; @@ -82,7 +81,7 @@ public boolean removeByCast(IIngredient cast) { })) return true; GroovyLog.msg("Error removing Tinkers Construct Casting Table recipe") - .add("could not find recipe with cast %s", cast) + .add("could not find recipe with cast {}", cast) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Materials.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Materials.java index d83f105dc..372d1eef9 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Materials.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Materials.java @@ -45,7 +45,7 @@ public void addMaterial(GroovyMaterial material) { public boolean removeMaterial(String material) { if (TinkerRegistryAccessor.getMaterials().entrySet().removeIf(entry -> entry.getKey().equals(material))) return true; GroovyLog.msg("Error removing Tinkers Construct material") - .add("could not find material with name %s", material) + .add("could not find material with name {}", material) .error() .post(); return false; @@ -58,7 +58,7 @@ public boolean removeTrait(String trait) { return found; })) return true; GroovyLog.msg("Error removing Tinkers Construct material trait") - .add("could not find trait with name %s", trait) + .add("could not find trait with name {}", trait) .error() .post(); return false; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Melting.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Melting.java index 018e0c8a1..dcb16163a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Melting.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/tinkersconstruct/Melting.java @@ -1,6 +1,5 @@ package com.cleanroommc.groovyscript.compat.mods.tinkersconstruct; -import com.cleanroommc.groovyscript.GroovyScript; import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; @@ -165,7 +164,7 @@ public boolean removeByInput(EntityEntry entity) { })) return true; GroovyLog.msg("Error removing Tinkers Construct Entity Melting recipe") - .add("could not find recipe with input %s", name) + .add("could not find recipe with input {}", name) .error() .post(); return false; @@ -179,7 +178,7 @@ public boolean removeByOutput(FluidStack output) { })) return true; GroovyLog.msg("Error removing Tinkers Construct Entity Melting recipe") - .add("could not find recipe with output %s", output) + .add("could not find recipe with output {}", output) .error() .post(); return false; From 248761ecc4e120e548e7f347645e51da4d48a474 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Fri, 21 Jul 2023 17:07:35 -0700 Subject: [PATCH 10/28] return early if required mod isnt loaded --- examples/postInit/actuallyadditions.groovy | 6 ++++++ examples/postInit/astral.groovy | 5 +++++ examples/postInit/bloodmagic.groovy | 6 ++++++ examples/postInit/botania.groovy | 5 +++++ examples/postInit/chisel.groovy | 6 ++++++ examples/postInit/draconicevolution.groovy | 5 +++++ examples/postInit/enderio.groovy | 5 +++++ examples/postInit/evilcraft.groovy | 5 +++++ examples/postInit/extendedcrafting.groovy | 5 +++++ examples/postInit/forestry.groovy | 6 ++++++ examples/postInit/immersiveengineering.groovy | 5 +++++ examples/postInit/mekanism.groovy | 5 +++++ examples/postInit/roots.groovy | 5 +++++ examples/postInit/thaumcraft.groovy | 6 ++++++ examples/postInit/thermal.groovy | 5 +++++ examples/preInit/mekanism.groovy | 6 ++++++ 16 files changed, 86 insertions(+) diff --git a/examples/postInit/actuallyadditions.groovy b/examples/postInit/actuallyadditions.groovy index aad6e1847..4378ceeb6 100644 --- a/examples/postInit/actuallyadditions.groovy +++ b/examples/postInit/actuallyadditions.groovy @@ -1,4 +1,10 @@ +if (!isLoaded('actuallyadditions')) { + println 'Cancelled running script actuallyadditions' + return +} + + // Atomic Reconstructor // The Atomic Reconstructor is a block which uses energy to convert a block or item in front of it into other items. mods.actuallyadditions.atomicreconstructor.recipeBuilder() diff --git a/examples/postInit/astral.groovy b/examples/postInit/astral.groovy index e3b6fdd60..d756518f6 100644 --- a/examples/postInit/astral.groovy +++ b/examples/postInit/astral.groovy @@ -1,5 +1,10 @@ import net.minecraft.util.math.MathHelper +if (!isLoaded('astralsorcery')) { + println 'Cancelled running script astralsorcery' + return +} + mods.astralsorcery.StarlightAltar.discoveryRecipeBuilder() .output(item('minecraft:water_bucket')) .row(' ') diff --git a/examples/postInit/bloodmagic.groovy b/examples/postInit/bloodmagic.groovy index 770044ade..356959b28 100644 --- a/examples/postInit/bloodmagic.groovy +++ b/examples/postInit/bloodmagic.groovy @@ -1,3 +1,9 @@ + +if (!isLoaded('bloodmagic')) { + println 'Cancelled running script bloodmagic' + return +} + mods.bloodmagic.bloodaltar.removeByInput(item("minecraft:ender_pearl")) mods.bloodmagic.bloodaltar.removeByOutput(item("bloodmagic:slate:4")) diff --git a/examples/postInit/botania.groovy b/examples/postInit/botania.groovy index bd1d459ed..bba1a44a3 100644 --- a/examples/postInit/botania.groovy +++ b/examples/postInit/botania.groovy @@ -1,6 +1,11 @@ import net.minecraft.potion.PotionEffect import net.minecraft.util.text.TextFormatting +if (!isLoaded('botania')) { + println 'Cancelled running script botania' + return +} + // Bracket Handlers // Brew: diff --git a/examples/postInit/chisel.groovy b/examples/postInit/chisel.groovy index 4a8bfed65..1a5dc4106 100644 --- a/examples/postInit/chisel.groovy +++ b/examples/postInit/chisel.groovy @@ -1,3 +1,9 @@ + +if (!isLoaded('chisel')) { + println 'Cancelled running script chisel' + return +} + // Carving mods.chisel.carving.addGroup('demo') mods.chisel.carving.removeGroup('blockDiamond') diff --git a/examples/postInit/draconicevolution.groovy b/examples/postInit/draconicevolution.groovy index 22f10f2c1..a92f54a9f 100644 --- a/examples/postInit/draconicevolution.groovy +++ b/examples/postInit/draconicevolution.groovy @@ -1,4 +1,9 @@ +if (!isLoaded('draconicevolution')) { + println 'Cancelled running script draconicevolution' + return +} + // Fusion: // Consumes items and power from up to 54 pedestals of at least a given tier pointing towards a Fusion Crafting Core containing a catalyst to produce an output item. mods.draconicevolution.fusion.recipeBuilder() diff --git a/examples/postInit/enderio.groovy b/examples/postInit/enderio.groovy index 55fba1a77..ad6cf8733 100644 --- a/examples/postInit/enderio.groovy +++ b/examples/postInit/enderio.groovy @@ -1,4 +1,9 @@ +if (!isLoaded('enderio')) { + println 'Cancelled running script enderio' + return +} + // Alloy Smelter (Alloying): // Convert up to 3 itemstack inputs into an itemstack output, using energy and giving XP. Can be restricted to require a given tier of machine. // Can be set to require at least SIMPLE, NORMAL, or ENHANCED tiers, or to IGNORE the tier. SIMPLE and IGNORE are effectively the same. diff --git a/examples/postInit/evilcraft.groovy b/examples/postInit/evilcraft.groovy index 6d362c046..d15b85638 100644 --- a/examples/postInit/evilcraft.groovy +++ b/examples/postInit/evilcraft.groovy @@ -1,4 +1,9 @@ +if (!isLoaded('evilcraft')) { + println 'Cancelled running script evilcraft' + return +} + // Weather Bracket Handler weather('clear') weather('rain') diff --git a/examples/postInit/extendedcrafting.groovy b/examples/postInit/extendedcrafting.groovy index 98fa4a976..adbf889d4 100644 --- a/examples/postInit/extendedcrafting.groovy +++ b/examples/postInit/extendedcrafting.groovy @@ -1,4 +1,9 @@ +if (!isLoaded('extendedcrafting')) { + println 'Cancelled running script extendedcrafting' + return +} + // Combination crafting // there are no combination recipes by default, and so none can be removed diff --git a/examples/postInit/forestry.groovy b/examples/postInit/forestry.groovy index f77084f9b..ebb4c4c78 100644 --- a/examples/postInit/forestry.groovy +++ b/examples/postInit/forestry.groovy @@ -1,3 +1,9 @@ + +if (!isLoaded('forestry')) { + println 'Cancelled running script forestry' + return +} + // Species Bracket Handler // While forestry:speciesCommon is the actual name, for convenience, both will work. species("forestry:common") diff --git a/examples/postInit/immersiveengineering.groovy b/examples/postInit/immersiveengineering.groovy index 23d756ea0..d43b45fda 100644 --- a/examples/postInit/immersiveengineering.groovy +++ b/examples/postInit/immersiveengineering.groovy @@ -1,4 +1,9 @@ +if (!isLoaded('immersiveengineering')) { + println 'Cancelled running script immersiveengineering' + return +} + // Alloy Kiln: // Converts two input itemstacks into an output itemstack, consuming fuel (based on burn time). mods.immersiveengineering.alloykiln.recipeBuilder() diff --git a/examples/postInit/mekanism.groovy b/examples/postInit/mekanism.groovy index a94b7b8e9..875875385 100644 --- a/examples/postInit/mekanism.groovy +++ b/examples/postInit/mekanism.groovy @@ -1,4 +1,9 @@ +if (!isLoaded('mekanism')) { + println 'Cancelled running script mekanism' + return +} + // Bracket Handlers // Gas gas('gold') diff --git a/examples/postInit/roots.groovy b/examples/postInit/roots.groovy index 27fd5ba57..468e7d4c9 100644 --- a/examples/postInit/roots.groovy +++ b/examples/postInit/roots.groovy @@ -1,4 +1,9 @@ +if (!isLoaded('roots')) { + println 'Cancelled running script roots' + return +} + // Bracket Handlers // Cost Bracket Handler diff --git a/examples/postInit/thaumcraft.groovy b/examples/postInit/thaumcraft.groovy index 9ba5460fe..f2335b92a 100644 --- a/examples/postInit/thaumcraft.groovy +++ b/examples/postInit/thaumcraft.groovy @@ -1,3 +1,9 @@ + +if (!isLoaded('thaumcraft')) { + println 'Cancelled running script thaumcraft' + return +} + mods.thaumcraft.Crucible.removeByOutput(item('minecraft:gunpowder')) mods.thaumcraft.Crucible.recipeBuilder() diff --git a/examples/postInit/thermal.groovy b/examples/postInit/thermal.groovy index f3132f625..13ae4bf63 100644 --- a/examples/postInit/thermal.groovy +++ b/examples/postInit/thermal.groovy @@ -1,4 +1,9 @@ +if (!isLoaded('thermalexpansion')) { + println 'Cancelled running script thermalexpansion' + return +} + mods.te.Pulverizer.recipeBuilder() .input(item('minecraft:bookshelf')) .output(item('minecraft:diamond')) diff --git a/examples/preInit/mekanism.groovy b/examples/preInit/mekanism.groovy index 62530d18b..789c45bd5 100644 --- a/examples/preInit/mekanism.groovy +++ b/examples/preInit/mekanism.groovy @@ -1,4 +1,10 @@ +import net.minecraftforge.client.event.TextureStitchEvent + +if (!isLoaded('mekanism')) { + println 'cancelled loading script mekanism' + return +} eventManager.listen { TextureStitchEvent.Pre event -> event.getMap().registerSprite(resource('groovytest:blocks/example')) From a2d0f85c3242358ff959fb3d073bd93bd56df1dd Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Fri, 21 Jul 2023 17:10:36 -0700 Subject: [PATCH 11/28] fix scripts more --- .../assets/placeholdername/lang/en_us.lang | 0 .../textures/block/example.png | Bin 0 -> 213 bytes examples/postInit/loot.groovy | 50 ++++++++++-------- examples/postInit/mekanism.groovy | 8 +-- examples/postInit/thermal.groovy | 5 +- examples/preInit/mekanism.groovy | 2 +- .../groovyscript/compat/loot/Loot.java | 12 ++++- .../starlightaltar/AltarRecipeBuilder.java | 7 --- .../compat/mods/bloodmagic/AlchemyArray.java | 2 +- .../compat/mods/bloodmagic/Tranquility.java | 4 +- .../extendedcrafting/EnderRecipeBuilder.java | 8 +++ .../extendedcrafting/TableRecipeBuilder.java | 8 +++ .../mods/immersiveengineering/Squeezer.java | 4 +- .../arcane/ArcaneRecipeBuilder.java | 12 +++++ .../mods/thermalexpansion/Pulverizer.java | 2 +- .../compat/vanilla/CraftingRecipeBuilder.java | 8 +-- 16 files changed, 87 insertions(+), 45 deletions(-) create mode 100644 examples/assets/placeholdername/lang/en_us.lang create mode 100644 examples/assets/placeholdername/textures/block/example.png diff --git a/examples/assets/placeholdername/lang/en_us.lang b/examples/assets/placeholdername/lang/en_us.lang new file mode 100644 index 000000000..e69de29bb diff --git a/examples/assets/placeholdername/textures/block/example.png b/examples/assets/placeholdername/textures/block/example.png new file mode 100644 index 0000000000000000000000000000000000000000..cb83468a4c93c77fed680a18c41aaf43d7187957 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`b39!fLn`9tPCm=qpdivb^N8x6 z$`ZEo?;bMvJvzHp#)a9_Q}gKl=1%#m)4~nc6xY8yJ!4(P|EbJ}H=b>^;Eg@FDxLXx z&GCyIG9e{vPVU*9@?g$m=W{+gUpTn>u`A2Y;hC^Ze}Cfb#&c(^`e*V+BnVnxHoWm? zW3!m@hDyG7#}c;5YAmjl6V480ud2D~^Rt}&K^l9)_tI7M4|5ay^tTB*p9%hQuMFr; N22WQ%mvv4FO#q=gSN8w_ literal 0 HcmV?d00001 diff --git a/examples/postInit/loot.groovy b/examples/postInit/loot.groovy index ad3eb5fc6..39c703d80 100644 --- a/examples/postInit/loot.groovy +++ b/examples/postInit/loot.groovy @@ -1,13 +1,21 @@ -def pyramidLootTable = loot.getTable("minecraft:chests/stronghold_library") +if (isReloading()) { + println 'Cancelled running script loot' + return +} -pyramidLootTable.removePool("main") +// TODO: `loot` (all lowercase` is a default package in groovy. figure out how to not have this implode (rename to LootTable?) + + +def pyramidLootTable = Loot.getTable(resource('minecraft:chests/stronghold_library')) + +pyramidLootTable.removePool('main') pyramidLootTable.addPool( - loot.poolBuilder("main") + Loot.poolBuilder('main') .entry( - loot.entryBuilder("minecraft:diamond_block") - .item(item("minecraft:diamond_block")) + Loot.entryBuilder('minecraft:diamond_block') + .item(item('minecraft:diamond_block')) .weight(1) .quality(1) .build()) @@ -20,15 +28,15 @@ pyramidLootTable.addPool( -def pyramidLootTable2 = loot.getTable("minecraft:chests/stronghold_corridor") +def pyramidLootTable2 = Loot.getTable('minecraft:chests/stronghold_corridor') -pyramidLootTable2.removePool("main") +pyramidLootTable2.removePool('main') pyramidLootTable2.addPool( - loot.poolBuilder("main") + Loot.poolBuilder('main') .entry( - loot.entryBuilder("minecraft:diamond_block") - .item(item("minecraft:diamond_block")) + Loot.entryBuilder('minecraft:diamond_block') + .item(item('minecraft:diamond_block')) .weight(1) .quality(1) .build()) @@ -38,14 +46,14 @@ pyramidLootTable2.addPool( .build() ) -def chickenLootTable = loot.getTable("minecraft:entities/chicken") +def chickenLootTable = Loot.getTable('minecraft:entities/chicken') -chickenLootTable.removePool("main") +chickenLootTable.removePool('main') chickenLootTable.addPool( - loot.poolBuilder("main").entry( - loot.entryBuilder("minecraft:pumpkin") - .item(item("minecraft:pumpkin")) + Loot.poolBuilder('main').entry( + Loot.entryBuilder('minecraft:pumpkin') + .item(item('minecraft:pumpkin')) .weight(1) .quality(1) .build() @@ -56,14 +64,14 @@ chickenLootTable.addPool( .build() ) -def zombieLootTable = loot.getTable("minecraft:entities/zombie") +def zombieLootTable = Loot.getTable('minecraft:entities/zombie') -zombieLootTable.removePool("main") +zombieLootTable.removePool('main') zombieLootTable.addPool( - loot.poolBuilder("main").entry( - loot.entryBuilder("minecraft:potato") - .item(item("minecraft:potato")) + Loot.poolBuilder('main').entry( + Loot.entryBuilder('minecraft:potato') + .item(item('minecraft:potato')) .weight(1) .quality(1) .smelt() @@ -76,4 +84,4 @@ zombieLootTable.addPool( .build() ) -loot.printEntries() \ No newline at end of file +//Loot.printEntries() \ No newline at end of file diff --git a/examples/postInit/mekanism.groovy b/examples/postInit/mekanism.groovy index 875875385..ec043add3 100644 --- a/examples/postInit/mekanism.groovy +++ b/examples/postInit/mekanism.groovy @@ -32,9 +32,9 @@ mods.mekanism.infusion.infusion(infusion('carbon')) // NOTE: // To register the texture used, you have to add the following event listen to a PreInit file. -// event_manager.listen { TextureStitchEvent.Pre event -> event.getMap().registerSprite(resource('groovytest:blocks/example')) } -// Where 'assets/groovytest/textures/blocks/example.png' is the location of the desired texture. -mods.mekanism.infusion.infusion('groovy_example', resource('groovytest:blocks/example')) +// event_manager.listen { TextureStitchEvent.Pre event -> event.getMap().registerSprite(resource('placeholdername:blocks/example')) } +// Where 'assets/placeholdername/textures/blocks/example.png' is the location of the desired texture. +mods.mekanism.infusion.infusion('groovy_example', resource('placeholdername:blocks/example')) .add(10, item('minecraft:ice')) .add(20, item('minecraft:packed_ice')) @@ -75,7 +75,7 @@ mods.mekanism.combiner.recipeBuilder() .register() //mods.mekanism.combiner.add(ore('gemQuartz') * 8, item('minecraft:netherrack'), item('minecraft:quartz_ore')) -mods.mekanism.combiner.removeByInput(ore('gemQuartz') * 8, item('minecraft:cobblestone')) +mods.mekanism.combiner.removeByInput(item('minecraft:flint'), item('minecraft:cobblestone')) //mods.mekanism.combiner.removeAll() diff --git a/examples/postInit/thermal.groovy b/examples/postInit/thermal.groovy index 13ae4bf63..4b03d00a6 100644 --- a/examples/postInit/thermal.groovy +++ b/examples/postInit/thermal.groovy @@ -28,6 +28,7 @@ mods.thermalexpansion.Crucible.recipeBuilder() //mods.thermalexpansion.Crucible.removeByInput(item('thermalfoundation:material:1027')) +/* mods.thermalexpansion.Centrifuge.recipeBuilder() .input(item('minecraft:diamond')) .output(item('minecraft:wool:5'), 0.3) @@ -40,6 +41,7 @@ mods.thermalexpansion.Centrifuge.recipeBuilder() mods.thermalexpansion.Centrifuge.removeByInput(item('minecraft:concrete_powder:6')) + mods.thermalexpansion.Charger.recipeBuilder() .input(item('minecraft:iron_ingot')) .output(item('minecraft:diamond')) @@ -59,4 +61,5 @@ mods.thermalexpansion.Compactor.Coin.recipeBuilder() .output(item('minecraft:diamond')) .register() -mods.thermalexpansion.Compactor.Gear.removeByInput(ore('ingotEnderium')) \ No newline at end of file +mods.thermalexpansion.Compactor.Gear.removeByInput(ore('ingotEnderium')) + */ \ No newline at end of file diff --git a/examples/preInit/mekanism.groovy b/examples/preInit/mekanism.groovy index 789c45bd5..2fc927af4 100644 --- a/examples/preInit/mekanism.groovy +++ b/examples/preInit/mekanism.groovy @@ -7,5 +7,5 @@ if (!isLoaded('mekanism')) { } eventManager.listen { TextureStitchEvent.Pre event -> - event.getMap().registerSprite(resource('groovytest:blocks/example')) + event.getMap().registerSprite(resource('placeholdername:blocks/example')) } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/loot/Loot.java b/src/main/java/com/cleanroommc/groovyscript/compat/loot/Loot.java index ca0945246..b32b6717f 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/loot/Loot.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/loot/Loot.java @@ -43,12 +43,20 @@ public void afterScriptRun() { public static final Map TABLES = new Object2ObjectOpenHashMap<>(); public static LootTableManager TABLE_MANAGER; - public LootTable getTable(String name) { - LootTable lootTable = TABLES.get(new ResourceLocation(name)); + public LootTable getTable(ResourceLocation name) { + LootTable lootTable = TABLES.get(name); if (lootTable == null) GroovyLog.msg("GroovyScript found 0 LootTable(s) named " + name).post(); return lootTable; } + public LootTable getTable(String name) { + return getTable(new ResourceLocation(name)); + } + + public void removeTable(ResourceLocation name) { + TABLES.put(name, LootTable.EMPTY_LOOT_TABLE); + } + public void removeTable(String name) { TABLES.put(new ResourceLocation(name), LootTable.EMPTY_LOOT_TABLE); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java index 9e1838518..9f89a3afb 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java @@ -8,7 +8,6 @@ import hellfirepvp.astralsorcery.common.constellation.IConstellation; import hellfirepvp.astralsorcery.common.crafting.ItemHandle; import hellfirepvp.astralsorcery.common.tile.TileAltar; -import it.unimi.dsi.fastutil.chars.Char2ObjectOpenHashMap; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.IRecipe; import org.apache.commons.lang3.ArrayUtils; @@ -27,14 +26,8 @@ public class AltarRecipeBuilder extends CraftingRecipeBuilder.Shaped { protected int starlightRequired = 0; protected int craftingTickTime = 0; private final TileAltar.AltarLevel altarLevel; - private String[] keyBasedMatrix = null; private IConstellation requiredConstellation = null; private final ArrayList outerIngredients = new ArrayList<>(); - private final Char2ObjectOpenHashMap keyMap = new Char2ObjectOpenHashMap<>(); - - private List> ingredientMatrix = null; - - private final List errors = new ArrayList<>(); public AltarRecipeBuilder(int width, int height, TileAltar.AltarLevel level) { super(width, height); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java index 56a32d606..135cb1432 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyArray.java @@ -118,7 +118,7 @@ public boolean removeByInputAndCatalyst(IIngredient input, IIngredient catalyst) public boolean removeByOutput(ItemStack output) { if (((BloodMagicRecipeRegistrarAccessor) BloodMagicAPI.INSTANCE.getRecipeRegistrar()).getAlchemyArrayRecipes().removeIf(recipe -> { - boolean matches = ItemStack.areItemStacksEqual(recipe.getOutput(), output); + boolean matches = recipe.getOutput().isItemEqual(output); if (matches) { addBackup(recipe); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/Tranquility.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/Tranquility.java index ed90aec72..72c504160 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/Tranquility.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/Tranquility.java @@ -30,8 +30,8 @@ public RecipeBuilder recipeBuilder() { @Override public void onReload() { - removeScripted().forEach(pair -> ((BloodMagicValueManagerAccessor) BloodMagicAPI.INSTANCE.getValueManager()).getTranquility().put(pair.getKey(), pair.getValue())); - restoreFromBackup().forEach(pair -> ((BloodMagicValueManagerAccessor) BloodMagicAPI.INSTANCE.getValueManager()).getTranquility().remove(pair.getKey())); + removeScripted().forEach(pair -> ((BloodMagicValueManagerAccessor) BloodMagicAPI.INSTANCE.getValueManager()).getTranquility().remove(pair.getKey(), pair.getValue())); + restoreFromBackup().forEach(pair -> ((BloodMagicValueManagerAccessor) BloodMagicAPI.INSTANCE.getValueManager()).getTranquility().put(pair.getKey(), pair.getValue())); } public void add(Block block, String tranquility, double value) { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/EnderRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/EnderRecipeBuilder.java index 02efafa8c..a31559dd2 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/EnderRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/EnderRecipeBuilder.java @@ -14,6 +14,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; public class EnderRecipeBuilder extends CraftingRecipeBuilder { @@ -97,6 +98,13 @@ public EnderRecipeBuilder.Shaped key(String c, IIngredient ingredient) { return this; } + public EnderRecipeBuilder.Shaped key(Map map) { + for (Map.Entry x : map.entrySet()) { + key(x.getKey(), x.getValue()); + } + return this; + } + public EnderRecipeBuilder.Shaped matrix(List> matrix) { this.ingredientMatrix = matrix; return this; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/TableRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/TableRecipeBuilder.java index f19d6efa4..fe06b0f0f 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/TableRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/extendedcrafting/TableRecipeBuilder.java @@ -13,6 +13,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; public abstract class TableRecipeBuilder extends CraftingRecipeBuilder { @@ -105,6 +106,13 @@ public TableRecipeBuilder.Shaped key(String c, IIngredient ingredient) { return this; } + public TableRecipeBuilder.Shaped key(Map map) { + for (Map.Entry x : map.entrySet()) { + key(x.getKey(), x.getValue()); + } + return this; + } + public TableRecipeBuilder.Shaped matrix(List> matrix) { this.ingredientMatrix = matrix; return this; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java index 6ce991d3a..e21a8b545 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java @@ -102,7 +102,9 @@ public void removeByOutput(ItemStack itemOutput) { .postIfNotEmpty()) { return; } - List recipes = SqueezerRecipe.recipeList.stream().filter(r -> r.itemOutput.isItemEqual(itemOutput)).collect(Collectors.toList()); + // "Condition 'r.itemOutput != null' is always 'true'" is a lie. It can be null, and if it is it *will* throw an NPE if we don't check against it. + @SuppressWarnings("ConstantValue") + List recipes = SqueezerRecipe.recipeList.stream().filter(r -> r != null && r.itemOutput != null && r.itemOutput.isItemEqual(itemOutput)).collect(Collectors.toList()); for (SqueezerRecipe recipe : recipes) { remove(recipe); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/arcane/ArcaneRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/arcane/ArcaneRecipeBuilder.java index 8d606cbce..69f42f784 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/arcane/ArcaneRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thaumcraft/arcane/ArcaneRecipeBuilder.java @@ -17,6 +17,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; public abstract class ArcaneRecipeBuilder extends CraftingRecipeBuilder { @@ -38,6 +39,10 @@ public ArcaneRecipeBuilder aspect(AspectStack aspect) { return this; } + public ArcaneRecipeBuilder aspect(String tag) { + return aspect(tag, 1); + } + public ArcaneRecipeBuilder aspect(String tag, int amount) { Aspect a = AspectBracketHandler.validateAspect(tag); if (a != null) this.aspects.add(a, amount); @@ -110,6 +115,13 @@ public ArcaneRecipeBuilder.Shaped key(String c, IIngredient ingredient) { return this; } + public ArcaneRecipeBuilder.Shaped key(Map map) { + for (Map.Entry x : map.entrySet()) { + key(x.getKey(), x.getValue()); + } + return this; + } + public ArcaneRecipeBuilder.Shaped matrix(List> matrix) { this.ingredientMatrix = matrix; return this; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java index dfba9a4a9..a36c9c31e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java @@ -84,7 +84,7 @@ public void removeByInput(IIngredient input) { } } - public SimpleObjectStream stream() { + public SimpleObjectStream streamRecipes() { return new SimpleObjectStream<>(PulverizerManagerAccessor.getRecipeMap().values()).setRemover(this::remove); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/CraftingRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/CraftingRecipeBuilder.java index 3b5d1fe69..c605bda3a 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/CraftingRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/CraftingRecipeBuilder.java @@ -110,12 +110,12 @@ public void validateName() { public static class Shaped extends CraftingRecipeBuilder { protected boolean mirrored = false; - private String[] keyBasedMatrix; - private final Char2ObjectOpenHashMap keyMap = new Char2ObjectOpenHashMap<>(); + protected String[] keyBasedMatrix; + protected final Char2ObjectOpenHashMap keyMap = new Char2ObjectOpenHashMap<>(); - private List> ingredientMatrix; + protected List> ingredientMatrix; - private final List errors = new ArrayList<>(); + protected final List errors = new ArrayList<>(); public Shaped(int width, int height) { super(width, height); From a59d11c2de31dc62a21c3773248cf91607cf01bd Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Sat, 22 Jul 2023 03:10:51 -0700 Subject: [PATCH 12/28] fix ic2 debug --- build.gradle | 7 ++++--- gradle.properties | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index dd8a1c14e..3a2ba3ced 100644 --- a/build.gradle +++ b/build.gradle @@ -172,11 +172,12 @@ dependencies { runtimeOnly rfg.deobf('curse.maven:brandons_core-231382:3408276') } - compileOnly rfg.deobf('curse.maven:industrialcraft_experimental-242638:3838713') compileOnly rfg.deobf('curse.maven:industrialcraft_classic-242942:3093607') - if (project.debug_ic2.toBoolean()) { - runtimeOnly rfg.deobf('curse.maven:industrialcraft_experimental-242638:3838713') + compileOnly rfg.deobf('curse.maven:industrialcraft_experimental-242638:3838713') + if (project.debug_industrial_craft_2_classic.toBoolean()) { runtimeOnly rfg.deobf('curse.maven:industrialcraft_classic-242942:3093607') + } else if (project.debug_industrial_craft_2_experimental.toBoolean()) { + runtimeOnly rfg.deobf('curse.maven:industrialcraft_experimental-242638:3838713') } compileOnly rfg.deobf('curse.maven:baubles-227083:2518667') diff --git a/gradle.properties b/gradle.properties index a0ed5a55d..18563b353 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,7 +22,8 @@ debug_mekanism = false debug_evilcraft = false debug_thermal = false debug_thaum = false -debug_ic2 = false +debug_industrial_craft_2_classic = false +debug_industrial_craft_2_experimental = false debug_draconic_evolution = false debug_immersive_engineering = false debug_enderio = false From ff59e0ea15bac8169a8500b0544c852f085295ca Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Sat, 22 Jul 2023 05:00:45 -0700 Subject: [PATCH 13/28] rename loot examples file --- .../{loot.groovy => loottables.groovy} | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) rename examples/postInit/{loot.groovy => loottables.groovy} (70%) diff --git a/examples/postInit/loot.groovy b/examples/postInit/loottables.groovy similarity index 70% rename from examples/postInit/loot.groovy rename to examples/postInit/loottables.groovy index 39c703d80..15e9f9cac 100644 --- a/examples/postInit/loot.groovy +++ b/examples/postInit/loottables.groovy @@ -4,17 +4,14 @@ if (isReloading()) { return } -// TODO: `loot` (all lowercase` is a default package in groovy. figure out how to not have this implode (rename to LootTable?) - - -def pyramidLootTable = Loot.getTable(resource('minecraft:chests/stronghold_library')) +def pyramidLootTable = loot.getTable(resource('minecraft:chests/stronghold_library')) pyramidLootTable.removePool('main') pyramidLootTable.addPool( - Loot.poolBuilder('main') + loot.poolBuilder('main') .entry( - Loot.entryBuilder('minecraft:diamond_block') + loot.entryBuilder('minecraft:diamond_block') .item(item('minecraft:diamond_block')) .weight(1) .quality(1) @@ -28,14 +25,14 @@ pyramidLootTable.addPool( -def pyramidLootTable2 = Loot.getTable('minecraft:chests/stronghold_corridor') +def pyramidLootTable2 = loot.getTable('minecraft:chests/stronghold_corridor') pyramidLootTable2.removePool('main') pyramidLootTable2.addPool( - Loot.poolBuilder('main') + loot.poolBuilder('main') .entry( - Loot.entryBuilder('minecraft:diamond_block') + loot.entryBuilder('minecraft:diamond_block') .item(item('minecraft:diamond_block')) .weight(1) .quality(1) @@ -46,13 +43,13 @@ pyramidLootTable2.addPool( .build() ) -def chickenLootTable = Loot.getTable('minecraft:entities/chicken') +def chickenLootTable = loot.getTable('minecraft:entities/chicken') chickenLootTable.removePool('main') chickenLootTable.addPool( - Loot.poolBuilder('main').entry( - Loot.entryBuilder('minecraft:pumpkin') + loot.poolBuilder('main').entry( + loot.entryBuilder('minecraft:pumpkin') .item(item('minecraft:pumpkin')) .weight(1) .quality(1) @@ -64,13 +61,13 @@ chickenLootTable.addPool( .build() ) -def zombieLootTable = Loot.getTable('minecraft:entities/zombie') +def zombieLootTable = loot.getTable('minecraft:entities/zombie') zombieLootTable.removePool('main') zombieLootTable.addPool( - Loot.poolBuilder('main').entry( - Loot.entryBuilder('minecraft:potato') + loot.poolBuilder('main').entry( + loot.entryBuilder('minecraft:potato') .item(item('minecraft:potato')) .weight(1) .quality(1) From f3a4d884276a0b22b9a3cb59bc1d1b0aba489d1e Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Mon, 24 Jul 2023 15:29:57 -0700 Subject: [PATCH 14/28] preinit vanilla examples and assets --- .../blockstates/dragon_egg.json | 7 ++ .../blockstates/dragon_egg_lamp.json | 7 ++ .../blockstates/generic_block.json | 7 ++ .../assets/placeholdername/lang/en_us.lang | 7 ++ .../models/block/dragon_egg_lamp.json | 6 ++ .../models/block/generic_block.json | 6 ++ .../placeholdername/models/item/clay_2.json | 6 ++ .../placeholdername/models/item/clay_3.json | 6 ++ .../models/item/dragon_egg_lamp.json | 3 + .../models/item/generic_block.json | 3 + .../models/item/heartofauniverse.json | 6 ++ .../placeholdername/models/item/snack.json | 6 ++ .../textures/blocks/dragon_egg_lamp.png | Bin 0 -> 202 bytes .../textures/blocks/generic_block.png | Bin 0 -> 468 bytes .../mekanism_infusion_texture.png} | Bin .../placeholdername/textures/items/clay_2.png | Bin 0 -> 189 bytes .../placeholdername/textures/items/clay_3.png | Bin 0 -> 189 bytes .../textures/items/heartofauniverse.png | Bin 0 -> 72647 bytes .../items/heartofauniverse.png.mcmeta | 4 + .../placeholdername/textures/items/snack.png | Bin 0 -> 670 bytes examples/preInit/mekanism.groovy | 2 +- examples/preInit/vanilla.groovy | 95 ++++++++++++++++++ .../groovyscript/compat/content/Content.java | 4 + .../compat/content/GroovyItem.java | 6 +- 24 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 examples/assets/placeholdername/blockstates/dragon_egg.json create mode 100644 examples/assets/placeholdername/blockstates/dragon_egg_lamp.json create mode 100644 examples/assets/placeholdername/blockstates/generic_block.json create mode 100644 examples/assets/placeholdername/models/block/dragon_egg_lamp.json create mode 100644 examples/assets/placeholdername/models/block/generic_block.json create mode 100644 examples/assets/placeholdername/models/item/clay_2.json create mode 100644 examples/assets/placeholdername/models/item/clay_3.json create mode 100644 examples/assets/placeholdername/models/item/dragon_egg_lamp.json create mode 100644 examples/assets/placeholdername/models/item/generic_block.json create mode 100644 examples/assets/placeholdername/models/item/heartofauniverse.json create mode 100644 examples/assets/placeholdername/models/item/snack.json create mode 100644 examples/assets/placeholdername/textures/blocks/dragon_egg_lamp.png create mode 100644 examples/assets/placeholdername/textures/blocks/generic_block.png rename examples/assets/placeholdername/textures/{block/example.png => blocks/mekanism_infusion_texture.png} (100%) create mode 100644 examples/assets/placeholdername/textures/items/clay_2.png create mode 100644 examples/assets/placeholdername/textures/items/clay_3.png create mode 100644 examples/assets/placeholdername/textures/items/heartofauniverse.png create mode 100644 examples/assets/placeholdername/textures/items/heartofauniverse.png.mcmeta create mode 100644 examples/assets/placeholdername/textures/items/snack.png create mode 100644 examples/preInit/vanilla.groovy diff --git a/examples/assets/placeholdername/blockstates/dragon_egg.json b/examples/assets/placeholdername/blockstates/dragon_egg.json new file mode 100644 index 000000000..e10df24ce --- /dev/null +++ b/examples/assets/placeholdername/blockstates/dragon_egg.json @@ -0,0 +1,7 @@ +{ + "variants": { + "normal": { + "model": "placeholdername:dragon_egg" + } + } +} \ No newline at end of file diff --git a/examples/assets/placeholdername/blockstates/dragon_egg_lamp.json b/examples/assets/placeholdername/blockstates/dragon_egg_lamp.json new file mode 100644 index 000000000..d575e5727 --- /dev/null +++ b/examples/assets/placeholdername/blockstates/dragon_egg_lamp.json @@ -0,0 +1,7 @@ +{ + "variants": { + "normal": { + "model": "placeholdername:dragon_egg_lamp" + } + } +} \ No newline at end of file diff --git a/examples/assets/placeholdername/blockstates/generic_block.json b/examples/assets/placeholdername/blockstates/generic_block.json new file mode 100644 index 000000000..7b1e585c7 --- /dev/null +++ b/examples/assets/placeholdername/blockstates/generic_block.json @@ -0,0 +1,7 @@ +{ + "variants": { + "normal": { + "model": "placeholdername:generic_block" + } + } +} \ No newline at end of file diff --git a/examples/assets/placeholdername/lang/en_us.lang b/examples/assets/placeholdername/lang/en_us.lang index e69de29bb..c655d554a 100644 --- a/examples/assets/placeholdername/lang/en_us.lang +++ b/examples/assets/placeholdername/lang/en_us.lang @@ -0,0 +1,7 @@ +itemGroup.groovyscript.example_creative_tab=GroovyScript Creative Tab +item.placeholdername.heartofauniverse.name=Heart of the Universe +item.placeholdername.clay_2.name=If clay is so good... +item.placeholdername.clay_3.name=Enchanted Clay +item.placeholdername.snack.name=Snack +tile.placeholdername.generic_block.name=Generic Block +tile.placeholdername.dragon_egg_lamp.name=Dragon Egg Lamp diff --git a/examples/assets/placeholdername/models/block/dragon_egg_lamp.json b/examples/assets/placeholdername/models/block/dragon_egg_lamp.json new file mode 100644 index 000000000..24dd3f896 --- /dev/null +++ b/examples/assets/placeholdername/models/block/dragon_egg_lamp.json @@ -0,0 +1,6 @@ +{ + "parent": "block/dragon_egg", + "textures": { + "all": "placeholdername:blocks/dragon_egg_lamp" + } +} \ No newline at end of file diff --git a/examples/assets/placeholdername/models/block/generic_block.json b/examples/assets/placeholdername/models/block/generic_block.json new file mode 100644 index 000000000..3c4e7b328 --- /dev/null +++ b/examples/assets/placeholdername/models/block/generic_block.json @@ -0,0 +1,6 @@ +{ + "parent": "block/cube_all", + "textures": { + "all": "placeholdername:blocks/generic_block" + } +} \ No newline at end of file diff --git a/examples/assets/placeholdername/models/item/clay_2.json b/examples/assets/placeholdername/models/item/clay_2.json new file mode 100644 index 000000000..73272f6ed --- /dev/null +++ b/examples/assets/placeholdername/models/item/clay_2.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "placeholdername:items/clay_2" + } +} \ No newline at end of file diff --git a/examples/assets/placeholdername/models/item/clay_3.json b/examples/assets/placeholdername/models/item/clay_3.json new file mode 100644 index 000000000..96d36b2b8 --- /dev/null +++ b/examples/assets/placeholdername/models/item/clay_3.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "placeholdername:items/clay_3" + } +} \ No newline at end of file diff --git a/examples/assets/placeholdername/models/item/dragon_egg_lamp.json b/examples/assets/placeholdername/models/item/dragon_egg_lamp.json new file mode 100644 index 000000000..1fb046c4e --- /dev/null +++ b/examples/assets/placeholdername/models/item/dragon_egg_lamp.json @@ -0,0 +1,3 @@ +{ + "parent": "placeholdername:block/dragon_egg_lamp" +} \ No newline at end of file diff --git a/examples/assets/placeholdername/models/item/generic_block.json b/examples/assets/placeholdername/models/item/generic_block.json new file mode 100644 index 000000000..8b218e06f --- /dev/null +++ b/examples/assets/placeholdername/models/item/generic_block.json @@ -0,0 +1,3 @@ +{ + "parent": "placeholdername:block/generic_block" +} \ No newline at end of file diff --git a/examples/assets/placeholdername/models/item/heartofauniverse.json b/examples/assets/placeholdername/models/item/heartofauniverse.json new file mode 100644 index 000000000..767d717d1 --- /dev/null +++ b/examples/assets/placeholdername/models/item/heartofauniverse.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "placeholdername:items/heartofauniverse" + } +} \ No newline at end of file diff --git a/examples/assets/placeholdername/models/item/snack.json b/examples/assets/placeholdername/models/item/snack.json new file mode 100644 index 000000000..758109e6b --- /dev/null +++ b/examples/assets/placeholdername/models/item/snack.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "placeholdername:items/snack" + } +} \ No newline at end of file diff --git a/examples/assets/placeholdername/textures/blocks/dragon_egg_lamp.png b/examples/assets/placeholdername/textures/blocks/dragon_egg_lamp.png new file mode 100644 index 0000000000000000000000000000000000000000..ed8ef2376c8eb0ea3c487bbc1e74854ddfad9c90 GIT binary patch literal 202 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`6FprVLn`8WCpq#pC1V|pf*I%Ni9C47$5BxIZxZW3SvkQZwuo~u0n z3S5PSdPAZTk*q{7Z2QuJaW4X>h9p=6w3^zt(RZK%woRzp zBHkEe95}^KT?c3ZN$SE2BtulEfq4G4=pG_^_I-BbCstd)#%#I3Q-vJU#eoq>MMS{= z)fEB6dWaeWaH*3~w@wR20OY;zo&YgiVAU7^Sy!9`E*^yfM!;N8CEHK|tqvl3hyC$< zhAFt~3TP#-8|>9G=08(^Tb0|9??iPDWF5Ydx%KX zG3ng(=3$JJkGBrVOif-Y4sd_R2p|{)<4jhQES60nfeJ*AWsE;t+7XbJA=ohh0000< KMNUMnLSTYdXv!l1 literal 0 HcmV?d00001 diff --git a/examples/assets/placeholdername/textures/block/example.png b/examples/assets/placeholdername/textures/blocks/mekanism_infusion_texture.png similarity index 100% rename from examples/assets/placeholdername/textures/block/example.png rename to examples/assets/placeholdername/textures/blocks/mekanism_infusion_texture.png diff --git a/examples/assets/placeholdername/textures/items/clay_2.png b/examples/assets/placeholdername/textures/items/clay_2.png new file mode 100644 index 0000000000000000000000000000000000000000..7f5cea1f57637e50469910b675e91f57f6057b96 GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EuJopAr*1S2@>}X+`07Bo?~&h zFpEL2clf(M^QXn~rwQi@cqATg*_v?HfX9d>O<-4*2*YO4G=`40jmnR^IHZ}38Kl)R z7&g5<5!dk1an?sECLtD2rQ2OO0w>uNcC(0e7&vc`Vqj9>oS}Qd?6AqBt31pbEZnbg m6q`AoJ;AW7F{QVJone2^Jwt<+ODllxVeoYIb6Mw<&;$UIU_VO$ literal 0 HcmV?d00001 diff --git a/examples/assets/placeholdername/textures/items/clay_3.png b/examples/assets/placeholdername/textures/items/clay_3.png new file mode 100644 index 0000000000000000000000000000000000000000..7f5cea1f57637e50469910b675e91f57f6057b96 GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EuJopAr*1S2@>}X+`07Bo?~&h zFpEL2clf(M^QXn~rwQi@cqATg*_v?HfX9d>O<-4*2*YO4G=`40jmnR^IHZ}38Kl)R z7&g5<5!dk1an?sECLtD2rQ2OO0w>uNcC(0e7&vc`Vqj9>oS}Qd?6AqBt31pbEZnbg m6q`AoJ;AW7F{QVJone2^Jwt<+ODllxVeoYIb6Mw<&;$UIU_VO$ literal 0 HcmV?d00001 diff --git a/examples/assets/placeholdername/textures/items/heartofauniverse.png b/examples/assets/placeholdername/textures/items/heartofauniverse.png new file mode 100644 index 0000000000000000000000000000000000000000..ffc6a37f5b323bf8e59d48495a983a55ff7adc2a GIT binary patch literal 72647 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 - event.getMap().registerSprite(resource('placeholdername:blocks/example')) + event.getMap().registerSprite(resource('placeholdername:blocks/mekanism_infusion_texture')) } diff --git a/examples/preInit/vanilla.groovy b/examples/preInit/vanilla.groovy new file mode 100644 index 000000000..9cd412f26 --- /dev/null +++ b/examples/preInit/vanilla.groovy @@ -0,0 +1,95 @@ + +import net.minecraft.item.ItemFood +import net.minecraft.potion.PotionEffect +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.block.material.Material +import net.minecraft.block.state.BlockFaceShape +import net.minecraft.block.state.IBlockState +import net.minecraft.util.math.AxisAlignedBB +import net.minecraft.world.IBlockAccess + + +// Localization is done in 'assets/placeholdername/lang/[language].lang' + +// Textures for items are created at 'assets/placeholdername/textures/items/'. +// Add a file called '[itemname].png' to create a static item texture, and a file called +// '[itemname].png.mcmeta' to create an animated file. +// A file will be created in 'assets/placeholdername/models/item/' called '[itemname].json' and point to this location in textures. + +def HOAU = content.createItem('heartofauniverse') // Set item name at 'item.[itemname].name=[desired name]' + .setRarity(EnumRarity.EPIC) // Optional IRarity, sets the default text formatting (default none) + .setMaxStackSize(1) // Optional int, sets the max stack size (default 64) +// Note: by not running '.register()' this item will not be created yet. This is done so we can set the creative tab correctly. + +// Create the creative tab, using the not-yet-registered item +def tab = content.createCreativeTab('groovyscript.example_creative_tab', HOAU) + +// When registering items, this will add them to the given creative tab without having to manually do so. +content.setDefaultCreativeTab(tab) + +// Now, we register to HOAU item. +HOAU.register() + + +// Create an item at the location 'placeholdername:clay_2' +content.createItem('clay_2') + .setMaxStackSize(5) // Optional int, sets the max stack size (default 64) + .setRarity(EnumRarity.RARE) // Optional IRarity, sets the default text formatting (default none) + .register() + +// Create an item at the location 'placeholdername:clay_3'. +content.createItem('clay_3') + .setCreativeTab(creativeTab('misc')) // Optional CreativeTab, sets the creative tab (default set via setDefaultCreativeTab) + .setEnchantedEffect() // Optional boolean, controls if the enchanted effect plays on the item + .register() + + + +// You can register any item created, even items created via custom means. +content.registerItem('snack', (new ItemFood(20, 10, false) { + protected void onFoodEaten(ItemStack stack, World worldIn, EntityPlayer player) { + if (!worldIn.isRemote) { + player.addPotionEffect(new PotionEffect(potion('regeneration'), 240000, 3, false, false)) + player.addPotionEffect(new PotionEffect(potion('resistance'), 240000, 3, false, false)) + } + } +}).setAlwaysEdible()) + + + +// block + +// Textures for blocks are created at 'assets/placeholdername/textures/blocks/'. +// Add a file called '[blockname].png' to create a static item texture, and a file called +// '[blockname].png.mcmeta' to create an animated file. +// A file will be created in 'assets/placeholdername/models/block/' called '[blockname].json' and point to this location in textures. + +// Create a block at the location 'placeholdername:generic_block' +content.createBlock('generic_block')// Set block name at 'tile.[blockname].name=[desired name]' + .register() + +// Create a custom block at the location 'placeholdername:dragon_egg_lamp' +// Also changes the 'parent' setting in 'assets/placeholdername/models/block/[blockname].json' from 'block/cube_all' to 'block/dragon_egg' +content.registerBlock('dragon_egg_lamp', (new Block(Material.REDSTONE_LIGHT) { + protected static final AxisAlignedBB DRAGON_EGG_AABB = new AxisAlignedBB(0.0625D, 0.0D, 0.0625D, 0.9375D, 1.0D, 0.9375D) + + AxisAlignedBB getBoundingBox(IBlockState state, IBlockAccess source, BlockPos pos) { + return DRAGON_EGG_AABB + } + + boolean isOpaqueCube(IBlockState state) { + return false + } + + boolean isFullCube(IBlockState state) { + return false + } + + boolean shouldSideBeRendered(IBlockState blockState, IBlockAccess blockAccess, BlockPos pos, EnumFacing side) { + return true + } + + BlockFaceShape getBlockFaceShape(IBlockAccess worldIn, IBlockState state, BlockPos pos, EnumFacing face) { + return BlockFaceShape.UNDEFINED + } +}).setLightLevel(1.0F)) diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/content/Content.java b/src/main/java/com/cleanroommc/groovyscript/compat/content/Content.java index 635b5b2cc..29d80e89b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/content/Content.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/content/Content.java @@ -56,6 +56,10 @@ public CreativeTabs createCreativeTab(String name, ItemStack icon) { }; } + public CreativeTabs createCreativeTab(String name, Item icon) { + return createCreativeTab(name, new ItemStack(icon)); + } + public CreativeTabs getDefaultTab() { return defaultTab; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/content/GroovyItem.java b/src/main/java/com/cleanroommc/groovyscript/compat/content/GroovyItem.java index 2c4b7d33c..0c4b28736 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/content/GroovyItem.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/content/GroovyItem.java @@ -35,9 +35,13 @@ public static void registerItem(Item item) { GroovyLog.get().errorMC("Items must registered in preInit. Tried to register {} too late!", item.getRegistryName()); return; } + if (item.getCreativeTab() == null && VanillaModule.content.getDefaultTab() != null) { + item.setCreativeTab(VanillaModule.content.getDefaultTab()); + } ResourceLocation key = item.getRegistryName(); if (key == null || ITEMS.containsKey(key.getPath())) { - throw new IllegalArgumentException(); + GroovyLog.get().exception(new IllegalArgumentException("The registry name of the item must be non-null and not match an already registered item!")); + return; } ITEMS.put(key.getPath(), item); } From ac277d8274e17670f38b47843ec2fb8646e87bd7 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Mon, 24 Jul 2023 16:07:55 -0700 Subject: [PATCH 15/28] deprecate EnergyRecipeBuilder and TimeRecipeBuilder --- .../groovyscript/compat/EnergyRecipeBuilder.java | 1 + .../compat/mods/immersiveengineering/Crusher.java | 11 +++++++++-- .../compat/mods/immersiveengineering/Fermenter.java | 11 +++++++++-- .../compat/mods/immersiveengineering/MetalPress.java | 10 ++++++++-- .../compat/mods/immersiveengineering/Mixer.java | 11 +++++++++-- .../compat/mods/immersiveengineering/Refinery.java | 11 +++++++++-- .../compat/mods/immersiveengineering/Squeezer.java | 11 +++++++++-- .../mods/immersiveengineering/TimeRecipeBuilder.java | 1 + .../compat/mods/thermalexpansion/Brewer.java | 11 +++++++++-- .../compat/mods/thermalexpansion/Crucible.java | 11 +++++++++-- .../compat/mods/thermalexpansion/Pulverizer.java | 10 ++++++++-- 11 files changed, 81 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/EnergyRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/EnergyRecipeBuilder.java index cc7ae5a7c..965f7e7c8 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/EnergyRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/EnergyRecipeBuilder.java @@ -2,6 +2,7 @@ import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +@Deprecated public abstract class EnergyRecipeBuilder extends AbstractRecipeBuilder { protected int energy; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Crusher.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Crusher.java index 26d2a9c9f..eff4f4f38 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Crusher.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Crusher.java @@ -3,10 +3,10 @@ import blusunrize.immersiveengineering.api.crafting.CrusherRecipe; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.compat.EnergyRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.Nullable; @@ -95,7 +95,14 @@ public void removeAll() { CrusherRecipe.recipeList.clear(); } - public static class RecipeBuilder extends EnergyRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private int energy; + + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } @Override public String getErrorMsg() { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Fermenter.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Fermenter.java index 816c352cd..49c64df36 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Fermenter.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Fermenter.java @@ -3,10 +3,10 @@ import blusunrize.immersiveengineering.api.crafting.FermenterRecipe; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.compat.EnergyRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; @@ -100,7 +100,14 @@ public void removeAll() { FermenterRecipe.recipeList.clear(); } - public static class RecipeBuilder extends EnergyRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private int energy; + + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } @Override public String getErrorMsg() { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/MetalPress.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/MetalPress.java index 0665d9c7a..909813740 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/MetalPress.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/MetalPress.java @@ -5,10 +5,10 @@ import blusunrize.immersiveengineering.api.crafting.MetalPressRecipe; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.compat.EnergyRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.Nullable; @@ -173,10 +173,16 @@ public SimpleObjectStream streamRecipes() { return new SimpleObjectStream<>(recipes).setRemover(this::remove); } - public static class RecipeBuilder extends EnergyRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { + private int energy; private ItemStack mold = ItemStack.EMPTY; + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } + public RecipeBuilder mold(ItemStack mold) { this.mold = mold; return this; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Mixer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Mixer.java index d05dc60cb..63cd12b9d 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Mixer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Mixer.java @@ -3,11 +3,11 @@ import blusunrize.immersiveengineering.api.crafting.MixerRecipe; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.compat.EnergyRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.ArrayUtils; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; @@ -128,7 +128,14 @@ public void removeAll() { MixerRecipe.recipeList.clear(); } - public static class RecipeBuilder extends EnergyRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private int energy; + + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } @Override public String getErrorMsg() { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Refinery.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Refinery.java index 2d603669e..fd27ad34b 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Refinery.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Refinery.java @@ -2,10 +2,10 @@ import blusunrize.immersiveengineering.api.crafting.RefineryRecipe; import com.cleanroommc.groovyscript.api.GroovyLog; -import com.cleanroommc.groovyscript.compat.EnergyRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; @@ -101,7 +101,14 @@ public void removeAll() { RefineryRecipe.recipeList.clear(); } - public static class RecipeBuilder extends EnergyRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private int energy; + + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } @Override public String getErrorMsg() { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java index e21a8b545..92fa1c089 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/Squeezer.java @@ -3,10 +3,10 @@ import blusunrize.immersiveengineering.api.crafting.SqueezerRecipe; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.compat.EnergyRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; @@ -142,7 +142,14 @@ public void removeAll() { SqueezerRecipe.recipeList.clear(); } - private static class RecipeBuilder extends EnergyRecipeBuilder { + private static class RecipeBuilder extends AbstractRecipeBuilder { + + private int energy; + + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } @Override public String getErrorMsg() { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/TimeRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/TimeRecipeBuilder.java index b8d90e3c7..5cca0ff39 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/TimeRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/TimeRecipeBuilder.java @@ -2,6 +2,7 @@ import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +@Deprecated public abstract class TimeRecipeBuilder extends AbstractRecipeBuilder { protected int time; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Brewer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Brewer.java index e58c1afc3..da70a9d79 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Brewer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Brewer.java @@ -6,10 +6,10 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.compat.EnergyRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.core.mixin.thermalexpansion.BrewerManagerAccessor; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidStack; @@ -77,7 +77,14 @@ public void onReload() { validationFluidsBackup.clear(); } - public static class RecipeBuilder extends EnergyRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private int energy; + + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } @Override public String getErrorMsg() { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Crucible.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Crucible.java index 12657c6d6..7efaf40c0 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Crucible.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Crucible.java @@ -5,10 +5,10 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.compat.EnergyRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.core.mixin.thermalexpansion.CrucibleManagerAccessor; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.FluidRegistry; @@ -74,7 +74,14 @@ public void removeByInput(IIngredient input) { } - public static class RecipeBuilder extends EnergyRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { + + private int energy; + + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } @Override public String getErrorMsg() { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java index a36c9c31e..c77200683 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/thermalexpansion/Pulverizer.java @@ -6,11 +6,11 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.compat.EnergyRecipeBuilder; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.core.mixin.thermalexpansion.PulverizerManagerAccessor; import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper; +import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import net.minecraft.item.ItemStack; import org.jetbrains.annotations.ApiStatus; @@ -94,11 +94,17 @@ public void removeAll() { } } - public static class RecipeBuilder extends EnergyRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { + private int energy; private ItemStack secOutput; private int chance; + public RecipeBuilder energy(int energy) { + this.energy = energy; + return this; + } + public RecipeBuilder secondaryOutput(ItemStack itemStack, int chance) { this.secOutput = itemStack; this.chance = chance; From fd54dd52dd215059da862175f6c3d906ee6c1dfd Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Mon, 24 Jul 2023 16:37:54 -0700 Subject: [PATCH 16/28] industrialcraft build.gradle fix --- build.gradle | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 3a2ba3ced..f5997c8d7 100644 --- a/build.gradle +++ b/build.gradle @@ -172,12 +172,13 @@ dependencies { runtimeOnly rfg.deobf('curse.maven:brandons_core-231382:3408276') } - compileOnly rfg.deobf('curse.maven:industrialcraft_classic-242942:3093607') + // WARNING: experimental must be placed before classic, otherwise you will crash when debugging either. compileOnly rfg.deobf('curse.maven:industrialcraft_experimental-242638:3838713') - if (project.debug_industrial_craft_2_classic.toBoolean()) { - runtimeOnly rfg.deobf('curse.maven:industrialcraft_classic-242942:3093607') - } else if (project.debug_industrial_craft_2_experimental.toBoolean()) { + compileOnly rfg.deobf('curse.maven:industrialcraft_classic-242942:3093607') + if (project.debug_industrial_craft_2_experimental.toBoolean()) { runtimeOnly rfg.deobf('curse.maven:industrialcraft_experimental-242638:3838713') + } else if (project.debug_industrial_craft_2_classic.toBoolean()) { + runtimeOnly rfg.deobf('curse.maven:industrialcraft_classic-242942:3093607') } compileOnly rfg.deobf('curse.maven:baubles-227083:2518667') From e7fdcfa0ea00cd5170fbd3d70962e0ef8891c903 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Mon, 24 Jul 2023 16:44:47 -0700 Subject: [PATCH 17/28] tweaked conditional loading of examples --- examples/postInit/actuallyadditions.groovy | 6 ++---- examples/postInit/astral.groovy | 6 ++---- examples/postInit/bloodmagic.groovy | 6 ++---- examples/postInit/botania.groovy | 6 ++---- examples/postInit/chisel.groovy | 6 ++---- examples/postInit/draconicevolution.groovy | 6 ++---- examples/postInit/enderio.groovy | 6 ++---- examples/postInit/evilcraft.groovy | 6 ++---- examples/postInit/extendedcrafting.groovy | 6 ++---- examples/postInit/forestry.groovy | 6 ++---- examples/postInit/immersiveengineering.groovy | 6 ++---- examples/postInit/mekanism.groovy | 6 ++---- examples/postInit/roots.groovy | 6 ++---- examples/postInit/thaumcraft.groovy | 6 ++---- examples/postInit/thermal.groovy | 6 ++---- 15 files changed, 30 insertions(+), 60 deletions(-) diff --git a/examples/postInit/actuallyadditions.groovy b/examples/postInit/actuallyadditions.groovy index 4378ceeb6..f878a60b1 100644 --- a/examples/postInit/actuallyadditions.groovy +++ b/examples/postInit/actuallyadditions.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('actuallyadditions')) { - println 'Cancelled running script actuallyadditions' - return -} +if (!isLoaded('actuallyadditions')) return +println 'mod \'actuallyadditions\' detected, running script' // Atomic Reconstructor diff --git a/examples/postInit/astral.groovy b/examples/postInit/astral.groovy index d756518f6..e641333c8 100644 --- a/examples/postInit/astral.groovy +++ b/examples/postInit/astral.groovy @@ -1,9 +1,7 @@ import net.minecraft.util.math.MathHelper -if (!isLoaded('astralsorcery')) { - println 'Cancelled running script astralsorcery' - return -} +if (!isLoaded('astralsorcery')) return +println 'mod \'astralsorcery\' detected, running script' mods.astralsorcery.StarlightAltar.discoveryRecipeBuilder() .output(item('minecraft:water_bucket')) diff --git a/examples/postInit/bloodmagic.groovy b/examples/postInit/bloodmagic.groovy index 356959b28..fcb417489 100644 --- a/examples/postInit/bloodmagic.groovy +++ b/examples/postInit/bloodmagic.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('bloodmagic')) { - println 'Cancelled running script bloodmagic' - return -} +if (!isLoaded('bloodmagic')) return +println 'mod \'bloodmagic\' detected, running script' mods.bloodmagic.bloodaltar.removeByInput(item("minecraft:ender_pearl")) mods.bloodmagic.bloodaltar.removeByOutput(item("bloodmagic:slate:4")) diff --git a/examples/postInit/botania.groovy b/examples/postInit/botania.groovy index bba1a44a3..a605a8302 100644 --- a/examples/postInit/botania.groovy +++ b/examples/postInit/botania.groovy @@ -1,10 +1,8 @@ import net.minecraft.potion.PotionEffect import net.minecraft.util.text.TextFormatting -if (!isLoaded('botania')) { - println 'Cancelled running script botania' - return -} +if (!isLoaded('botania')) return +println 'mod \'botania\' detected, running script' // Bracket Handlers diff --git a/examples/postInit/chisel.groovy b/examples/postInit/chisel.groovy index 1a5dc4106..0ad9c38a5 100644 --- a/examples/postInit/chisel.groovy +++ b/examples/postInit/chisel.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('chisel')) { - println 'Cancelled running script chisel' - return -} +if (!isLoaded('chisel')) return +println 'mod \'chisel\' detected, running script' // Carving mods.chisel.carving.addGroup('demo') diff --git a/examples/postInit/draconicevolution.groovy b/examples/postInit/draconicevolution.groovy index a92f54a9f..94b12c4be 100644 --- a/examples/postInit/draconicevolution.groovy +++ b/examples/postInit/draconicevolution.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('draconicevolution')) { - println 'Cancelled running script draconicevolution' - return -} +if (!isLoaded('draconicevolution')) return +println 'mod \'draconicevolution\' detected, running script' // Fusion: // Consumes items and power from up to 54 pedestals of at least a given tier pointing towards a Fusion Crafting Core containing a catalyst to produce an output item. diff --git a/examples/postInit/enderio.groovy b/examples/postInit/enderio.groovy index ad6cf8733..3a4e2c6cc 100644 --- a/examples/postInit/enderio.groovy +++ b/examples/postInit/enderio.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('enderio')) { - println 'Cancelled running script enderio' - return -} +if (!isLoaded('enderio')) return +println 'mod \'enderio\' detected, running script' // Alloy Smelter (Alloying): // Convert up to 3 itemstack inputs into an itemstack output, using energy and giving XP. Can be restricted to require a given tier of machine. diff --git a/examples/postInit/evilcraft.groovy b/examples/postInit/evilcraft.groovy index d15b85638..0b77ed154 100644 --- a/examples/postInit/evilcraft.groovy +++ b/examples/postInit/evilcraft.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('evilcraft')) { - println 'Cancelled running script evilcraft' - return -} +if (!isLoaded('evilcraft')) return +println 'mod \'evilcraft\' detected, running script' // Weather Bracket Handler weather('clear') diff --git a/examples/postInit/extendedcrafting.groovy b/examples/postInit/extendedcrafting.groovy index adbf889d4..4fe788bb0 100644 --- a/examples/postInit/extendedcrafting.groovy +++ b/examples/postInit/extendedcrafting.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('extendedcrafting')) { - println 'Cancelled running script extendedcrafting' - return -} +if (!isLoaded('extendedcrafting')) return +println 'mod \'extendedcrafting\' detected, running script' // Combination crafting diff --git a/examples/postInit/forestry.groovy b/examples/postInit/forestry.groovy index ebb4c4c78..4d17394b7 100644 --- a/examples/postInit/forestry.groovy +++ b/examples/postInit/forestry.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('forestry')) { - println 'Cancelled running script forestry' - return -} +if (!isLoaded('forestry')) return +println 'mod \'forestry\' detected, running script' // Species Bracket Handler // While forestry:speciesCommon is the actual name, for convenience, both will work. diff --git a/examples/postInit/immersiveengineering.groovy b/examples/postInit/immersiveengineering.groovy index d43b45fda..9a7606592 100644 --- a/examples/postInit/immersiveengineering.groovy +++ b/examples/postInit/immersiveengineering.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('immersiveengineering')) { - println 'Cancelled running script immersiveengineering' - return -} +if (!isLoaded('immersiveengineering')) return +println 'mod \'immersiveengineering\' detected, running script' // Alloy Kiln: // Converts two input itemstacks into an output itemstack, consuming fuel (based on burn time). diff --git a/examples/postInit/mekanism.groovy b/examples/postInit/mekanism.groovy index ec043add3..7d493b1bb 100644 --- a/examples/postInit/mekanism.groovy +++ b/examples/postInit/mekanism.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('mekanism')) { - println 'Cancelled running script mekanism' - return -} +if (!isLoaded('mekanism')) return +println 'mod \'mekanism\' detected, running script' // Bracket Handlers // Gas diff --git a/examples/postInit/roots.groovy b/examples/postInit/roots.groovy index 468e7d4c9..9adb140da 100644 --- a/examples/postInit/roots.groovy +++ b/examples/postInit/roots.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('roots')) { - println 'Cancelled running script roots' - return -} +if (!isLoaded('roots')) return +println 'mod \'roots\' detected, running script' // Bracket Handlers diff --git a/examples/postInit/thaumcraft.groovy b/examples/postInit/thaumcraft.groovy index f2335b92a..f2cf749b8 100644 --- a/examples/postInit/thaumcraft.groovy +++ b/examples/postInit/thaumcraft.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('thaumcraft')) { - println 'Cancelled running script thaumcraft' - return -} +if (!isLoaded('thaumcraft')) return +println 'mod \'thaumcraft\' detected, running script' mods.thaumcraft.Crucible.removeByOutput(item('minecraft:gunpowder')) diff --git a/examples/postInit/thermal.groovy b/examples/postInit/thermal.groovy index 4b03d00a6..4d638caae 100644 --- a/examples/postInit/thermal.groovy +++ b/examples/postInit/thermal.groovy @@ -1,8 +1,6 @@ -if (!isLoaded('thermalexpansion')) { - println 'Cancelled running script thermalexpansion' - return -} +if (!isLoaded('thermalexpansion')) return +println 'mod \'thermalexpansion\' detected, running script' mods.te.Pulverizer.recipeBuilder() .input(item('minecraft:bookshelf')) From f1d7d90e7095f653a9b9c76c1d1a6e074cad2ea6 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Mon, 24 Jul 2023 16:45:00 -0700 Subject: [PATCH 18/28] fix thermal build.gradle --- build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index f5997c8d7..69c2405cc 100644 --- a/build.gradle +++ b/build.gradle @@ -118,8 +118,10 @@ dependencies { runtimeOnly rfg.deobf('curse.maven:mekanism-268560:2835175') } + compileOnly rfg.deobf('curse.maven:codechicken_lib_1_8-242818:2779848') compileOnly rfg.deobf('curse.maven:redstone_flux-270789:2920436') if (project.debug_thermal.toBoolean() || project.debug_draconic_evolution.toBoolean()) { + runtimeOnly rfg.deobf('curse.maven:codechicken_lib_1_8-242818:2779848') runtimeOnly rfg.deobf('curse.maven:redstone_flux-270789:2920436') } @@ -163,11 +165,9 @@ dependencies { runtimeOnly rfg.deobf('curse.maven:thermal_foundation-222880:2926428') } - compileOnly rfg.deobf('curse.maven:codechicken_lib_1_8-242818:2779848') compileOnly rfg.deobf('curse.maven:draconic_evolution-223565:3431261') compileOnly rfg.deobf('curse.maven:brandons_core-231382:3408276') if (project.debug_draconic_evolution.toBoolean()) { - runtimeOnly rfg.deobf('curse.maven:codechicken_lib_1_8-242818:2779848') runtimeOnly rfg.deobf('curse.maven:draconic_evolution-223565:3431261') runtimeOnly rfg.deobf('curse.maven:brandons_core-231382:3408276') } From cdc1620be575ead47cea6cb8bdcf988a75d9c685 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Mon, 24 Jul 2023 16:52:07 -0700 Subject: [PATCH 19/28] remove duplicate binding casings --- .../groovyscript/sandbox/GroovyScriptSandbox.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java b/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java index 18de92183..ac3136a4f 100644 --- a/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java +++ b/src/main/java/com/cleanroommc/groovyscript/sandbox/GroovyScriptSandbox.java @@ -36,11 +36,9 @@ public class GroovyScriptSandbox extends GroovySandbox { public GroovyScriptSandbox(URL... scriptEnvironment) { super(scriptEnvironment); - registerBinding("mods", ModSupport.INSTANCE); - registerBinding("log", GroovyLog.get()); + registerBinding("Mods", ModSupport.INSTANCE); + registerBinding("Log", GroovyLog.get()); registerBinding("EventManager", GroovyEventManager.INSTANCE); - registerBinding("eventManager", GroovyEventManager.INSTANCE); - registerBinding("event_manager", GroovyEventManager.INSTANCE); this.importCustomizer.addStaticStars(GroovyHelper.class.getName(), MathHelper.class.getName()); this.importCustomizer.addImports("net.minecraft.world.World", "net.minecraft.block.state.IBlockState", From 8f15da16eb850f090bddcaf54c01a5cfe66fa4fb Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Mon, 24 Jul 2023 17:01:21 -0700 Subject: [PATCH 20/28] tweaked conditional loading of examples (missed one) --- examples/preInit/mekanism.groovy | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/preInit/mekanism.groovy b/examples/preInit/mekanism.groovy index f0939a026..e884cde8d 100644 --- a/examples/preInit/mekanism.groovy +++ b/examples/preInit/mekanism.groovy @@ -1,10 +1,8 @@ import net.minecraftforge.client.event.TextureStitchEvent -if (!isLoaded('mekanism')) { - println 'cancelled loading script mekanism' - return -} +if (!isLoaded('mekanism')) return +println 'mod \'mekanism\' detected, running script' eventManager.listen { TextureStitchEvent.Pre event -> event.getMap().registerSprite(resource('placeholdername:blocks/mekanism_infusion_texture')) From 4fe2df3f0fe0be068d16f48133f2ff7ad98e49fb Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Mon, 24 Jul 2023 21:28:17 -0700 Subject: [PATCH 21/28] a horrid lack of a whitespace --- .../cleanroommc/groovyscript/compat/mods/botania/RuneAltar.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/RuneAltar.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/RuneAltar.java index b077b931e..b5376e346 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/RuneAltar.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/botania/RuneAltar.java @@ -66,7 +66,7 @@ public boolean removeByOutput(IIngredient output) { public boolean removeByInput(IIngredient... inputs) { List converted = Arrays.stream(inputs).map(i -> i instanceof OreDictIngredient ? ((OreDictIngredient) i).getOreDict() : i.getMatchingStacks()[0]).collect(Collectors.toList()); if (BotaniaAPI.runeAltarRecipes.removeIf(recipe -> { - boolean found = converted.stream().allMatch(o -> recipe.getInputs().stream().anyMatch(i -> (i instanceof String || o instanceof String)? i.equals(o) : ItemStack.areItemStacksEqual((ItemStack) i, (ItemStack) o))); + boolean found = converted.stream().allMatch(o -> recipe.getInputs().stream().anyMatch(i -> (i instanceof String || o instanceof String) ? i.equals(o) : ItemStack.areItemStacksEqual((ItemStack) i, (ItemStack) o))); if (found) addBackup(recipe); return found; })) return true; From 9d79b22397e91ae6b847346b8ac0ba062fa8babe Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Tue, 25 Jul 2023 13:32:01 -0700 Subject: [PATCH 22/28] remove leftover dev comments --- .../groovyscript/compat/mods/enderio/FluidCoolant.java | 2 +- .../cleanroommc/groovyscript/compat/vanilla/Furnace.java | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidCoolant.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidCoolant.java index d8e3d3125..8d4a43b17 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidCoolant.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/enderio/FluidCoolant.java @@ -78,7 +78,7 @@ public void remove(Fluid fluid) { @Nullable public IFluidCoolant find(Fluid fluid) { - return ((FluidFuelRegisterAccessor) FluidFuelRegister.instance).getCoolants().get(fluid.getName()); //FluidFuelRegister.instance.getCoolant(fluid); + return ((FluidFuelRegisterAccessor) FluidFuelRegister.instance).getCoolants().get(fluid.getName()); } @GroovyBlacklist diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Furnace.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Furnace.java index 6e90154e5..0bbda3c19 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Furnace.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Furnace.java @@ -177,12 +177,6 @@ public void removeAll() { addBackup(recipe); return true; }); - /*for (Map.Entry entry : FurnaceRecipes.instance().getSmeltingList().entrySet()) { - float exp = FurnaceRecipes.instance().getSmeltingExperience(entry.getValue()); - Recipe recipe = new Recipe(entry.getKey(), entry.getValue(), exp); - addBackup(recipe); - FurnaceRecipes.instance().getSmeltingList().remove(recipe.input); - }*/ } @GroovyBlacklist From 7cf8ffc2d06df434e76d443ae54630fa63398d3e Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Tue, 1 Aug 2023 21:45:34 -0700 Subject: [PATCH 23/28] astral sorcery examples and fixes --- examples/postInit/astral.groovy | 516 +++++++++++------- .../mods/astralsorcery/AstralSorcery.java | 11 + .../astralsorcery/ChaliceInteraction.java | 161 ++++-- .../mods/astralsorcery/Constellation.java | 180 +++--- .../compat/mods/astralsorcery/Fountain.java | 58 +- .../compat/mods/astralsorcery/Grindstone.java | 57 +- .../mods/astralsorcery/InfusionAltar.java | 103 +++- .../astralsorcery/LightTransmutation.java | 104 ++-- .../compat/mods/astralsorcery/Lightwell.java | 99 +++- .../compat/mods/astralsorcery/OreChance.java | 83 +-- .../compat/mods/astralsorcery/Utils.java | 70 --- .../perktree/GroovyPerkTree.java | 4 + .../starlightaltar/AltarInputOrder.java | 27 +- .../starlightaltar/AltarRecipeBuilder.java | 20 +- .../starlightaltar/StarlightAltar.java | 51 +- .../FluidRarityEntryAccessor.java | 20 + .../WellLiquefactionAccessor.java | 19 + .../mixin.groovyscript.astralsorcery.json | 4 +- 18 files changed, 1015 insertions(+), 572 deletions(-) delete mode 100644 src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Utils.java create mode 100644 src/main/java/com/cleanroommc/groovyscript/core/mixin/astralsorcery/FluidRarityEntryAccessor.java create mode 100644 src/main/java/com/cleanroommc/groovyscript/core/mixin/astralsorcery/WellLiquefactionAccessor.java diff --git a/examples/postInit/astral.groovy b/examples/postInit/astral.groovy index e641333c8..3de4922b8 100644 --- a/examples/postInit/astral.groovy +++ b/examples/postInit/astral.groovy @@ -3,199 +3,323 @@ import net.minecraft.util.math.MathHelper if (!isLoaded('astralsorcery')) return println 'mod \'astralsorcery\' detected, running script' -mods.astralsorcery.StarlightAltar.discoveryRecipeBuilder() - .output(item('minecraft:water_bucket')) - .row(' ') - .row(' B ') - .row(' ') - .key('B', item('minecraft:bucket')) - .starlight(1) - .craftTime(1) - .register() - -mods.astralsorcery.StarlightAltar.constellationRecipeBuilder() - .output(item('minecraft:pumpkin')) - .matrix('ss ss', - 's s', - ' d ', - 's s', - 'ss ss') - .key('s', item('minecraft:pumpkin_seeds')) - .key('d', ore('dirt')) - .starlight(0) - .craftTime(0) - .register() - -mods.astralsorcery.StarlightAltar.traitRecipeBuilder() - .output(item('astralsorcery:itemrockcrystalsimple').setSize(300).setPurity(50).setCutting(50)) - .matrix('sssss', - 'sgggs', - 'sgdgs', - 'sgggs', - 'sssss') - .key('s', item('minecraft:pumpkin')) - .key('g', ore('treeLeaves')) - .key('d', item('minecraft:diamond_block')) - .outerInput(item('astralsorcery:blockmarble')) - .outerInput(ore('ingotAstralStarmetal')) - .outerInput(fluid('astralsorcery.liquidstarlight') * 1000) - .outerInput(ore('treeSapling')) - .constellation(constellation('discidia')) - .starlight(0) - .craftTime(0) - .register() - -mods.astralsorcery.StarlightAltar.removeByOutput(item('astralsorcery:itemarchitectwand')) - -mods.astralsorcery.Lightwell.removeByOutput(fluid('lava')) - -mods.astralsorcery.Lightwell.recipeBuilder() - .catalyst(item('minecraft:stone')) - .output(fluid('lava')) - .productionMultiplier(1.0F) - .shatterMultiplier(15.0F) - .register() - -mods.astralsorcery.Lightwell.recipeBuilder() - .catalyst(item('minecraft:obsidian')) - .output(fluid('lava')) - .productionMultiplier(1.0F) - .shatterMultiplier(15.0F) - .catalystColor(16725260) - .register() - -mods.astralsorcery.InfusionAltar.recipeBuilder() - .input(item('minecraft:dirt')) - .output(item('minecraft:pumpkin')) - .register() - -mods.astralsorcery.InfusionAltar.removeByOutput(item('minecraft:iron_ingot')) - -mods.astralsorcery.Grindstone.recipeBuilder() - .input(item('minecraft:stone')) - .output(item('minecraft:cobblestone')) - .weight(1) - .register() - -mods.astralsorcery.Grindstone.recipeBuilder() - .input(ore('cropPumpkin')) - .output(item('minecraft:pumpkin_seeds')) - .weight(1) - .secondaryChance(1.0F) - .register() - -mods.astralsorcery.Grindstone.removeByOutput(ore('dustIron')) -mods.astralsorcery.Grindstone.removeByOutput(item('minecraft:redstone')) - -mods.astralsorcery.LightTransmutation.removeByOutput(blockstate('minecraft:cake')) -mods.astralsorcery.LightTransmutation.removeByOutput(block('minecraft:lapis_block')) - -mods.astralsorcery.LightTransmutation.recipeBuilder() - .input(block('minecraft:stone')) - .output(block('astralsorcery:blockmarble')) - .cost(100.0) - .register() - -mods.astralsorcery.LightTransmutation.recipeBuilder() - .input(blockstate('minecraft:pumpkin')) - .output(blockstate('minecraft:diamond_block')) - .cost(400.0) - .register() - -mods.astralsorcery.ChaliceInteraction.removeByOutput(item('minecraft:ice')) - -mods.astralsorcery.ChaliceInteraction.recipeBuilder() - .result(item('astralsorcery:blockmarble')) - .component(fluid('water') * 10) - .component(fluid('astralsorcery.liquidstarlight') * 30) - .register() - -mods.astralsorcery.Constellation.constellationBuilder() - .major() - .name('square') - .color(0xE01903) - .connection(12, 2, 2, 2) - .connection(12, 12, 12, 2) - .connection(2, 12, 12, 12) - .connection(2, 2, 2, 12) - .register() - -mods.astralsorcery.Constellation.remove(constellation('bootes')) - -mods.astralsorcery.Constellation.constellationMapEffectBuilder() - .constellation(constellation('square')) - .enchantmentEffect(enchantment('luck_of_the_sea'), 1, 3) - .potionEffect(potion('luck'), 1,2) - .register() - -mods.astralsorcery.Constellation.removeConstellationMapEffect(constellation('discidia')) - -mods.astralsorcery.Constellation.signatureItems() - .constellation(constellation('square')) - .addItem(ore('gemDiamond')) - .addItem(item('minecraft:water_bucket')) - .addItem(item('minecraft:rabbit_foot')) - .addItem(item('minecraft:fish')) - .register() - -mods.astralsorcery.PerkTree.attributePerkBuilder() - .name("this_is_fun") - .point(28, 28) - .connection("astralsorcery:magnet_ats_reach") - .modifier(mods.astralsorcery.PerkTree.effectBuilder() - .modifier(3) - .mode(2) - .type("ATTR_TYPE_REACH")) - .register() - -mods.astralsorcery.PerkTree.movePerk(mods.astralsorcery.PerkTree.getPerk("astralsorcery:magnet_ats_reach"), 30, 30) - -mods.astralsorcery.PerkTree.remove("astralsorcery:magnet_ats_reach") - -mods.astralsorcery.Research.researchBuilder() - .name('MY_TEST_RESEARCH') - .point(5,5) - .icon(item('minecraft:pumpkin')) - .discovery() - .page(mods.astralsorcery.Research.pageBuilder().textPage('GROOVYSCRIPT.RESEARCH.PAGE.TEST')) - .page(mods.astralsorcery.Research.pageBuilder().emptyPage()) - .connectionFrom('ALTAR1') - .register() - -mods.astralsorcery.Research.researchBuilder() - .name('MY_TEST_RESEARCH2') - .point(5,5) - .icon(item('minecraft:pumpkin')) - .constellation() - .page(mods.astralsorcery.Research.pageBuilder().textPage('GROOVYSCRIPT.RESEARCH.PAGE.TEST2')) - .page(mods.astralsorcery.Research.pageBuilder().constellationRecipePage(item('minecraft:pumpkin'))) - .register() - -mods.astralsorcery.Research.connectNodes('MY_TEST_RESEARCH2', 'ENHANCED_COLLECTOR') - -mods.astralsorcery.Research.moveNode('SOOTYMARBLE', 5, 6) - -mods.astralsorcery.Research.removeNode('CPAPER') - -mods.astralsorcery.Research.disconnectNodes('MY_TEST_RESEARCH', 'ALTAR1') - -mods.astralsorcery.Fountain.remove(fluid('lava')) - -mods.astralsorcery.Fountain.chanceHelper() - .fluid(fluid('astralsorcery.liquidstarlight')) - .rarity(10000000) - .minimumAmount(4000000) - .variance(1000000) - .register() - -mods.astralsorcery.aevitasPerkOreChance.remove(ore('oreCoal')) -mods.astralsorcery.aevitasPerkOreChance.remove(ore('oreIron')) -mods.astralsorcery.aevitasPerkOreChance.remove(ore('oreLapis')) -mods.astralsorcery.aevitasPerkOreChance.remove(ore('oreRedstone')) -mods.astralsorcery.aevitasPerkOreChance.remove(ore('oreGold')) -mods.astralsorcery.aevitasPerkOreChance.remove(ore('oreEmerald')) - -mods.astralsorcery.aevitasPerkOreChance.add(ore('oreQuartz'), 1000) - -mods.astralsorcery.PerkTreeConfig.setLevelCap(50) -mods.astralsorcery.PerkTreeConfig.setXpFunction{ int i, long prev -> prev + 1000L + MathHelper.lfloor(Math.pow(2.0, i / 2.0F + 3)) } + +// Constellation bracket handler: +// Major (Bright) Constellations: +constellation('aevitas') +constellation('armara') +constellation('discidia') +constellation('evorsio') +constellation('vicio') +// Weak (Dim) Constellations: +constellation('bootes') +constellation('fornax') +constellation('horologium') +constellation('lucerna') +constellation('mineralis') +constellation('octans') +constellation('pelotrio') +// Minor (Faint) Constellations: +constellation('alcara') +constellation('gelu') +constellation('ulteria') +constellation('vorux') + + +// ItemStack Mixin: +// When interacting with a rock crystal item, you can use the following methods to specify data about it. +item('astralsorcery:itemrockcrystalsimple') + .setSize(300) // Size is increased via sitting in liquid starlight and decreased by increasing cutting. From 0 - 400 for normal and 900 for Celestial. + .setPurity(50) // Purity is increased when at max size in liquid starlight, consuming the starlight and creating a new crystal. From 0-100. + .setCutting(50) // Cutting is increased by using the Grindstone with a rock crystal and decreased by increasing size. From 0-100. + .setFracturation(0) // Fracturation is increased by being used on a Ritual Pedestal, breaking at 100, and decreased by increasing size. From 0-100. + .setSizeOverride(-1) // Overrides the size value if anything other than -1 + .tuneTo(constellation('discidia')) // Major or Weak constellation, relevant for the Ritual Pedestal. + .setTrait(constellation('vorux')) // Dim constellation, relevant for the Ritual Pedestal. + + +// Perk Tree Config: +// Control the Perk level cap (between 1 and 100) and the XP formula per level. +mods.astralsorcery.perktreeconfig.setLevelCap(50) +// i = level number, prev = prior level xp cost. +mods.astralsorcery.perktreeconfig.setXpFunction{ int i, long prev -> prev + 1000L + MathHelper.lfloor(Math.pow(2.0, i / 2.0F + 3)) } + + +// Constellation: +// Create a custom constellation. +mods.astralsorcery.constellation.constellationBuilder() + .major() // Mutually exclusive, designates the constellation as major. + //.weak() // Mutually exclusive, designates the constellation as weak. + //.minor() // Mutually exclusive, designates the constellation as minor. + .name('square') + .color(0xE01903) // Optional int, color of the constellation. (Default based on major/weak/minor) + .connection(12, 2, 2, 2) // Any number of connections, draws the constellation + .connection(12, 12, 12, 2) + .connection(2, 12, 12, 12) + .connection(2, 2, 2, 12) + //.phase(MoonPhase.FULL) // Only required for minor constellations, MoonPhase... or [MoonPhase] + .register() + +mods.astralsorcery.constellation.remove(constellation('bootes')) +//mods.astralsorcery.constellation.removeAll() + + +// Adjust the enchantment or potion effects related to a constellation. +mods.astralsorcery.constellation.constellationMapEffectBuilder() + .constellation(constellation('square')) + .enchantmentEffect(enchantment('luck_of_the_sea'), 1, 3) + .potionEffect(potion('luck'), 1,2) + .register() + +mods.astralsorcery.constellation.removeConstellationMapEffect(constellation('discidia')) +//mods.astralsorcery.constellation.removeAllConstellationMapEffect() + +// Set the signature items used for a constellation's mantle or paper. +mods.astralsorcery.constellation.signatureItems() + .constellation(constellation('square')) + .addItem(ore('gemDiamond')) + .addItem(item('minecraft:water_bucket')) + .addItem(item('minecraft:rabbit_foot')) + .addItem(item('minecraft:fish')) + .register() + +mods.astralsorcery.constellation.removeSignatureItems(constellation('discidia')) +//mods.astralsorcery.constellation.removeAllSignatureItems() + + +// Perk Tree: +// Create a custom perk with a custom effect, at a given location +mods.astralsorcery.perktree.attributePerkBuilder() + .name("this_is_fun") + .point(28, 28) + .connection("astralsorcery:magnet_ats_reach") + .modifier(mods.astralsorcery.perktree.effectBuilder() + .modifier(3) + .mode(2) + .type("ATTR_TYPE_REACH")) + .register() + +mods.astralsorcery.perktree.movePerk(mods.astralsorcery.perktree.getPerk("astralsorcery:magnet_ats_reach"), 30, 30) + +mods.astralsorcery.perktree.remove("astralsorcery:magnet_ats_reach") + + +// Add custom research pages +mods.astralsorcery.research.researchBuilder() + .name('MY_TEST_RESEARCH') + .point(5,5) + .icon(item('minecraft:pumpkin')) + .discovery() + .page(mods.astralsorcery.research.pageBuilder().textPage('GROOVYSCRIPT.RESEARCH.PAGE.TEST')) + .page(mods.astralsorcery.research.pageBuilder().emptyPage()) + .connectionFrom('ALTAR1') + .register() + +mods.astralsorcery.research.researchBuilder() + .name('MY_TEST_RESEARCH2') + .point(5,5) + .icon(item('minecraft:pumpkin')) + .constellation() + .page(mods.astralsorcery.research.pageBuilder().textPage('GROOVYSCRIPT.RESEARCH.PAGE.TEST2')) + .page(mods.astralsorcery.research.pageBuilder().constellationRecipePage(item('minecraft:pumpkin'))) + .register() + +mods.astralsorcery.research.connectNodes('MY_TEST_RESEARCH2', 'ENHANCED_COLLECTOR') + +mods.astralsorcery.research.moveNode('SOOTYMARBLE', 5, 6) + +mods.astralsorcery.research.removeNode('CPAPER') + +mods.astralsorcery.research.disconnectNodes('MY_TEST_RESEARCH', 'ALTAR1') + + + +// Starlight Altar: +// Allows creation of shaped recipes in the Astral Sorcery Crafting Altar chain. +mods.astralsorcery.starlightaltar.discoveryRecipeBuilder() + .output(item('minecraft:water_bucket')) + .row(' ') + .row(' B ') + .row(' ') + .key('B', item('minecraft:bucket')) + .starlight(1) // Optional int, amount of starlight the recipe requires. Has a cap per tier of table at 1000, 2000, 4000, 8000 for Luminous, Starlight, Celestial, and Iridescent respectively. (Default 0) + .craftTime(10) // Optional int, how long the craft will take to complete in ticks. (Default 1) + .register() + +mods.astralsorcery.starlightaltar.constellationRecipeBuilder() + .output(item('minecraft:pumpkin')) + .matrix('ss ss', + 's s', + ' d ', + 's s', + 'ss ss') + .key('s', item('minecraft:pumpkin_seeds')) + .key('d', ore('dirt')) + .register() + +mods.astralsorcery.starlightaltar.traitRecipeBuilder() + .output(item('astralsorcery:itemrockcrystalsimple').setSize(300).setPurity(50).setCutting(50)) + .matrix('sssss', + 'sgggs', + 'sgdgs', + 'sgggs', + 'sssss') + .key('s', item('minecraft:pumpkin')) + .key('g', ore('treeLeaves')) + .key('d', item('minecraft:diamond_block')) + .outerInput(item('astralsorcery:blockmarble')) // Items which are places on nearby relays once the craft has started. + .outerInput(ore('ingotAstralStarmetal')) + .outerInput(fluid('astralsorcery.liquidstarlight') * 1000) + .outerInput(ore('treeSapling')) + .constellation(constellation('discidia')) + .register() + +mods.astralsorcery.starlightaltar.removeByOutput(item('astralsorcery:itemarchitectwand')) +//mods.astralsorcery.starlightaltar.removeAll() + + +// Lightwell: +// Converts an input item into fluid, with a chance at breaking every time fluid is produced. The amount of fluid produced per interval can be increased via starlight. +mods.astralsorcery.lightwell.recipeBuilder() + .catalyst(item('minecraft:stone')) + .output(fluid('astralsorcery.liquidstarlight')) + .productionMultiplier(1.0F) // Optional float, base amount of output produced per tick. (Default 0) + .shatterMultiplier(15.0F) // Optional float, how likely the catalyst is to shatter when producing fluid, with higher being less likely but never 0%. (Default 0) + .catalystColor(16725260) // Optional int, color code for particles. (Default null) + .register() + +mods.astralsorcery.lightwell.recipeBuilder() + .catalyst(item('minecraft:obsidian')) + .output(fluid('astralsorcery.liquidstarlight')) + .productionMultiplier(1.0F) + .shatterMultiplier(15.0F) + .register() + +mods.astralsorcery.lightwell.removeByCatalyst(item('minecraft:ice')) +mods.astralsorcery.lightwell.removeByInput(item('minecraft:packed_ice')) +mods.astralsorcery.lightwell.removeByOutput(fluid('lava')) +//mods.astralsorcery.lightwell.removeAll() + + +// Infusion Altar: +// Consumes buckets of Liquid Starlight when interacted with by a Resonating Wand to convert input items into output itemstacks after a time. +mods.astralsorcery.infusionaltar.recipeBuilder() + .input(item('minecraft:diamond')) + .output(item('minecraft:clay')) + .consumption(1f) // Optional float, chance to consume a bucket of Liquid Starlight from around the altar. (Default 0.05f) + .chalice(false) // Optional boolean, allows the recipe time to be reduced by *0.3 if a chalice is nearby if true. (Default true) + .consumeMultiple(true) // Optional boolean, when consuming liquid starlight, consume all 12 source blocks instead of just one. (Default false) + .time(10) // Optional integer, how long the recipe takes to complete in ticks. (Default 200) + .register() + +mods.astralsorcery.infusionaltar.recipeBuilder() + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:clay')) + .register() + +mods.astralsorcery.infusionaltar.removeByInput(item('minecraft:diamond_ore')) +mods.astralsorcery.infusionaltar.removeByOutput(item('minecraft:iron_ingot')) +//mods.astralsorcery.infusionaltar.removeAll() + + +// Grindstone: +// Converts an item into an itemstack with a chance of getting twice the amount after right clicking the grindstone based on weight. +mods.astralsorcery.grindstone.recipeBuilder() + .input(ore('blockDiamond')) + .output(item('minecraft:clay')) + .weight(1) // Optional int, how likely to craft the recipe per right click (1/weight chance). (Default 0) + .secondaryChance(1.0F) // Optional int, how likely to double the output. (Default 0) + .register() + +mods.astralsorcery.grindstone.recipeBuilder() + .input(item('minecraft:stone')) + .output(item('minecraft:cobblestone')) + .weight(5) + .register() + +mods.astralsorcery.grindstone.removeByInput(item('minecraft:redstone_ore')) +mods.astralsorcery.grindstone.removeByOutput(ore('dustIron')) +//mods.astralsorcery.grindstone.removeAll() + + +// Light Transmutation: +// Converts an input Block or IBlockState into an output IBlockState after being sent a given amount of starlight, with the ability to require a specific constellation of starlight. +mods.astralsorcery.lighttransmutation.recipeBuilder() + .input(block('minecraft:stone')) + .output(block('astralsorcery:blockmarble')) + .cost(100.0) + .constellation(constellation('armara')) // Optional IWeakConstellation, a Major or Weak Constellation that the celestial crystal sending starlight must be attuned to. (Default: any) + .inputDisplayStack(item('minecraft:stone')) // Optional itemstack, what item to be displayed as input in JEI. (Default: input) + .outputDisplayStack(item('minecraft:dye:15').withNbt([display:[Name:'Marble']])) // Optional itemstack, what item to be displayed as output in JEI. (Default: output) + .register() + +mods.astralsorcery.lighttransmutation.recipeBuilder() + .input(blockstate('minecraft:pumpkin')) // Will only convert a pumpkin facing north. Block should be used instead if this behavior is undesired. + .output(blockstate('minecraft:diamond_block')) + .cost(0) + .register() + +mods.astralsorcery.lighttransmutation.removeByInput(blockstate('minecraft:sandstone')) +mods.astralsorcery.lighttransmutation.removeByInput(block('minecraft:netherrack')) +mods.astralsorcery.lighttransmutation.removeByOutput(blockstate('minecraft:cake')) +mods.astralsorcery.lighttransmutation.removeByOutput(block('minecraft:lapis_block')) +//mods.astralsorcery.lighttransmutation.removeAll() + + +// Chalice Interaction: +// When two chalices containing different fluids are placed nearby, fluid may be consumed to produce an output itemstack. +mods.astralsorcery.chaliceinteraction.recipeBuilder() + .output(item('astralsorcery:blockmarble')) + .fluidInput(fluid('water') * 10) + .fluidInput(fluid('astralsorcery.liquidstarlight') * 30) + .register() + +mods.astralsorcery.chaliceinteraction.removeByInput(fluid('water'), fluid('lava')) +//mods.astralsorcery.chaliceinteraction.removeByInput(fluid('astralsorcery.liquidstarlight')) +mods.astralsorcery.chaliceinteraction.removeByOutput(item('minecraft:ice')) +//mods.astralsorcery.chaliceinteraction.removeAll() + + +// Fountian: +// Adds virtual aquifers that can be accessed via the Evershifting Fountain's Necromantic Prime +mods.astralsorcery.fountain.chanceHelper() + .fluid(fluid('astralsorcery.liquidstarlight')) + .rarity(10000000) + .minimumAmount(4000000) + .variance(1000000) + .register() + +mods.astralsorcery.fountain.remove(fluid('lava')) +//mods.astralsorcery.fountain.removeAll() + + +// Mineralis Ritual Registry: +// Using a mineralis ritual will convert nearby stone blocks into random ores. +mods.astralsorcery.mineralisRitualRegistry.add(ore('blockDiamond'), 10000) + +mods.astralsorcery.mineralisRitualRegistry.remove(ore('oreDiamond')) +//mods.astralsorcery.mineralisRitualRegistry.removeAll() + + +// Aevitas Perk Registry: +// Having the Stone Enrichment perk will convert nearby stone blocks into random ores. +mods.astralsorcery.aevitasPerkRegistry.add(ore('blockDiamond'), 10000) + +mods.astralsorcery.aevitasPerkRegistry.remove(ore('oreDiamond')) +//mods.astralsorcery.aevitasPerkRegistry.removeAll() + + +// Trash Perk Registry: +// Having the Trash to Treasure perk turns items the player drops in the list defined in the config at 'perks/key_void_trash/DropList' into a chance at random ores. +mods.astralsorcery.trashPerkRegistry.add(ore('blockDiamond'), 10000) + +mods.astralsorcery.trashPerkRegistry.remove(ore('oreDiamond')) +//mods.astralsorcery.trashPerkRegistry.removeAll() + + +// Treasure Shrine Registry: +// When the block in the middle of a Treasure Shrine structure is broken, a random ore from this list will replace it until the Treasure Shrine is exhausted. +mods.astralsorcery.treasureShrineRegistry.add(ore('blockDiamond'), 10000) + +mods.astralsorcery.treasureShrineRegistry.remove(ore('oreDiamond')) +//mods.astralsorcery.treasureShrineRegistry.removeAll() diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/AstralSorcery.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/AstralSorcery.java index 81b259985..ec2ecce85 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/AstralSorcery.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/AstralSorcery.java @@ -1,5 +1,6 @@ package com.cleanroommc.groovyscript.compat.mods.astralsorcery; +import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.brackets.BracketHandlerManager; import com.cleanroommc.groovyscript.compat.mods.ModPropertyContainer; import com.cleanroommc.groovyscript.compat.mods.astralsorcery.crystal.CrystalItemStackExpansion; @@ -7,9 +8,12 @@ import com.cleanroommc.groovyscript.compat.mods.astralsorcery.perktree.PerkTreeConfig; import com.cleanroommc.groovyscript.compat.mods.astralsorcery.starlightaltar.StarlightAltar; import com.cleanroommc.groovyscript.core.mixin.astralsorcery.ConstellationRegistryAccessor; +import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper; import hellfirepvp.astralsorcery.common.constellation.IConstellation; +import hellfirepvp.astralsorcery.common.crafting.ItemHandle; import net.minecraft.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; public class AstralSorcery extends ModPropertyContainer { @@ -59,4 +63,11 @@ public void initialize() { }); ExpansionHelper.mixinClass(ItemStack.class, CrystalItemStackExpansion.class); } + + public static ItemHandle toItemHandle(IIngredient ingredient) { + if (ingredient instanceof FluidStack) return new ItemHandle(((FluidStack) ingredient).getFluid()); + if (ingredient instanceof OreDictIngredient) return new ItemHandle(((OreDictIngredient) ingredient).getOreDict()); + return new ItemHandle(ingredient.getMatchingStacks()); + } + } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/ChaliceInteraction.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/ChaliceInteraction.java index 4f0dc72b2..f7a0a1a32 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/ChaliceInteraction.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/ChaliceInteraction.java @@ -3,9 +3,14 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.core.mixin.astralsorcery.LightOreTransmutationsAccessor; import com.cleanroommc.groovyscript.core.mixin.astralsorcery.LiquidInteractionAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; +import com.cleanroommc.groovyscript.helper.ingredient.FluidStackList; +import com.cleanroommc.groovyscript.helper.ingredient.ItemStackList; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import hellfirepvp.astralsorcery.common.base.LightOreTransmutations; import hellfirepvp.astralsorcery.common.base.LiquidInteraction; import it.unimi.dsi.fastutil.floats.FloatArrayList; import it.unimi.dsi.fastutil.ints.IntArrayList; @@ -16,126 +21,164 @@ import java.util.ArrayList; import java.util.LinkedList; +import java.util.List; -public class ChaliceInteraction extends VirtualizedRegistry { +public class ChaliceInteraction extends VirtualizedRegistry { + + private static List getRegistry() { + if (LiquidInteractionAccessor.getRegisteredInteractions() == null) { + throw new IllegalStateException("Astral Sorcery Chalice Interaction getRegisteredInteractions() is not yet initialized!"); + } + return LiquidInteractionAccessor.getRegisteredInteractions(); + } + + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } @Override @GroovyBlacklist @ApiStatus.Internal public void onReload() { - removeScripted().forEach(this::remove); - restoreFromBackup().forEach(this::add); + removeScripted().forEach(getRegistry()::remove); + restoreFromBackup().forEach(getRegistry()::add); } - private void add(hellfirepvp.astralsorcery.common.base.LiquidInteraction recipe) { - LinkedList rts = (LinkedList) LiquidInteractionAccessor.getRegisteredInteractions(); - - if (rts == null) rts = new LinkedList<>(); - rts.add(recipe); + private void add(LiquidInteraction recipe) { + addScripted(recipe); + getRegistry().add(recipe); } - public hellfirepvp.astralsorcery.common.base.LiquidInteraction add(int probability, FluidStack component1, FluidStack component2, hellfirepvp.astralsorcery.common.base.LiquidInteraction.FluidInteractionAction action) { - hellfirepvp.astralsorcery.common.base.LiquidInteraction recipe = new hellfirepvp.astralsorcery.common.base.LiquidInteraction(probability, component1, component2, action); + public LiquidInteraction add(int probability, FluidStack component1, FluidStack component2, LiquidInteraction.FluidInteractionAction action) { + LiquidInteraction recipe = new LiquidInteraction(probability, component1, component2, action); addScripted(recipe); - - LinkedList rts = (LinkedList) LiquidInteractionAccessor.getRegisteredInteractions(); - - if (rts == null) rts = new LinkedList<>(); - rts.add(recipe); - + getRegistry().add(recipe); return recipe; } - private void remove(hellfirepvp.astralsorcery.common.base.LiquidInteraction recipe) { - LinkedList rts = (LinkedList) LiquidInteractionAccessor.getRegisteredInteractions(); - - if (rts == null) return; - rts.removeIf(rec -> rec.equals(recipe)); + private boolean remove(LiquidInteraction recipe) { + return getRegistry().removeIf(rec -> rec.equals(recipe)); } - public void remove(FluidStack fluid1, FluidStack fluid2) { - this.remove(fluid1.getFluid(), fluid2.getFluid()); + public void removeByInput(Fluid fluid1, Fluid fluid2) { + getRegistry().removeIf(rec -> { + if ((rec.getComponent1().getFluid().equals(fluid1) && rec.getComponent2().getFluid().equals(fluid2)) || + (rec.getComponent1().getFluid().equals(fluid2) && rec.getComponent2().getFluid().equals(fluid1))) { + addBackup(rec); + return true; + } + return false; + }); } - public void remove(Fluid fluid1, Fluid fluid2) { - LinkedList rts = (LinkedList) LiquidInteractionAccessor.getRegisteredInteractions(); + public void removeByInput(FluidStack fluid1, FluidStack fluid2) { + this.removeByInput(fluid1.getFluid(), fluid2.getFluid()); + } - if (rts == null) return; - rts.forEach(rec -> { - if ((rec.getComponent1().getFluid().equals(fluid1) && rec.getComponent2().getFluid().equals(fluid2)) - || (rec.getComponent1().getFluid().equals(fluid2) && rec.getComponent2().getFluid().equals(fluid1))) + public void removeByInput(Fluid fluid) { + getRegistry().removeIf(rec -> { + if ((rec.getComponent1().getFluid().equals(fluid) || rec.getComponent2().getFluid().equals(fluid))) { addBackup(rec); + return true; + } + return false; }); - rts.removeIf(rec -> ((rec.getComponent1().getFluid().equals(fluid1) && rec.getComponent2().getFluid().equals(fluid2)) - || (rec.getComponent1().getFluid().equals(fluid2) && rec.getComponent2().getFluid().equals(fluid1)))); } - public void removeByOutput(ItemStack output) { - LinkedList rts = (LinkedList) LiquidInteractionAccessor.getRegisteredInteractions(); + public void removeByInput(FluidStack fluid) { + this.removeByInput(fluid.getFluid()); + } - if (rts == null) return; - rts.forEach(rec -> { - if (((LiquidInteractionAccessor) rec).getFluidInteractionAction().getOutputForMatching().isItemEqual(output)) + public void removeByOutput(ItemStack output) { + getRegistry().removeIf(rec -> { + if (((LiquidInteractionAccessor) rec).getFluidInteractionAction().getOutputForMatching().isItemEqual(output)) { addBackup(rec); + return true; + } + return false; }); - rts.removeIf(rec -> ((LiquidInteractionAccessor) rec).getFluidInteractionAction().getOutputForMatching().isItemEqual(output)); } - public static RecipeBuilder recipeBuilder() { - return new RecipeBuilder(); + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(getRegistry()) + .setRemover(this::remove); + } + + public void removeAll() { + getRegistry().forEach(this::addBackup); + getRegistry().clear(); } - public static class RecipeBuilder extends AbstractRecipeBuilder { + public static class RecipeBuilder extends AbstractRecipeBuilder { private final FloatArrayList chances = new FloatArrayList(); - private final ArrayList results = new ArrayList<>(); - private final ArrayList components = new ArrayList<>(); private final IntArrayList probabilities = new IntArrayList(); + public RecipeBuilder result(ItemStack item, int weight) { + this.output.add(item); + this.probabilities.add(weight); + return this; + } + public RecipeBuilder result(ItemStack item) { return this.result(item, 1); } - public RecipeBuilder result(ItemStack item, int weight) { - this.results.add(item); - this.probabilities.add(weight); - return this; + public RecipeBuilder output(ItemStack item, int weight) { + return this.result(item, weight); } - public RecipeBuilder component(FluidStack fluid) { - return this.component(fluid, 1.0F); + public RecipeBuilder output(ItemStack item) { + return this.result(item, 1); } public RecipeBuilder component(FluidStack fluid, float chance) { - this.components.add(fluid); + this.fluidInput.add(fluid); this.chances.add(chance); return this; } + public RecipeBuilder component(FluidStack fluid) { + return this.component(fluid, 1.0F); + } + + public RecipeBuilder fluidInput(FluidStack fluid, float chance) { + return this.component(fluid, chance); + } + + public RecipeBuilder fluidInput(FluidStack fluid) { + return this.component(fluid, 1.0F); + } + @Override public String getErrorMsg() { - return "Error adding Astral Sorcery Liquid Interaction"; + return "Error adding Astral Sorcery Chalice Interaction"; } @Override public void validate(GroovyLog.Msg msg) { - msg.add(this.results.isEmpty(), () -> "No output(s) provided."); - for (Integer probability : this.probabilities) { + validateItems(msg, 0, 0, 1, Integer.MAX_VALUE); + for (Integer probability : probabilities) { if (probability <= 0) msg.add("Weight must be a positive integer. Instead found: " + probability); } - msg.add(this.components.size() != 2, () -> "Exactly two fluids must be provided. Number provided: " + this.components.size()); - if (this.components.size() < 2) return; - msg.add(this.components.get(0) == null || this.components.get(1) == null, () -> "Neither fluid can be null"); - msg.add(this.chances.getFloat(0) < 0 || this.chances.getFloat(1) < 0, () -> "Consumption chance cannot be negative"); + validateFluids(msg, 2, 2, 0, 0); + msg.add(chances.getFloat(0) < 0 || chances.getFloat(1) < 0, () -> "Consumption chance cannot be negative"); } @Override public LiquidInteraction register() { if (!validate()) return null; - for (int i = 0; i < this.results.size(); i++) { - ModSupport.ASTRAL_SORCERY.get().chaliceInteraction.add(this.probabilities.getInt(i), this.components.get(0), this.components.get(1), hellfirepvp.astralsorcery.common.base.LiquidInteraction.createItemDropAction(this.chances.getFloat(0), this.chances.getFloat(1), this.results.get(i))); + LiquidInteraction recipe = null; + for (int i = 0; i < this.output.size(); i++) { + recipe = new LiquidInteraction( + probabilities.getInt(i), + fluidInput.get(0), + fluidInput.get(1), + LiquidInteraction.createItemDropAction(chances.getFloat(0), chances.getFloat(1), output.get(i)) + ); + ModSupport.ASTRAL_SORCERY.get().chaliceInteraction.add(recipe); } - return null; + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Constellation.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Constellation.java index cf8851e0f..3a3dbbd75 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Constellation.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Constellation.java @@ -7,6 +7,7 @@ import com.cleanroommc.groovyscript.core.mixin.astralsorcery.ConstellationBaseAccessor; import com.cleanroommc.groovyscript.core.mixin.astralsorcery.ConstellationMapEffectRegistryAccessor; import com.cleanroommc.groovyscript.core.mixin.astralsorcery.ConstellationRegistryAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import com.google.common.collect.Iterables; import hellfirepvp.astralsorcery.common.constellation.*; @@ -23,11 +24,13 @@ import hellfirepvp.astralsorcery.common.item.ItemCraftingComponent; import hellfirepvp.astralsorcery.common.lib.ItemsAS; import hellfirepvp.astralsorcery.common.lib.RecipesAS; +import hellfirepvp.astralsorcery.common.tile.TileAltar; import hellfirepvp.astralsorcery.common.util.OreDictAlias; import net.minecraft.enchantment.Enchantment; import net.minecraft.init.Items; import net.minecraft.item.EnumDyeColor; import net.minecraft.potion.Potion; +import net.minecraft.util.ResourceLocation; import org.jetbrains.annotations.ApiStatus; import java.awt.*; @@ -45,13 +48,27 @@ public class Constellation extends VirtualizedRegistry { @GroovyBlacklist @ApiStatus.Internal public void onReload() { - removeScripted().forEach(c -> this.remove(c, false)); - restoreFromBackup().forEach(c -> this.add(c, false)); + removeScripted().forEach(c -> { + if (ConstellationMapEffectRegistryAccessor.getEffectRegistry() != null) { + ConstellationMapEffectRegistryAccessor.getEffectRegistry().remove(c); + } + ConstellationRegistryAccessor.getConstellationList().removeIf(registeredConstellation -> c.getSimpleName().equals(registeredConstellation.getSimpleName())); + if (c instanceof IMajorConstellation && ConstellationRegistryAccessor.getMajorConstellations() != null) { + ConstellationRegistryAccessor.getMajorConstellations().removeIf(registeredConstellation -> c.getSimpleName().equals(registeredConstellation.getSimpleName())); + } + if (c instanceof IMinorConstellation && ConstellationRegistryAccessor.getMinorConstellations() != null) { + ConstellationRegistryAccessor.getMinorConstellations().removeIf(registeredConstellation -> c.getSimpleName().equals(registeredConstellation.getSimpleName())); + } + if (c instanceof IWeakConstellation && ConstellationRegistryAccessor.getWeakConstellations() != null) { + ConstellationRegistryAccessor.getWeakConstellations().removeIf(registeredConstellation -> c.getSimpleName().equals(registeredConstellation.getSimpleName())); + } + }); + restoreFromBackup().forEach(ConstellationRegistry::registerConstellation); this.constellationMapEffectsRemoved.forEach((constellation, effect) -> ConstellationMapEffectRegistry.registerMapEffect(constellation, effect.enchantmentEffects, effect.potionEffects)); - this.constellationMapEffectsAdded.forEach((constellation, effect) -> this.removeConstellationMapEffect(constellation, false)); - this.signatureItemsAdded.keySet().forEach(this::removeSignatureItems); - this.signatureItemsRemoved.forEach((constellation, items) -> items.forEach(item -> this.addSignatureItem(constellation, item))); + this.constellationMapEffectsAdded.forEach((constellation, effect) -> ConstellationMapEffectRegistryAccessor.getEffectRegistry().remove(constellation)); + this.signatureItemsAdded.forEach((constellation, items) -> items.forEach(item -> ((ConstellationBaseAccessor) constellation).getSignatureItems().remove(item))); + this.signatureItemsRemoved.forEach((constellation, items) -> items.forEach(constellation::addSignatureItem)); this.constellationMapEffectsAdded.clear(); this.constellationMapEffectsRemoved.clear(); @@ -59,49 +76,64 @@ public void onReload() { this.signatureItemsRemoved.clear(); } - private void add(IConstellation constellation) { - this.add(constellation, true); + public void afterScriptLoad() { + ConstellationRegistryAccessor.getConstellationList().forEach(constellation -> { + if (!(constellation instanceof IMinorConstellation)) updateDefaultCapeRecipe(constellation); + updateDefaultPaperRecipe(constellation); + }); } - private void add(IConstellation constellation, boolean addScripted) { - if (addScripted) this.addScripted(constellation); + private void add(IConstellation constellation) { + addScripted(constellation); ConstellationRegistry.registerConstellation(constellation); } - private void remove(IConstellation constellation) { - this.remove(constellation, true); - } - - private void remove(IConstellation constellation, boolean doBackup) { - if (ConstellationRegistryAccessor.getConstellationList() == null) return; - if (doBackup) this.addBackup(constellation); - this.removeConstellationMapEffect(constellation, doBackup); + private boolean remove(IConstellation constellation) { + if (ConstellationRegistryAccessor.getConstellationList() == null) return false; + addBackup(constellation); + this.removeConstellationMapEffect(constellation); ConstellationRegistryAccessor.getConstellationList().removeIf(registeredConstellation -> constellation.getSimpleName().equals(registeredConstellation.getSimpleName())); if (constellation instanceof IMajorConstellation && ConstellationRegistryAccessor.getMajorConstellations() != null) - ConstellationRegistryAccessor.getMajorConstellations().removeIf(registeredConstellation -> constellation.getSimpleName().equals(registeredConstellation.getSimpleName())); + return ConstellationRegistryAccessor.getMajorConstellations().removeIf(registeredConstellation -> constellation.getSimpleName().equals(registeredConstellation.getSimpleName())); if (constellation instanceof IMinorConstellation && ConstellationRegistryAccessor.getMinorConstellations() != null) - ConstellationRegistryAccessor.getMinorConstellations().removeIf(registeredConstellation -> constellation.getSimpleName().equals(registeredConstellation.getSimpleName())); + return ConstellationRegistryAccessor.getMinorConstellations().removeIf(registeredConstellation -> constellation.getSimpleName().equals(registeredConstellation.getSimpleName())); if (constellation instanceof IWeakConstellation && ConstellationRegistryAccessor.getWeakConstellations() != null) - ConstellationRegistryAccessor.getWeakConstellations().removeIf(registeredConstellation -> constellation.getSimpleName().equals(registeredConstellation.getSimpleName())); + return ConstellationRegistryAccessor.getWeakConstellations().removeIf(registeredConstellation -> constellation.getSimpleName().equals(registeredConstellation.getSimpleName())); + return false; } - private void addConstellationMapEffect(IConstellation constellation, List enchantmentEffectList, List potionEffectList) { - this.constellationMapEffectsAdded.put(constellation, ConstellationMapEffectRegistry.registerMapEffect(constellation, enchantmentEffectList, potionEffectList)); + public SimpleObjectStream streamConstellations() { + return new SimpleObjectStream<>(ConstellationRegistryAccessor.getConstellationList()) + .setRemover(this::remove); } - public void removeConstellationMapEffect(IConstellation constellation) { - this.removeConstellationMapEffect(constellation, true); + public void removeAll() { + ConstellationRegistryAccessor.getConstellationList().forEach(this::addBackup); + ConstellationRegistryAccessor.getConstellationList().clear(); + ConstellationRegistryAccessor.getMajorConstellations().clear(); + ConstellationRegistryAccessor.getMinorConstellations().clear(); + ConstellationRegistryAccessor.getWeakConstellations().clear(); } - private void removeConstellationMapEffect(IConstellation constellation, boolean doBackup) { + private void addConstellationMapEffect(IConstellation constellation, List enchantmentEffectList, List potionEffectList) { + this.constellationMapEffectsAdded.put(constellation, ConstellationMapEffectRegistry.registerMapEffect(constellation, enchantmentEffectList, potionEffectList)); + } + + private void removeConstellationMapEffect(IConstellation constellation) { if (ConstellationMapEffectRegistryAccessor.getEffectRegistry() == null) return; if (ConstellationMapEffectRegistryAccessor.getEffectRegistry().containsKey(constellation)) { - if (doBackup) - this.constellationMapEffectsRemoved.put(constellation, ConstellationMapEffectRegistryAccessor.getEffectRegistry().get(constellation)); + this.constellationMapEffectsRemoved.put(constellation, ConstellationMapEffectRegistryAccessor.getEffectRegistry().get(constellation)); ConstellationMapEffectRegistryAccessor.getEffectRegistry().remove(constellation); } } + public void removeAllConstellationMapEffect() { + ConstellationRegistryAccessor.getConstellationList().forEach(constellation -> { + this.constellationMapEffectsRemoved.put(constellation, ConstellationMapEffectRegistryAccessor.getEffectRegistry().get(constellation)); + ConstellationMapEffectRegistryAccessor.getEffectRegistry().remove(constellation); + }); + } + private void addSignatureItem(IConstellation constellation, ItemHandle item) { constellation.addSignatureItem(item); } @@ -110,11 +142,8 @@ public void addSignatureItem(IConstellation constellation, IIngredient ing) { if (!this.signatureItemsAdded.containsKey(constellation)) { this.signatureItemsAdded.put(constellation, new ArrayList<>()); } - this.signatureItemsAdded.get(constellation).add(Utils.convertToItemHandle(ing)); - constellation.addSignatureItem(Utils.convertToItemHandle(ing)); - if (!(constellation instanceof IMinorConstellation)) this.updateDefaultCapeRecipe(constellation); - this.updateDefaultPaperRecipe(constellation); - + this.signatureItemsAdded.get(constellation).add(AstralSorcery.toItemHandle(ing)); + constellation.addSignatureItem(AstralSorcery.toItemHandle(ing)); } public void addSignatureItem(IConstellation constellation, IIngredient... ings) { @@ -128,41 +157,53 @@ public void addSignatureItem(IConstellation constellation, Collection { this.signatureItemsRemoved.put(constellation, ((ConstellationBaseAccessor) constellation).getSignatureItems()); - ((ConstellationBaseAccessor) constellation).getSignatureItems().clear(); - if (!(constellation instanceof IMinorConstellation)) this.updateDefaultCapeRecipe(constellation); - this.updateDefaultPaperRecipe(constellation); + ((ConstellationBaseAccessor) constellation).getSignatureItems().clear(); + }); } private void updateDefaultPaperRecipe(IConstellation constellation) { - AccessibleRecipeAdapater shapedPaper = ShapedRecipe.Builder.newShapedRecipe("internal/altar/constellationpaper/" + constellation.getSimpleName().toLowerCase(), ItemsAS.constellationPaper).addPart(ItemCraftingComponent.MetaType.PARCHMENT.asStack(), ShapedRecipeSlot.CENTER).addPart(Items.FEATHER, ShapedRecipeSlot.UPPER_CENTER).addPart(OreDictAlias.getDyeOreDict(EnumDyeColor.BLACK), ShapedRecipeSlot.LOWER_CENTER).addPart(OreDictAlias.ITEM_STARMETAL_DUST, ShapedRecipeSlot.LEFT, ShapedRecipeSlot.RIGHT).unregisteredAccessibleShapedRecipe(); - ConstellationPaperRecipe recipe = new ConstellationPaperRecipe(shapedPaper, constellation); ItemHandle first = (ItemHandle) Iterables.getFirst(constellation.getConstellationSignatureItems(), (Object) null); + AccessibleRecipeAdapater shapedPaper = ShapedRecipe.Builder.newShapedRecipe("internal/altar/constellationpaper/" + constellation.getSimpleName().toLowerCase(), ItemsAS.constellationPaper) + .addPart(ItemCraftingComponent.MetaType.PARCHMENT.asStack(), ShapedRecipeSlot.CENTER) + .addPart(Items.FEATHER, ShapedRecipeSlot.UPPER_CENTER) + .addPart(OreDictAlias.getDyeOreDict(EnumDyeColor.BLACK), ShapedRecipeSlot.LOWER_CENTER) + .addPart(OreDictAlias.ITEM_STARMETAL_DUST, ShapedRecipeSlot.LEFT, ShapedRecipeSlot.RIGHT) + .unregisteredAccessibleShapedRecipe(); + ConstellationPaperRecipe recipe = new ConstellationPaperRecipe(shapedPaper, constellation); recipe.setInnerTraitItem(first, TraitRecipe.TraitRecipeSlot.values()); for (ItemHandle s : constellation.getConstellationSignatureItems()) { recipe.addOuterTraitItem(s); } + AltarRecipeRegistry.recipes.get(TileAltar.AltarLevel.TRAIT_CRAFT) + .removeIf(r -> new ResourceLocation("astralsorcery:shaped/internal/altar/constellationpaper/" + constellation.getSimpleName().toLowerCase()).equals(r.getNativeRecipe().getRegistryName())); AltarRecipeRegistry.registerAltarRecipe(recipe); RecipesAS.paperCraftingRecipes.put(constellation, recipe); } private void updateDefaultCapeRecipe(IConstellation constellation) { ItemHandle first = (ItemHandle) Iterables.getFirst(constellation.getConstellationSignatureItems(), (Object) null); - AccessibleRecipeAdapater ar = ShapedRecipe.Builder.newShapedRecipe("internal/cape/att/" + constellation.getSimpleName().toLowerCase(), ItemsAS.armorImbuedCape).addPart(ItemsAS.armorImbuedCape, ShapedRecipeSlot.CENTER).addPart(first, ShapedRecipeSlot.UPPER_CENTER, ShapedRecipeSlot.LEFT, ShapedRecipeSlot.RIGHT, ShapedRecipeSlot.LOWER_CENTER).unregisteredAccessibleShapedRecipe(); + AccessibleRecipeAdapater ar = ShapedRecipe.Builder.newShapedRecipe("internal/cape/att/" + constellation.getSimpleName().toLowerCase(), ItemsAS.armorImbuedCape) + .addPart(ItemsAS.armorImbuedCape, ShapedRecipeSlot.CENTER) + .addPart(first, ShapedRecipeSlot.UPPER_CENTER, ShapedRecipeSlot.LEFT, ShapedRecipeSlot.RIGHT, ShapedRecipeSlot.LOWER_CENTER) + .unregisteredAccessibleShapedRecipe(); CapeAttunementRecipe recipe = new CapeAttunementRecipe(constellation, ar); + recipe.setInnerTraitItem(OreDictAlias.ITEM_STARMETAL_DUST, TraitRecipe.TraitRecipeSlot.values()); for (ItemHandle s : constellation.getConstellationSignatureItems()) { recipe.addOuterTraitItem(s); } - recipe.setInnerTraitItem(OreDictAlias.ITEM_STARMETAL_DUST, TraitRecipe.TraitRecipeSlot.values()); + AltarRecipeRegistry.recipes.get(TileAltar.AltarLevel.TRAIT_CRAFT) + .removeIf(r -> new ResourceLocation("astralsorcery:shaped/internal/cape/att/" + constellation.getSimpleName().toLowerCase()).equals(r.getNativeRecipe().getRegistryName())); AltarRecipeRegistry.registerAltarRecipe(recipe); RecipesAS.capeCraftingRecipes.put(constellation, recipe); } @@ -181,17 +222,11 @@ public SignatureItemsHelper signatureItems() { public static class ConstellationBuilder { + private final ArrayList connections = new ArrayList<>(); + private final ArrayList phases = new ArrayList<>(); private String name; private Color color = null; private ConstellationBuilder.Type type; - private final ArrayList connections = new ArrayList<>(); - private final ArrayList phases = new ArrayList<>(); - - private enum Type { - MAJOR, - MINOR, - WEAK - } public ConstellationBuilder name(String name) { this.name = name; @@ -262,8 +297,10 @@ private boolean validate() { switch (this.type) { case MAJOR: this.color = new Color(40, 67, 204); + break; case WEAK: this.color = new Color(67, 44, 176); + break; case MINOR: this.color = new Color(93, 25, 127); } @@ -273,23 +310,33 @@ private boolean validate() { } public void register() { - if (!this.validate()) return; + if (!validate()) return; IConstellation constellation; - if (type.equals(Type.MAJOR)) constellation = new ConstellationBase.Major(name, color); - else if (type.equals(Type.MINOR)) - constellation = new ConstellationBase.Minor(name, color, phases.toArray(new MoonPhase[0])); - else if (type.equals(Type.WEAK)) constellation = new ConstellationBase.Weak(name, color); - else return; + switch (this.type) { + case MAJOR: + constellation = new ConstellationBase.Major(name, color); + break; + case WEAK: + constellation = new ConstellationBase.Minor(name, color, phases.toArray(new MoonPhase[0])); + break; + case MINOR: + constellation = new ConstellationBase.Weak(name, color); + break; + default: + return; + } HashMap addedStars = new HashMap<>(); this.connections.forEach(connection -> { StarLocation s1, s2; - if (addedStars.containsKey(connection.p1)) s1 = addedStars.get(connection.p1); - else { + if (addedStars.containsKey(connection.p1)) { + s1 = addedStars.get(connection.p1); + } else { s1 = constellation.addStar(connection.p1.x, connection.p1.y); addedStars.put(connection.p1, s1); } - if (addedStars.containsKey(connection.p2)) s2 = addedStars.get(connection.p2); - else { + if (addedStars.containsKey(connection.p2)) { + s2 = addedStars.get(connection.p2); + } else { s2 = constellation.addStar(connection.p2.x, connection.p2.y); addedStars.put(connection.p2, s2); } @@ -298,13 +345,19 @@ else if (type.equals(Type.MINOR)) ModSupport.ASTRAL_SORCERY.get().constellation.add(constellation); } + + private enum Type { + MAJOR, + MINOR, + WEAK + } } public static class ConstellationMapEffectBuilder { - private IConstellation constellation = null; private final List enchantmentEffect = new ArrayList<>(); private final List potionEffect = new ArrayList<>(); + private IConstellation constellation = null; public ConstellationMapEffectBuilder constellation(IConstellation constellation) { this.constellation = constellation; @@ -339,9 +392,9 @@ public void register() { public static class SignatureItemsHelper { + private final ArrayList items = new ArrayList<>(); private IConstellation constellation = null; private boolean doStrip = false; - private final ArrayList items = new ArrayList<>(); public SignatureItemsHelper constellation(IConstellation constellation) { this.constellation = constellation; @@ -360,8 +413,7 @@ public SignatureItemsHelper addItem(IIngredient ing) { public void register() { if (this.constellation != null) { - if (this.doStrip) - ModSupport.ASTRAL_SORCERY.get().constellation.removeSignatureItems(this.constellation); + if (this.doStrip) ModSupport.ASTRAL_SORCERY.get().constellation.removeSignatureItems(this.constellation); ModSupport.ASTRAL_SORCERY.get().constellation.addSignatureItem(this.constellation, this.items); } else { GroovyLog.msg("Error modifying Astral Sorcery constellation signature items").add("No constellation specified.").error().post(); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Fountain.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Fountain.java index a3da4b9de..47755d11d 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Fountain.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Fountain.java @@ -3,7 +3,10 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.core.mixin.astralsorcery.FluidRarityEntryAccessor; import com.cleanroommc.groovyscript.core.mixin.astralsorcery.FluidRarityRegistryAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; +import com.cleanroommc.groovyscript.helper.recipe.IRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import hellfirepvp.astralsorcery.common.base.FluidRarityRegistry; import net.minecraftforge.fluids.Fluid; @@ -13,15 +16,30 @@ public class Fountain extends VirtualizedRegistry { + public FountainChanceHelper chanceHelper() { + return new FountainChanceHelper(); + } + @Override @GroovyBlacklist @ApiStatus.Internal public void onReload() { - removeScripted().forEach(this::remove); - restoreFromBackup().forEach(this::add); + removeScripted().forEach(((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList()::remove); + restoreFromBackup().forEach(((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList()::add); + } + + public void afterScriptLoad() { + // If the rarity list is empty, generating new chunks will cause a NPE. To prevent this, we add a "water" entry that will always have 0mb inside, + // which causes it to be marked as empty, and thus not be interactable. + if (((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList().isEmpty()) { + FluidRarityRegistry.FluidRarityEntry errorBlocker = FluidRarityEntryAccessor.createFluidRarityEntry("water", 1, 0, 0); + ((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList().add(errorBlocker); + addScripted(errorBlocker); + } } public void add(FluidRarityRegistry.FluidRarityEntry entry) { + addScripted(entry); ((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList().add(entry); } @@ -30,13 +48,12 @@ public void add(FluidStack fluid, int rarity, int guaranteedAmt, int addRand) { } public void add(Fluid fluid, int rarity, int guaranteedAmt, int addRand) { - FluidRarityRegistry.FluidRarityEntry newFRE = Utils.createNewFRE(fluid, rarity, guaranteedAmt, addRand); - this.addScripted(newFRE); - this.add(newFRE); + this.add(FluidRarityEntryAccessor.createFluidRarityEntry(fluid, rarity, guaranteedAmt, addRand)); } - public void remove(FluidRarityRegistry.FluidRarityEntry entry) { - ((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList().removeIf(fluidRarityEntry -> fluidRarityEntry.fluid.equals(entry.fluid)); + public boolean remove(FluidRarityRegistry.FluidRarityEntry entry) { + addBackup(entry); + return ((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList().removeIf(fluidRarityEntry -> fluidRarityEntry == entry); } public void remove(FluidStack entry) { @@ -45,19 +62,25 @@ public void remove(FluidStack entry) { public void remove(Fluid entry) { ((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList().removeIf(fluidRarityEntry -> { - if (fluidRarityEntry.fluid.equals(entry)) { - this.addBackup(fluidRarityEntry); + if (fluidRarityEntry.fluid != null && fluidRarityEntry.fluid.equals(entry)) { + addBackup(fluidRarityEntry); return true; } return false; }); } - public FountainChanceHelper chanceHelper() { - return new FountainChanceHelper(); + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList()) + .setRemover(this::remove); } - public static class FountainChanceHelper { + public void removeAll() { + ((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList().forEach(this::addBackup); + ((FluidRarityRegistryAccessor) FluidRarityRegistry.INSTANCE).getRarityList().clear(); + } + + public static class FountainChanceHelper implements IRecipeBuilder { private Fluid fluid = null; private int rarity = 0; @@ -88,7 +111,7 @@ public FountainChanceHelper variance(int variance) { return this; } - private boolean validate() { + public boolean validate() { GroovyLog.Msg out = GroovyLog.msg("Error adding fluid to Astral Sorcery Fountain").warn(); if (this.fluid == null) { @@ -111,10 +134,11 @@ private boolean validate() { return out.getLevel() != Level.ERROR; } - public void register() { - if (validate()) { - ModSupport.ASTRAL_SORCERY.get().fountain.add(this.fluid, this.rarity, this.minimumAmount, this.variance); - } + public FluidRarityRegistry.FluidRarityEntry register() { + if (!validate()) return null; + FluidRarityRegistry.FluidRarityEntry recipe = FluidRarityEntryAccessor.createFluidRarityEntry(fluid, rarity, minimumAmount, variance); + ModSupport.ASTRAL_SORCERY.get().fountain.add(recipe); + return recipe; } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Grindstone.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Grindstone.java index 1887aaf0f..506706440 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Grindstone.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Grindstone.java @@ -3,6 +3,7 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; @@ -16,26 +17,46 @@ public class Grindstone extends VirtualizedRegistry { + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + @Override @GroovyBlacklist @ApiStatus.Internal public void onReload() { - removeScripted().forEach(this::remove); - restoreFromBackup().forEach(this::add); + removeScripted().forEach(r -> GrindstoneRecipeRegistry.recipes.removeIf(recipe -> r == recipe)); + restoreFromBackup().forEach(GrindstoneRecipeRegistry::registerGrindstoneRecipe); } private void add(GrindstoneRecipe recipe) { + addScripted(recipe); GrindstoneRecipeRegistry.registerGrindstoneRecipe(recipe); } + public GrindstoneRecipe add(ItemHandle input, ItemStack output, int weight) { + return add(input, output, weight, 0); + } + public GrindstoneRecipe add(ItemHandle input, ItemStack output, int weight, float secondaryChance) { GrindstoneRecipe recipe = new GrindstoneRecipe(input, output, weight, secondaryChance); addScripted(recipe); return GrindstoneRecipeRegistry.registerGrindstoneRecipe(recipe); } - private void remove(GrindstoneRecipe recipe) { - GrindstoneRecipeRegistry.recipes.remove(recipe); + private boolean remove(GrindstoneRecipe recipe) { + addBackup(recipe); + return GrindstoneRecipeRegistry.recipes.remove(recipe); + } + + public void removeByInput(ItemStack item) { + GrindstoneRecipeRegistry.recipes.removeIf(recipe -> { + if (recipe.isValid() && recipe.matches(item)) { + addBackup(recipe); + return true; + } + return false; + }); } public void removeByOutput(OreDictIngredient ore) { @@ -44,20 +65,23 @@ public void removeByOutput(OreDictIngredient ore) { } public void removeByOutput(ItemStack item) { - ArrayList remove = new ArrayList<>(); - - for (GrindstoneRecipe recipe : GrindstoneRecipeRegistry.recipes) { + GrindstoneRecipeRegistry.recipes.removeIf(recipe -> { if (recipe.isValid() && recipe.getOutputForMatching().isItemEqual(item)) { addBackup(recipe); - remove.add(recipe); + return true; } - } + return false; + }); + } - remove.forEach(recipe -> GrindstoneRecipeRegistry.recipes.remove(recipe)); + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(GrindstoneRecipeRegistry.recipes) + .setRemover(this::remove); } - public static RecipeBuilder recipeBuilder() { - return new RecipeBuilder(); + public void removeAll() { + GrindstoneRecipeRegistry.recipes.forEach(this::addBackup); + GrindstoneRecipeRegistry.recipes.clear(); } public static class RecipeBuilder extends AbstractRecipeBuilder { @@ -83,12 +107,15 @@ public String getErrorMsg() { @Override public void validate(GroovyLog.Msg msg) { validateItems(msg, 1, 1, 1, 1); - msg.add(this.weight < 0, () -> "Weight cannot be negative"); - msg.add(this.secondaryChance < 0 || this.secondaryChance > 1, () -> "Secondary chance must be between [0,1]. Instead found " + this.secondaryChance + "."); + msg.add(weight < 0, () -> "Weight cannot be negative"); + msg.add(secondaryChance < 0 || secondaryChance > 1, () -> "Secondary chance must be between [0,1]. Instead found " + secondaryChance + "."); } public GrindstoneRecipe register() { - return ModSupport.ASTRAL_SORCERY.get().grindstone.add(Utils.convertToItemHandle(input.get(0)), output.get(0), weight, secondaryChance); + if (!validate()) return null; + GrindstoneRecipe recipe = new GrindstoneRecipe(AstralSorcery.toItemHandle(input.get(0)), output.get(0), weight, secondaryChance); + ModSupport.ASTRAL_SORCERY.get().grindstone.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/InfusionAltar.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/InfusionAltar.java index 7eda6e5f7..888868f03 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/InfusionAltar.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/InfusionAltar.java @@ -2,9 +2,13 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; +import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import hellfirepvp.astralsorcery.common.crafting.ItemHandle; +import hellfirepvp.astralsorcery.common.crafting.infusion.AbstractInfusionRecipe; import hellfirepvp.astralsorcery.common.crafting.infusion.InfusionRecipeRegistry; import hellfirepvp.astralsorcery.common.crafting.infusion.recipes.BasicInfusionRecipe; import net.minecraft.item.ItemStack; @@ -13,53 +17,113 @@ public class InfusionAltar extends VirtualizedRegistry { + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + @Override @GroovyBlacklist @ApiStatus.Internal public void onReload() { - removeScripted().forEach(this::remove); - removeScripted().forEach(this::add); + removeScripted().forEach(r -> InfusionRecipeRegistry.recipes.removeIf(rec -> rec.getUniqueRecipeId() == r.getUniqueRecipeId())); + restoreFromBackup().forEach(InfusionRecipeRegistry::registerInfusionRecipe); + } + + public void afterScriptLoad() { + InfusionRecipeRegistry.compileRecipes(); } private void add(BasicInfusionRecipe recipe) { + addScripted(recipe); InfusionRecipeRegistry.registerInfusionRecipe(recipe); - InfusionRecipeRegistry.compileRecipes(); } - public BasicInfusionRecipe add(ItemStack output, ItemStack input, float consumption) { + public BasicInfusionRecipe add(ItemStack output, IIngredient input, float consumption) { + return add(output, AstralSorcery.toItemHandle(input), consumption); + } + + public BasicInfusionRecipe add(ItemStack output, ItemHandle input, float consumption) { BasicInfusionRecipe recipe = new BasicInfusionRecipe(output, input); recipe.setLiquidStarlightConsumptionChance(consumption); InfusionRecipeRegistry.registerInfusionRecipe(recipe); - InfusionRecipeRegistry.compileRecipes(); addScripted(recipe); return recipe; } - private void remove(BasicInfusionRecipe recipe) { - InfusionRecipeRegistry.recipes.removeIf(rec -> rec.getUniqueRecipeId() == recipe.getUniqueRecipeId()); - InfusionRecipeRegistry.compileRecipes(); + private boolean remove(AbstractInfusionRecipe recipe) { + if (recipe instanceof BasicInfusionRecipe) addBackup((BasicInfusionRecipe) recipe); + return InfusionRecipeRegistry.recipes.removeIf(rec -> rec.getUniqueRecipeId() == recipe.getUniqueRecipeId()); + } + + public void removeByInput(ItemStack input) { + InfusionRecipeRegistry.recipes.removeIf(r -> { + if (r instanceof BasicInfusionRecipe && r.getInput().matchCrafting(input)) { + addBackup((BasicInfusionRecipe) r); + return true; + } + return false; + }); } public void removeByOutput(ItemStack output) { addBackup((BasicInfusionRecipe) InfusionRecipeRegistry.removeFindRecipeByOutput(output)); - InfusionRecipeRegistry.compileRecipes(); } - public static RecipeBuilder recipeBuilder() { - return new RecipeBuilder(); + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(InfusionRecipeRegistry.recipes) + .setRemover(this::remove); + } + + public void removeAll() { + InfusionRecipeRegistry.recipes.removeIf(r -> { + if (r instanceof BasicInfusionRecipe) { + addBackup((BasicInfusionRecipe) r); + return true; + } + return false; + }); } public static class RecipeBuilder extends AbstractRecipeBuilder { private float consumption = 0.05F; + private boolean chalice = true; + private boolean consumeMultiple = false; + private int time = 200; + public RecipeBuilder consumption(float chance) { this.consumption = chance; return this; } + public RecipeBuilder chalice(boolean chalice) { + this.chalice = chalice; + return this; + } + + public RecipeBuilder chalice() { + this.chalice = !chalice; + return this; + } + + public RecipeBuilder consumeMultiple(boolean consumeMultiple) { + this.consumeMultiple = consumeMultiple; + return this; + } + + public RecipeBuilder consumeMultiple() { + this.consumeMultiple = !consumeMultiple; + return this; + } + + public RecipeBuilder time(int time) { + this.time = time; + return this; + } + @Override public String getErrorMsg() { return "Error adding Astral Infusion recipe"; @@ -67,14 +131,25 @@ public String getErrorMsg() { @Override public void validate(GroovyLog.Msg msg) { - validateItems(msg, 1, 64, 1, 64); - msg.add(this.consumption <= 0.0F, () -> "Consumption must be a positive value."); + validateItems(msg, 1, 1, 1, 1); + msg.add(consumption < 0 || consumption > 1, "consumption must be a float between 0 and 1, yet it was {}", consumption); + msg.add(time <= 0, "time must be an integer greater than 0, yet it was {}", time); } @Override public @Nullable BasicInfusionRecipe register() { if (!validate()) return null; - return ModSupport.ASTRAL_SORCERY.get().infusionAltar.add(output.get(0), input.get(0).getMatchingStacks()[0], consumption); + BasicInfusionRecipe recipe = new BasicInfusionRecipe(output.get(0), AstralSorcery.toItemHandle(input.get(0))) { + public int craftingTickTime() { + return time; + } + }; + recipe.setLiquidStarlightConsumptionChance(consumption); + recipe.setCanBeSupportedByChalices(chalice); + if (consumeMultiple) recipe.setConsumeMultiple(); + recipe.craftingTickTime(); + ModSupport.ASTRAL_SORCERY.get().infusionAltar.add(recipe); + return recipe; } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/LightTransmutation.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/LightTransmutation.java index 9175d870f..34a8850c9 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/LightTransmutation.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/LightTransmutation.java @@ -4,9 +4,11 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.core.mixin.astralsorcery.LightOreTransmutationsAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import hellfirepvp.astralsorcery.common.base.LightOreTransmutations; +import hellfirepvp.astralsorcery.common.constellation.IWeakConstellation; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.item.ItemStack; @@ -14,34 +16,39 @@ import javax.annotation.Nonnull; import java.util.ArrayList; +import java.util.List; public class LightTransmutation extends VirtualizedRegistry { + private static List getRegistry() { + if (LightOreTransmutationsAccessor.getRegisteredTransmutations() == null) { + throw new IllegalStateException("Astral Sorcery Light Transmutation getRegisteredTransmutations() is not yet initialized!"); + } + return (ArrayList) LightOreTransmutationsAccessor.getRegisteredTransmutations(); + } + + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + @Override @GroovyBlacklist @ApiStatus.Internal public void onReload() { - removeScripted().forEach(this::remove); - restoreFromBackup().forEach(this::add); + removeScripted().forEach(r -> getRegistry().removeIf(recipe -> r == recipe)); + restoreFromBackup().forEach(r -> getRegistry().add(r)); } private void add(LightOreTransmutations.Transmutation recipe) { - ArrayList rts = (ArrayList) LightOreTransmutationsAccessor.getRegisteredTransmutations(); - - if (rts == null) rts = new ArrayList<>(); - rts.add(recipe); + getRegistry().add(recipe); + addScripted(recipe); } public LightOreTransmutations.Transmutation add(Block input, IBlockState output, @Nonnull ItemStack inputDisplay, @Nonnull ItemStack outputDisplay, double cost) { LightOreTransmutations.Transmutation recipe = new LightOreTransmutations.Transmutation(input, output, inputDisplay, outputDisplay, cost); addScripted(recipe); - - ArrayList rts = (ArrayList) LightOreTransmutationsAccessor.getRegisteredTransmutations(); - - if (rts == null) rts = new ArrayList<>(); - rts.add(recipe); - + getRegistry().add(recipe); return recipe; } @@ -49,40 +56,50 @@ public LightOreTransmutations.Transmutation add(IBlockState input, IBlockState o @Nonnull ItemStack inputDisplay, @Nonnull ItemStack outputDisplay, double cost) { LightOreTransmutations.Transmutation recipe = new LightOreTransmutations.Transmutation(input, output, inputDisplay, outputDisplay, cost); addScripted(recipe); - - ArrayList rts = (ArrayList) LightOreTransmutationsAccessor.getRegisteredTransmutations(); - - if (rts == null) rts = new ArrayList<>(); - rts.add(recipe); - + getRegistry().add(recipe); return recipe; } - private void remove(LightOreTransmutations.Transmutation recipe) { - ArrayList rts = (ArrayList) LightOreTransmutationsAccessor.getRegisteredTransmutations(); + private boolean remove(LightOreTransmutations.Transmutation recipe) { + return getRegistry().removeIf(rec -> rec.equals(recipe)); + } - if (rts == null) return; - rts.removeIf(rec -> rec.equals(recipe)); + public void removeByInput(IBlockState block) { + getRegistry().removeIf(rec -> { + if (rec.matchesInput(block)) { + addBackup(rec); + return true; + } + return false; + }); } - public void removeByOutput(IBlockState block) { - ArrayList rts = (ArrayList) LightOreTransmutationsAccessor.getRegisteredTransmutations(); + public void removeByInput(Block block) { + removeByInput(block.getDefaultState()); + } - if (rts == null) return; - rts.forEach(rec -> { + public void removeByOutput(IBlockState block) { + getRegistry().removeIf(rec -> { if (rec.matchesOutput(block)) { addBackup(rec); + return true; } + return false; }); - rts.removeIf(rec -> rec.matchesOutput(block)); } public void removeByOutput(Block block) { - this.removeByOutput(block.getDefaultState()); + removeByOutput(block.getDefaultState()); } - public static RecipeBuilder recipeBuilder() { - return new RecipeBuilder(); + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(getRegistry()) + .setRemover(this::remove); + } + + public void removeAll() { + getRegistry().forEach(this::addBackup); + getRegistry().clear(); } public static class RecipeBuilder extends AbstractRecipeBuilder { @@ -93,6 +110,7 @@ public static class RecipeBuilder extends AbstractRecipeBuilder "Input cannot be null"); - msg.add(this.output == null, () -> "Output cannot be null"); - msg.add(this.cost < 0, () -> "Cost cannot be negative"); - if (this.inStack == null && this.inBlock != null) this.inStack = new ItemStack(this.inBlock); - if (this.inStack == null && this.input != null) this.inStack = new ItemStack(this.input.getBlock()); - if (this.outStack == null && this.output != null) this.outStack = new ItemStack(this.output.getBlock()); + msg.add(input == null && inBlock == null, () -> "Input cannot be null"); + msg.add(output == null, () -> "Output cannot be null"); + msg.add(cost < 0, () -> "Cost cannot be negative"); + if (inStack == null && inBlock != null) inStack = new ItemStack(inBlock); + if (inStack == null && input != null) inStack = new ItemStack(input.getBlock()); + if (outStack == null && output != null) outStack = new ItemStack(output.getBlock()); } public LightOreTransmutations.Transmutation register() { if (!validate()) return null; + LightOreTransmutations.Transmutation recipe; if (inBlock == null) { - return ModSupport.ASTRAL_SORCERY.get().lightTransmutation.add(input, output, inStack, outStack, cost); + recipe = new LightOreTransmutations.Transmutation(input, output, inStack, outStack, cost); + } else { + recipe = new LightOreTransmutations.Transmutation(inBlock, output, inStack, outStack, cost); } - return ModSupport.ASTRAL_SORCERY.get().lightTransmutation.add(inBlock, output, inStack, outStack, cost); + recipe.setRequiredType(constellation); + ModSupport.ASTRAL_SORCERY.get().lightTransmutation.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Lightwell.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Lightwell.java index 7fffb0569..f3654f028 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Lightwell.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Lightwell.java @@ -3,7 +3,12 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.compat.mods.ModSupport; +import com.cleanroommc.groovyscript.core.mixin.astralsorcery.LiquidInteractionAccessor; +import com.cleanroommc.groovyscript.core.mixin.astralsorcery.WellLiquefactionAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; +import com.cleanroommc.groovyscript.helper.recipe.IRecipeBuilder; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; +import hellfirepvp.astralsorcery.common.base.LiquidInteraction; import hellfirepvp.astralsorcery.common.base.WellLiquefaction; import net.minecraft.item.ItemStack; import net.minecraftforge.fluids.Fluid; @@ -14,47 +19,80 @@ import java.awt.*; import java.util.List; +import java.util.Map; public class Lightwell extends VirtualizedRegistry { + private static Map getRegistry() { + if (WellLiquefactionAccessor.getRegisteredLiquefactions() == null) { + throw new IllegalStateException("Astral Sorcery Lightwell getRegisteredLiquefactions() is not yet initialized!"); + } + return WellLiquefactionAccessor.getRegisteredLiquefactions(); + } + + public static RecipeBuilder recipeBuilder() { + return new RecipeBuilder(); + } + @Override @GroovyBlacklist @ApiStatus.Internal public void onReload() { - removeScripted().forEach(this::remove); - restoreFromBackup().forEach(this::add); + removeScripted().forEach(r -> getRegistry().remove(r.catalyst)); + restoreFromBackup().forEach(r -> getRegistry().put(r.catalyst, r)); } public void add(WellLiquefaction.LiquefactionEntry recipe) { - WellLiquefaction.registerLiquefaction(recipe.catalyst, recipe.producing, recipe.productionMultiplier, recipe.shatterMultiplier, recipe.catalystColor); + getRegistry().put(recipe.catalyst, recipe); + addScripted(recipe); } public void add(ItemStack catalyst, Fluid output, float productionMultiplier, float shatterMultiplier, @Nullable Color color) { - WellLiquefaction.registerLiquefaction(catalyst, output, productionMultiplier, shatterMultiplier, color); - addScripted(new WellLiquefaction.LiquefactionEntry(catalyst, output, productionMultiplier, shatterMultiplier, color)); + add(new WellLiquefaction.LiquefactionEntry(catalyst, output, productionMultiplier, shatterMultiplier, color)); } - public void remove(WellLiquefaction.LiquefactionEntry recipe) { - WellLiquefaction.tryRemoveLiquefaction(recipe.catalyst, recipe.producing); + public void add(ItemStack catalyst, Fluid output, float productionMultiplier, float shatterMultiplier) { + add(new WellLiquefaction.LiquefactionEntry(catalyst, output, productionMultiplier, shatterMultiplier, null)); } - public void remove(ItemStack catalyst, Fluid fluid) { - addBackup(WellLiquefaction.tryRemoveLiquefaction(catalyst, fluid)); + public boolean remove(WellLiquefaction.LiquefactionEntry recipe) { + addBackup(recipe); + return getRegistry().remove(recipe.catalyst) != null; + } + + public void removeByCatalyst(ItemStack catalyst) { + WellLiquefaction.getRegisteredLiquefactions().forEach(le -> { + if (le.catalyst.isItemEqual(catalyst)) { + addBackup(getRegistry().remove(le.catalyst)); + } + }); + } + + public void removeByInput(ItemStack input) { + removeByCatalyst(input); } public void removeByOutput(FluidStack fluid) { - List list = WellLiquefaction.getRegisteredLiquefactions(); - list.forEach(le -> { - if (le.producing.equals(fluid.getFluid())) - addBackup(WellLiquefaction.tryRemoveLiquefaction(le.catalyst, fluid.getFluid())); + getRegistry().entrySet().removeIf(entry -> { + if (entry.getValue().producing.equals(fluid.getFluid())) { + addBackup(entry.getValue()); + return true; + } + return false; }); } - public static RecipeBuilder recipeBuilder() { - return new RecipeBuilder(); + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(WellLiquefaction.getRegisteredLiquefactions()) + .setRemover(this::remove); + } + + public void removeAll() { + getRegistry().values().forEach(this::addBackup); + getRegistry().clear(); } - public static class RecipeBuilder { + public static class RecipeBuilder implements IRecipeBuilder { private ItemStack catalyst = null; private Fluid output = null; @@ -82,12 +120,27 @@ public RecipeBuilder shatterMultiplier(float shatterMultiplier) { return this; } + public RecipeBuilder catalystColor(Color color) { + this.color = color; + return this; + } + public RecipeBuilder catalystColor(int rgb) { this.color = new Color(rgb); return this; } - private boolean validate() { + public RecipeBuilder catalystColor(int r, int g, int b) { + this.color = new Color(r, g, b); + return this; + } + + public RecipeBuilder catalystColor(int r, int g, int b, int a) { + this.color = new Color(r, g, b, a); + return this; + } + + public boolean validate() { GroovyLog.Msg out = GroovyLog.msg("Error adding recipe to Astral Sorcery Lightwell"); if (this.productionMultiplier < 0.0F) { @@ -98,16 +151,18 @@ private boolean validate() { out.add("Shatter multiplier may not be negative, defaulting to 0.").warn(); this.shatterMultiplier = 0.0F; } - out.add(this.output == null, "No output specified.").error(); - out.add(this.catalyst == null, "No catalyst specified.").error(); + if (this.output == null) out.add("No output specified.").error(); + if (this.catalyst == null) out.add("No catalyst specified.").error(); out.postIfNotEmpty(); return out.getLevel() != Level.ERROR; } - public void register() { - if (!validate()) return; - ModSupport.ASTRAL_SORCERY.get().lightwell.add(catalyst, output, productionMultiplier, shatterMultiplier, color); + public WellLiquefaction.LiquefactionEntry register() { + if (!validate()) return null; + WellLiquefaction.LiquefactionEntry recipe = new WellLiquefaction.LiquefactionEntry(catalyst, output, productionMultiplier, shatterMultiplier, color); + ModSupport.ASTRAL_SORCERY.get().lightwell.add(recipe); + return recipe; } } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/OreChance.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/OreChance.java index e6901bda3..c7f2f2761 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/OreChance.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/OreChance.java @@ -3,6 +3,7 @@ import com.cleanroommc.groovyscript.api.GroovyBlacklist; import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.core.mixin.astralsorcery.OreTypesAccessor; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import hellfirepvp.astralsorcery.common.base.OreTypes; @@ -13,45 +14,44 @@ public class OreChance extends VirtualizedRegistry { private final OreTypesAccessor REGISTRY; - public OreChance(OreTypes registry) { - super(); - this.REGISTRY = (OreTypesAccessor) registry; + public OreChance(String name, OreTypes registry) { + super(false, VirtualizedRegistry.generateAliases(name)); + REGISTRY = (OreTypesAccessor) registry; } public static OreChance mineralisRitualRegistry() { - return new OreChance(OreTypes.RITUAL_MINERALIS); + return new OreChance("MineralisRitualRegistry", OreTypes.RITUAL_MINERALIS); } public static OreChance aevitasPerkRegistry() { - return new OreChance(OreTypes.AEVITAS_ORE_PERK); + return new OreChance("AevitasPerkRegistry", OreTypes.AEVITAS_ORE_PERK); } public static OreChance trashPerkRegistry() { - return new OreChance(OreTypes.PERK_VOID_TRASH_REPLACEMENT); + return new OreChance("TrashPerkRegistry", OreTypes.PERK_VOID_TRASH_REPLACEMENT); } public static OreChance treasureShrineRegistry() { - return new OreChance(OreTypes.TREASURE_SHRINE_GEN); + return new OreChance("TreasureShrineRegistry", OreTypes.TREASURE_SHRINE_GEN); } @Override @GroovyBlacklist @ApiStatus.Internal public void onReload() { - removeScripted().forEach(this::remove); - restoreFromBackup().forEach(this::add); + removeScripted().forEach(r -> REGISTRY.getEntries().removeIf(entry -> { + if (entry.oreName.equals(r.oreName)) { + REGISTRY.setTotalWeight(REGISTRY.getTotalWeight() - entry.weight); + return true; + } + return false; + })); + restoreFromBackup().forEach(REGISTRY::add); } public void add(OreEntry entry) { - this.REGISTRY.add(entry); - } - - public void add(OreDictIngredient ore, int weight) { - if (ore == null || ore.getOreDict() == null || ore.getOreDict().equals("")) { - GroovyLog.msg("Error adding Astral Sorcery OreChance. Ore name cannot be null.").error().post(); - return; - } - this.add(ore.getOreDict(), weight); + addScripted(entry); + REGISTRY.add(entry); } public void add(String ore, int weight) { @@ -63,31 +63,44 @@ public void add(String ore, int weight) { GroovyLog.msg("Error adding Astral Sorcery OreChance. Ore name cannot be null.").error().post(); return; } - OreEntry newOE = new OreEntry(ore, weight); - this.addScripted(newOE); - this.add(newOE); + add(new OreEntry(ore, weight)); } - public void remove(OreEntry entry) { - this.REGISTRY.getEntries().forEach(registeredEntry -> { - if (registeredEntry.oreName.equals(entry.oreName)) - this.REGISTRY.setTotalWeight(this.REGISTRY.getTotalWeight() - registeredEntry.weight); - }); - this.REGISTRY.getEntries().removeIf(registeredEntry -> registeredEntry.oreName.equals(entry.oreName)); + public void add(OreDictIngredient ore, int weight) { + if (ore == null || ore.getOreDict() == null || ore.getOreDict().equals("")) { + GroovyLog.msg("Error adding Astral Sorcery OreChance. Ore name cannot be null.").error().post(); + return; + } + add(ore.getOreDict(), weight); + } + + public boolean remove(OreEntry entry) { + return remove(entry.oreName); } - public void remove(OreDictIngredient entry) { - this.remove(entry.getOreDict()); + public boolean remove(OreDictIngredient entry) { + return remove(entry.getOreDict()); } - public void remove(String ore) { - this.REGISTRY.getEntries().forEach(registeredEntry -> { - if (registeredEntry.oreName.equals(ore)) { - this.addBackup(registeredEntry); - this.REGISTRY.setTotalWeight(this.REGISTRY.getTotalWeight() - registeredEntry.weight); + public boolean remove(String ore) { + return REGISTRY.getEntries().removeIf(entry -> { + if (entry.oreName.equals(ore)) { + REGISTRY.setTotalWeight(REGISTRY.getTotalWeight() - entry.weight); + addBackup(entry); + return true; } + return false; }); - this.REGISTRY.getEntries().removeIf(registeredEntry -> registeredEntry.oreName.equals(ore)); + } + + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(REGISTRY.getEntries()) + .setRemover(this::remove); + } + + public void removeAll() { + REGISTRY.getEntries().forEach(this::addBackup); + REGISTRY.getEntries().clear(); } } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Utils.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Utils.java deleted file mode 100644 index 5ece7faa6..000000000 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/Utils.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.cleanroommc.groovyscript.compat.mods.astralsorcery; - -import com.cleanroommc.groovyscript.api.GroovyLog; -import com.cleanroommc.groovyscript.api.IIngredient; -import com.cleanroommc.groovyscript.helper.ingredient.OreDictIngredient; -import hellfirepvp.astralsorcery.common.base.FluidRarityRegistry; -import hellfirepvp.astralsorcery.common.crafting.ItemHandle; -import net.minecraft.item.ItemStack; -import net.minecraftforge.fluids.Fluid; -import net.minecraftforge.fluids.FluidStack; - -import java.lang.reflect.Constructor; - -public class Utils { - - public static ItemHandle convertToItemHandle(IIngredient in) { - return Utils.convertToItemHandle((Object) in); - } - - private static ItemHandle convertToItemHandle(Object in) { - if (in == null) { - return ItemHandle.EMPTY; - } - if (in instanceof ItemStack) { - return new ItemHandle((ItemStack) in); - } else if (in instanceof ItemStack[]) { - return new ItemHandle((ItemStack[]) in); - } else if (in instanceof OreDictIngredient) { - return new ItemHandle(((OreDictIngredient) in).getOreDict()); - } else if (in instanceof FluidStack) { - return new ItemHandle((FluidStack) in); - } - return ItemHandle.EMPTY; - } - - public static boolean isEqual(ItemHandle item1, ItemHandle item2) { - if (item1.getOreDictName() != null && item2.getOreDictName() != null - && !item1.getOreDictName().equals("") && !item2.getOreDictName().equals("") - && item1.getOreDictName().equals(item2.getOreDictName())) { - return true; - } else if (item1.getApplicableItems() != null && item2.getApplicableItems() != null - && item1.getApplicableItems().size() == item2.getApplicableItems().size()) { - boolean rVal = true; - for (int i = 0; i < item1.getApplicableItems().size(); i++) { - if (!item1.getApplicableItems().get(i).isItemEqual(item2.getApplicableItems().get(i))) - rVal = false; - } - return rVal; - } - return false; - } - - public static FluidRarityRegistry.FluidRarityEntry createNewFRE(Fluid fluid, int rarity, int guaranteedAmt, int addRand) { - try { - Class[] args = new Class[4]; - args[0] = Fluid.class; - args[1] = int.class; - args[2] = int.class; - args[3] = int.class; - Constructor constructor = FluidRarityRegistry.FluidRarityEntry.class.getDeclaredConstructor(args); - constructor.setAccessible(true); - return constructor.newInstance(fluid, rarity, guaranteedAmt, addRand); - } catch (Exception e) { - GroovyLog.get().exception(e); - } - - return null; - } - -} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/perktree/GroovyPerkTree.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/perktree/GroovyPerkTree.java index 8ac863329..0d6bc4837 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/perktree/GroovyPerkTree.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/perktree/GroovyPerkTree.java @@ -16,6 +16,10 @@ public class GroovyPerkTree extends VirtualizedRegistry { + public GroovyPerkTree() { + super(false, VirtualizedRegistry.generateAliases("PerkTree")); + } + public static AttributeModifierPerkBuilder attributePerkBuilder() { return new AttributeModifierPerkBuilder(); } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarInputOrder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarInputOrder.java index ce0025f4c..3120c23ee 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarInputOrder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarInputOrder.java @@ -13,24 +13,24 @@ public class AltarInputOrder { {6, 7, 8} }; public static final int[][] ATTUNEMENT = new int[][]{ - {9, -1, -1, -1, 10}, - {-1, 0, 1, 2, -1}, - {-1, 3, 4, 5, -1}, - {-1, 6, 7, 8, -1}, + { 9, -1, -1, -1, 10}, + {-1, 0, 1, 2, -1}, + {-1, 3, 4, 5, -1}, + {-1, 6, 7, 8, -1}, {11, -1, -1, -1, 12} }; public static final int[][] CONSTELLATION_CRAFT = new int[][]{ - {9, 13, -1, 14, 10}, - {15, 0, 1, 2, 16}, - {-1, 3, 4, 5, -1}, - {17, 6, 7, 8, 18}, + { 9, 13, -1, 14, 10}, + {15, 0, 1, 2, 16}, + {-1, 3, 4, 5, -1}, + {17, 6, 7, 8, 18}, {11, 19, -1, 20, 12} }; public static final int[][] TRAIT_CRAFT = new int[][]{ - {9, 13, 21, 14, 10}, - {15, 0, 1, 2, 16}, - {22, 3, 4, 5, 23}, - {17, 6, 7, 8, 18}, + { 9, 13, 21, 14, 10}, + {15, 0, 1, 2, 16}, + {22, 3, 4, 5, 23}, + {17, 6, 7, 8, 18}, {11, 19, 24, 20, 12} }; @@ -54,10 +54,13 @@ public static ItemHandle[] initInputList(TileAltar.AltarLevel level) { switch (level) { case DISCOVERY: rVal = new ItemHandle[9]; + break; case ATTUNEMENT: rVal = new ItemHandle[13]; + break; case CONSTELLATION_CRAFT: rVal = new ItemHandle[21]; + break; case TRAIT_CRAFT: rVal = new ItemHandle[25]; } diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java index 9f89a3afb..5d5319797 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/AltarRecipeBuilder.java @@ -3,7 +3,7 @@ import com.cleanroommc.groovyscript.api.GroovyLog; import com.cleanroommc.groovyscript.api.IIngredient; import com.cleanroommc.groovyscript.compat.mods.ModSupport; -import com.cleanroommc.groovyscript.compat.mods.astralsorcery.Utils; +import com.cleanroommc.groovyscript.compat.mods.astralsorcery.AstralSorcery; import com.cleanroommc.groovyscript.compat.vanilla.CraftingRecipeBuilder; import hellfirepvp.astralsorcery.common.constellation.IConstellation; import hellfirepvp.astralsorcery.common.crafting.ItemHandle; @@ -20,14 +20,14 @@ public class AltarRecipeBuilder extends CraftingRecipeBuilder.Shaped { + private final TileAltar.AltarLevel altarLevel; + private final ArrayList outerIngredients = new ArrayList<>(); protected String name; protected ItemHandle[] inputs = null; protected ItemHandle[] outerInputs = null; protected int starlightRequired = 0; - protected int craftingTickTime = 0; - private final TileAltar.AltarLevel altarLevel; + protected int craftingTickTime = 1; private IConstellation requiredConstellation = null; - private final ArrayList outerIngredients = new ArrayList<>(); public AltarRecipeBuilder(int width, int height, TileAltar.AltarLevel level) { super(width, height); @@ -112,7 +112,7 @@ private boolean flattenMatrix() { String row = this.keyBasedMatrix[i]; for (int j = 0; j < row.length(); j++) { if (map[i][j] >= 0 && row.charAt(j) != ' ') { - in[map[i][j]] = Utils.convertToItemHandle(keyMap.get(row.charAt(j))); + in[map[i][j]] = AstralSorcery.toItemHandle(keyMap.get(row.charAt(j))); } } } @@ -121,14 +121,14 @@ private boolean flattenMatrix() { ItemHandle[] outerIn = new ItemHandle[this.outerIngredients.size()]; for (int j = 0; j < this.outerIngredients.size(); j++) - outerIn[j] = Utils.convertToItemHandle(this.outerIngredients.get(j)); + outerIn[j] = AstralSorcery.toItemHandle(this.outerIngredients.get(j)); this.outerInputs = outerIn; return true; } public boolean validate() { - GroovyLog.Msg out = GroovyLog.msg("Error adding Astral Sorcery Starlight Alter recipe").warn(); + GroovyLog.Msg out = GroovyLog.msg("Error adding Astral Sorcery Starlight Altar recipe").warn(); if (this.output == null || this.output.isItemEqual(ItemStack.EMPTY)) { out.add("Recipe output cannot be empty.").error(); @@ -137,9 +137,9 @@ public boolean validate() { out.add("Starlight amount cannot be negative, setting starlight amount to 0."); this.starlightRequired = 0; } - if (this.craftingTickTime < 0) { - out.add("Crafting time cannot be negative, setting crafting time to 0."); - this.craftingTickTime = 0; + if (this.craftingTickTime <= 0) { + out.add("Crafting time cannot be negative or 0, setting crafting time to 1."); + this.craftingTickTime = 1; } switch (this.altarLevel) { diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/StarlightAltar.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/StarlightAltar.java index c842d891b..b29f433ca 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/StarlightAltar.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/astralsorcery/starlightaltar/StarlightAltar.java @@ -1,6 +1,7 @@ package com.cleanroommc.groovyscript.compat.mods.astralsorcery.starlightaltar; import com.cleanroommc.groovyscript.api.GroovyBlacklist; +import com.cleanroommc.groovyscript.helper.SimpleObjectStream; import com.cleanroommc.groovyscript.helper.recipe.RecipeName; import com.cleanroommc.groovyscript.registry.VirtualizedRegistry; import com.google.common.collect.Lists; @@ -22,19 +23,24 @@ import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.stream.Collectors; public class StarlightAltar extends VirtualizedRegistry { public StarlightAltar() { - super("StarlightAltar", "starlight_altar"); + super(); } @Override @GroovyBlacklist @ApiStatus.Internal public void onReload() { - removeScripted().forEach(this::remove); - restoreFromBackup().forEach(this::applyRecipe); + removeScripted().forEach(r -> AltarRecipeRegistry.recipes.get(r.getNeededLevel()).removeIf(rec -> rec.equals(r))); + restoreFromBackup().forEach(r -> AltarRecipeRegistry.recipes.get(r.getNeededLevel()).add(r)); + } + + public void afterScriptLoad() { + AltarRecipeRegistry.compileRecipes(); } public @Nullable AbstractAltarRecipe add(String name, ItemStack output, ItemHandle[] inputs, int starlightRequired, int craftingTickTime, TileAltar.AltarLevel altarLevel, IConstellation requiredConstellation, ItemHandle[] outerInputs) { @@ -58,8 +64,7 @@ public boolean mayDecrement(TileAltar ta, ShapedRecipeSlot slot) { } }; - addScripted(dRec); - return applyRecipe(dRec); + return add(dRec); case ATTUNEMENT: AttunementRecipe aRec = new AttunementRecipe(this.registerNative(name, output, inputs)) { public int getPassiveStarlightRequired() { @@ -83,8 +88,7 @@ public boolean mayDecrement(TileAltar ta, AttunementAltarSlot slot) { if (inputs[al.getSlotId()] != null) aRec.setAttItem(inputs[al.getSlotId()], al); } - addScripted(aRec); - return applyRecipe(aRec); + return add(aRec); case CONSTELLATION_CRAFT: ConstellationRecipe cRec = new ConstellationRecipe(this.registerNative(name, output, inputs)) { public int getPassiveStarlightRequired() { @@ -115,8 +119,7 @@ public boolean mayDecrement(TileAltar ta, ConstellationAtlarSlot slot) { if (inputs[al.getSlotId()] != null) cRec.setCstItem(inputs[al.getSlotId()], al); } - addScripted(cRec); - return applyRecipe(cRec); + return add(cRec); case TRAIT_CRAFT: TraitRecipe rRec = new TraitRecipe(this.registerNative(name, output, inputs)) { public int getPassiveStarlightRequired() { @@ -164,8 +167,7 @@ public boolean mayDecrement(TileAltar ta, TraitRecipeSlot slot) { for (ItemHandle item : outerInputs) rRec.addOuterTraitItem(item); - addScripted(rRec); - return applyRecipe(rRec); + return add(rRec); default: return null; } @@ -185,9 +187,9 @@ private AccessibleRecipeAdapater registerNative(String name, ItemStack output, I return builder.unregisteredAccessibleShapedRecipe(); } - private AbstractAltarRecipe applyRecipe(AbstractAltarRecipe recipe) { + private AbstractAltarRecipe add(AbstractAltarRecipe recipe) { + addScripted(recipe); AltarRecipeRegistry.recipes.get(recipe.getNeededLevel()).add(recipe); - AltarRecipeRegistry.compileRecipes(); return recipe; } @@ -212,18 +214,29 @@ public void removeByOutput(ItemStack output) { } public void removeByOutput(ItemStack output, TileAltar.AltarLevel altarLevel) { - AltarRecipeRegistry.recipes.get(altarLevel).forEach(recipe -> { + AltarRecipeRegistry.recipes.get(altarLevel).removeIf(recipe -> { if (recipe.getOutputForMatching().isItemEqual(output)) { addBackup(recipe); + return true; } + return false; }); - AltarRecipeRegistry.recipes.get(altarLevel).removeIf(recipe -> recipe.getOutputForMatching().isItemEqual(output)); - AltarRecipeRegistry.compileRecipes(); } - private void remove(AbstractAltarRecipe recipe) { - AltarRecipeRegistry.recipes.get(recipe.getNeededLevel()).removeIf(rec -> rec.equals(recipe)); - AltarRecipeRegistry.compileRecipes(); + private boolean remove(AbstractAltarRecipe recipe) { + return AltarRecipeRegistry.recipes.get(recipe.getNeededLevel()).removeIf(rec -> rec.equals(recipe)); + } + + public SimpleObjectStream streamRecipes() { + return new SimpleObjectStream<>(AltarRecipeRegistry.recipes.entrySet().stream().flatMap(r -> r.getValue().stream()).collect(Collectors.toList())) + .setRemover(this::remove); + } + + public void removeAll() { + AltarRecipeRegistry.recipes.forEach((level, recipes) -> { + recipes.forEach(this::addBackup); + recipes.clear(); + }); } public static AltarRecipeBuilder discoveryRecipeBuilder() { diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/astralsorcery/FluidRarityEntryAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/astralsorcery/FluidRarityEntryAccessor.java new file mode 100644 index 000000000..deca0db1e --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/astralsorcery/FluidRarityEntryAccessor.java @@ -0,0 +1,20 @@ +package com.cleanroommc.groovyscript.core.mixin.astralsorcery; + +import hellfirepvp.astralsorcery.common.base.FluidRarityRegistry; +import net.minecraftforge.fluids.Fluid; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(FluidRarityRegistry.FluidRarityEntry.class) +public interface FluidRarityEntryAccessor { + + @Invoker("") + static FluidRarityRegistry.FluidRarityEntry createFluidRarityEntry(String fluidNameTmp, int rarity, int guaranteedAmount, int additionalRandomAmount) { + throw new UnsupportedOperationException(); + } + + @Invoker("") + static FluidRarityRegistry.FluidRarityEntry createFluidRarityEntry(Fluid fluid, int rarity, int guaranteedAmount, int additionalRandomAmount) { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/core/mixin/astralsorcery/WellLiquefactionAccessor.java b/src/main/java/com/cleanroommc/groovyscript/core/mixin/astralsorcery/WellLiquefactionAccessor.java new file mode 100644 index 000000000..43c510876 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/core/mixin/astralsorcery/WellLiquefactionAccessor.java @@ -0,0 +1,19 @@ +package com.cleanroommc.groovyscript.core.mixin.astralsorcery; + +import hellfirepvp.astralsorcery.common.base.WellLiquefaction; +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.Map; + +@Mixin(value = WellLiquefaction.class, remap = false) +public interface WellLiquefactionAccessor { + + @Accessor + static Map getRegisteredLiquefactions() { + throw new UnsupportedOperationException(); + } + +} diff --git a/src/main/resources/mixin.groovyscript.astralsorcery.json b/src/main/resources/mixin.groovyscript.astralsorcery.json index 19f5481fb..ead40f024 100644 --- a/src/main/resources/mixin.groovyscript.astralsorcery.json +++ b/src/main/resources/mixin.groovyscript.astralsorcery.json @@ -8,6 +8,7 @@ "ConstellationBaseAccessor", "ConstellationMapEffectRegistryAccessor", "ConstellationRegistryAccessor", + "FluidRarityEntryAccessor", "FluidRarityRegistryAccessor", "LightOreTransmutationsAccessor", "LiquidInteractionAccessor", @@ -16,6 +17,7 @@ "PerkLevelManagerMixin", "PerkTreeAccessor", "ResearchNodeAccessor", - "TraitRecipeAccessor" + "TraitRecipeAccessor", + "WellLiquefactionAccessor" ] } \ No newline at end of file From 14041169a63f4dd791660c40fe1ebb315b3c07e7 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Wed, 2 Aug 2023 01:10:28 -0700 Subject: [PATCH 24/28] blood magic examples and fix --- examples/postInit/bloodmagic.groovy | 186 +++++++++--------- .../compat/mods/bloodmagic/AlchemyTable.java | 2 +- 2 files changed, 99 insertions(+), 89 deletions(-) diff --git a/examples/postInit/bloodmagic.groovy b/examples/postInit/bloodmagic.groovy index fcb417489..a6fa393ef 100644 --- a/examples/postInit/bloodmagic.groovy +++ b/examples/postInit/bloodmagic.groovy @@ -2,145 +2,155 @@ if (!isLoaded('bloodmagic')) return println 'mod \'bloodmagic\' detected, running script' -mods.bloodmagic.bloodaltar.removeByInput(item("minecraft:ender_pearl")) -mods.bloodmagic.bloodaltar.removeByOutput(item("bloodmagic:slate:4")) - -// mods.bloodmagic.bloodaltar.removeAll() +// Blood Altar: +// Converts an input item into an output itemstack, draining life essence from the altar at a base rate and requiring at least a specific tier. mods.bloodmagic.bloodaltar.recipeBuilder() - .input(item("minecraft:clay")) - .output(item("minecraft:gold_ingot")) - .tier(0) - .drainRate(5) - .syphon(10) - .consumeRate(5) - .register() + .input(item('minecraft:clay')) + .output(item('minecraft:gold_ingot')) + .tier(0) // Optional int, required tier of the altar. Maximum of either 5 or 6 depending on the config general/enableTierSixEvenThoughThereIsNoContent. (Default 0) + .drainRate(5) + .syphon(10) + .consumeRate(5) + .register() mods.bloodmagic.bloodaltar.recipeBuilder() - .input(item("minecraft:gold_ingot")) - .output(item("minecraft:diamond")) - .minimumTier(3) - .drainRate(100) - .syphon(50000) - .consumeRate(500) - .register() - + .input(item('minecraft:gold_ingot')) + .output(item('minecraft:diamond')) + .minimumTier(3) + .drainRate(100) + .syphon(50000) + .consumeRate(500) + .register() -mods.bloodmagic.alchemyarray.removeByInput(item("bloodmagic:component:13")) -mods.bloodmagic.alchemyarray.removeByCatalyst(item("bloodmagic:slate:2")) -mods.bloodmagic.alchemyarray.removeByInputAndCatalyst(item("bloodmagic:component:7"), item("bloodmagic:slate:1")) -mods.bloodmagic.alchemyarray.removeByOutput(item("bloodmagic:sigil_void")) +mods.bloodmagic.bloodaltar.removeByInput(item('minecraft:ender_pearl')) +mods.bloodmagic.bloodaltar.removeByOutput(item('bloodmagic:slate:4')) +//mods.bloodmagic.bloodaltar.removeAll() -// mods.bloodmagic.alchemyarray.removeAll() +// Alchemy Array: +// Converts two items into an output itemstack by using Arcane Ashes in-world. Has a configurable texture for the animation. mods.bloodmagic.alchemyarray.recipeBuilder() - .input(item("minecraft:diamond")) - .catalyst(item("bloodmagic:slate:1")) - .output(item("minecraft:gold_ingot")) - .register() + .input(item('minecraft:diamond')) + .catalyst(item('bloodmagic:slate:1')) + .output(item('minecraft:gold_ingot')) + .texture('bloodmagic:textures/models/AlchemyArrays/LightSigil.png') // Optional String/ResourceLocation of a texture to use as the animation. (Default 'bloodmagic:textures/models/AlchemyArrays/WIPArray.png') + .register() mods.bloodmagic.alchemyarray.recipeBuilder() - .input(item("minecraft:clay")) - .catalyst(item("minecraft:gold_ingot")) - .output(item("minecraft:diamond")) - .texture("bloodmagic:textures/models/AlchemyArrays/LightSigil.png") - .register() - - + .input(item('minecraft:clay')) + .catalyst(item('minecraft:gold_ingot')) + .output(item('minecraft:diamond')) + .register() -mods.bloodmagic.tartaricforge.removeByInput(item("minecraft:cauldron"), item("minecraft:stone"), item("minecraft:dye:4"), item("minecraft:diamond")) -mods.bloodmagic.tartaricforge.removeByInput(item("minecraft:gunpowder"), item("minecraft:redstone")) -mods.bloodmagic.tartaricforge.removeByOutput(item("bloodmagic:demon_crystal")) +mods.bloodmagic.alchemyarray.removeByInput(item('bloodmagic:component:13')) +mods.bloodmagic.alchemyarray.removeByCatalyst(item('bloodmagic:slate:2')) +mods.bloodmagic.alchemyarray.removeByInputAndCatalyst(item('bloodmagic:component:7'), item('bloodmagic:slate:1')) +mods.bloodmagic.alchemyarray.removeByOutput(item('bloodmagic:sigil_void')) +//mods.bloodmagic.alchemyarray.removeAll() -// mods.bloodmagic.tartaricforge.removeAll() +// Tartaric Forge: +// Converts up to 4 input items into an output itemstack, requiring a Tartaric gem with a minimum amount of souls, and consuming some. mods.bloodmagic.tartaricforge.recipeBuilder() - .input(item("minecraft:clay"), item("minecraft:clay"), item("minecraft:clay"), item("minecraft:clay")) - .output(item("minecraft:gold_ingot")) - .drain(5) - .minimumSouls(10) - .register() + .input(item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay'), item('minecraft:clay')) + .output(item('minecraft:gold_ingot')) + .drain(5) + .minimumSouls(10) + .register() mods.bloodmagic.tartaricforge.recipeBuilder() - .input(item("minecraft:gold_ingot"), item("minecraft:clay")) - .output(item("minecraft:diamond")) - .soulDrain(200) - .minimumSouls(500) - .register() - + .input(item('minecraft:gold_ingot'), item('minecraft:clay')) + .output(item('minecraft:diamond')) + .soulDrain(200) // Alias to drain + .minimumSouls(500) + .register() -mods.bloodmagic.alchemytable.removeByInput(item("minecraft:nether_wart"), item("minecraft:gunpowder")) -mods.bloodmagic.alchemytable.removeByOutput(item("minecraft:sand")) +mods.bloodmagic.tartaricforge.removeByInput(item('minecraft:cauldron'), item('minecraft:stone'), item('minecraft:dye:4'), item('minecraft:diamond')) +mods.bloodmagic.tartaricforge.removeByInput(item('minecraft:gunpowder'), item('minecraft:redstone')) +mods.bloodmagic.tartaricforge.removeByOutput(item('bloodmagic:demon_crystal')) +//mods.bloodmagic.tartaricforge.removeAll() -// mods.bloodmagic.alchemytable.removeAll() +// Alchemy Table: +// Converts up to 6 input items into an output itemstack, with configurable time, minimum tier of Blood Orb required, and Life Essence drained from the Orb network. mods.bloodmagic.alchemytable.recipeBuilder() - .input(item("minecraft:diamond"), item("minecraft:diamond")) - .output(item("minecraft:clay")) - .ticks(100) - .minimumTier(2) - .syphon(500) - .register() + .input(item('minecraft:diamond'), item('minecraft:diamond')) + .output(item('minecraft:clay')) + .ticks(100) + .minimumTier(2) // Optional int, tier of the Blood Orb inside the table. Maximum of either 5 or 6 depending on the config general/enableTierSixEvenThoughThereIsNoContent. (Default 0) + .syphon(500) + .register() mods.bloodmagic.alchemytable.recipeBuilder() - .input(item("minecraft:diamond"), item("minecraft:diamond"), item("minecraft:gold_ingot"), item("minecraft:gold_ingot"), item("bloodmagic:slate"), item("bloodmagic:slate")) - .output(item("minecraft:clay")) - .time(2000) - .tier(5) - .drain(25000) - .register() + .input(item('minecraft:diamond'), item('minecraft:diamond'), item('minecraft:gold_ingot'), item('minecraft:gold_ingot'), item('bloodmagic:slate'), item('bloodmagic:slate')) + .output(item('minecraft:clay')) + .time(2000) // Alias to ticks + .tier(5) // Alias to minimumTier + .drain(25000) // Alias to syphon + .register() +mods.bloodmagic.alchemytable.removeByInput(item('minecraft:nether_wart'), item('minecraft:gunpowder')) +mods.bloodmagic.alchemytable.removeByOutput(item('minecraft:sand')) +//mods.bloodmagic.alchemytable.removeAll() -mods.bloodmagic.tranquility.remove(blockstate("minecraft:netherrack"), "FIRE") -mods.bloodmagic.tranquility.remove(blockstate("minecraft:dirt").getBlock(), "EARTHEN") +// Tranquility: +// Blocks in the area around the Tranquility Altar provide tranquility up to the Altar's cap, with reduced effect the more of a particular type of Tranquility is provided. mods.bloodmagic.tranquility.recipeBuilder() - .block(blockstate("minecraft:obsidian").getBlock()) - .tranquility("LAVA") + .block(block('minecraft:obsidian')) + .tranquility('LAVA') .value(10) .register() mods.bloodmagic.tranquility.recipeBuilder() - .block(blockstate("minecraft:obsidian").getBlock()) - .tranquility("WATER") + .block(block('minecraft:obsidian')) + .tranquility('WATER') .value(10) .register() mods.bloodmagic.tranquility.recipeBuilder() - .blockstate(blockstate("minecraft:obsidian")) - .tranquility("LAVA") + .blockstate(blockstate('minecraft:obsidian')) + .tranquility('LAVA') .value(500) .register() +mods.bloodmagic.tranquility.remove(blockstate('minecraft:netherrack'), 'FIRE') +mods.bloodmagic.tranquility.remove(block('minecraft:dirt'), 'EARTHEN') +//mods.bloodmagic.tranquility.removeAll() -mods.bloodmagic.sacrificial.remove("minecraft:villager") - -// mods.bloodmagic.sacrificial.removeAll() +// Sacrificial: +// How much Life Essence is gained when using the Sacrificial Dagger on a mob. mods.bloodmagic.sacrificial.recipeBuilder() - .entity("minecraft:enderman") + .entity('minecraft:enderman') .value(1000) .register() -mods.bloodmagic.meteor.remove(item("minecraft:diamond_block")) -mods.bloodmagic.meteor.removeByInput(item("minecraft:gold_block")) -mods.bloodmagic.meteor.removeByCatalyst(item("minecraft:iron_block")) +mods.bloodmagic.sacrificial.remove('minecraft:villager') +//mods.bloodmagic.sacrificial.removeAll() -// mods.bloodmagic.meteor.removeAll() +// Meteor: +// Throwing an input catalyst atop an activated Mark of the Falling Tower Ritual will spawn a meteor made of the given components, size, explosion strength, and Life Essence cost. mods.bloodmagic.meteor.recipeBuilder() - .catalyst(item("minecraft:gold_ingot")) - .component(ore("oreIron"), 10) - .component(ore("oreDiamond"), 10) - .component(ore("stone"), 70) + .catalyst(item('minecraft:gold_ingot')) + .component(ore('oreIron'), 10) + .component(ore('oreDiamond'), 10) + .component(ore('stone'), 70) .radius(7) .explosionStrength(10) - .cost(1000) + .cost(1000) // Optional int, Life Essence cost of the ritual. (Default 1000000) .register() mods.bloodmagic.meteor.recipeBuilder() - .catalyst(item("minecraft:clay")) - .component("blockClay", 10) + .catalyst(item('minecraft:clay')) + .component('blockClay', 10) .radius(20) .explosionStrength(20) .register() + +mods.bloodmagic.meteor.remove(item('minecraft:diamond_block')) +mods.bloodmagic.meteor.removeByInput(item('minecraft:gold_block')) +mods.bloodmagic.meteor.removeByCatalyst(item('minecraft:iron_block')) +//mods.bloodmagic.meteor.removeAll() diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyTable.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyTable.java index e34edd3d2..ca55951f5 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyTable.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/bloodmagic/AlchemyTable.java @@ -156,7 +156,7 @@ public void validate(GroovyLog.Msg msg) { validateItems(msg, 1, 6, 1, 1); msg.add(syphon < 0, "syphon must be a nonnegative integer, yet it was {}", syphon); msg.add(ticks <= 0, "ticks must be a positive integer greater than 0, yet it was {}", ticks); - msg.add(minimumTier <= 0, "minimumTier must be a positive integer greater than 0, yet it was {}", minimumTier); + msg.add(minimumTier < 0, "minimumTier must be a nonnegative integer, yet it was {}", minimumTier); } @Override From 54f19f99406a3c0d548ebc6f5397ef3b0312497f Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Wed, 2 Aug 2023 11:10:19 -0700 Subject: [PATCH 25/28] extended crafting examples --- examples/postInit/extendedcrafting.groovy | 63 ++++++++++++----------- 1 file changed, 33 insertions(+), 30 deletions(-) diff --git a/examples/postInit/extendedcrafting.groovy b/examples/postInit/extendedcrafting.groovy index 4fe788bb0..4cef9eac2 100644 --- a/examples/postInit/extendedcrafting.groovy +++ b/examples/postInit/extendedcrafting.groovy @@ -2,55 +2,54 @@ if (!isLoaded('extendedcrafting')) return println 'mod \'extendedcrafting\' detected, running script' -// Combination crafting - -// there are no combination recipes by default, and so none can be removed -//mods.extendedcrafting.combination.removeAll() -//mods.extendedcrafting.combination.removeByInput(item('minecraft:pumpkin')) -//mods.extendedcrafting.combination.removeByOutput(item('minecraft:gold_ingot')) - +// Combination Crafting (Combination): +// Converts one main item and any number of additional items into an output itemstack, with a configurable rf cost and consumption per tick amount. mods.extendedcrafting.combination.recipeBuilder() - .cost(100) - .perTick(100) - .output(item('minecraft:diamond') * 2) .input(item('minecraft:pumpkin')) .pedestals(item('minecraft:pumpkin') * 8) + .output(item('minecraft:diamond') * 2) + .cost(100) + .perTick(100) // Optional int, maximum amount of RF consumed per tick until the cost is paid. (Default ModConfig.confCraftingCoreRFRate, 500) .register() mods.extendedcrafting.combinationcrafting.recipeBuilder() - .cost(10000) - .output(item('minecraft:gold_ingot') * 2) .input(item('minecraft:pumpkin')) .pedestals(item('minecraft:pumpkin'), item('minecraft:clay'), item('minecraft:clay'), item('minecraft:pumpkin')) + .output(item('minecraft:gold_ingot') * 2) + .cost(10000) .register() -// Compression crafting - +// there are no combination recipes by default, and so none can be removed +//mods.extendedcrafting.combination.removeByInput(item('minecraft:pumpkin')) +//mods.extendedcrafting.combination.removeByOutput(item('minecraft:gold_ingot')) //mods.extendedcrafting.combination.removeAll() -//mods.extendedcrafting.combination.removeByInput(item('minecraft:gold_ingot')) -//mods.extendedcrafting.combination.removeByCatalyst(item('extendedcrafting:material:11')) -//mods.extendedcrafting.combination.removeByOutput(item('extendedcrafting:singularity:6')) -mods.extendedcrafting.compression.recipeBuilder() - .input(item('minecraft:clay') * 10) - .output(item('minecraft:diamond') * 2) - .powerCost(1000) - .register() +// Compression Crafting (Compression): +// Converts any number of a single item into an output itemstack, with a configurable rf cost, consumption per tick amount, catalyst, and if the catalyst is consumed. mods.extendedcrafting.compressioncrafting.recipeBuilder() .input(item('minecraft:clay')) .inputCount(100) .output(item('minecraft:gold_ingot') * 7) - .catalyst(item('minecraft:diamond')) - .consumeCatalyst(true) + .catalyst(item('minecraft:diamond')) // Optional IIngredient, the item in the catalyst slot. (Default ModConfig.confSingularityCatalyst, ItemMaterial.itemUltimateCatalyst) + .consumeCatalyst(true) // Optional boolean, if the catalyst stack is consumed when the recipe completes. (Default false) .powerCost(10000) - .powerRate(1000) + .powerRate(1000) // Optional int, maximum amount of RF consumed per tick until the cost is paid. (Default ModConfig.confCompressorRFRate, 5000) .register() -// Ender crafting +mods.extendedcrafting.compression.recipeBuilder() + .input(item('minecraft:clay') * 10) // Input count can also be defined like this. + .output(item('minecraft:diamond') * 2) + .powerCost(1000) + .register() -//mods.extendedcrafting.endercrafting.removeByOutput(item('extendedcrafting:material:40')) +mods.extendedcrafting.compression.removeByInput(item('minecraft:gold_ingot')) +mods.extendedcrafting.compression.removeByCatalyst(item('extendedcrafting:material:11')) +mods.extendedcrafting.compression.removeByOutput(item('extendedcrafting:singularity:6')) +//mods.extendedcrafting.compression.removeAll() +// Ender Crafting: +// A normal crafting recipe, with the recipe being slowly crafted based on nearby Ender Alternators. mods.extendedcrafting.endercrafting.shapelessBuilder() .output(item('minecraft:clay') * 8) .input(item('minecraft:stone'),item('minecraft:stone'),item('minecraft:stone')) @@ -80,10 +79,11 @@ mods.extendedcrafting.endercrafting.shapedBuilder() .time(1) .register() -// Table crafting - -//mods.extendedcrafting.tablecrafting.removeByOutput(item('extendedcrafting:singularity_ultimate')) +mods.extendedcrafting.endercrafting.removeByOutput(item('extendedcrafting:material:40')) +//mods.extendedcrafting.endercrafting.removeAll() +// Table Crafting +// A normal crafting recipe, but requiring either a specific tier, or at least a given tier, from 3x3 to 9x9. mods.extendedcrafting.tablecrafting.shapedBuilder() .output(item('minecraft:stone') * 64) .matrix( @@ -146,3 +146,6 @@ mods.extendedcrafting.tablecrafting.shapelessBuilder() item('minecraft:stone'),item('minecraft:stone'),item('minecraft:stone'),item('minecraft:stone'),item('minecraft:stone')) .register() +mods.extendedcrafting.tablecrafting.removeByOutput(item('extendedcrafting:singularity_ultimate')) +//mods.extendedcrafting.tablecrafting.removeAll() + From acab3bb194ae3dc345db915d3312deff46f4e2ef Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Wed, 2 Aug 2023 21:33:41 -0700 Subject: [PATCH 26/28] make scriptPath be set to the examples folder in dev --- .../cleanroommc/groovyscript/GroovyScript.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java b/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java index 6d41d88d1..4d646f839 100644 --- a/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java +++ b/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java @@ -4,14 +4,14 @@ import com.cleanroommc.groovyscript.brackets.BracketHandlerManager; import com.cleanroommc.groovyscript.command.CustomClickAction; import com.cleanroommc.groovyscript.command.GSCommand; -import com.cleanroommc.groovyscript.compat.loot.Loot; import com.cleanroommc.groovyscript.compat.content.GroovyResourcePack; +import com.cleanroommc.groovyscript.compat.loot.Loot; import com.cleanroommc.groovyscript.compat.mods.ModSupport; import com.cleanroommc.groovyscript.compat.mods.tinkersconstruct.TinkersConstruct; import com.cleanroommc.groovyscript.compat.vanilla.VanillaModule; +import com.cleanroommc.groovyscript.core.mixin.DefaultResourcePackAccessor; import com.cleanroommc.groovyscript.core.mixin.loot.LootPoolAccessor; import com.cleanroommc.groovyscript.core.mixin.loot.LootTableAccessor; -import com.cleanroommc.groovyscript.core.mixin.DefaultResourcePackAccessor; import com.cleanroommc.groovyscript.event.EventHandler; import com.cleanroommc.groovyscript.helper.JsonHelper; import com.cleanroommc.groovyscript.network.CReload; @@ -33,6 +33,7 @@ import net.minecraft.client.settings.KeyBinding; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.item.Item; +import net.minecraft.launchwrapper.Launch; import net.minecraft.util.text.Style; import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentTranslation; @@ -45,7 +46,10 @@ import net.minecraftforge.fml.client.registry.ClientRegistry; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.common.event.*; +import net.minecraftforge.fml.common.event.FMLConstructionEvent; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLServerStartingEvent; import net.minecraftforge.fml.common.eventhandler.EventPriority; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.gameevent.InputEvent; @@ -128,7 +132,9 @@ public void onRegisterItem(RegistryEvent.Register event) { @ApiStatus.Internal public static void initializeRunConfig(File minecraftHome) { - scriptPath = new File(minecraftHome, "groovy"); + // If we are launching a dev environment, use the examples folder for easy and consistent testing. + if (Launch.blackboard.containsKey("fml.deobfuscatedEnvironment")) scriptPath = new File(minecraftHome.getParentFile(), "examples"); + else scriptPath = new File(minecraftHome, "groovy"); runConfigFile = new File(scriptPath, "runConfig.json"); resourcesFile = new File(scriptPath, "assets"); reloadRunConfig(); @@ -166,8 +172,8 @@ public void onPostInit(FMLPostInitializationEvent event) { CustomClickAction.registerAction("copy", value -> { GuiScreen.setClipboardString(value); Minecraft.getMinecraft().player.sendMessage(new TextComponentTranslation("groovyscript.command.copy.copied_start") - .appendSibling(new TextComponentString(value).setStyle(new Style().setColor(TextFormatting.GOLD))) - .appendSibling(new TextComponentTranslation("groovyscript.command.copy.copied_end"))); + .appendSibling(new TextComponentString(value).setStyle(new Style().setColor(TextFormatting.GOLD))) + .appendSibling(new TextComponentTranslation("groovyscript.command.copy.copied_end"))); }); } From bb42ce1e2d6ffa48ff5906f238144a55e541fb25 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Wed, 2 Aug 2023 21:35:40 -0700 Subject: [PATCH 27/28] starting items off by one logging mistake --- .../com/cleanroommc/groovyscript/compat/vanilla/Player.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Player.java b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Player.java index d8795d1fb..644a70612 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Player.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/Player.java @@ -46,7 +46,7 @@ public void addStartingItem(ItemStack item) { } public void addStartingItem(ItemStack item, int slot) { - if (slot >= 41) { + if (slot > 41) { GroovyLog.msg("Warning: assigning items to a player's inventory slot greater than 41 may cause some items to not be received by the player.") .warn().post(); } @@ -63,7 +63,7 @@ public void addStartingItem(ItemStack item, int slot) { } public void setStartingItems(boolean isSlotSpecific, ItemStack... items) { - if (items.length >= 41) { + if (items.length > 41) { GroovyLog.msg("Warning: assigning items to a player's inventory slot greater than 41 may cause some items to not be received by the player.") .warn().post(); } @@ -79,7 +79,7 @@ public void setStartingItems(boolean isSlotSpecific, ItemStack... items) { } public void setStartingItems(boolean isSlotSpecific, List items) { - if (items.size() >= 41) { + if (items.size() > 41) { GroovyLog.msg("Warning: assigning items to a player's inventory slot greater than 41 may cause some items to not be received by the player.") .warn().post(); } From 53c07f2982cd231cb89e16e7a756d36e8c741037 Mon Sep 17 00:00:00 2001 From: Waiting Idly <25394029+WaitingIdly@users.noreply.github.com> Date: Fri, 4 Aug 2023 04:45:32 -0700 Subject: [PATCH 28/28] address review --- build.gradle | 1 + gradle.properties | 1 + .../com/cleanroommc/groovyscript/GroovyScript.java | 10 +++++++--- .../groovyscript/compat/EnergyRecipeBuilder.java | 2 ++ .../mods/immersiveengineering/TimeRecipeBuilder.java | 2 ++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 69c2405cc..c592037aa 100644 --- a/build.gradle +++ b/build.gradle @@ -43,6 +43,7 @@ minecraft { args << '-Dmixin.hotSwap=true' args << '-Dmixin.checks.interfaces=true' args << '-Dmixin.debug.export=true' + if (project.debug_use_examples_folder.toBoolean()) args << '-Dgroovyscript.use_examples_folder=true' extraRunJvmArguments.addAll(args) useDependencyAccessTransformers = true diff --git a/gradle.properties b/gradle.properties index 18563b353..3f6f623a6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,6 +11,7 @@ archives_base_name = groovyscript groovy_version = 4.0.8 mod_ref_path=com.cleanroommc.groovyscript.GroovyScript debug_load_all_mods = true +debug_use_examples_folder = true # Coremod Arguments coremod_plugin_class_name = com.cleanroommc.groovyscript.core.GroovyScriptCore diff --git a/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java b/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java index 4d646f839..6f440b727 100644 --- a/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java +++ b/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java @@ -61,6 +61,7 @@ import java.io.File; import java.io.IOException; +import java.lang.management.ManagementFactory; import java.net.MalformedURLException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -132,9 +133,12 @@ public void onRegisterItem(RegistryEvent.Register event) { @ApiStatus.Internal public static void initializeRunConfig(File minecraftHome) { - // If we are launching a dev environment, use the examples folder for easy and consistent testing. - if (Launch.blackboard.containsKey("fml.deobfuscatedEnvironment")) scriptPath = new File(minecraftHome.getParentFile(), "examples"); - else scriptPath = new File(minecraftHome, "groovy"); + // If we are launching with the environment variable set to use the examples folder, use the examples folder for easy and consistent testing. + if (ManagementFactory.getRuntimeMXBean().getInputArguments().contains("-Dgroovyscript.use_examples_folder=true")) { + scriptPath = new File(minecraftHome.getParentFile(), "examples"); + } else { + scriptPath = new File(minecraftHome, "groovy"); + } runConfigFile = new File(scriptPath, "runConfig.json"); resourcesFile = new File(scriptPath, "assets"); reloadRunConfig(); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/EnergyRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/EnergyRecipeBuilder.java index 965f7e7c8..5b3d07d05 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/EnergyRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/EnergyRecipeBuilder.java @@ -1,8 +1,10 @@ package com.cleanroommc.groovyscript.compat; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import org.jetbrains.annotations.ApiStatus; @Deprecated +@ApiStatus.ScheduledForRemoval public abstract class EnergyRecipeBuilder extends AbstractRecipeBuilder { protected int energy; diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/TimeRecipeBuilder.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/TimeRecipeBuilder.java index 5cca0ff39..4d37a7b91 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/TimeRecipeBuilder.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/immersiveengineering/TimeRecipeBuilder.java @@ -1,8 +1,10 @@ package com.cleanroommc.groovyscript.compat.mods.immersiveengineering; import com.cleanroommc.groovyscript.helper.recipe.AbstractRecipeBuilder; +import org.jetbrains.annotations.ApiStatus; @Deprecated +@ApiStatus.ScheduledForRemoval public abstract class TimeRecipeBuilder extends AbstractRecipeBuilder { protected int time;