CoFHLib HashFix

Hey greg, just a quick note/headsup.

I was dealing with the good old

IllegalArgumentException: Equal objects must have equal hashcodes

crash from CoFH’s itemwrapper, and while investigating I noticed the HashFix transformer in GT6.
The function does an equals check for hashcode rather than hashCode, so that asm transformer never gets applied.

Not that it matters since the whole cofh thing still breaks so I don’t think this thing was ever tested? I don’t know enough about objects and equality in java to make sense of any of this; I’d just figured I’d let you know atleast…

3 Likes

You say it does not work even IF it is fixed to hashCode? Did you test that?

Also if you have Factorization, please update it, it does some unregistered Items to the OreDict and someone forked it to fix that. Should be linked on my Downloads Page somewhere. ^^

This Issue generally happens when a Mod registers things to the OreDictionary BEFORE registering it to the Item Registry.

2 Likes

Correct, it still does. And no, not using Factorization.

gregtech_1.7.10-6.17.00-33-gc86dcb955-dirty.jar

[20:15:24] [Client thread/INFO] [GT_ASM/CoFHCore]: Transforming cofh.lib.util.ComparableItem.hashCode

[20:15:56] [Client thread/ERROR] [FML/gregapi]: Exception caught during firing event net.minecraftforge.oredict.OreDictionary$OreRegisterEvent@34aae7d5:
java.lang.IllegalArgumentException: Equal objects must have equal hashcodes. During rehashing, Trove discovered that the following two objects claim to be equal (as in java.lang.Object.equals()) but their hashCodes (or those calculated by your TObjectHashingStrategy) are not equal.This violates the general contract of java.lang.Object.hashCode().  See bullet point two in that method's documentation. object #1 =class cofh.lib.util.ItemWrapper id= 1915621763 hashCode= 1915621763 toString= cofh.lib.util.ItemWrapper@1915621763{m:0, i:DelirusCrux.Netherlicious.Common.ItemBlocks.ItemBlockFullWood@764879660, v:1331}; object #2 =class cofh.lib.util.ItemWrapper id= 1220979379 hashCode= 1220979379 toString= cofh.lib.util.ItemWrapper@1220979379{m:0, i:DelirusCrux.Netherlicious.Common.ItemBlocks.ItemBlockFullWood@764879660, v:1331}

	at gnu.trove.impl.hash.TObjectHash.buildObjectContractViolation(TObjectHash.java:464) ~[TObjectHash.class:3.0.3]
	at gnu.trove.impl.hash.TObjectHash.throwObjectContractViolation(TObjectHash.java:448) ~[TObjectHash.class:3.0.3]
	at gnu.trove.map.hash.THashMap.rehash(THashMap.java:403) ~[THashMap.class:3.0.3]
	at gnu.trove.impl.hash.THash.postInsertHook(THash.java:388) ~[THash.class:3.0.3]
	at gnu.trove.map.hash.THashMap.doPut(THashMap.java:178) ~[THashMap.class:3.0.3]
	at gnu.trove.map.hash.THashMap.put(THashMap.java:145) ~[THashMap.class:3.0.3]
	at cofh.core.util.oredict.OreDictionaryArbiter.registerOreDictionaryEntry(OreDictionaryArbiter.java:92) ~[OreDictionaryArbiter.class:?]
	at cofh.core.Proxy.onOreRegisterEvent(Proxy.java:100) ~[Proxy.class:?]
	at cpw.mods.fml.common.eventhandler.ASMEventHandler_275_Proxy_onOreRegisterEvent_OreRegisterEvent.invoke(.dynamic) ~[?:?]
	at cpw.mods.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:54) ~[ASMEventHandler.class:?]
	at cpw.mods.fml.common.eventhandler.EventBus.post(EventBus.java:140) [EventBus.class:?]
	at net.minecraftforge.oredict.OreDictionary.registerOreImpl(Unknown Source) [OreDictionary.class:?]
	at net.minecraftforge.oredict.OreDictionary.registerOre(Unknown Source) [OreDictionary.class:?]
	at gregapi.oredict.OreDictManager.registerOre_(OreDictManager.java:761) [OreDictManager.class:?]
	at gregapi.oredict.OreDictManager.setTarget_(OreDictManager.java:520) [OreDictManager.class:?]
	at gregapi.oredict.OreDictManager.addTarget_(OreDictManager.java:492) [OreDictManager.class:?]
	at gregapi.block.prefixblock.PrefixBlock.run(PrefixBlock.java:245) [PrefixBlock.class:?]
	at gregapi.api.Abstract_Mod.loadRunnables(Abstract_Mod.java:140) [Abstract_Mod.class:?]
	at gregapi.api.Abstract_Mod.onModInit(Abstract_Mod.java:205) [Abstract_Mod.class:?]
	at gregapi.GT_API.onLoad(GT_API.java:258) [GT_API.class:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_382]
