diff options
-rw-r--r-- | src/main/java/gregtech/api/util/GT_AssemblyLineUtils.java | 44 | ||||
-rw-r--r-- | src/main/java/gregtech/api/util/GT_Recipe.java | 47 | ||||
-rw-r--r-- | src/main/java/gregtech/common/GT_RecipeAdder.java | 13 |
3 files changed, 76 insertions, 28 deletions
diff --git a/src/main/java/gregtech/api/util/GT_AssemblyLineUtils.java b/src/main/java/gregtech/api/util/GT_AssemblyLineUtils.java index 25f4b35ab3..07353882ec 100644 --- a/src/main/java/gregtech/api/util/GT_AssemblyLineUtils.java +++ b/src/main/java/gregtech/api/util/GT_AssemblyLineUtils.java @@ -17,6 +17,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; +import net.minecraftforge.common.util.Constants.NBT; import net.minecraftforge.fluids.FluidStack; import javax.annotation.Nonnull; @@ -72,11 +73,11 @@ public class GT_AssemblyLineUtils { */ @Nonnull public static LookupResult findAssemblyLineRecipeFromDataStick(ItemStack aDataStick, boolean aReturnBuiltRecipe) { - if (!isItemDataStick(aDataStick)) { + if (!isItemDataStick(aDataStick) || doesDataStickHaveOutput(aDataStick)) { return LookupResultType.INVALID_STICK.getResult(); } List<ItemStack> aInputs = new ArrayList<>(15); - ItemStack aOutput = null; + ItemStack aOutput = getDataStickOutput(aDataStick); List<List<ItemStack>> mOreDictAlt = new ArrayList<>(15); List<FluidStack> aFluidInputs = new ArrayList<>(4); @@ -88,9 +89,9 @@ public class GT_AssemblyLineUtils { //Get From Cache if (doesDataStickHaveRecipeHash(aDataStick)) { GT_Recipe_AssemblyLine aRecipeFromCache = sRecipeCacheByRecipeHash.get(getHashFromDataStack(aDataStick)); - if (aRecipeFromCache != null) { + if (aRecipeFromCache != null && GT_Utility.areStacksEqual(aOutput, aRecipeFromCache.mOutput)) { return LookupResultType.VALID_STACK_AND_VALID_HASH.getResult(aRecipeFromCache); - } + } // else: no cache, or the old recipe run into a hash collision with a different new recipe } for (int i = 0; i < 15; i++) { @@ -133,7 +134,6 @@ public class GT_AssemblyLineUtils { GT_FML_LOGGER.info("Fluid " + i + " " + tLoaded.getUnlocalizedName()); } } - aOutput = GT_Utility.loadItem(aTag, "output"); if (!aTag.hasKey("output") || !aTag.hasKey("time") || aTag.getInteger("time") <= 0 || !aTag.hasKey("eu") || !GT_Utility.isStackValid(aOutput)) { return LookupResultType.INVALID_STICK.getResult(); } @@ -227,14 +227,29 @@ public class GT_AssemblyLineUtils { } /** + * @param aRecipe - The recipe to add to internal caches + * @throws IllegalArgumentException if given recipe collide with any existing recipe in the cache + */ + public static void addRecipeToCache(GT_Recipe_AssemblyLine aRecipe) { + if (aRecipe != null) { + String aHash = "Hash." + aRecipe.getPersistentHash(); + GT_Recipe_AssemblyLine existing = sRecipeCacheByOutput.put(new GT_ItemStack(aRecipe.mOutput), aRecipe); + if (existing != null) + throw new IllegalArgumentException("Duplicate assline recipe for " + aRecipe.mOutput); + existing = sRecipeCacheByRecipeHash.put(aHash, aRecipe); + if (existing != null && !existing.equals(aRecipe)) + throw new IllegalArgumentException("Recipe hash collision for " + aRecipe + " and " + existing); + } + } + + /** * @param aHash - Recipe hash String, may be null but will just be treated as invalid. * @return Is this Recipe Hash String valid? */ public static boolean isValidHash(String aHash) { if (aHash != null && aHash.length() > 0) { - if (!aHash.equals("Invalid.Recipe.Hash") && aHash.contains("Hash.")) { - return true; - } + // persistent hash can never be 0 + return !aHash.equals("Invalid.Recipe.Hash") && !aHash.equals("Hash.0"); } return false; } @@ -283,7 +298,7 @@ public class GT_AssemblyLineUtils { public static boolean doesDataStickHaveRecipeHash(ItemStack aDataStick) { if (isItemDataStick(aDataStick) && aDataStick.hasTagCompound()) { NBTTagCompound aNBT = aDataStick.getTagCompound(); - if (aNBT.hasKey("Data.Recipe.Hash")) { + if (aNBT.hasKey("Data.Recipe.Hash") && aNBT.getString("Data.Recipe.Hash").equals("Hash.0")) { return true; } } @@ -304,17 +319,18 @@ public class GT_AssemblyLineUtils { } /** - * @param aDataStick - The Data Stick to procces. + * @param aDataStick - The Data Stick to process. * @return The stored Recipe Hash String on the Data Stick, will return an invalid Hash if one is not found. <p> - * Check with isValidHash(). <p> + * The hash will be guaranteed to pass isValidHash(). <p> * Will not return Null. */ public static String getHashFromDataStack(ItemStack aDataStick) { if (isItemDataStick(aDataStick) && aDataStick.hasTagCompound()) { NBTTagCompound aNBT = aDataStick.getTagCompound(); - if (aNBT.hasKey("Data.Recipe.Hash")) { - return aNBT.getString("Data.Recipe.Hash"); - + if (aNBT.hasKey("Data.Recipe.Hash", NBT.TAG_STRING)) { + String hash = aNBT.getString("Data.Recipe.Hash"); + if (isValidHash(hash)) + return hash; } } return "Invalid.Recipe.Hash"; diff --git a/src/main/java/gregtech/api/util/GT_Recipe.java b/src/main/java/gregtech/api/util/GT_Recipe.java index 1b54e10795..84d4eb25c7 100644 --- a/src/main/java/gregtech/api/util/GT_Recipe.java +++ b/src/main/java/gregtech/api/util/GT_Recipe.java @@ -556,7 +556,7 @@ public class GT_Recipe implements Comparable<GT_Recipe> { public static class GT_Recipe_AssemblyLine{ public static final ArrayList<GT_Recipe_AssemblyLine> sAssemblylineRecipes = new ArrayList<GT_Recipe_AssemblyLine>(); - + public ItemStack mResearchItem; public int mResearchTime; public ItemStack[] mInputs; @@ -567,10 +567,31 @@ public class GT_Recipe implements Comparable<GT_Recipe> { public ItemStack[][] mOreDictAlt; private int mPersistentHash; + /** + * THIS CONSTRUCTOR DOES SET THE PERSISTENT HASH. + * + * if you set one yourself, it will give you one of the RunetimeExceptions! + */ public GT_Recipe_AssemblyLine(ItemStack aResearchItem, int aResearchTime, ItemStack[] aInputs, FluidStack[] aFluidInputs, ItemStack aOutput, int aDuration, int aEUt) { this(aResearchItem, aResearchTime, aInputs, aFluidInputs, aOutput, aDuration, aEUt, new ItemStack[aInputs.length][]); + int tPersistentHash = 1; + for (ItemStack tInput : aInputs) + tPersistentHash = tPersistentHash * 31 + GT_Utility.persistentHash(tInput, true, false); + tPersistentHash = tPersistentHash * 31 + GT_Utility.persistentHash(aResearchItem, true, false); + tPersistentHash = tPersistentHash * 31 + GT_Utility.persistentHash(aOutput, true, false); + for (FluidStack tFluidInput : aFluidInputs) + tPersistentHash = tPersistentHash * 31 + GT_Utility.persistentHash(tFluidInput, true, false); + tPersistentHash = tPersistentHash * 31 + aResearchTime; + tPersistentHash = tPersistentHash * 31 + aDuration; + tPersistentHash = tPersistentHash * 31 + aEUt; + setPersistentHash(tPersistentHash); } - + + /** + * THIS CONSTRUCTOR DOES <b>NOT</b> SET THE PERSISTENT HASH. + * + * if you don't set one yourself, it will break a lot of stuff! + */ public GT_Recipe_AssemblyLine(ItemStack aResearchItem, int aResearchTime, ItemStack[] aInputs, FluidStack[] aFluidInputs, ItemStack aOutput, int aDuration, int aEUt, ItemStack[][] aAlt) { mResearchItem = aResearchItem; mResearchTime = aResearchTime; @@ -661,9 +682,30 @@ public class GT_Recipe implements Comparable<GT_Recipe> { } public int getPersistentHash() { + if (mPersistentHash == 0) + GT_Log.err.println("Assline recipe persistent hash has not been set! Recipe: " + mOutput); return mPersistentHash; } + @Override + public String toString() { + return "GT_Recipe_AssemblyLine{" + + "mResearchItem=" + mResearchItem + + ", mResearchTime=" + mResearchTime + + ", mInputs=" + Arrays.toString(mInputs) + + ", mFluidInputs=" + Arrays.toString(mFluidInputs) + + ", mOutput=" + mOutput + + ", mDuration=" + mDuration + + ", mEUt=" + mEUt + + ", mOreDictAlt=" + Arrays.toString(mOreDictAlt) + + '}'; + } + + /** + * @param aPersistentHash the persistent hash. it should reflect the exact input used to generate this recipe + * If 0 is passed in, the actual persistent hash will be automatically remapped to 1 instead. + * @throws IllegalStateException if the persistent hash has been set already + */ public void setPersistentHash(int aPersistentHash) { if (this.mPersistentHash != 0) throw new IllegalStateException("Cannot set persistent hash twice!"); @@ -671,6 +713,7 @@ public class GT_Recipe implements Comparable<GT_Recipe> { this.mPersistentHash = 1; else this.mPersistentHash = aPersistentHash; + GT_AssemblyLineUtils.addRecipeToCache(this); } } diff --git a/src/main/java/gregtech/common/GT_RecipeAdder.java b/src/main/java/gregtech/common/GT_RecipeAdder.java index f130c65adf..72a187f23a 100644 --- a/src/main/java/gregtech/common/GT_RecipeAdder.java +++ b/src/main/java/gregtech/common/GT_RecipeAdder.java @@ -1422,17 +1422,6 @@ public class GT_RecipeAdder implements IGT_RecipeAdder { GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe(false, new ItemStack[]{aResearchItem}, new ItemStack[]{aOutput}, new ItemStack[]{ItemList.Tool_DataStick.getWithName(1L, "Writes Research result", new Object[0])}, null, null, aResearchTime, 30, -201); GT_Recipe.GT_Recipe_Map.sAssemblylineVisualRecipes.addFakeRecipe(false, aInputs, new ItemStack[]{aOutput}, new ItemStack[]{ItemList.Tool_DataStick.getWithName(1L, "Reads Research result", new Object[0])}, aFluidInputs, null, aDuration, aEUt, 0,true); GT_Recipe_AssemblyLine tRecipe = new GT_Recipe_AssemblyLine(aResearchItem, aResearchTime, aInputs, aFluidInputs, aOutput, aDuration, aEUt); - int tPersistentHash = 1; - for (ItemStack tInput : aInputs) - tPersistentHash = tPersistentHash * 31 + GT_Utility.persistentHash(tInput, true, false); - tPersistentHash = tPersistentHash * 31 + GT_Utility.persistentHash(aResearchItem, true, false); - tPersistentHash = tPersistentHash * 31 + GT_Utility.persistentHash(aOutput, true, false); - for (FluidStack tFluidInput : aFluidInputs) - tPersistentHash = tPersistentHash * 31 + GT_Utility.persistentHash(tFluidInput, true, false); - tPersistentHash = tPersistentHash * 31 + aResearchTime; - tPersistentHash = tPersistentHash * 31 + aDuration; - tPersistentHash = tPersistentHash * 31 + aEUt; - tRecipe.setPersistentHash(tPersistentHash == 0 ? 1 : tPersistentHash); GT_Recipe.GT_Recipe_AssemblyLine.sAssemblylineRecipes.add(tRecipe); return true; } @@ -1508,7 +1497,7 @@ public class GT_RecipeAdder implements IGT_RecipeAdder { GT_Recipe.GT_Recipe_Map.sScannerFakeRecipes.addFakeRecipe(false, new ItemStack[]{aResearchItem}, new ItemStack[]{aOutput}, new ItemStack[]{ItemList.Tool_DataStick.getWithName(1L, "Writes Research result", new Object[0])}, null, null, aResearchTime, 30, -201); GT_Recipe.GT_Recipe_Map.sAssemblylineVisualRecipes.addFakeRecipe(false,tInputs,new ItemStack[]{aOutput},new ItemStack[]{ItemList.Tool_DataStick.getWithName(1L, "Reads Research result", new Object[0])},aFluidInputs,null,aDuration,aEUt,0,tAlts,true); GT_Recipe_AssemblyLine tRecipe = new GT_Recipe_AssemblyLine(aResearchItem, aResearchTime, tInputs, aFluidInputs, aOutput, aDuration, aEUt, tAlts); - tRecipe.setPersistentHash(tPersistentHash == 0 ? 1 : tPersistentHash); + tRecipe.setPersistentHash(tPersistentHash); GT_Recipe.GT_Recipe_AssemblyLine.sAssemblylineRecipes.add(tRecipe); return true; } |