Skip to content
2 changes: 2 additions & 0 deletions examples/postInit/immersiveengineering.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ mods.immersiveengineering.blueprint_crafting.recipeBuilder()
.register()


mods.immersiveengineering.blueprint_crafting.streamRecipesByCategory('molds')

// Bottling Machine:
// Converts an input itemstack and fluidstack into an output itemstack.

Expand Down
5 changes: 5 additions & 0 deletions examples/postInit/minecraft.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,11 @@ mods.minecraft.ore_dict.remove('netherStar', item('minecraft:nether_star'))
mods.minecraft.ore_dict.add('ingotGold', item('minecraft:nether_star'))
mods.minecraft.ore_dict.add('netherStar', item('minecraft:gold_ingot'))

mods.minecraft.ore_dict.getOres(~/.*/)
mods.minecraft.ore_dict.getOres(~/.*Gold/)
mods.minecraft.ore_dict.getOres(~/.*or.*/)
mods.minecraft.ore_dict.getOres('ingot*')

// Starting Inventory:
// Sets the starting inventory of the player, including armor slots and offhand.

Expand Down
13 changes: 8 additions & 5 deletions src/main/java/com/cleanroommc/groovyscript/api/IOreDicts.java
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package com.cleanroommc.groovyscript.api;

import java.util.List;
import org.jetbrains.annotations.UnmodifiableView;

import java.util.Collection;