[...]
java.lang.IllegalArgumentException: Equal objects must have equal hashcodes. During rehashing, Trove discovered that the following two objects claim to be equal (as in java.lang.Object.equals()) but their hashCodes (or those calculated by your TObjectHashingStrategy) are not equal.This violates the general contract of java.lang.Object.hashCode().  See bullet point two in that method's documentation. object #1 =class cofh.thermalexpansion.util.crafting.SmelterManager$ComparableItemStackSmelter id= 924717358 hashCode= 924717358 toString= cofh.thermalexpansion.util.crafting.SmelterManager$ComparableItemStackSmelter@924717358{m:0, i:net.minecraft.item.ItemMultiTexture@259604245, v:12}; object #2 =class cofh.thermalexpansion.util.crafting.SmelterManager$ComparableItemStackSmelter id= 982362316 hashCode= 982362316 toString= cofh.thermalexpansion.util.crafting.SmelterManager$ComparableItemStackSmelter@982362316{m:0, i:net.minecraft.item.ItemMultiTexture@259604245, v:12}

	at gnu.trove.impl.hash.TObjectHash.buildObjectContractViolation(TObjectHash.java:464)
	at gnu.trove.impl.hash.TObjectHash.throwObjectContractViolation(TObjectHash.java:448)
	at gnu.trove.set.hash.THashSet.rehash(THashSet.java:172)
	at gnu.trove.impl.hash.THash.postInsertHook(THash.java:388)
	at gnu.trove.set.hash.THashSet.add(THashSet.java:112)
	at cofh.thermalexpansion.util.crafting.SmelterManager.addRecipe(SmelterManager.java:329)
	at cofh.thermalexpansion.util.crafting.SmelterManager.addRecipe(SmelterManager.java:526)
	at cofh.thermalexpansion.util.crafting.SmelterManager.addDustToIngotRecipe(SmelterManager.java:447)
	at cofh.thermalexpansion.util.crafting.SmelterManager.addDefaultOreDictionaryRecipe(SmelterManager.java:357)
	at cofh.thermalexpansion.util.crafting.SmelterManager.addDefaultOreDictionaryRecipe(SmelterManager.java:421)
	at cofh.thermalexpansion.util.crafting.SmelterManager.addDefaultRecipes(SmelterManager.java:148)
	at cofh.thermalexpansion.ThermalExpansion.postInit(ThermalExpansion.java:177)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at cpw.mods.fml.common.FMLModContainer.handleModStateEvent(FMLModContainer.java:532)
	at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74)
[...]

etc. Adding or removing mods will of course change up the collision…

