diff options
-rw-r--r-- | src/main/java/gregtech/GT_Mod.java | 4 | ||||
-rw-r--r-- | src/main/java/gregtech/api/GregTech_API.java | 6 | ||||
-rw-r--r-- | src/main/java/gregtech/api/enums/OrePrefixes.java | 14 | ||||
-rw-r--r-- | src/main/java/gregtech/api/objects/GT_ItemStack.java | 38 | ||||
-rw-r--r-- | src/main/java/gregtech/api/objects/GT_ItemStack2.java | 3 | ||||
-rw-r--r-- | src/main/java/gregtech/api/util/GT_OreDictUnificator.java | 43 | ||||
-rw-r--r-- | src/main/java/gregtech/api/util/GT_Recipe.java | 20 | ||||
-rw-r--r-- | src/main/java/gregtech/api/util/GT_Utility.java | 27 |
8 files changed, 118 insertions, 37 deletions
diff --git a/src/main/java/gregtech/GT_Mod.java b/src/main/java/gregtech/GT_Mod.java index 645702055b..90791c95f2 100644 --- a/src/main/java/gregtech/GT_Mod.java +++ b/src/main/java/gregtech/GT_Mod.java @@ -128,7 +128,7 @@ import ic2.api.recipe.RecipeOutput; version = "MC1710", guiFactory = "gregtech.client.GT_GuiFactory", dependencies = " required-after:IC2;" + " required-after:structurelib;" - + " required-after:gtnhlib@[0.0.8,);" + + " required-after:gtnhlib@[0.2.1,);" + " required-after:modularui@[1.1.12,);" + " required-after:appliedenergistics2@[rv3-beta-258,);" + " after:dreamcraft;" @@ -796,7 +796,7 @@ public class GT_Mod implements IGT_Mod { GT_Utility.reInit(); GT_Recipe.reInit(); try { - for (Map<? extends ItemHolder, ?> gt_itemStackMap : GregTech_API.sItemStackMappings) { + for (Map<?, ?> gt_itemStackMap : GregTech_API.sItemStackMappings) { GT_Utility.reMap(gt_itemStackMap); } for (SetMultimap<? extends ItemHolder, ?> gt_itemStackMap : GregTech_API.itemStackMultiMaps) { diff --git a/src/main/java/gregtech/api/GregTech_API.java b/src/main/java/gregtech/api/GregTech_API.java index 1f936f3119..7617b2c195 100644 --- a/src/main/java/gregtech/api/GregTech_API.java +++ b/src/main/java/gregtech/api/GregTech_API.java @@ -107,8 +107,12 @@ public class GregTech_API { public static final long FLUID_MATERIAL_UNIT = L; /** * Fixes the HashMap Mappings for ItemStacks once the Server started + * <br> + * <br> + * NOTE: We use wildcards generics for the key because it could be for example {@link ItemStack} or + * {@link GT_ItemStack} */ - public static final Collection<Map<? extends ItemHolder, ?>> sItemStackMappings = new ArrayList<>(); + public static final Collection<Map<?, ?>> sItemStackMappings = new ArrayList<>(); public static final Collection<SetMultimap<? extends ItemHolder, ?>> itemStackMultiMaps = new ArrayList<>(); /** diff --git a/src/main/java/gregtech/api/enums/OrePrefixes.java b/src/main/java/gregtech/api/enums/OrePrefixes.java index e9294e7258..26dee844e7 100644 --- a/src/main/java/gregtech/api/enums/OrePrefixes.java +++ b/src/main/java/gregtech/api/enums/OrePrefixes.java @@ -20,13 +20,14 @@ import gregtech.api.interfaces.ICondition; import gregtech.api.interfaces.IOreRecipeRegistrator; import gregtech.api.interfaces.ISubTagContainer; import gregtech.api.objects.GT_ArrayList; -import gregtech.api.objects.GT_HashSet; -import gregtech.api.objects.GT_ItemStack2; +import gregtech.api.objects.GT_ItemStack; import gregtech.api.objects.ItemData; import gregtech.api.objects.MaterialStack; import gregtech.api.util.GT_Log; import gregtech.api.util.GT_Utility; import gregtech.loaders.materialprocessing.ProcessingModSupport; +import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; +import it.unimi.dsi.fastutil.objects.ObjectSet; public enum OrePrefixes { @@ -1015,7 +1016,10 @@ public enum OrePrefixes { public MaterialStack mSecondaryMaterial = null; public OrePrefixes mPrefixInto = this; public float mHeatDamage = 0.0F; // Negative for Frost Damage - private final GT_HashSet<GT_ItemStack2> mContainsTestCache = new GT_HashSet<>(512, 0.5f); + private final ObjectSet<ItemStack> mContainsTestCache = new ObjectOpenCustomHashSet<>( + 512, + 0.5f, + GT_ItemStack.ITEMSTACK_HASH_STRATEGY2); public static final List<OrePrefixes> mPreventableComponents = new LinkedList<>( Arrays.asList( OrePrefixes.gem, @@ -1205,13 +1209,13 @@ public enum OrePrefixes { if (!contains(aStack)) { mPrefixedItems.add(aStack); // It's now in there... so update the cache - mContainsTestCache.add(new GT_ItemStack2(aStack)); + mContainsTestCache.add(aStack); } return true; } public boolean contains(ItemStack aStack) { - return !GT_Utility.isStackInvalid(aStack) && mContainsTestCache.contains(new GT_ItemStack2(aStack)); + return !GT_Utility.isStackInvalid(aStack) && mContainsTestCache.contains(aStack); } public boolean containsUnCached(ItemStack aStack) { diff --git a/src/main/java/gregtech/api/objects/GT_ItemStack.java b/src/main/java/gregtech/api/objects/GT_ItemStack.java index 210f807c5d..492655740d 100644 --- a/src/main/java/gregtech/api/objects/GT_ItemStack.java +++ b/src/main/java/gregtech/api/objects/GT_ItemStack.java @@ -7,6 +7,7 @@ import net.minecraft.item.ItemStack; import gregtech.api.enums.GT_Values; import gregtech.api.util.GT_Utility; import gregtech.api.util.item.ItemHolder; +import it.unimi.dsi.fastutil.Hash; /** * An optimization of {@link ItemStack} to have a better {@code hashcode} and {@code equals} in order to improve @@ -14,6 +15,25 @@ import gregtech.api.util.item.ItemHolder; */ public class GT_ItemStack extends ItemHolder { + /** + * A better {@link Hash.Strategy} for {@link ItemStack}. Implementation originally from {@code GT_ItemStack2}. + */ + public static final Hash.Strategy<ItemStack> ITEMSTACK_HASH_STRATEGY2 = new Hash.Strategy<>() { + + @Override + public int hashCode(ItemStack o) { + return o.getItem() + .hashCode() * 38197 + Items.feather.getDamage(o); + } + + @Override + public boolean equals(ItemStack a, ItemStack b) { + if (a == b) return true; + if (a == null || b == null) return false; + return a.getItem() == b.getItem() && Items.feather.getDamage(a) == Items.feather.getDamage(b); + } + }; + public final Item mItem; public final byte mStackSize; public final short mMetaData; @@ -66,4 +86,22 @@ public class GT_ItemStack extends ItemHolder { public int hashCode() { return GT_Utility.stackToInt(toStack()); } + + /** + * @see #internalCopyStack(ItemStack, boolean) + */ + public static ItemStack internalCopyStack(ItemStack aStack) { + return internalCopyStack(aStack, false); + } + + /** + * Replicates the copy behavior of {@link #toStack()} but for normal {@link ItemStack}s. + * + * @param aStack the stack to copy + * @param wildcard whether to use wildcard damage value + * @return a copy of the stack with stack size 1 and no NBT + */ + public static ItemStack internalCopyStack(ItemStack aStack, boolean wildcard) { + return new ItemStack(aStack.getItem(), 1, wildcard ? GT_Values.W : Items.feather.getDamage(aStack)); + } } diff --git a/src/main/java/gregtech/api/objects/GT_ItemStack2.java b/src/main/java/gregtech/api/objects/GT_ItemStack2.java index b137e78829..aa93876830 100644 --- a/src/main/java/gregtech/api/objects/GT_ItemStack2.java +++ b/src/main/java/gregtech/api/objects/GT_ItemStack2.java @@ -7,7 +7,10 @@ import net.minecraft.item.ItemStack; * GT_ItemStack, but with a better hashCode(). Due to this change, it should not be placed in the same hash based data * structure with GT_ItemStack. It also shouldn't be used to construct search query into a hash based data structure * that contains GT_ItemStack. + * + * @deprecated See {@link GT_ItemStack#ITEMSTACK_HASH_STRATEGY2} */ +@Deprecated public class GT_ItemStack2 extends GT_ItemStack { public GT_ItemStack2(Item aItem, long aStackSize, long aMetaData) { diff --git a/src/main/java/gregtech/api/util/GT_OreDictUnificator.java b/src/main/java/gregtech/api/util/GT_OreDictUnificator.java index 2d493ebe2d..7032fc87fc 100644 --- a/src/main/java/gregtech/api/util/GT_OreDictUnificator.java +++ b/src/main/java/gregtech/api/util/GT_OreDictUnificator.java @@ -7,7 +7,6 @@ import static gregtech.api.enums.GT_Values.W; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -25,9 +24,10 @@ import gregtech.api.enums.Materials; import gregtech.api.enums.OrePrefixes; import gregtech.api.enums.SubTag; import gregtech.api.objects.GT_ItemStack; -import gregtech.api.objects.GT_ItemStack2; import gregtech.api.objects.ItemData; import gregtech.api.objects.MaterialStack; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; +import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; /** * NEVER INCLUDE THIS FILE IN YOUR MOD!!! @@ -41,9 +41,12 @@ import gregtech.api.objects.MaterialStack; public class GT_OreDictUnificator { private static final Map<String, ItemStack> sName2StackMap = new HashMap<>(); - private static final Map<GT_ItemStack2, ItemData> sItemStack2DataMap = new HashMap<>(); - private static final Map<GT_ItemStack2, List<ItemStack>> sUnificationTable = new HashMap<>(); - private static final Set<GT_ItemStack2> sNoUnificationList = new HashSet<>(); + private static final Map<ItemStack, ItemData> sItemStack2DataMap = new Object2ObjectOpenCustomHashMap<>( + GT_ItemStack.ITEMSTACK_HASH_STRATEGY2); + private static final Map<ItemStack, List<ItemStack>> sUnificationTable = new Object2ObjectOpenCustomHashMap<>( + GT_ItemStack.ITEMSTACK_HASH_STRATEGY2); + private static final Set<ItemStack> sNoUnificationList = new ObjectOpenCustomHashSet<>( + GT_ItemStack.ITEMSTACK_HASH_STRATEGY2); private static int isRegisteringOre = 0, isAddingOre = 0; private static boolean mRunThroughTheList = true; @@ -57,12 +60,12 @@ public class GT_OreDictUnificator { * the Industrial Diamond, which is better than regular Diamond, but also usable in absolutely all Diamond Recipes. */ public static void addToBlacklist(ItemStack aStack) { - if (GT_Utility.isStackValid(aStack) && !GT_Utility.isStackInList(aStack, sNoUnificationList)) - sNoUnificationList.add(new GT_ItemStack2(aStack)); + if (GT_Utility.isStackValid(aStack) && !GT_Utility.isStackInStackSet(aStack, sNoUnificationList)) + sNoUnificationList.add(aStack); } public static boolean isBlacklisted(ItemStack aStack) { - return GT_Utility.isStackInList(aStack, sNoUnificationList); + return GT_Utility.isStackInStackSet(aStack, sNoUnificationList); } public static void add(OrePrefixes aPrefix, Materials aMaterial, ItemStack aStack) { @@ -281,12 +284,11 @@ public class GT_OreDictUnificator { // 5900x tries to do NEI lookup synchronized (sUnificationTable) { if (sUnificationTable.isEmpty() && !sItemStack2DataMap.isEmpty()) { - for (GT_ItemStack tGTStack0 : sItemStack2DataMap.keySet()) { - ItemStack tStack0 = tGTStack0.toStack(); + for (ItemStack tGTStack0 : sItemStack2DataMap.keySet()) { + ItemStack tStack0 = GT_ItemStack.internalCopyStack(tGTStack0); ItemStack tStack1 = get_nocopy(false, tStack0); if (!GT_Utility.areStacksEqual(tStack0, tStack1)) { - GT_ItemStack2 tGTStack1 = new GT_ItemStack2(tStack1); - List<ItemStack> list = sUnificationTable.computeIfAbsent(tGTStack1, k -> new ArrayList<>()); + List<ItemStack> list = sUnificationTable.computeIfAbsent(tStack1, k -> new ArrayList<>()); // greg's original code tries to dedupe the list using List#contains, which won't work // on vanilla ItemStack. I removed it since it never worked and can be slow. list.add(tStack0); @@ -303,7 +305,7 @@ public class GT_OreDictUnificator { for (ItemStack aStack : aStacks) { if (aStack == null) continue; rList.add(aStack); - List<ItemStack> tList = sUnificationTable.get(new GT_ItemStack2(aStack)); + List<ItemStack> tList = sUnificationTable.get(aStack); if (tList != null) { for (ItemStack tStack : tList) { ItemStack tStack1 = GT_Utility.copyAmount(aStack.stackSize, tStack); @@ -346,7 +348,7 @@ public class GT_OreDictUnificator { for (MaterialStack tMaterial : aData.mByProducts) tMaterial.mAmount /= aStack.stackSize; aStack = GT_Utility.copyAmount(1, aStack); } - sItemStack2DataMap.put(new GT_ItemStack2(aStack), aData); + sItemStack2DataMap.put(aStack, aData); if (aData.hasValidMaterialData()) { long tValidMaterialAmount = aData.mMaterial.mMaterial.contains(SubTag.NO_RECYCLING) ? 0 : aData.mMaterial.mAmount >= 0 ? aData.mMaterial.mAmount : M; @@ -358,11 +360,10 @@ public class GT_OreDictUnificator { if (mRunThroughTheList) { if (GregTech_API.sLoadStarted) { mRunThroughTheList = false; - for (Entry<GT_ItemStack2, ItemData> tEntry : sItemStack2DataMap.entrySet()) if (!tEntry.getValue() + for (Entry<ItemStack, ItemData> tEntry : sItemStack2DataMap.entrySet()) if (!tEntry.getValue() .hasValidPrefixData() || tEntry.getValue().mPrefix.mAllowNormalRecycling) GT_RecipeRegistrator.registerMaterialRecycling( - tEntry.getKey() - .toStack(), + GT_ItemStack.internalCopyStack(tEntry.getKey()), tEntry.getValue()); } } else { @@ -379,7 +380,7 @@ public class GT_OreDictUnificator { if (GT_Utility.isStackInvalid(aStack)) { return; } - sItemStack2DataMap.remove(new GT_ItemStack2(aStack)); + sItemStack2DataMap.remove(aStack); } public static void addAssociation(OrePrefixes aPrefix, Materials aMaterial, ItemStack aStack, @@ -393,8 +394,10 @@ public class GT_OreDictUnificator { @Nullable public static ItemData getItemData(ItemStack aStack) { if (GT_Utility.isStackInvalid(aStack)) return null; - ItemData rData = sItemStack2DataMap.get(new GT_ItemStack2(aStack)); - if (rData == null) rData = sItemStack2DataMap.get(new GT_ItemStack2(aStack, true)); + ItemData rData = sItemStack2DataMap.get(aStack); + if (rData == null) { // Try the lookup again but with wildcard damage value + rData = sItemStack2DataMap.get(GT_ItemStack.internalCopyStack(aStack, true)); + } return rData; } diff --git a/src/main/java/gregtech/api/util/GT_Recipe.java b/src/main/java/gregtech/api/util/GT_Recipe.java index a7c6c654e7..b06c7f9e64 100644 --- a/src/main/java/gregtech/api/util/GT_Recipe.java +++ b/src/main/java/gregtech/api/util/GT_Recipe.java @@ -36,6 +36,8 @@ import gregtech.api.recipe.metadata.IRecipeMetadataStorage; import gregtech.api.util.extensions.ArrayExt; import gregtech.api.util.item.ItemHolder; import ic2.core.Ic2Items; +import it.unimi.dsi.fastutil.objects.Reference2LongArrayMap; +import it.unimi.dsi.fastutil.objects.Reference2LongMap; public class GT_Recipe implements Comparable<GT_Recipe> { @@ -486,25 +488,27 @@ public class GT_Recipe implements Comparable<GT_Recipe> { double currentParallel = maxParallel; - if (aFluidInputs != null) { + // We need to have any fluids inputs, otherwise the code below does nothing. The second check is always true + // because of early exit condition above. + if (mFluidInputs.length > 0 /* && aFluidInputs != null */) { // Create map for fluid -> stored amount - Map<Fluid, Long> fluidMap = new HashMap<>(); - Map<Fluid, Long> fluidCost = new HashMap<>(); + Reference2LongMap<Fluid> fluidMap = new Reference2LongArrayMap<>(4); + Reference2LongMap<Fluid> fluidCost = new Reference2LongArrayMap<>(4); for (FluidStack fluidStack : aFluidInputs) { if (fluidStack == null) continue; - fluidMap.merge(fluidStack.getFluid(), (long) fluidStack.amount, Long::sum); + fluidMap.mergeLong(fluidStack.getFluid(), fluidStack.amount, Long::sum); } for (FluidStack fluidStack : mFluidInputs) { if (fluidStack == null) continue; - fluidCost.merge(fluidStack.getFluid(), (long) fluidStack.amount, Long::sum); + fluidCost.mergeLong(fluidStack.getFluid(), fluidStack.amount, Long::sum); } // Check how many parallels can it perform for each fluid - for (Map.Entry<Fluid, Long> costEntry : fluidCost.entrySet()) { - if (costEntry.getValue() > 0) { + for (Reference2LongMap.Entry<Fluid> costEntry : fluidCost.reference2LongEntrySet()) { + if (costEntry.getLongValue() > 0) { currentParallel = Math.min( currentParallel, - (double) fluidMap.getOrDefault(costEntry.getKey(), 0L) / costEntry.getValue()); + (double) fluidMap.getOrDefault(costEntry.getKey(), 0L) / costEntry.getLongValue()); } if (currentParallel <= 0) { return 0; diff --git a/src/main/java/gregtech/api/util/GT_Utility.java b/src/main/java/gregtech/api/util/GT_Utility.java index d41e2a3b04..7959789532 100644 --- a/src/main/java/gregtech/api/util/GT_Utility.java +++ b/src/main/java/gregtech/api/util/GT_Utility.java @@ -3137,6 +3137,13 @@ public class GT_Utility { return aList[aIndex]; } + public static boolean isStackInStackSet(ItemStack aStack, Set<ItemStack> aSet) { + if (aStack == null) return false; + if (aSet.contains(aStack)) return true; + + return aSet.contains(GT_ItemStack.internalCopyStack(aStack, true)); + } + public static boolean isStackInList(ItemStack aStack, Collection<GT_ItemStack> aList) { if (aStack == null) { return false; @@ -3165,7 +3172,25 @@ public class GT_Utility { * re-maps all Keys of a Map after the Keys were weakened. */ public static <X, Y> Map<X, Y> reMap(Map<X, Y> aMap) { - Map<X, Y> tMap = new HashMap<>(aMap); + Map<X, Y> tMap = null; + // We try to clone the Map first (most Maps are Cloneable) in order to retain as much state of the Map as + // possible when rehashing. For example, "Custom" HashMaps from fastutil may have a custom hash function which + // would not be used to rehash if we just create a new HashMap. + if (aMap instanceof Cloneable) { + try { + tMap = (Map<X, Y>) aMap.getClass() + .getMethod("clone") + .invoke(aMap); + } catch (Throwable e) { + GT_Log.err.println("Failed to clone Map of type " + aMap.getClass()); + e.printStackTrace(GT_Log.err); + } + } + + if (tMap == null) { + tMap = new HashMap<>(aMap); + } + aMap.clear(); aMap.putAll(tMap); return aMap; |