diff --git a/examples/postInit/custom/vanilla.groovy b/examples/postInit/custom/vanilla.groovy index 88e7d2ae5..4c3405ebc 100644 --- a/examples/postInit/custom/vanilla.groovy +++ b/examples/postInit/custom/vanilla.groovy @@ -21,17 +21,21 @@ log.info(ore_iron >> (item_iron * 3)) // false println file.path }*/ +for (var stack in mods.minecraft.allItems[5..12]) { + log.info stack +} + // 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() +mods.minecraft.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() +minecraft.crafting.shapedBuilder() .name('gold_v_to_clay') .output(item('minecraft:clay')) .shape([[item('minecraft:gold_ingot'),null,item('minecraft:gold_ingot')],[null,item('minecraft:stone_pickaxe').transformDamage(2).whenAnyDamage(),null]]) diff --git a/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java b/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java index 52d0470d5..bc0b260a4 100644 --- a/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java +++ b/src/main/java/com/cleanroommc/groovyscript/GroovyScript.java @@ -165,7 +165,6 @@ public static void initializeGroovyPreInit() { // called via mixin in between construction and fml pre init ObjectMapperManager.init(); StandardInfoParserRegistry.init(); - VanillaModule.initializeBinding(); ModSupport.init(); for (ObjectMapper goh : ObjectMapperManager.getObjectMappers()) { getSandbox().registerBinding(goh); diff --git a/src/main/java/com/cleanroommc/groovyscript/api/IIngredient.java b/src/main/java/com/cleanroommc/groovyscript/api/IIngredient.java index 6dccc43a0..8592ed148 100644 --- a/src/main/java/com/cleanroommc/groovyscript/api/IIngredient.java +++ b/src/main/java/com/cleanroommc/groovyscript/api/IIngredient.java @@ -1,12 +1,15 @@ package com.cleanroommc.groovyscript.api; import com.cleanroommc.groovyscript.helper.ingredient.OrIngredient; +import com.google.common.collect.AbstractIterator; +import groovy.lang.IntRange; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import net.minecraftforge.common.ForgeHooks; import net.minecraftforge.fluids.FluidStack; import org.jetbrains.annotations.Nullable; +import java.util.Iterator; import java.util.function.Predicate; /** @@ -51,6 +54,33 @@ default boolean isCase(ItemStack ingredient) { return ingredient != null && test(ingredient); } + // [i] operator + default ItemStack getAt(int index) { + ItemStack[] stacks = getMatchingStacks(); + while (index < 0) index += stacks.length; + return getMatchingStacks()[index]; + } + + default ItemStack getFirst() { + return getAt(0); + } + + // allows using a range in [] operator like [5..12] + default Iterable getAt(IntRange range) { + return () -> new AbstractIterator<>() { + + private final Iterator it = range.iterator(); + + @Override + protected ItemStack computeNext() { + if (it.hasNext()) { + return getAt(it.next()); + } + return endOfData(); + } + }; + } + @Override default IIngredient withAmount(int amount) { IIngredient iIngredientStack = exactCopy(); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ForgeModWrapper.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ForgeModWrapper.java new file mode 100644 index 000000000..21cd6cf42 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ForgeModWrapper.java @@ -0,0 +1,64 @@ +package com.cleanroommc.groovyscript.compat.mods; + +import com.cleanroommc.groovyscript.helper.ingredient.ItemsIngredient; +import net.minecraft.creativetab.CreativeTabs; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; +import net.minecraftforge.fml.common.registry.ForgeRegistries; + +import java.util.ArrayList; +import java.util.List; + +public class ForgeModWrapper { + + private ModContainer container; + private ItemsIngredient items; + + public ForgeModWrapper(ModContainer container) { + this.container = container; + } + + public ForgeModWrapper() {} + + void initialize(String owner) { + this.container = Loader.instance().getIndexedModList().get(owner); + if (this.container == null) { + throw new IllegalStateException("Can't create property container for unloaded mod!"); + } + } + + public ItemsIngredient getAllItems() { + if (this.items == null) { + List items = new ArrayList<>(); + NonNullList stacks = NonNullList.create(); + for (Item item : ForgeRegistries.ITEMS) { + if (item.getRegistryName().getNamespace().equals(container.getModId())) { + item.getSubItems(CreativeTabs.SEARCH, stacks); + items.addAll(stacks); + stacks.clear(); + } + } + this.items = new ItemsIngredient(items); + } + return this.items; + } + + public ModContainer getContainer() { + return container; + } + + public String getId() { + return this.container.getModId(); + } + + public String getName() { + return this.container.getName(); + } + + public String getVersion() { + return this.container.getVersion(); + } +} diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyPropertyContainer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyPropertyContainer.java index e9c95ef6b..c85e0c945 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyPropertyContainer.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/GroovyPropertyContainer.java @@ -17,7 +17,7 @@ import java.util.Collections; import java.util.Map; -public class GroovyPropertyContainer { +public class GroovyPropertyContainer extends ForgeModWrapper { private final Map properties = new Object2ObjectOpenHashMap<>(); private final Map view = Collections.unmodifiableMap(properties); diff --git a/src/main/java/com/cleanroommc/groovyscript/compat/mods/MinecraftModContainer.java b/src/main/java/com/cleanroommc/groovyscript/compat/mods/MinecraftModContainer.java new file mode 100644 index 000000000..2ed232b79 --- /dev/null +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/MinecraftModContainer.java @@ -0,0 +1,60 @@ +package com.cleanroommc.groovyscript.compat.mods; + +import com.cleanroommc.groovyscript.compat.vanilla.VanillaModule; +import com.google.common.base.Supplier; +import com.google.common.base.Suppliers; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +public final class MinecraftModContainer extends GroovyContainer { + + private static final String modId = "minecraft"; + private static final String containerName = "Minecraft"; + private final Supplier modProperty; + private final Collection aliases; + + MinecraftModContainer() { + this.modProperty = Suppliers.memoize(() -> { + VanillaModule t = VanillaModule.INSTANCE; + t.addPropertyFieldsOf(t, false); + return t; + }); + Set aliasSet = new ObjectOpenHashSet<>(); + aliasSet.add("mc"); + aliasSet.add(modId); + this.aliases = Collections.unmodifiableSet(aliasSet); + ModSupport.INSTANCE.registerContainer(this); + } + + @Override + public boolean isLoaded() { + return true; + } + + @Override + public @NotNull Collection getAliases() { + return aliases; + } + + @Override + public VanillaModule get() { + return modProperty.get(); + } + + @Override + public @NotNull String getModId() { + return modId; + } + + @Override + public @NotNull String getContainerName() { + return containerName; + } + + @Override + public void onCompatLoaded(GroovyContainer container) {} +} 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 0bee1eb2e..6f82287ec 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/mods/ModSupport.java @@ -67,9 +67,11 @@ import com.cleanroommc.groovyscript.compat.mods.tinkersconstruct.TinkersConstruct; import com.cleanroommc.groovyscript.compat.mods.woot.Woot; import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper; +import com.google.common.base.Suppliers; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.discovery.ASMDataTable; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; @@ -86,6 +88,8 @@ public class ModSupport { public static final ModSupport INSTANCE = new ModSupport(); // Just for Binding purposes + public static final MinecraftModContainer MINECRAFT = new MinecraftModContainer(); + public static final GroovyContainer ACTUALLY_ADDITIONS = new InternalModContainer<>("actuallyadditions", "Actually Additions", ActuallyAdditions::new, "aa"); public static final GroovyContainer ADDITIONAL_ENCHANTED_MINER = new InternalModContainer<>("quarryplus", "Additional Enchanted Miner", AdditionalEnchantedMiner::new); public static final GroovyContainer ADVANCED_MORTARS = new InternalModContainer<>("advancedmortars", "Advanced Mortars", AdvancedMortars::new); @@ -224,7 +228,9 @@ public static void init() { for (GroovyContainer container : containerList) { if (container.isLoaded()) { container.onCompatLoaded(container); - container.get().initialize(container); + GroovyPropertyContainer propertyContainer = container.get(); + propertyContainer.initialize(container); + propertyContainer.initialize(container.getModId()); ExpansionHelper.mixinConstProperty(ModSupport.class, container.getModId(), container.get(), false); for (String s : container.getAliases()) { if (!container.getModId().equals(s)) { @@ -233,6 +239,17 @@ public static void init() { } } } + for (ModContainer container : Loader.instance().getModList()) { + if (!INSTANCE.hasCompatFor(container.getModId())) { + ExpansionHelper.mixinProperty( + ModSupport.class, + container.getModId(), + ForgeModWrapper.class, + Suppliers.memoize(() -> new ForgeModWrapper(container)), + null, + false); + } + } } public @NotNull GroovyContainer getContainer(String mod) { 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 74ee1c544..6a2024fc6 100644 --- a/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java +++ b/src/main/java/com/cleanroommc/groovyscript/compat/vanilla/VanillaModule.java @@ -1,20 +1,16 @@ package com.cleanroommc.groovyscript.compat.vanilla; import com.cleanroommc.groovyscript.GroovyScript; -import com.cleanroommc.groovyscript.api.GroovyBlacklist; -import com.cleanroommc.groovyscript.api.IScriptReloadable; import com.cleanroommc.groovyscript.compat.content.Content; import com.cleanroommc.groovyscript.compat.inworldcrafting.InWorldCrafting; import com.cleanroommc.groovyscript.compat.loot.Loot; +import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.sandbox.expand.ExpansionHelper; import net.minecraft.command.ICommandSender; import net.minecraft.item.ItemStack; -import java.util.Collection; -import java.util.Collections; - -public class VanillaModule extends GroovyPropertyContainer implements IScriptReloadable { +public class VanillaModule extends GroovyPropertyContainer { public static final VanillaModule INSTANCE = new VanillaModule(); @@ -29,7 +25,13 @@ public class VanillaModule extends GroovyPropertyContainer implements IScriptRel public static final Command command = new Command(); public static final GameRule gameRule = new GameRule(); - public static void initializeBinding() { + private VanillaModule() {} + + @Override + public void initialize(GroovyContainer owner) { + GroovyScript.getSandbox().registerBinding("Minecraft", this); + GroovyScript.getSandbox().registerBinding("Vanilla", this); + // maybe remove some of these as globals? GroovyScript.getSandbox().registerBinding(crafting); GroovyScript.getSandbox().registerBinding(furnace); GroovyScript.getSandbox().registerBinding(loot); @@ -44,31 +46,4 @@ public static void initializeBinding() { ExpansionHelper.mixinClass(ItemStack.class, ItemStackExpansion.class); ExpansionHelper.mixinClass(ICommandSender.class, CommandSenderExpansion.class); } - - @Override - @GroovyBlacklist - public void onReload() { - crafting.onReload(); - furnace.onReload(); - loot.onReload(); - oreDict.onReload(); - rarity.onReload(); - player.onReload(); - inWorldCrafting.onReload(); - command.onReload(); - gameRule.onReload(); - } - - @Override - @GroovyBlacklist - public void afterScriptLoad() { - furnace.afterScriptLoad(); - loot.afterScriptLoad(); - inWorldCrafting.afterScriptLoad(); - } - - @Override - public Collection getAliases() { - return Collections.emptyList(); - } } diff --git a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/ItemsIngredient.java b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/ItemsIngredient.java index d0b0b75a6..25180b59e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/ItemsIngredient.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/ItemsIngredient.java @@ -1,7 +1,7 @@ package com.cleanroommc.groovyscript.helper.ingredient; import com.cleanroommc.groovyscript.api.IIngredient; -import com.google.common.collect.Iterators; +import com.google.common.collect.AbstractIterator; import net.minecraft.item.ItemStack; import net.minecraft.item.crafting.Ingredient; import net.minecraftforge.oredict.OreDictionary; @@ -17,6 +17,8 @@ public class ItemsIngredient extends IngredientBase implements Iterable itemStacks) { + setItemStacks(itemStacks); + } + + protected final void setItemStacks(Collection itemStacks) { this.itemStacks.addAll(itemStacks); this.itemStacks.trim(); this.itemStacks.copyElements(); @@ -47,13 +53,18 @@ public Ingredient toMcIngredient() { public ItemStack[] getMatchingStacks() { ItemStack[] stacks = new ItemStack[itemStacks.size()]; for (int i = 0; i < stacks.length; i++) { - ItemStack stack = itemStacks.get(i).copy(); - stack.setCount(getAmount()); - stacks[i] = stack; + stacks[i] = getAt(i); } return stacks; } + @Override + public ItemStack getAt(int index) { + ItemStack stack = this.itemStacks.get(index).copy(); + stack.setCount(getAmount()); + return stack; + } + @Override public int getAmount() { return itemStacks.isEmpty() ? 0 : amount; @@ -74,12 +85,22 @@ public boolean matches(ItemStack itemStack) { return false; } - public List getItemStacks() { + // protected since modifying un-copied stack directly can result in unexpected results + protected List getItemStacks() { return Collections.unmodifiableList(this.itemStacks); } @Override public @NotNull Iterator iterator() { - return Iterators.unmodifiableIterator(this.itemStacks.iterator()); + return new AbstractIterator<>() { + + private int index = 0; + + @Override + protected ItemStack computeNext() { + if (index >= itemStacks.size()) return endOfData(); + return getAt(index++); + } + }; } } 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 978b9acc5..d1bcc72af 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictIngredient.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictIngredient.java @@ -4,20 +4,22 @@ import com.cleanroommc.groovyscript.compat.vanilla.VanillaModule; import com.google.common.collect.ImmutableList; import net.minecraft.item.ItemStack; -import net.minecraft.item.crafting.Ingredient; import net.minecraftforge.oredict.OreDictionary; -import org.jetbrains.annotations.NotNull; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; -public class OreDictIngredient extends IngredientBase implements Iterable, IOreDicts { +public class OreDictIngredient extends ItemsIngredient implements Iterable, IOreDicts { private final String oreDict; - private int count = 1; public OreDictIngredient(String oreDict) { + super(OreDictionary.getOres(oreDict)); + this.oreDict = oreDict; + } + + // fast copy + private OreDictIngredient(String oreDict, List itemStacks) { + super(itemStacks); this.oreDict = oreDict; } @@ -30,66 +32,18 @@ public List getOreDicts() { return ImmutableList.of(getOreDict()); } - @Override - public int getAmount() { - return count; - } - - @Override - public void setAmount(int amount) { - count = Math.max(0, amount); - } - @Override public OreDictIngredient exactCopy() { - OreDictIngredient oreDictIngredient = new OreDictIngredient(this.oreDict); - oreDictIngredient.setAmount(this.count); + OreDictIngredient oreDictIngredient = new OreDictIngredient(this.oreDict, getItemStacks()); + oreDictIngredient.setAmount(getAmount()); oreDictIngredient.transformer = transformer; oreDictIngredient.matchCondition = matchCondition; return oreDictIngredient; } - @Override - public boolean matches(ItemStack stack) { - // TODO this sucks - if (IngredientHelper.isEmpty(stack)) return false; - for (int id : OreDictionary.getOreIDs(stack)) { - String oreName = OreDictionary.getOreName(id); - if (oreDict.equals(oreName)) { - return true; - } - } - return false; - } - - @Override - public Ingredient toMcIngredient() { - return Ingredient.fromStacks(getMatchingStacks()); - } - - @Override - public ItemStack[] getMatchingStacks() { - List stacks = OreDictionary.getOres(this.oreDict); - ItemStack[] copies = new ItemStack[stacks.size()]; - for (int i = 0; i < stacks.size(); i++) { - ItemStack stack = stacks.get(i).copy(); - stack.setCount(getAmount()); - copies[i] = stack; - } - return copies; - } - - public ItemStack getFirst() { - return getMatchingStacks()[0]; - } - - public ItemStack getAt(int index) { - return getMatchingStacks()[index]; - } - @Override public String toString() { - return "OreDictIngredient{ " + oreDict + " } * " + count; + return "OreDictIngredient{ " + oreDict + " } * " + getAmount(); } public void add(ItemStack itemStack) { @@ -127,9 +81,4 @@ public void remove(Iterable itemStacks) { remove(itemStack); } } - - @Override - public @NotNull Iterator iterator() { - return Arrays.asList(getMatchingStacks()).listIterator(); - } } 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 55b667ba0..d77882a9d 100644 --- a/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictWildcardIngredient.java +++ b/src/main/java/com/cleanroommc/groovyscript/helper/ingredient/OreDictWildcardIngredient.java @@ -18,7 +18,14 @@ public class OreDictWildcardIngredient extends ItemsIngredient implements IOreDi private final List matchingOreDictionaries = new ArrayList<>(); public final List ores = Collections.unmodifiableList(this.matchingOreDictionaries); - public static OreDictWildcardIngredient of(String oreDict) { + private OreDictWildcardIngredient(String oreDict, List matchingOreDictionaries, List itemStacks) { + super(itemStacks); + this.oreDict = oreDict; + this.matchingOreDictionaries.addAll(matchingOreDictionaries); + } + + public OreDictWildcardIngredient(String oreDict) { + this.oreDict = oreDict; List matchingOreDictionaries = new ArrayList<>(); List stacks = new ArrayList<>(); Pattern pattern = Pattern.compile(oreDict.replace("*", ".*")); @@ -31,13 +38,8 @@ public static OreDictWildcardIngredient of(String oreDict) { } } } - return new OreDictWildcardIngredient(oreDict, matchingOreDictionaries, stacks); - } - - public OreDictWildcardIngredient(String oreDict, List matchingOreDictionaries, List itemStacks) { - super(itemStacks); - this.oreDict = oreDict; this.matchingOreDictionaries.addAll(matchingOreDictionaries); + setItemStacks(stacks); } public String getOreDict() { diff --git a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java index 219411d6e..65220e86e 100644 --- a/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java +++ b/src/main/java/com/cleanroommc/groovyscript/mapper/ObjectMapperManager.java @@ -84,7 +84,7 @@ public static void init() { .docOfType("resource location") .register(); ObjectMapper.builder("ore", IIngredient.class) - .parser((s, args) -> s.contains(WILDCARD) ? Result.some(OreDictWildcardIngredient.of(s)) : Result.some(new OreDictIngredient(s))) + .parser((s, args) -> s.contains(WILDCARD) ? Result.some(new OreDictWildcardIngredient(s)) : Result.some(new OreDictIngredient(s))) .completerOfNames(OreDictionaryAccessor::getIdToName) .docOfType("ore dict entry") .textureBinder(TextureBinder.of(i -> Arrays.asList(i.getMatchingStacks()), TextureBinder.ofItem(), i -> String.format("![](${item('%s')}) %s", i.getItem().getRegistryName(), i.getDisplayName()))) diff --git a/src/main/java/com/cleanroommc/groovyscript/registry/ReloadableRegistryManager.java b/src/main/java/com/cleanroommc/groovyscript/registry/ReloadableRegistryManager.java index 647a5ec44..2d7e68c63 100644 --- a/src/main/java/com/cleanroommc/groovyscript/registry/ReloadableRegistryManager.java +++ b/src/main/java/com/cleanroommc/groovyscript/registry/ReloadableRegistryManager.java @@ -8,7 +8,6 @@ import com.cleanroommc.groovyscript.compat.mods.GroovyContainer; import com.cleanroommc.groovyscript.compat.mods.GroovyPropertyContainer; import com.cleanroommc.groovyscript.compat.mods.ModSupport; -import com.cleanroommc.groovyscript.compat.vanilla.VanillaModule; import com.cleanroommc.groovyscript.core.mixin.jei.JeiProxyAccessor; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import mezz.jei.Internal; @@ -76,7 +75,6 @@ public static void init() { @ApiStatus.Internal public static void onReload() { GroovyScript.reloadRunConfig(false); - VanillaModule.INSTANCE.onReload(); ModSupport.getAllContainers() .stream() .filter(GroovyContainer::isLoaded) @@ -103,7 +101,6 @@ public static void afterScriptRun() { .filter(IScriptReloadable.class::isInstance) .map(IScriptReloadable.class::cast) .forEach(IScriptReloadable::afterScriptLoad); - VanillaModule.INSTANCE.afterScriptLoad(); unfreezeForgeRegistries(); }