Merge pull request #829 from yueh/fix-improve-orehelper-performance

Improved OreHelper performance
This commit is contained in:
yueh 2015-03-09 12:59:38 +01:00
commit a5f58bb22f
2 changed files with 156 additions and 117 deletions

View file

@ -18,8 +18,18 @@
package appeng.util.item;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
@ -27,99 +37,74 @@ import net.minecraftforge.oredict.OreDictionary;
import appeng.api.storage.data.IAEItemStack;
public class OreHelper
{
public static final OreHelper INSTANCE = new OreHelper();
static class ItemRef
/**
* A local cache to speed up OreDictionary lookups.
*/
private final LoadingCache<String, List<ItemStack>> oreDictCache = CacheBuilder
.newBuilder().build( new CacheLoader<String, List<ItemStack>>(){
public List<ItemStack> load( String oreName )
{
ItemRef(ItemStack stack)
{
this.ref = stack.getItem();
if ( stack.getItem().isDamageable() )
this.damage = 0; // IGNORED
else
this.damage = stack.getItemDamage(); // might be important...
this.hash = this.ref.hashCode() ^ this.damage;
return OreDictionary.getOres( oreName );
}
} );
final Item ref;
final int damage;
final int hash;
@Override
public boolean equals(Object obj)
{
if ( obj == null )
return false;
if ( this.getClass() != obj.getClass() )
return false;
ItemRef other = (ItemRef) obj;
return this.damage == other.damage && this.ref == other.ref;
}
@Override
public int hashCode()
{
return this.hash;
}
}
static class OreResult
{
public OreReference oreValue = null;
}
final HashMap<ItemRef, OreResult> references = new HashMap<ItemRef, OreResult>();
private final Map<ItemRef, OreReference> references = new HashMap<ItemRef, OreReference>();
/**
* Test if the passed {@link ItemStack} is an ore.
*
* @param ItemStack the itemstack to test
* @return true if an ore entry exists, false otherwise
*/
public OreReference isOre( ItemStack ItemStack )
{
ItemRef ir = new ItemRef( ItemStack );
OreResult or = this.references.get( ir );
if ( or == null )
if ( !this.references.containsKey( ir ) )
{
or = new OreResult();
this.references.put( ir, or );
final OreReference ref = new OreReference();
final Collection<Integer> ores = ref.getOres();
final Collection<String> set = ref.getEquivalents();
OreReference ref = new OreReference();
Collection<Integer> ores = ref.getOres();
Collection<ItemStack> set = ref.getEquivalents();
Set<String> toAdd = new HashSet<String>();
for ( String ore : OreDictionary.getOreNames() )
{
boolean add = false;
// skip ore if it is a match already.
if ( toAdd.contains( ore ) )
{
continue;
}
for (ItemStack oreItem : OreDictionary.getOres( ore ))
for ( ItemStack oreItem : oreDictCache.getUnchecked( ore ) )
{
if ( OreDictionary.itemMatches( oreItem, ItemStack, false ) )
{
add = true;
toAdd.add( ore );
break;
}
}
if ( add )
{
for (ItemStack oreItem : OreDictionary.getOres( ore ))
set.add( oreItem.copy() );
ores.add( OreDictionary.getOreID( ore ) );
}
for ( String ore : toAdd )
{
set.add( ore );
ores.add( OreDictionary.getOreID( ore ) );
}
if ( !set.isEmpty() )
or.oreValue = ref;
this.references.put( ir, ref );
else
this.references.put( ir, null );
}
return or.oreValue;
return this.references.get( ir );
}
public boolean sameOre( AEItemStack aeItemStack, IAEItemStack is )
@ -127,20 +112,7 @@ public class OreHelper
OreReference a = aeItemStack.def.isOre;
OreReference b = aeItemStack.def.isOre;
if ( a == null || b == null )
return false;
if ( a == b )
return true;
Collection<Integer> bOres = b.getOres();
for (Integer ore : a.getOres())
{
if ( bOres.contains( ore ) )
return true;
}
return false;
return this.sameOre( a, b );
}
public boolean sameOre( OreReference a, OreReference b )
@ -167,12 +139,68 @@ public class OreHelper
if ( a == null )
return false;
for (ItemStack oreItem : a.getEquivalents())
for ( String oreName : a.getEquivalents() )
{
for ( ItemStack oreItem : oreDictCache.getUnchecked( oreName ) )
{
if ( OreDictionary.itemMatches( oreItem, o, false ) )
return true;
}
}
return false;
}
public List<ItemStack> getCachedOres( String oreName )
{
return oreDictCache.getUnchecked( oreName );
}
private static class ItemRef
{
ItemRef( ItemStack stack )
{
this.ref = stack.getItem();
if ( stack.getItem().isDamageable() )
this.damage = 0; // IGNORED
else
this.damage = stack.getItemDamage(); // might be important...
this.hash = this.ref.hashCode() ^ this.damage;
}
private final Item ref;
private final int damage;
private final int hash;
@Override
public boolean equals( Object obj )
{
if ( obj == null )
return false;
if ( this.getClass() != obj.getClass() )
return false;
ItemRef other = ( ItemRef ) obj;
return this.damage == other.damage && this.ref == other.ref;
}
@Override
public int hashCode()
{
return this.hash;
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append( "ItemRef [ref=" ).append( ref.getUnlocalizedName() )
.append( ", damage=" ).append( damage ).append( ", hash=" )
.append( hash ).append( "]" );
return builder.toString();
}
}
}

View file

@ -18,24 +18,27 @@
package appeng.util.item;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import net.minecraft.item.ItemStack;
import appeng.api.storage.data.IAEItemStack;
public class OreReference
{
private final LinkedList<ItemStack> otherOptions = new LinkedList<ItemStack>();
private ArrayList<IAEItemStack> aeOtherOptions = null;
private final HashSet<Integer> ores = new HashSet<Integer>();
private final List<String> otherOptions = new LinkedList<String>();
private List<IAEItemStack> aeOtherOptions = null;
private final Set<Integer> ores = new HashSet<Integer>();
public Collection<ItemStack> getEquivalents()
public Collection<String> getEquivalents()
{
return this.otherOptions;
}
@ -47,11 +50,19 @@ public class OreReference
this.aeOtherOptions = new ArrayList<IAEItemStack>( this.otherOptions.size() );
// SUMMON AE STACKS!
for (ItemStack is : this.otherOptions)
for ( String oreName : this.otherOptions )
{
for ( ItemStack is : OreHelper.INSTANCE.getCachedOres( oreName ) )
{
if ( is.getItem() != null )
{
this.aeOtherOptions.add( AEItemStack.create( is ) );
}
}
}
}
return this.aeOtherOptions;
}