/**
* Indicates that the IIngredient represents one or more oredicts.
* Indicates something that represents one or more oredicts, typically an {@link IIngredient}.
*/
public interface IOreDicts extends IIngredient {
public interface IOreDicts {
// TODO
// There are a large number of places currently in the GroovyScript codebase
// that check if something is "instanceof OreDictIngredient".
// these should be replaced by checks against IOreDicts,
// and surrounding code changed appropriately.

/**
* @return a list of oredict strings
* @return a collection of oredict strings
*/
List<String> getOreDicts();
@UnmodifiableView
Collection<String> getOreDicts();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

import com.cleanroommc.groovyscript.api.GroovyBlacklist;
import com.cleanroommc.groovyscript.api.GroovyLog;
import com.cleanroommc.groovyscript.api.IIngredient;
import com.cleanroommc.groovyscript.api.documentation.annotations.Example;
import com.cleanroommc.groovyscript.api.documentation.annotations.MethodDescription;
import com.cleanroommc.groovyscript.api.documentation.annotations.RegistryDescription;
import com.cleanroommc.groovyscript.core.mixin.OreDictionaryAccessor;
import com.cleanroommc.groovyscript.helper.Alias;
import com.cleanroommc.groovyscript.helper.SimpleObjectStream;
import com.cleanroommc.groovyscript.helper.ingredient.IngredientHelper;
import com.cleanroommc.groovyscript.helper.ingredient.OreDictMatcherIngredient;
import com.cleanroommc.groovyscript.registry.VirtualizedRegistry;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
Expand All @@ -18,6 +21,7 @@

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

@RegistryDescription(category = RegistryDescription.Category.ENTRIES)
public class OreDict extends VirtualizedRegistry<OreDictEntry> {
Expand Down Expand Up @@ -150,4 +154,23 @@ public void removeAll() {
}
}
}

@MethodDescription(type = MethodDescription.Type.QUERY)
public SimpleObjectStream<String> streamOreNames() {
return new SimpleObjectStream<>(OreDictionaryAccessor.getIdToName()).setRemover(this::removeAll);
}

@MethodDescription(type = MethodDescription.Type.QUERY, example = @Example("'ingot*'"))
public IIngredient getOres(String pattern) {
return new OreDictMatcherIngredient(pattern);
}

@MethodDescription(type = MethodDescription.Type.QUERY, example = {
@Example("~/.*Gold/"),
@Example("~/.*or.*/"),
@Example("~/.*/"),
})
public IIngredient getOres(Pattern pattern) {
return new OreDictMatcherIngredient(pattern);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ public String exampleBlock() {
}
out.append(documentMethodDescriptionType(MethodDescription.Type.ADDITION));
out.append(documentMethodDescriptionType(MethodDescription.Type.VALUE));
out.append(documentMethodDescriptionType(MethodDescription.Type.QUERY));
return out.toString();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ public static IIngredient toIIngredient(FluidStack fluidStack) {
public static @NotNull List<List<Object>> cartesianProductOres(@NotNull List<IIngredient> inputs) {
List<List<?>> entries = new ArrayList<>();
for (var input : inputs) {
if (input instanceof IOreDicts ore) entries.add(ore.getOreDicts());
if (input instanceof IOreDicts ore) entries.add(new ArrayList<>(ore.getOreDicts()));
else entries.add(Arrays.asList(input.getMatchingStacks()));
}
return Lists.cartesianProduct(entries);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

public class ItemsIngredient extends IngredientBase implements Iterable<ItemStack> {

Expand Down Expand Up @@ -85,11 +84,6 @@ public boolean matches(ItemStack itemStack) {
return false;
}

// protected since modifying un-copied stack directly can result in unexpected results
protected List<ItemStack> getItemStacks() {
return Collections.unmodifiableList(this.itemStacks);
}

@Override
public @NotNull Iterator<ItemStack> iterator() {
return new AbstractIterator<>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,111 @@

import com.cleanroommc.groovyscript.api.IOreDicts;
import com.cleanroommc.groovyscript.compat.vanilla.VanillaModule;
import com.google.common.collect.AbstractIterator;
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 org.jetbrains.annotations.UnmodifiableView;

import java.util.Collection;
import java.util.Iterator;
import java.util.List;

public class OreDictIngredient extends ItemsIngredient implements Iterable<ItemStack>, IOreDicts {
public class OreDictIngredient extends IngredientBase implements Iterable<ItemStack>, IOreDicts {

private final String oreDict;
private int amount = 1;

public OreDictIngredient(String oreDict) {
super(OreDictionary.getOres(oreDict));
this.oreDict = oreDict;
}

// fast copy
private OreDictIngredient(String oreDict, List<ItemStack> itemStacks) {
super(itemStacks);
this.oreDict = oreDict;
private static ItemStack selectItemStack(List<ItemStack> stacks, int index, int amount) {
if (amount == 0 || stacks.isEmpty() || stacks.size() < index) return ItemStack.EMPTY;
ItemStack stack = stacks.get(index).copy();
stack.setCount(amount);
return stack;
}

public String getOreDict() {
return oreDict;
}

@Override
public List<String> getOreDicts() {
public @UnmodifiableView Collection<String> getOreDicts() {
return ImmutableList.of(getOreDict());
}

@Override
public OreDictIngredient exactCopy() {
OreDictIngredient oreDictIngredient = new OreDictIngredient(this.oreDict, getItemStacks());
oreDictIngredient.setAmount(getAmount());
OreDictIngredient oreDictIngredient = new OreDictIngredient(this.oreDict);
oreDictIngredient.amount = amount;
oreDictIngredient.transformer = transformer;
oreDictIngredient.matchCondition = matchCondition;
return oreDictIngredient;
}

@Override
public Ingredient toMcIngredient() {
return Ingredient.fromStacks(getMatchingStacks());
}

@Override
public ItemStack[] getMatchingStacks() {
var stacks = getItemStacks();
ItemStack[] output = new ItemStack[stacks.size()];
for (int i = 0; i < output.length; i++) {
output[i] = selectItemStack(stacks, i, amount);
}
return output;
}

@Override
public ItemStack getAt(int index) {
return selectItemStack(getItemStacks(), index, amount);
}

@Override
public int getAmount() {
return getItemStacks().isEmpty() ? 0 : amount;
}

@Override
public void setAmount(int amount) {
this.amount = Math.max(0, amount);
}

@Override
public boolean matches(ItemStack itemStack) {
for (ItemStack itemStack1 : getItemStacks()) {
if (OreDictionary.itemMatches(itemStack1, itemStack, false)) {
return true;
}
}
return false;
}

private List<ItemStack> getItemStacks() {
return OreDictionary.getOres(oreDict);
}

@Override
public @NotNull Iterator<ItemStack> iterator() {
return new AbstractIterator<>() {

private int index = 0;

@Override
protected ItemStack computeNext() {
var stacks = getItemStacks();
if (index >= stacks.size()) return endOfData();
return selectItemStack(stacks, index++, amount);
}
};
}

@Override
public String toString() {
return "OreDictIngredient{ " + oreDict + " } * " + getAmount();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package com.cleanroommc.groovyscript.helper.ingredient;

import com.cleanroommc.groovyscript.api.IIngredient;
import com.cleanroommc.groovyscript.api.IOreDicts;
import com.cleanroommc.groovyscript.core.mixin.OreDictionaryAccessor;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import net.minecraft.item.ItemStack;
import net.minecraft.item.crafting.Ingredient;
import net.minecraftforge.oredict.OreDictionary;
import org.jetbrains.annotations.UnmodifiableView;

import java.util.Collection;
import java.util.regex.Pattern;

public class OreDictMatcherIngredient extends IngredientBase implements IOreDicts {

private static final Pattern WILDCARD = Pattern.compile("\\*");

private final Collection<String> oreDicts;
private final ItemStackList itemStacks;
private final Pattern pattern;
private int amount = 1;

public OreDictMatcherIngredient(String pattern) {
this(Pattern.compile(WILDCARD.matcher(pattern).replaceAll(".*")));
}

public OreDictMatcherIngredient(Pattern pattern) {
this.pattern = pattern;
this.oreDicts = new ObjectOpenHashSet<>();
this.itemStacks = new ItemStackList();
generate();
}

private OreDictMatcherIngredient(Pattern pattern, Collection<String> oreDicts, ItemStackList itemStacks) {
this.pattern = pattern;
this.oreDicts = new ObjectOpenHashSet<>(oreDicts);
this.itemStacks = new ItemStackList(itemStacks);
}

private void generate() {
for (var ore : OreDictionaryAccessor.getIdToName()) {
if (pattern.matcher(ore).matches() && oreDicts.add(ore)) {
itemStacks.addAll(OreDictionary.getOres(ore));
}
}
}

@Override
public IIngredient exactCopy() {
var ingredient = new OreDictMatcherIngredient(pattern, oreDicts, itemStacks);
ingredient.amount = amount;
ingredient.transformer = transformer;
ingredient.matchCondition = matchCondition;
return ingredient;
}

@Override
public Ingredient toMcIngredient() {
return Ingredient.fromStacks(getMatchingStacks());
}

@Override
public ItemStack[] getMatchingStacks() {
ItemStack[] stacks = new ItemStack[itemStacks.size()];
for (int i = 0; i < stacks.length; i++) {
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;
}

@Override
public void setAmount(int amount) {
this.amount = amount;
}

@Override
public boolean matches(ItemStack itemStack) {
for (ItemStack itemStack1 : itemStacks) {
if (OreDictionary.itemMatches(itemStack1, itemStack, false)) {
return true;
}
}
return false;
}

@Override
public @UnmodifiableView Collection<String> getOreDicts() {
return oreDicts;
}

public OreDictMatcherIngredient regenerate() {
oreDicts.clear();
itemStacks.clear();
generate();
return this;
}
}
Loading