[20:37:24] [Client thread/TRACE] [ThermalFoundation/ThermalFoundation]: Sending event FMLPreInitializationEvent to mod ThermalFoundation
[20:37:24] [Client thread/ERROR] [FML/ThermalFoundation]: Exception caught during firing event net.minecraftforge.oredict.OreDictionary$OreRegisterEvent@19cf7960:
java.lang.IllegalArgumentException: Equal objects must have equal hashcodes. During rehashing, Trove discovered that the following two objects claim to be equal (as in java.lang.Object.equals()) but their hashCodes (or those calculated by your TObjectHashingStrategy) are not equal.This violates the general contract of java.lang.Object.hashCode().  See bullet point two in that method's documentation. object #1 =class cofh.lib.util.ItemWrapper id= 596431057 hashCode= 596431057 toString= cofh.lib.util.ItemWrapper@596431057{m:16, i:cofh.core.item.ItemBase@811577645, v:4911}; object #2 =class cofh.lib.util.ItemWrapper id= 880796814 hashCode= 880796814 toString= cofh.lib.util.ItemWrapper@880796814{m:16, i:cofh.core.item.ItemBase@811577645, v:4911}

	at gnu.trove.impl.hash.TObjectHash.buildObjectContractViolation(TObjectHash.java:464) ~[TObjectHash.class:3.0.3]
	at gnu.trove.impl.hash.TObjectHash.throwObjectContractViolation(TObjectHash.java:448) ~[TObjectHash.class:3.0.3]
	at gnu.trove.map.hash.THashMap.rehash(THashMap.java:403) ~[THashMap.class:3.0.3]
	at gnu.trove.impl.hash.THash.postInsertHook(THash.java:388) ~[THash.class:3.0.3]
	at gnu.trove.map.hash.THashMap.doPut(THashMap.java:178) ~[THashMap.class:3.0.3]
	at gnu.trove.map.hash.THashMap.put(THashMap.java:145) ~[THashMap.class:3.0.3]
	at cofh.core.util.oredict.OreDictionaryArbiter.registerOreDictionaryEntry(OreDictionaryArbiter.java:92) ~[OreDictionaryArbiter.class:?]
	at cofh.core.Proxy.onOreRegisterEvent(Proxy.java:100) ~[Proxy.class:?]
	at cpw.mods.fml.common.eventhandler.ASMEventHandler_275_Proxy_onOreRegisterEvent_OreRegisterEvent.invoke(.dynamic) ~[?:?]
	at cpw.mods.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:54) ~[ASMEventHandler.class:?]
	at cpw.mods.fml.common.eventhandler.EventBus.post(EventBus.java:140) [EventBus.class:?]
	at net.minecraftforge.oredict.OreDictionary.registerOreImpl(Unknown Source) [OreDictionary.class:?]
	at net.minecraftforge.oredict.OreDictionary.registerOre(Unknown Source) [OreDictionary.class:?]
	at cofh.core.item.ItemBase.addOreDictItem(ItemBase.java:133) [ItemBase.class:?]
	at cofh.thermalfoundation.item.TFItems.preInit(TFItems.java:82) [TFItems.class:?]
	at cofh.thermalfoundation.ThermalFoundation.preInit(ThermalFoundation.java:98) [ThermalFoundation.class:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_382]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_382]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_382]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_382]
	at cpw.mods.fml.common.FMLModContainer.handleModStateEvent(FMLModContainer.java:532) [FMLModContainer.class:?]
	at sun.reflect.GeneratedMethodAccessor5.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_382]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_382]
	at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74) [guava-17.0.jar:?]
	at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.post(EventBus.java:275) [guava-17.0.jar:?]
	at cpw.mods.fml.common.LoadController.sendEventToModContainer(LoadController.java:212) [LoadController.class:?]
	at cpw.mods.fml.common.LoadController.propogateStateMessage(LoadController.java:190) [LoadController.class:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_382]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_382]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_382]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_382]
	at com.google.common.eventbus.EventSubscriber.handleEvent(EventSubscriber.java:74) [guava-17.0.jar:?]
	at com.google.common.eventbus.SynchronizedEventSubscriber.handleEvent(SynchronizedEventSubscriber.java:47) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.dispatch(EventBus.java:322) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.dispatchQueuedEvents(EventBus.java:304) [guava-17.0.jar:?]
	at com.google.common.eventbus.EventBus.post(EventBus.java:275) [guava-17.0.jar:?]
	at cpw.mods.fml.common.LoadController.distributeStateMessage(LoadController.java:119) [LoadController.class:?]
	at cpw.mods.fml.common.Loader.preinitializeMods(Loader.java:556) [Loader.class:?]
	at cpw.mods.fml.client.FMLClientHandler.beginMinecraftLoading(FMLClientHandler.java:243) [FMLClientHandler.class:?]
	at net.minecraft.client.Minecraft.func_71384_a(Minecraft.java:480) [bao.class:?]
	at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:878) [bao.class:?]
	at net.minecraft.client.main.Main.main(SourceFile:148) [Main.class:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_382]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_382]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_382]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_382]
	at net.minecraft.launchwrapper.Launch.launch(Launch.java:135) [launchwrapper-1.12.jar:?]
	at net.minecraft.launchwrapper.Launch.main(Launch.java:28) [launchwrapper-1.12.jar:?]
	at org.prismlauncher.launcher.impl.StandardLauncher.launch(StandardLauncher.java:88) [NewLaunch.jar:?]
	at org.prismlauncher.EntryPoint.listen(EntryPoint.java:126) [NewLaunch.jar:?]
	at org.prismlauncher.EntryPoint.main(EntryPoint.java:71) [NewLaunch.jar:?]
