Compare commits
2 Commits
a1c74b64c0
...
a49c75bce0
Author | SHA1 | Date |
---|---|---|
Tom Dodd | a49c75bce0 | |
Tom Dodd | 84360b38c0 |
|
@ -3,7 +3,7 @@ v2o.4.7
|
||||||
+ Added quantum computer Python Qiskit code generation
|
+ Added quantum computer Python Qiskit code generation
|
||||||
* Code is now generated by using a code generator component rather than the controller
|
* Code is now generated by using a code generator component rather than the controller
|
||||||
|
|
||||||
+ Added salt to recipe hash caching to avoid clashes (salt is incremented if a clash occurs and hashes are recalculated)
|
+ Fixed issues with rare hash clashes while caching recipe inputs
|
||||||
|
|
||||||
* Fixed broken quantum computer component recipes
|
* Fixed broken quantum computer component recipes
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import com.google.common.collect.Lists;
|
||||||
import crafttweaker.annotations.ZenRegister;
|
import crafttweaker.annotations.ZenRegister;
|
||||||
import it.unimi.dsi.fastutil.ints.*;
|
import it.unimi.dsi.fastutil.ints.*;
|
||||||
import it.unimi.dsi.fastutil.longs.*;
|
import it.unimi.dsi.fastutil.longs.*;
|
||||||
|
import it.unimi.dsi.fastutil.objects.*;
|
||||||
import nc.recipe.ingredient.*;
|
import nc.recipe.ingredient.*;
|
||||||
import nc.tile.internal.fluid.Tank;
|
import nc.tile.internal.fluid.Tank;
|
||||||
import nc.util.*;
|
import nc.util.*;
|
||||||
|
@ -25,8 +26,7 @@ public abstract class AbstractRecipeHandler<RECIPE extends IRecipe> {
|
||||||
|
|
||||||
protected @Nonnull List<RECIPE> recipeList = new ArrayList<>();
|
protected @Nonnull List<RECIPE> recipeList = new ArrayList<>();
|
||||||
|
|
||||||
protected @Nonnull Long2ObjectMap<RECIPE> recipeCache = new Long2ObjectOpenHashMap<>();
|
protected @Nonnull Long2ObjectMap<ObjectSet<RECIPE>> recipeCache = new Long2ObjectOpenHashMap<>();
|
||||||
protected long cacheSalt = 0L;
|
|
||||||
|
|
||||||
private static List<Class<?>> validItemInputs = Lists.newArrayList(IItemIngredient.class, ArrayList.class, String.class, Item.class, Block.class, ItemStack.class, ItemStack[].class);
|
private static List<Class<?>> validItemInputs = Lists.newArrayList(IItemIngredient.class, ArrayList.class, String.class, Item.class, Block.class, ItemStack.class, ItemStack[].class);
|
||||||
private static List<Class<?>> validFluidInputs = Lists.newArrayList(IFluidIngredient.class, ArrayList.class, String.class, Fluid.class, FluidStack.class, FluidStack[].class);
|
private static List<Class<?>> validFluidInputs = Lists.newArrayList(IFluidIngredient.class, ArrayList.class, String.class, Fluid.class, FluidStack.class, FluidStack[].class);
|
||||||
|
@ -46,18 +46,19 @@ public abstract class AbstractRecipeHandler<RECIPE extends IRecipe> {
|
||||||
@ZenMethod
|
@ZenMethod
|
||||||
public abstract List<RECIPE> getRecipeList();
|
public abstract List<RECIPE> getRecipeList();
|
||||||
|
|
||||||
public Long2ObjectMap<RECIPE> getRecipeCache() {
|
|
||||||
return recipeCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract void addRecipe(Object... objects);
|
public abstract void addRecipe(Object... objects);
|
||||||
|
|
||||||
public @Nullable RecipeInfo<RECIPE> getRecipeInfoFromInputs(List<ItemStack> itemInputs, List<Tank> fluidInputs) {
|
public @Nullable RecipeInfo<RECIPE> getRecipeInfoFromInputs(List<ItemStack> itemInputs, List<Tank> fluidInputs) {
|
||||||
RECIPE recipe = recipeCache.get(RecipeHelper.hashMaterialsRaw(itemInputs, fluidInputs, cacheSalt));
|
long hash = RecipeHelper.hashMaterialsRaw(itemInputs, fluidInputs);
|
||||||
if (recipe != null) {
|
if (recipeCache.containsKey(hash)) {
|
||||||
RecipeMatchResult matchResult = recipe.matchInputs(itemInputs, fluidInputs);
|
ObjectSet<RECIPE> set = recipeCache.get(hash);
|
||||||
if (matchResult.matches()) {
|
for (RECIPE recipe : set) {
|
||||||
return new RecipeInfo(recipe, matchResult);
|
if (recipe != null) {
|
||||||
|
RecipeMatchResult matchResult = recipe.matchInputs(itemInputs, fluidInputs);
|
||||||
|
if (matchResult.matches()) {
|
||||||
|
return new RecipeInfo(recipe, matchResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -95,65 +96,68 @@ public abstract class AbstractRecipeHandler<RECIPE extends IRecipe> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void refreshCache() {
|
public void refreshCache() {
|
||||||
cacheSalt = 0L;
|
recipeCache.clear();
|
||||||
do {
|
fillHashCache();
|
||||||
recipeCache.clear();
|
|
||||||
}
|
|
||||||
while (!fillHashCache());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean fillHashCache() {
|
protected void fillHashCache() {
|
||||||
recipeLoop: for (RECIPE recipe : recipeList) {
|
for (RECIPE recipe : recipeList) {
|
||||||
List<List<ItemStack>> itemInputLists = new ArrayList<>();
|
|
||||||
List<List<FluidStack>> fluidInputLists = new ArrayList<>();
|
|
||||||
|
|
||||||
for (IItemIngredient item : recipe.getItemIngredients()) {
|
|
||||||
itemInputLists.add(item.getInputStackHashingList());
|
|
||||||
}
|
|
||||||
for (IFluidIngredient fluid : recipe.getFluidIngredients()) {
|
|
||||||
fluidInputLists.add(fluid.getInputStackHashingList());
|
|
||||||
}
|
|
||||||
|
|
||||||
int arrSize = recipe.getItemIngredients().size() + recipe.getFluidIngredients().size();
|
|
||||||
int[] inputNumbers = new int[arrSize];
|
|
||||||
Arrays.fill(inputNumbers, 0);
|
|
||||||
|
|
||||||
int[] maxNumbers = new int[arrSize];
|
|
||||||
for (int i = 0; i < itemInputLists.size(); i++) {
|
|
||||||
int maxNumber = itemInputLists.get(i).size() - 1;
|
|
||||||
if (maxNumber < 0) {
|
|
||||||
continue recipeLoop;
|
|
||||||
}
|
|
||||||
maxNumbers[i] = maxNumber;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < fluidInputLists.size(); i++) {
|
|
||||||
int maxNumber = fluidInputLists.get(i).size() - 1;
|
|
||||||
if (maxNumber < 0) {
|
|
||||||
continue recipeLoop;
|
|
||||||
}
|
|
||||||
maxNumbers[i + itemInputLists.size()] = maxNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<Pair<List<ItemStack>, List<FluidStack>>> materialListTuples = new ArrayList<>();
|
List<Pair<List<ItemStack>, List<FluidStack>>> materialListTuples = new ArrayList<>();
|
||||||
|
|
||||||
RecipeTupleGenerator.INSTANCE.generateMaterialListTuples(materialListTuples, maxNumbers, inputNumbers, itemInputLists, fluidInputLists);
|
if (!prepareMaterialListTuples(recipe, materialListTuples)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for (Pair<List<ItemStack>, List<FluidStack>> materials : materialListTuples) {
|
for (Pair<List<ItemStack>, List<FluidStack>> materials : materialListTuples) {
|
||||||
for (List<ItemStack> items : PermutationHelper.permutations(materials.getLeft())) {
|
for (List<ItemStack> items : PermutationHelper.permutations(materials.getLeft())) {
|
||||||
for (List<FluidStack> fluids : PermutationHelper.permutations(materials.getRight())) {
|
for (List<FluidStack> fluids : PermutationHelper.permutations(materials.getRight())) {
|
||||||
long hash = RecipeHelper.hashMaterials(items, fluids, cacheSalt);
|
long hash = RecipeHelper.hashMaterials(items, fluids);
|
||||||
if (recipeCache.containsKey(hash)) {
|
if (recipeCache.containsKey(hash)) {
|
||||||
cacheSalt++;
|
recipeCache.get(hash).add(recipe);
|
||||||
NCUtil.getLogger().info(getRecipeName() + " encountered a hash clash [" + RecipeHelper.getRecipeString(recipe) + " == " + RecipeHelper.getRecipeString(recipeCache.get(hash)) + "]! Incrementing salt to " + cacheSalt + " and restarting caching...");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
recipeCache.put(RecipeHelper.hashMaterials(items, fluids, cacheSalt), recipe);
|
ObjectSet<RECIPE> set = new ObjectOpenHashSet<>();
|
||||||
|
set.add(recipe);
|
||||||
|
recipeCache.put(hash, set);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean prepareMaterialListTuples(RECIPE recipe, List<Pair<List<ItemStack>, List<FluidStack>>> materialListTuples) {
|
||||||
|
List<List<ItemStack>> itemInputLists = new ArrayList<>();
|
||||||
|
List<List<FluidStack>> fluidInputLists = new ArrayList<>();
|
||||||
|
|
||||||
|
for (IItemIngredient item : recipe.getItemIngredients()) {
|
||||||
|
itemInputLists.add(item.getInputStackHashingList());
|
||||||
|
}
|
||||||
|
for (IFluidIngredient fluid : recipe.getFluidIngredients()) {
|
||||||
|
fluidInputLists.add(fluid.getInputStackHashingList());
|
||||||
|
}
|
||||||
|
|
||||||
|
int arrSize = recipe.getItemIngredients().size() + recipe.getFluidIngredients().size();
|
||||||
|
int[] inputNumbers = new int[arrSize];
|
||||||
|
Arrays.fill(inputNumbers, 0);
|
||||||
|
|
||||||
|
int[] maxNumbers = new int[arrSize];
|
||||||
|
for (int i = 0; i < itemInputLists.size(); i++) {
|
||||||
|
int maxNumber = itemInputLists.get(i).size() - 1;
|
||||||
|
if (maxNumber < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
maxNumbers[i] = maxNumber;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < fluidInputLists.size(); i++) {
|
||||||
|
int maxNumber = fluidInputLists.get(i).size() - 1;
|
||||||
|
if (maxNumber < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
maxNumbers[i + itemInputLists.size()] = maxNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecipeTupleGenerator.INSTANCE.generateMaterialListTuples(materialListTuples, maxNumbers, inputNumbers, itemInputLists, fluidInputLists);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -509,32 +509,32 @@ public class RecipeHelper {
|
||||||
return new OreIngredient(oreName, stackSize);
|
return new OreIngredient(oreName, stackSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long hashMaterialsRaw(List<ItemStack> items, List<Tank> fluids, long salt) {
|
public static long hashMaterialsRaw(List<ItemStack> items, List<Tank> fluids) {
|
||||||
long hash = 1L;
|
long hash = 1L;
|
||||||
Iterator<ItemStack> itemIter = items.iterator();
|
Iterator<ItemStack> itemIter = items.iterator();
|
||||||
while (itemIter.hasNext()) {
|
while (itemIter.hasNext()) {
|
||||||
ItemStack stack = itemIter.next();
|
ItemStack stack = itemIter.next();
|
||||||
hash = 31L * hash + (stack == null || stack.isEmpty() ? 0L : RecipeItemHelper.pack(stack)) + salt;
|
hash = 31L * hash + (stack == null || stack.isEmpty() ? 0L : RecipeItemHelper.pack(stack));
|
||||||
}
|
}
|
||||||
Iterator<Tank> fluidIter = fluids.iterator();
|
Iterator<Tank> fluidIter = fluids.iterator();
|
||||||
while (fluidIter.hasNext()) {
|
while (fluidIter.hasNext()) {
|
||||||
Tank tank = fluidIter.next();
|
Tank tank = fluidIter.next();
|
||||||
hash = 31L * hash + (tank == null || tank.getFluid() == null ? 0L : tank.getFluid().getFluid().getName().hashCode()) + salt;
|
hash = 31L * hash + (tank == null || tank.getFluid() == null ? 0L : tank.getFluid().getFluid().getName().hashCode());
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long hashMaterials(List<ItemStack> items, List<FluidStack> fluids, long salt) {
|
public static long hashMaterials(List<ItemStack> items, List<FluidStack> fluids) {
|
||||||
long hash = 1L;
|
long hash = 1L;
|
||||||
Iterator<ItemStack> itemIter = items.iterator();
|
Iterator<ItemStack> itemIter = items.iterator();
|
||||||
while (itemIter.hasNext()) {
|
while (itemIter.hasNext()) {
|
||||||
ItemStack stack = itemIter.next();
|
ItemStack stack = itemIter.next();
|
||||||
hash = 31L * hash + (stack == null || stack.isEmpty() ? 0L : RecipeItemHelper.pack(stack)) + salt;
|
hash = 31L * hash + (stack == null || stack.isEmpty() ? 0L : RecipeItemHelper.pack(stack));
|
||||||
}
|
}
|
||||||
Iterator<FluidStack> fluidIter = fluids.iterator();
|
Iterator<FluidStack> fluidIter = fluids.iterator();
|
||||||
while (fluidIter.hasNext()) {
|
while (fluidIter.hasNext()) {
|
||||||
FluidStack stack = fluidIter.next();
|
FluidStack stack = fluidIter.next();
|
||||||
hash = 31L * hash + (stack == null ? 0L : stack.getFluid().getName().hashCode()) + salt;
|
hash = 31L * hash + (stack == null ? 0L : stack.getFluid().getName().hashCode());
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ public class ManufactoryRecipes extends ProcessorRecipeHandler {
|
||||||
addLogRecipes();
|
addLogRecipes();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Set<String> BLACKLIST = Sets.newHashSet("silicon");
|
private static final Set<String> BLACKLIST = Sets.newHashSet("Silicon");
|
||||||
|
|
||||||
public void addMetalProcessingRecipes() {
|
public void addMetalProcessingRecipes() {
|
||||||
for (String ingot : OreDictionary.getOreNames()) {
|
for (String ingot : OreDictionary.getOreNames()) {
|
||||||
|
|
3
todo.txt
3
todo.txt
|
@ -1,6 +1,3 @@
|
||||||
Add salt-based fix for recipe hash caching (start from zero, if there's a clash, start again after incrementing)
|
|
||||||
Test with iron + coal alloy furnace recipe in modified Enigmatica 2 instance
|
|
||||||
|
|
||||||
Suggestions from: This probably won’t happen but in stead of multiblock reactors
|
Suggestions from: This probably won’t happen but in stead of multiblock reactors
|
||||||
|
|
||||||
Adjacent MSR vessels with same filter form bundle to share flux, shared criticality factor is sum of single vessel criticality factors
|
Adjacent MSR vessels with same filter form bundle to share flux, shared criticality factor is sum of single vessel criticality factors
|
||||||
|
|
Loading…
Reference in New Issue