Jump to content

[1.8]Problems with HashMap[SOLVED]


Atijaf

Recommended Posts

I wish to fill a HashMap with the key being the ItemStack.  I understand that I must override hashCode and equals, and it seems to work part of the time.

 

I created a wrapper class that I put into the hashMap, called MyItemStack.  It holds the stack.

 

Here is my HashCode override

public int hashCode(){
	//int result = 17
	int result = 13;
	result = 31 * result + Integer.valueOf(this.stack.getMetadata());
	result = 31 * result + Integer.valueOf(Item.getIdFromItem(stack.getItem()));

	return result;
}

 

This code works for vanilla items and blocks, but as soon as I attempt this with a item from my mod, it doesn't work..  My Custom Item only holds one extra item, but I'm only checking if the two items being compared have the same metadata and block Id, so that shouldn't matter, right?

 

 

Equals override

public boolean equals(Object object){
	if (!(object instanceof MyItemStack)){
		return false;
	}
	MyItemStack otherKey = (MyItemStack) object;

	return this.stack.isItemEqual(otherKey.stack);

}

 

I copy the vanilla code I use when adding a key to the hashmap to the customItem that I have.

 

Is there anything wrong with this bit of code, or must it be somewhere else?

Link to comment
Share on other sites

Are you really trying to hash with an itemstack or an item? Neither your hashcode() or equals() processes the size of the stack, and they only look at the item in the stack, so you're really hashing items, not itemstacks. Is that what you want to do?

 

Why is your hashcode so complicated? Can't you just add the metadata to the item id (and add the stack size if you want to actually hash stacks)? What's all the multiplication and the 31 for?  The hashcode does not have to be unique, although I think it is supposed to at least be sort of unique. The main thing though is to include each of the factors that you care about that make the key unique.

 

For your equals() if you really mean to hash stacks and not just items then you should also check that the stack size is the same.

 

Lastly, to debug these sorts of issues is easy. Just use System.out.println() statements at each point in the code to print out information useful to trace what is going on. Like print out the metadata and id and resulting hashcode and see what's going on when you use your custom item stack.

 

Check out my tutorials here: http://jabelarminecraft.blogspot.com/

Link to comment
Share on other sites

I changed it like so.

 

public class MyItemStack {
private short id;
private short meta;

public MyItemStack(ItemStack stack){
	this.id = (short) Item.getIdFromItem(stack.getItem());
	this.meta = (short) stack.getMetadata();
}

public int getMeta(){
	return this.meta;
}

public int getId(){
	return this.id;
}

public void setIdAndMeta(ItemStack stack){
	this.id = (short) Item.getIdFromItem(stack.getItem());
	this.meta = (short) stack.getMetadata();
}

/** Compares two MyItemStacks */
public boolean equals(Object object){
	if (!(object instanceof MyItemStack)){
		return false;
	}
	MyItemStack otherKey = (MyItemStack) object;

	return this.id == otherKey.id && this.meta == otherKey.meta;

}

/** Used to compare MyItemStacks */
public int hashCode(){

	return this.id + this.meta * 500; // if it was just meta, granite would equal 2.. Thats grass.
}
}

 

I'm not sure why, but it doesn't work with my new Items that I add.  I'll add a pastebin in a little.

It works with vanilla Items. 

Link to comment
Share on other sites

As for the 31 * all that stuff, idk.  I saw it used and it seemed to work...

 

"All that stuff" is an in-line Hash(int) function.  The point of it is to effectively generate a pseudorandom number with your data as the seed.  It works better than id + meta*500 because the ID can be larger than 500.  ID=500, meta=0 will have the same "hash" as ID=0,meta=1.  This makes your hash range very limited.  You should go back to what you had before.

 

Your new Equals() method looks fine, though.

Note:

A.equals(B) => a.hashCode() == b.hashCode()

a.hashCode() == b.hashCode() =/> A.equals(B)

 

Hint: ItemIds can get very very large, very very quickly.  1.6 had a block array that stored up to 4096 block IDs, each of which had an item ID that matched.  1.7 is effectively unlimited.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

 

1.7 is effectively unlimited.

 

Not really. Block and Item ID limits are still the same as ever.

 

 

They are? Ok.

One of those "it's 5am, I can't sleep, and digging around in the code requires moving and effort."

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Link to comment
Share on other sites

I have just tested that hashmap with vanilla item, Diamond Block, and default mod item, testItem.

 

 

testItem = new Item().setUnlocalizedName("testItem");//Other classGameRegistry.registerItem(testItem, "testItem");//Testing hashMap//Note, it doesn't store integers, but instances. that is not the part i'm focusing on, so I made it simple.public static HashMap<MyItemStack, Integer> requiredLevel = new HashMap(200);ItemStack DiamondBlockStack = new ItemStack(Blocks.diamond_block);ItemStack testBlock = new ItemStack(MCAItems.testBlock);requiredLevel.put(new MyItemStack(DiamondBlockStack), 1);requiredLevel.put(new MyItemStack(testBlock), 2);requiredLevel.get(new MyItemStack(DiamondBlockStack));//Returns 1requiredLevel.get(new MyItemStack(testBlock));//Returns null

 

Link to comment
Share on other sites

new Info, when adding testItem to the hashMap, testItem has an id of 4097.  I add this during "FMLInitializationEvent".

 

Later on, I use hashMap.get(newMyItemStack(testItem)), //hashMap being static variable..

But this time, testItem has id value of 4105.  Should I be doing this in post init?  What would change the id of the block between initEvent and during the game?

 

That is most definitely the problem.  I thought about checking within the hash method, of MyItemStack, to see if it is one of my items and just add 8 to the id, but that isn't constant among my other items..  i.e. testItem2 is registered immediately after testItem and initially has and id value of 4098.  It later then has a value of 4108.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.