[20:37:24] [Client thread/ERROR] [FML/ThermalFoundation]: Index: 4 Listeners:
[20:37:24] [Client thread/ERROR] [FML/ThermalFoundation]: 0: NORMAL
[20:37:24] [Client thread/ERROR] [FML/ThermalFoundation]: 1: ASM: gregapi.oredict.OreDictManager@302a6a92 onOreRegistration1(Lnet/minecraftforge/oredict/OreDictionary$OreRegisterEvent;)V
[20:37:24] [Client thread/ERROR] [FML/ThermalFoundation]: 2: ASM: appeng.recipes.ores.OreDictionaryHandler@8394ce onOreDictionaryRegister(Lnet/minecraftforge/oredict/OreDictionary$OreRegisterEvent;)V
[20:37:24] [Client thread/ERROR] [FML/ThermalFoundation]: 3: ASM: ic2.core.IC2@59067553 registerOre(Lnet/minecraftforge/oredict/OreDictionary$OreRegisterEvent;)V
[20:37:24] [Client thread/ERROR] [FML/ThermalFoundation]: 4: ASM: cofh.core.ProxyClient@42ad30bf onOreRegisterEvent(Lnet/minecraftforge/oredict/OreDictionary$OreRegisterEvent;)V
[20:37:24] [Client thread/TRACE] [ThermalFoundation/ThermalFoundation]: Sent event FMLPreInitializationEvent to mod ThermalFoundation
3 Likes

Okay, can you test with the Secret Version now?

1 Like

Thanks for caring about these other mods, testing…

I was using a custom build of TE with calls to its SmelterManager.addDefaultRecipes()|loadRecipes()|refreshRecipes() during init commented out, which let me work around the most common place where I’d see collisions.
It meant only 3rd party mods using TE’s API to add recipes to the TE Induction Smelter would show up in NEI (like ExU thickened glass and ProjRed red alloy ingots), which was fine since I don’t use TE machines, only its tools and such.

It would be the TE-custom in this matrix:

testing

While I can at least leave HashFix on now, I can still trigger it by adding ExU + letting the induction smelter load its recipes.

pastebin crash-report

Hmm…

2 Likes

Oh, and I guess I can sneak in an unrelated language fix in this thread while I’m at it.

Tips & Tricks with GregTech 6:
The proper verb is ‘halve’, not ‘half’, I believe…

2 Likes

Uhhhh, I need that version then, I’ve only been testing against the officially released versions.

1 Like

Also, for note, your issue resides in:

	at gnu.trove.set.hash.THashSet.add(THashSet.java:112)
	at cofh.thermalexpansion.util.crafting.SmelterManager.addTERecipe(SmelterManager.java:317)

That’s a bug in thermalexpansion, nothing to do with cofhlib or anything this fix could fix, it would require a ‘new’ asm to fix that, but since it had never been reported before I’m thinking it might be something in that fork you are running that is broken somehow?

1 Like

I mean, it’s the official builds that are crashing for me and my custom build just avoid the problem by never calling the offending code…

But trying to make sense of the crash…
SmelterManager.java:addTERecipe:317 is

[…]
314 │ RecipeSmelter recipe = new RecipeSmelter(primaryInput, secondaryInput, primaryOutput, secondaryOutput, secondaryChance, energy);
315 │ recipeMap.put(Arrays.asList(new ComparableItemStackSmelter(primaryInput), new ComparableItemStackSmelter(secondaryInput)), recipe);
316 │ validationSet.add(new ComparableItemStackSmelter(primaryInput));
317 │ validationSet.add(new ComparableItemStackSmelter(secondaryInput));
318 │ return true;

public static class ComparableItemStackSmelter extends ComparableItemStack {

ComparableItemStack is part of

import cofh.lib.inventory.ComparableItemStack;

import cofh.lib.util.ComparableItem;
[…]
public class ComparableItemStack extends ComparableItem {
[…]
@Override
public int hashCode() {
return oreID != -1 ? oreID : super.hashCode();

…and ComparableItem’s hashCode is the good old

// TODO: this hash conflicts a lot

So yeah, TE is buggy, but it’s still that cofhlib code that is causing troubles, I guess?
I’m not a java programmer :confused:

2 Likes

Yeah ComparableItemStack isn’t used in the crash area in cofh itself, doesn’t really seem to be used at all actually, guess only be dependent mods like TE. I have no interest in supporting the really buggy (and in my opinion poorly designed in a variety of ways) TE mod, but this should be simple to fix if that’s the class it is using, hold on…

1 Like

Ogod, it’s even worse than I expected! That proxy is caching the item ID from the ore dictionary of the given items… which change when loading other worlds, wtf…

How… like… who wrote this and how did they not know how this stuff works this poorly… o.O

1 Like

The ore ID isn’t even used for lookup or anything, it’s literally just used for comparisons, which sure is faster but buggy as hell if you don’t update it on ID changes, which they don’t… wtf…

1 Like

Try the current secret version now?

2 Likes