diff --git a/src/api/java/appeng/api/config/FuzzyMode.java b/src/api/java/appeng/api/config/FuzzyMode.java index d8353fac5..9e9ae6935 100644 --- a/src/api/java/appeng/api/config/FuzzyMode.java +++ b/src/api/java/appeng/api/config/FuzzyMode.java @@ -56,9 +56,6 @@ public enum FuzzyMode { */ public final float percentage; - public final float breakPoint; - public final float percentage; - FuzzyMode( final float p ) { this.percentage = p; diff --git a/src/api/java/appeng/api/storage/data/IAEItemStack.java b/src/api/java/appeng/api/storage/data/IAEItemStack.java index f0e983c97..7e6a8a7f5 100644 --- a/src/api/java/appeng/api/storage/data/IAEItemStack.java +++ b/src/api/java/appeng/api/storage/data/IAEItemStack.java @@ -112,4 +112,13 @@ public interface IAEItemStack extends IAEStack * @return definition stack */ ItemStack getDefinition(); + + /** + * Compare this AE item stack to another item stack, but ignores the amount. It checks the item type, NBT and damage + * values. + * + * @param is An item stack + */ + boolean equals(ItemStack is); + } \ No newline at end of file diff --git a/src/api/java/appeng/api/storage/data/IAEStack.java b/src/api/java/appeng/api/storage/data/IAEStack.java index 6a3d86ed3..94bc6fa96 100644 --- a/src/api/java/appeng/api/storage/data/IAEStack.java +++ b/src/api/java/appeng/api/storage/data/IAEStack.java @@ -23,27 +23,24 @@ package appeng.api.storage.data; - import java.io.IOException; import io.netty.buffer.ByteBuf; - import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; import appeng.api.config.FuzzyMode; import appeng.api.storage.IStorageChannel; - -public interface IAEStack> -{ +public interface IAEStack> { /** * add two stacks together * * @param is added item */ - void add( T is ); + void add(T is); /** * number of items in the stack. @@ -57,7 +54,7 @@ public interface IAEStack> * * @param stackSize , ItemStack.stackSize = N */ - T setStackSize( long stackSize ); + T setStackSize(long stackSize); /** * Same as getStackSize, but for requestable items. ( LP ) @@ -71,7 +68,7 @@ public interface IAEStack> * * @return basically itemStack.stackSize = N but for setStackSize items. */ - T setCountRequestable( long countRequestable ); + T setCountRequestable(long countRequestable); /** * true, if the item can be crafted. @@ -85,7 +82,7 @@ public interface IAEStack> * * @param isCraftable can item be crafted */ - T setCraftable( boolean isCraftable ); + T setCraftable(boolean isCraftable); /** * clears, requestable, craftable, and stack sizes. @@ -104,33 +101,33 @@ public interface IAEStack> * * @param i additional stack size */ - void incStackSize( long i ); + void incStackSize(long i); /** * removes some from the stack size. */ - void decStackSize( long i ); + void decStackSize(long i); /** * adds items to the requestable * * @param i increased amount of requested items */ - void incCountRequestable( long i ); + void incCountRequestable(long i); /** * removes items from the requestable * * @param i decreased amount of requested items */ - void decCountRequestable( long i ); + void decCountRequestable(long i); /** - * write to a NBTTagCompound. + * write to a CompoundNBT. * * @param i to be written data */ - void writeToNBT( NBTTagCompound i ); + void writeToNBT( NBTTagCompound i); /** * Compare stacks using precise logic. @@ -146,17 +143,18 @@ public interface IAEStack> * @return true if they are the same. */ @Override - boolean equals( Object obj ); + boolean equals(Object obj); /** - * Compare the same subtype of {@link IAEStack} with another using a fuzzy comparison. + * Compare the same subtype of {@link IAEStack} with another using a fuzzy + * comparison. * * @param other The stack to compare. - * @param mode Which {@link FuzzyMode} should be used. + * @param mode Which {@link FuzzyMode} should be used. * * @return true if two stacks are equal based on AE Fuzzy Comparison. */ - boolean fuzzyComparison( T other, FuzzyMode mode ); + boolean fuzzyComparison(T other, FuzzyMode mode); /** * Slower for disk saving, but smaller/more efficient for packets. @@ -165,7 +163,7 @@ public interface IAEStack> * * @throws IOException */ - void writeToPacket( ByteBuf data ) throws IOException; + void writeToPacket( ByteBuf data) throws IOException; /** * Clone the Item / Fluid Stack @@ -182,17 +180,7 @@ public interface IAEStack> T empty(); /** - * @return true if the stack is a {@link IAEItemStack} - */ - boolean isItem(); - - /** - * @return true if the stack is a {@link IAEFluidStack} - */ - boolean isFluid(); - - /** - * @return ITEM or FLUID + * @return The {@link IStorageChannel} backing this stack. */ IStorageChannel getChannel(); @@ -202,4 +190,4 @@ public interface IAEStack> * @return itemstack */ ItemStack asItemStackRepresentation(); -} +} \ No newline at end of file diff --git a/src/main/java/appeng/fluids/util/AEFluidStack.java b/src/main/java/appeng/fluids/util/AEFluidStack.java index d04652bcb..2acb30aba 100644 --- a/src/main/java/appeng/fluids/util/AEFluidStack.java +++ b/src/main/java/appeng/fluids/util/AEFluidStack.java @@ -32,6 +32,7 @@ import io.netty.buffer.ByteBuf; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; import net.minecraftforge.fluids.Fluid; import net.minecraftforge.fluids.FluidStack; @@ -216,18 +217,6 @@ public final class AEFluidStack extends AEStack implements IAEFlu return dup; } - @Override - public boolean isItem() - { - return false; - } - - @Override - public boolean isFluid() - { - return true; - } - @Override public IStorageChannel getChannel() { @@ -318,17 +307,17 @@ public final class AEFluidStack extends AEStack implements IAEFlu } @Override - public void writeToPacket( final ByteBuf buffer ) throws IOException + public void writeToPacket( final ByteBuf i ) throws IOException { final byte mask = (byte) ( ( this.getType( this.getStackSize() ) << 2 ) | ( this .getType( this.getCountRequestable() ) << 4 ) | ( (byte) ( this.isCraftable() ? 1 : 0 ) << 6 ) | ( this.hasTagCompound() ? 1 : 0 ) << 7 ); - buffer.writeByte( mask ); + i.writeByte( mask ); - this.writeToStream( buffer ); + this.writeToStream( i ); - this.putPacketValue( buffer, this.getStackSize() ); - this.putPacketValue( buffer, this.getCountRequestable() ); + this.putPacketValue( i, this.getStackSize() ); + this.putPacketValue( i, this.getCountRequestable() ); } private void writeToStream( final ByteBuf buffer ) throws IOException diff --git a/src/main/java/appeng/util/UUIDMatcher.java b/src/main/java/appeng/util/UUIDMatcher.java new file mode 100644 index 000000000..bd8dab7ac --- /dev/null +++ b/src/main/java/appeng/util/UUIDMatcher.java @@ -0,0 +1,51 @@ +/* + * This file is part of Applied Energistics 2. + * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. + * + * Applied Energistics 2 is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Applied Energistics 2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Applied Energistics 2. If not, see . + */ + +package appeng.util; + + +import java.util.regex.Pattern; + + +/** + * Regex wrapper for {@link java.util.UUID}s to not rely on try catch + */ +public final class UUIDMatcher +{ + /** + * String which is the regular expression for {@link java.util.UUID}s + */ + private static final String UUID_REGEX = "[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}"; + + /** + * Pattern which pre-compiles the {@link appeng.util.UUIDMatcher#UUID_REGEX} + */ + private static final Pattern PATTERN = Pattern.compile( UUID_REGEX ); + + /** + * Checks if a potential {@link java.util.UUID} is an {@link java.util.UUID} by applying a regular expression on it. + * + * @param potential to be checked potential {@link java.util.UUID} + * + * @return true, if the potential {@link java.util.UUID} is indeed an {@link java.util.UUID} + */ + public boolean isUUID( final CharSequence potential ) + { + return PATTERN.matcher( potential ).matches(); + } +} \ No newline at end of file diff --git a/src/main/java/appeng/util/item/AEItemStack.java b/src/main/java/appeng/util/item/AEItemStack.java index b2047f4bc..ecf171857 100644 --- a/src/main/java/appeng/util/item/AEItemStack.java +++ b/src/main/java/appeng/util/item/AEItemStack.java @@ -1,6 +1,6 @@ /* * This file is part of Applied Energistics 2. - * Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved. + * Copyright (c) 2013 - 2020, AlgorithmX2, All rights reserved. * * Applied Energistics 2 is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -18,7 +18,6 @@ package appeng.util.item; - import java.util.List; import java.util.Objects; import java.util.Optional; @@ -26,348 +25,287 @@ import java.util.Optional; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import appeng.api.AEApi; import io.netty.buffer.ByteBuf; - import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.util.ResourceLocation; import net.minecraftforge.fml.common.network.ByteBufUtils; import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import net.minecraftforge.items.ItemHandlerHelper; -import appeng.api.AEApi; import appeng.api.config.FuzzyMode; import appeng.api.storage.IStorageChannel; import appeng.api.storage.channels.IItemStorageChannel; import appeng.api.storage.data.IAEItemStack; import appeng.util.Platform; +public final class AEItemStack extends AEStack implements IAEItemStack { -public final class AEItemStack extends AEStack implements IAEItemStack -{ - private AESharedItemStack sharedStack; - private Optional oreReference; + private final AESharedItemStack sharedStack; + private Optional oreReference; - @SideOnly( Side.CLIENT ) - private String displayName; - @SideOnly( Side.CLIENT ) - private List tooltip; - @SideOnly( Side.CLIENT ) - private ResourceLocation uniqueID; + @SideOnly( Side.CLIENT ) + private String displayName; + @SideOnly( Side.CLIENT ) + private List tooltip; - private AEItemStack( final AEItemStack is ) - { - this.setStackSize( is.getStackSize() ); - this.setCraftable( is.isCraftable() ); - this.setCountRequestable( is.getCountRequestable() ); - this.sharedStack = is.sharedStack; - this.oreReference = is.oreReference; - } + private AEItemStack(final AEItemStack is) { + this.setStackSize(is.getStackSize()); + this.setCraftable(is.isCraftable()); + this.setCountRequestable(is.getCountRequestable()); + this.sharedStack = is.sharedStack; + this.oreReference = is.oreReference; + } - private AEItemStack( final AESharedItemStack is, long size ) - { - this.sharedStack = is; - this.setStackSize( size ); - this.setCraftable( false ); - this.setCountRequestable( 0 ); - this.oreReference = OreHelper.INSTANCE.getOre( is.getDefinition() ); - } + private AEItemStack(final AESharedItemStack is, long size) { + this.sharedStack = is; + this.setStackSize(size); + this.setCraftable(false); + this.setCountRequestable(0); + this.oreReference = OreHelper.INSTANCE.getOre( is.getDefinition() ); + } - @Nullable - public static AEItemStack fromItemStack( @Nonnull final ItemStack stack ) - { - if( stack.isEmpty() ) - { - return null; - } + @Nullable + public static AEItemStack fromItemStack(@Nonnull final ItemStack stack) { + if (stack.isEmpty()) { + return null; + } - return new AEItemStack( AEItemStackRegistry.getRegisteredStack( stack ), stack.getCount() ); - } + return new AEItemStack(AEItemStackRegistry.getRegisteredStack(stack), stack.getCount()); + } - public static IAEItemStack fromNBT( final NBTTagCompound i ) - { - if( i == null ) - { - return null; - } + public static IAEItemStack fromNBT( final NBTTagCompound i ) + { + if( i == null ) + { + return null; + } - final ItemStack itemstack = new ItemStack( i ); - if( itemstack.isEmpty() ) - { - return null; - } + final ItemStack itemstack = new ItemStack( i ); + if( itemstack.isEmpty() ) + { + return null; + } - final AEItemStack item = AEItemStack.fromItemStack( itemstack ); - item.setStackSize( i.getLong( "Cnt" ) ); - item.setCountRequestable( i.getLong( "Req" ) ); - item.setCraftable( i.getBoolean( "Craft" ) ); - return item; - } + final AEItemStack item = AEItemStack.fromItemStack( itemstack ); + item.setStackSize( i.getLong( "Cnt" ) ); + item.setCountRequestable( i.getLong( "Req" ) ); + item.setCraftable( i.getBoolean( "Craft" ) ); + return item; + } - @Override - public void writeToNBT( final NBTTagCompound i ) - { - this.getDefinition().writeToNBT( i ); - i.setLong( "Cnt", this.getStackSize() ); - i.setLong( "Req", this.getCountRequestable() ); - i.setBoolean( "Craft", this.isCraftable() ); - } + @Override + public void writeToNBT( final NBTTagCompound i ) + { + this.getDefinition().writeToNBT( i ); + i.setLong( "Cnt", this.getStackSize() ); + i.setLong( "Req", this.getCountRequestable() ); + i.setBoolean( "Craft", this.isCraftable() ); + } - public static AEItemStack fromPacket( final ByteBuf data ) - { - final byte mask = data.readByte(); - final byte stackType = (byte) ( ( mask & 0x0C ) >> 2 ); - final byte countReqType = (byte) ( ( mask & 0x30 ) >> 4 ); - final boolean isCraftable = ( mask & 0x40 ) > 0; + public static AEItemStack fromPacket( final ByteBuf data ) + { + final byte mask = data.readByte(); + final byte stackType = (byte) ( ( mask & 0x0C ) >> 2 ); + final byte countReqType = (byte) ( ( mask & 0x30 ) >> 4 ); + final boolean isCraftable = ( mask & 0x40 ) > 0; - final ItemStack itemstack = new ItemStack( ByteBufUtils.readTag( data ) ); - final long stackSize = getPacketValue( stackType, data ); - final long countRequestable = getPacketValue( countReqType, data ); + final ItemStack itemstack = new ItemStack( ByteBufUtils.readTag( data ) ); + final long stackSize = getPacketValue( stackType, data ); + final long countRequestable = getPacketValue( countReqType, data ); - if( itemstack.isEmpty() ) - { - return null; - } + if( itemstack.isEmpty() ) + { + return null; + } - final AEItemStack item = new AEItemStack( AEItemStackRegistry.getRegisteredStack( itemstack ), stackSize ); - item.setCountRequestable( countRequestable ); - item.setCraftable( isCraftable ); - return item; - } + final AEItemStack item = new AEItemStack( AEItemStackRegistry.getRegisteredStack( itemstack ), stackSize ); + item.setCountRequestable( countRequestable ); + item.setCraftable( isCraftable ); + return item; + } - @Override - public void writeToPacket( final ByteBuf i ) - { - final byte mask = (byte) ( ( this.getType( this.getStackSize() ) << 2 ) | ( this - .getType( this.getCountRequestable() ) << 4 ) | ( (byte) ( this.isCraftable() ? 1 : 0 ) << 6 ) | ( this.hasTagCompound() ? 1 : 0 ) << 7 ); + @Override + public void writeToPacket( final ByteBuf i ) + { + final byte mask = (byte) ( ( this.getType( this.getStackSize() ) << 2 ) | ( this + .getType( this.getCountRequestable() ) << 4 ) | ( (byte) ( this.isCraftable() ? 1 : 0 ) << 6 ) | ( this.hasTagCompound() ? 1 : 0 ) << 7 ); - i.writeByte( mask ); - ByteBufUtils.writeTag( i, this.getDefinition().serializeNBT() ); - this.putPacketValue( i, this.getStackSize() ); - this.putPacketValue( i, this.getCountRequestable() ); - } + i.writeByte( mask ); + ByteBufUtils.writeTag( i, this.getDefinition().serializeNBT() ); + this.putPacketValue( i, this.getStackSize() ); + this.putPacketValue( i, this.getCountRequestable() ); + } - @Override - public void add( final IAEItemStack option ) - { - if( option == null ) - { - return; - } + /** + * We're assuming that using capNBT here is safe, because {@link #getDefinition()} should have been created by + * {@link ItemStack#copy()}, and then never mutated. Copying an item stack will automatically serialize the + * capabilities of the source stack and initialize the target stacks capNBT field using that tag, which we are then + * reusing here. + */ - this.incStackSize( option.getStackSize() ); - this.setCountRequestable( this.getCountRequestable() + option.getCountRequestable() ); - this.setCraftable( this.isCraftable() || option.isCraftable() ); - } + @Override + public void add(final IAEItemStack option) { + if (option == null) { + return; + } - @Override - public boolean fuzzyComparison( final IAEItemStack other, final FuzzyMode mode ) - { - if( mode == FuzzyMode.IGNORE_ALL && OreHelper.INSTANCE.sameOre( this, other ) ) - { - return true; - } + this.incStackSize(option.getStackSize()); + this.setCountRequestable(this.getCountRequestable() + option.getCountRequestable()); + this.setCraftable(this.isCraftable() || option.isCraftable()); + } - final ItemStack itemStack = this.getDefinition(); - final ItemStack otherStack = other.getDefinition(); + @Override + public boolean fuzzyComparison(final IAEItemStack other, final FuzzyMode mode) { + final ItemStack itemStack = this.getDefinition(); + final ItemStack otherStack = other.getDefinition(); - return this.fuzzyItemStackComparison( itemStack, otherStack, mode ); - } + return this.fuzzyItemStackComparison(itemStack, otherStack, mode); + } - @Override - public IAEItemStack copy() - { - return new AEItemStack( this ); - } + @Override + public IAEItemStack copy() { + return new AEItemStack(this); + } - @Override - public boolean isItem() - { - return true; - } + @Override + public IStorageChannel getChannel() { + return AEApi.instance().storage().getStorageChannel(IItemStorageChannel.class); + } - @Override - public boolean isFluid() - { - return false; - } + @Override + public ItemStack createItemStack() { + return ItemHandlerHelper.copyStackWithSize(this.getDefinition(), + (int) Math.min(Integer.MAX_VALUE, this.getStackSize())); + } - @Override - public IStorageChannel getChannel() - { - return AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ); - } + @Override + public Item getItem() { + return this.getDefinition().getItem(); + } - @Override - public ItemStack createItemStack() - { - return ItemHandlerHelper.copyStackWithSize( this.getDefinition(), (int) Math.min( Integer.MAX_VALUE, this.getStackSize() ) ); - } + @Override + public int getItemDamage() { + return this.sharedStack.getItemDamage(); + } - @Override - public Item getItem() - { - return this.getDefinition().getItem(); - } + public Optional getOre() + { + return this.oreReference; + } - @Override - public int getItemDamage() - { - return this.sharedStack.getItemDamage(); - } + @Override + public boolean sameOre( final IAEItemStack is ) + { + return OreHelper.INSTANCE.sameOre( this, is ); + } - @Override - public boolean sameOre( final IAEItemStack is ) - { - return OreHelper.INSTANCE.sameOre( this, is ); - } + @Override + public boolean isSameType(final IAEItemStack otherStack) { + if (otherStack == null) { + return false; + } - @Override - public boolean isSameType( final IAEItemStack otherStack ) - { - if( otherStack == null ) - { - return false; - } + return Objects.equals(this.sharedStack, ((AEItemStack) otherStack).sharedStack); + } - return Objects.equals( this.sharedStack, ( (AEItemStack) otherStack ).sharedStack ); - } + @Override + public boolean isSameType(final ItemStack otherStack) { + if (otherStack.isEmpty()) { + return false; + } + int oldSize = otherStack.getCount(); - @Override - public boolean isSameType( final ItemStack otherStack ) - { - if( otherStack.isEmpty() ) - { - return false; - } - int oldSize = otherStack.getCount(); + otherStack.setCount(1); + boolean ret = ItemStack.areItemStacksEqual(this.getDefinition(), otherStack); + otherStack.setCount(oldSize); - otherStack.setCount( 1 ); - boolean ret = ItemStack.areItemStacksEqual( this.getDefinition(), otherStack ); - otherStack.setCount( oldSize ); + return ret; + } - return ret; - } + @Override + public int hashCode() { + return this.sharedStack.hashCode(); + } - @Override - public int hashCode() - { - return this.sharedStack.hashCode(); - } + @Override + public boolean equals(final Object ia) { + if (ia instanceof AEItemStack) { + return this.isSameType((AEItemStack) ia); + } else if (ia instanceof ItemStack) { + // this actually breaks the equals contract (being equals to unrelated classes) + return equals((ItemStack) ia); + } + return false; + } - @Override - public boolean equals( final Object ia ) - { - if( ia instanceof AEItemStack ) - { - return this.isSameType( (AEItemStack) ia ); - } - else if( ia instanceof ItemStack ) - { - return this.isSameType( (ItemStack) ia ); - } - return false; - } + @Override + public String toString() { + return this.getStackSize() + "x" + this.getDefinition().getItem().getRegistryName(); + } - @Override - public String toString() - { - return this.getStackSize() + "x" + this.getDefinition().getItem().getUnlocalizedName() + "@" + this.getDefinition().getItemDamage(); - } + @SideOnly( Side.CLIENT ) + public List getToolTip() { + if (this.tooltip == null) { + this.tooltip = Platform.getTooltip(this.asItemStackRepresentation()); + } + return this.tooltip; + } - @SideOnly( Side.CLIENT ) - public List getToolTip() - { - if( this.tooltip == null ) - { - this.tooltip = Platform.getTooltip( this.asItemStackRepresentation() ); - } - return this.tooltip; - } + @SideOnly( Side.CLIENT ) + public String getDisplayName() { + if (this.displayName == null) { + this.displayName = Platform.getItemDisplayName(this.asItemStackRepresentation()); + } + return this.displayName; + } - @SideOnly( Side.CLIENT ) - public String getDisplayName() - { - if( this.displayName == null ) - { - this.displayName = Platform.getItemDisplayName( this.asItemStackRepresentation() ); - } - return this.displayName; - } + @SideOnly( Side.CLIENT ) + public String getModID() { + return this.getDefinition().getItem().getRegistryName().getResourceDomain(); + } - @SideOnly( Side.CLIENT ) - public String getModID() - { - if( this.uniqueID == null ) - { - this.uniqueID = Item.REGISTRY.getNameForObject( this.getDefinition().getItem() ); - } + @Override + public boolean hasTagCompound() { + return this.getDefinition().hasTagCompound(); + } - if( this.uniqueID == null ) - { - return "** Null"; - } + @Override + public ItemStack asItemStackRepresentation() { + return this.getDefinition().copy(); + } - return this.uniqueID.getResourceDomain() == null ? "** Null" : this.uniqueID.getResourceDomain(); - } + @Override + public ItemStack getDefinition() { + return this.sharedStack.getDefinition(); + } - public Optional getOre() - { - return this.oreReference; - } + public boolean equals(final ItemStack is) { + return this.isSameType(is); + } - @Override - public boolean hasTagCompound() - { - return this.getDefinition().hasTagCompound(); - } + AESharedItemStack getSharedStack() { + return this.sharedStack; + } - @Override - public ItemStack asItemStackRepresentation() - { - return this.getDefinition().copy(); - } + private boolean fuzzyItemStackComparison(ItemStack a, ItemStack b, FuzzyMode mode) { + if (a.getItem() == b.getItem()) { + if (a.getItem().isDamageable()) { + if (mode == FuzzyMode.IGNORE_ALL) { + return true; + } else if (mode == FuzzyMode.PERCENT_99) { + return (a.getItemDamage() > 1) == (b.getItemDamage() > 1); + } else { + final float percentDamageOfA = (float) a.getItemDamage() / a.getMaxDamage(); + final float percentDamageOfB = (float) b.getItemDamage() / b.getMaxDamage(); - @Override - public ItemStack getDefinition() - { - return this.sharedStack.getDefinition(); - } - - AESharedItemStack getSharedStack() - { - return this.sharedStack; - } - - private boolean fuzzyItemStackComparison( ItemStack a, ItemStack b, FuzzyMode mode ) - { - if( a.getItem() == b.getItem() ) - { - if( a.getItem().isDamageable() ) - { - if( mode == FuzzyMode.IGNORE_ALL ) - { - return true; - } - else if( mode == FuzzyMode.PERCENT_99 ) - { - return ( a.getItemDamage() > 1 ) == ( b.getItemDamage() > 1 ); - } - else - { - final float percentDamageOfA = (float) a.getItemDamage() / (float) a.getMaxDamage(); - final float percentDamageOfB = (float) b.getItemDamage() / (float) b.getMaxDamage(); - - return ( percentDamageOfA > mode.breakPoint ) == ( percentDamageOfB > mode.breakPoint ); - } - } - - return a.getMetadata() == b.getMetadata(); - } - - return false; - } + return (percentDamageOfA > mode.breakPoint) == (percentDamageOfB > mode.breakPoint); + } + } + } + return false; + } } diff --git a/src/main/java/appeng/util/item/AEItemStackRegistry.java b/src/main/java/appeng/util/item/AEItemStackRegistry.java index 2bea02b88..0fce27e36 100644 --- a/src/main/java/appeng/util/item/AEItemStackRegistry.java +++ b/src/main/java/appeng/util/item/AEItemStackRegistry.java @@ -23,7 +23,6 @@ package appeng.util.item; - import java.lang.ref.WeakReference; import java.util.WeakHashMap; @@ -31,56 +30,34 @@ import javax.annotation.Nonnull; import net.minecraft.item.ItemStack; -import appeng.util.Platform; +public final class AEItemStackRegistry { + private static final WeakHashMap> REGISTRY = new WeakHashMap<>(); + private AEItemStackRegistry() { + } -public final class AEItemStackRegistry -{ - private static final WeakHashMap> SERVER_REGISTRY = new WeakHashMap<>(); - private static final WeakHashMap> CLIENT_REGISTRY = new WeakHashMap<>(); + static synchronized AESharedItemStack getRegisteredStack(final @Nonnull ItemStack itemStack) { + if (itemStack.isEmpty()) { + throw new IllegalArgumentException("stack cannot be empty"); + } - private AEItemStackRegistry() - { - } + int oldStackSize = itemStack.getCount(); + itemStack.setCount(1); - private static WeakHashMap> registry() - { - if( Platform.isClient() ) - { - return CLIENT_REGISTRY; - } - else - { - return SERVER_REGISTRY; - } - } + AESharedItemStack search = new AESharedItemStack(itemStack); + WeakReference weak = REGISTRY.get(search); + AESharedItemStack ret = null; - static synchronized AESharedItemStack getRegisteredStack( final @Nonnull ItemStack itemStack ) - { - if( itemStack.isEmpty() ) - { - throw new IllegalArgumentException( "stack cannot be empty" ); - } + if (weak != null) { + ret = weak.get(); + } - int oldStackSize = itemStack.getCount(); - itemStack.setCount( 1 ); + if (ret == null) { + ret = new AESharedItemStack(itemStack.copy()); + REGISTRY.put(ret, new WeakReference<>(ret)); + } + itemStack.setCount(oldStackSize); - AESharedItemStack search = new AESharedItemStack( itemStack ); - WeakReference weak = registry().get( search ); - AESharedItemStack ret = null; - - if( weak != null ) - { - ret = weak.get(); - } - - if( ret == null ) - { - ret = new AESharedItemStack( itemStack.copy() ); - registry().put( ret, new WeakReference<>( ret ) ); - } - itemStack.setCount( oldStackSize ); - - return ret; - } + return ret; + } } diff --git a/src/main/java/appeng/util/item/AESharedItemStack.java b/src/main/java/appeng/util/item/AESharedItemStack.java index 700e5b6b1..c5ab8038f 100644 --- a/src/main/java/appeng/util/item/AESharedItemStack.java +++ b/src/main/java/appeng/util/item/AESharedItemStack.java @@ -18,7 +18,6 @@ package appeng.util.item; - import java.util.Objects; import com.google.common.base.Preconditions; @@ -33,32 +32,32 @@ final class AESharedItemStack { private final int itemDamage; private final int hashCode; - private final ItemStack itemStack; - private final int itemId; - private final int itemDamage; - private final int hashCode; + public AESharedItemStack(final ItemStack itemStack) { + this(itemStack, itemStack.getItemDamage()); + } - public AESharedItemStack( final ItemStack itemStack ) - { - this.itemStack = itemStack; - this.itemId = Item.getIdFromItem( itemStack.getItem() ); - this.itemDamage = itemStack.getItemDamage(); - this.hashCode = this.makeHashCode(); - } + /** + * A constructor to explicitly set the damage value and not fetch it from the {@link ItemStack} + * + * @param itemStack The {@link ItemStack} to filter + * @param damage The damage of the item + */ + private AESharedItemStack(ItemStack itemStack, int damage) { + this.itemStack = itemStack; + this.itemId = Item.getIdFromItem(itemStack.getItem()); + this.itemDamage = damage; - Bounds getBounds( final FuzzyMode fuzzy, final boolean ignoreMeta ) - { - return new Bounds( this.itemStack, fuzzy, ignoreMeta ); - } + // Ensure this is always called last. + this.hashCode = this.makeHashCode(); + } ItemStack getDefinition() { return this.itemStack; } - int getItemID() - { - return this.itemId; - } + int getItemDamage() { + return this.itemDamage; + } @Override public int hashCode() { @@ -88,7 +87,7 @@ final class AESharedItemStack { return Objects.hash( this.itemId, this.itemDamage, - this.itemStack.hasTag() ? this.itemStack.getTag() : 0); + this.itemStack.hasTagCompound() ? this.itemStack.getTagCompound() : 0); } } diff --git a/src/main/java/appeng/util/item/AEStack.java b/src/main/java/appeng/util/item/AEStack.java index f2b42351d..9782663ab 100644 --- a/src/main/java/appeng/util/item/AEStack.java +++ b/src/main/java/appeng/util/item/AEStack.java @@ -18,169 +18,152 @@ package appeng.util.item; - +import appeng.api.storage.data.IAEStack; import io.netty.buffer.ByteBuf; -import appeng.api.storage.data.IAEStack; +public abstract class AEStack> implements IAEStack { -public abstract class AEStack> implements IAEStack -{ + private boolean isCraftable; + private long stackSize; + private long countRequestable; - private boolean isCraftable; - private long stackSize; - private long countRequestable; + @Override + public long getStackSize() { + return this.stackSize; + } - protected static long getPacketValue( final byte type, final ByteBuf tag ) - { - if( type == 0 ) - { - long l = tag.readByte(); - l -= Byte.MIN_VALUE; - return l; - } - else if( type == 1 ) - { - long l = tag.readShort(); - l -= Short.MIN_VALUE; - return l; - } - else if( type == 2 ) - { - long l = tag.readInt(); - l -= Integer.MIN_VALUE; - return l; - } + @Override + public T setStackSize(final long ss) { + this.stackSize = ss; + return (T) this; + } - return tag.readLong(); - } + @Override + public long getCountRequestable() { + return this.countRequestable; + } - @Override - public long getStackSize() - { - return this.stackSize; - } + @Override + public T setCountRequestable(final long countRequestable) { + this.countRequestable = countRequestable; + return (T) this; + } - @Override - public StackType setStackSize( final long ss ) - { - this.stackSize = ss; - return (StackType) this; - } + @Override + public boolean isCraftable() { + return this.isCraftable; + } - @Override - public long getCountRequestable() - { - return this.countRequestable; - } + @Override + public T setCraftable(final boolean isCraftable) { + this.isCraftable = isCraftable; + return (T) this; + } - @Override - public StackType setCountRequestable( final long countRequestable ) - { - this.countRequestable = countRequestable; - return (StackType) this; - } + @Override + public T reset() { + this.stackSize = 0; + this.setCountRequestable(0); + this.setCraftable(false); + return (T) this; + } - @Override - public boolean isCraftable() - { - return this.isCraftable; - } + @Override + public T empty() { + final T dup = this.copy(); + dup.reset(); + return dup; + } - @Override - public StackType setCraftable( final boolean isCraftable ) - { - this.isCraftable = isCraftable; - return (StackType) this; - } + @Override + public boolean isMeaningful() { + return this.stackSize != 0 || this.countRequestable > 0 || this.isCraftable; + } - @Override - public StackType reset() - { - this.stackSize = 0; - // priority = Integer.MIN_VALUE; - this.setCountRequestable( 0 ); - this.setCraftable( false ); - return (StackType) this; - } + @Override + public void incStackSize(final long i) { + this.stackSize += i; + } - @Override - public StackType empty() - { - final StackType dup = this.copy(); - dup.reset(); - return dup; - } + @Override + public void decStackSize(final long i) { + this.stackSize -= i; + } - @Override - public boolean isMeaningful() - { - return this.stackSize != 0 || this.countRequestable > 0 || this.isCraftable; - } + @Override + public void incCountRequestable(final long i) { + this.countRequestable += i; + } - @Override - public void incStackSize( final long i ) - { - this.stackSize += i; - } + @Override + public void decCountRequestable(final long i) { + this.countRequestable -= i; + } - @Override - public void decStackSize( final long i ) - { - this.stackSize -= i; - } + protected abstract boolean hasTagCompound(); - @Override - public void incCountRequestable( final long i ) - { - this.countRequestable += i; - } + protected static long getPacketValue( final byte type, final ByteBuf tag ) + { + if( type == 0 ) + { + long l = tag.readByte(); + l -= Byte.MIN_VALUE; + return l; + } + else if( type == 1 ) + { + long l = tag.readShort(); + l -= Short.MIN_VALUE; + return l; + } + else if( type == 2 ) + { + long l = tag.readInt(); + l -= Integer.MIN_VALUE; + return l; + } - @Override - public void decCountRequestable( final long i ) - { - this.countRequestable -= i; - } + return tag.readLong(); + } - protected byte getType( final long num ) - { - if( num <= 255 ) - { - return 0; - } - else if( num <= 65535 ) - { - return 1; - } - else if( num <= 4294967295L ) - { - return 2; - } - else - { - return 3; - } - } + protected void putPacketValue( final ByteBuf tag, final long num ) + { + if( num <= 255 ) + { + tag.writeByte( (byte) ( num + Byte.MIN_VALUE ) ); + } + else if( num <= 65535 ) + { + tag.writeShort( (short) ( num + Short.MIN_VALUE ) ); + } + else if( num <= 4294967295L ) + { + tag.writeInt( (int) ( num + Integer.MIN_VALUE ) ); + } + else + { + tag.writeLong( num ); + } + } - protected abstract boolean hasTagCompound(); - - protected void putPacketValue( final ByteBuf tag, final long num ) - { - if( num <= 255 ) - { - tag.writeByte( (byte) ( num + Byte.MIN_VALUE ) ); - } - else if( num <= 65535 ) - { - tag.writeShort( (short) ( num + Short.MIN_VALUE ) ); - } - else if( num <= 4294967295L ) - { - tag.writeInt( (int) ( num + Integer.MIN_VALUE ) ); - } - else - { - tag.writeLong( num ); - } - } + protected byte getType( final long num ) + { + if( num <= 255 ) + { + return 0; + } + else if( num <= 65535 ) + { + return 1; + } + else if( num <= 4294967295L ) + { + return 2; + } + else + { + return 3; + } + } } diff --git a/src/main/java/appeng/util/item/FuzzyItemVariantList.java b/src/main/java/appeng/util/item/FuzzyItemVariantList.java index 270a3df07..7ccc16f0c 100644 --- a/src/main/java/appeng/util/item/FuzzyItemVariantList.java +++ b/src/main/java/appeng/util/item/FuzzyItemVariantList.java @@ -145,14 +145,14 @@ class FuzzyItemVariantList extends ItemVariantList { * higher number than the upper bound. */ static ItemDamageBound makeLowerBound(final ItemStack stack, final FuzzyMode fuzzy) { - Preconditions.checkState(stack.isDamageable(), "ItemStack#isDamageable() has to be true"); + Preconditions.checkState(((stack.getMaxDamage() == 0 && stack.getItemDamage() > 0 ) || stack.isItemStackDamageable()), "ItemStack#isDamageable() has to be true"); int damage; if (fuzzy == FuzzyMode.IGNORE_ALL) { damage = stack.getMaxDamage(); } else { final int breakpoint = fuzzy.calculateBreakPoint(stack.getMaxDamage()); - damage = stack.getDamage() <= breakpoint ? breakpoint : stack.getMaxDamage(); + damage = stack.getItemDamage() <= breakpoint ? breakpoint : stack.getMaxDamage(); } return new ItemDamageBound(damage); @@ -163,14 +163,14 @@ class FuzzyItemVariantList extends ItemVariantList { * lower number than the lower bound. It also is exclusive. */ static ItemDamageBound makeUpperBound(final ItemStack stack, final FuzzyMode fuzzy) { - Preconditions.checkState(stack.isDamageable(), "ItemStack#isDamageable() has to be true"); + Preconditions.checkState(((stack.getMaxDamage() == 0 && stack.getItemDamage() > 0 ) || stack.isItemStackDamageable()), "ItemStack#isDamageable() has to be true"); int damage; if (fuzzy == FuzzyMode.IGNORE_ALL) { damage = MIN_DAMAGE_VALUE; } else { final int breakpoint = fuzzy.calculateBreakPoint(stack.getMaxDamage()); - damage = stack.getDamage() <= breakpoint ? MIN_DAMAGE_VALUE : breakpoint; + damage = stack.getItemDamage() <= breakpoint ? MIN_DAMAGE_VALUE : breakpoint; } return new ItemDamageBound(damage); diff --git a/src/main/java/appeng/util/item/ItemList.java b/src/main/java/appeng/util/item/ItemList.java index e50cd73b7..e7a4672a2 100644 --- a/src/main/java/appeng/util/item/ItemList.java +++ b/src/main/java/appeng/util/item/ItemList.java @@ -1,6 +1,6 @@ /* * This file is part of Applied Energistics 2. - * Copyright (c) 2013 - 2015, AlgorithmX2, All rights reserved. + * Copyright (c) 2013 - 2020, AlgorithmX2, All rights reserved. * * Applied Energistics 2 is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by @@ -18,8 +18,6 @@ package appeng.util.item; - -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.ConcurrentModificationException; @@ -27,13 +25,16 @@ import java.util.Iterator; import java.util.NoSuchElementException; import java.util.concurrent.atomic.AtomicInteger; -import net.minecraftforge.oredict.OreDictionary; +import net.minecraft.item.Item; + +import it.unimi.dsi.fastutil.objects.Reference2ObjectMap; +import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap; import appeng.api.config.FuzzyMode; import appeng.api.storage.data.IAEItemStack; import appeng.api.storage.data.IItemList; -import appeng.util.item.AESharedItemStack.Bounds; +public final class ItemList implements IItemList { private final Reference2ObjectMap records = new Reference2ObjectOpenHashMap<>(); /** @@ -53,18 +54,20 @@ import appeng.util.item.AESharedItemStack.Bounds; return record != null ? record.findPrecise(itemStack) : null; } - if( st != null ) - { - st.add( option ); - return; - } + @Override + public Collection findFuzzy(final IAEItemStack filter, final FuzzyMode fuzzy) { + if (filter == null) { + return Collections.emptyList(); + } ItemVariantList record = this.records.get(filter.getItem()); return record != null ? record.findFuzzy(filter, fuzzy) : Collections.emptyList(); } - this.putItemRecord( opt ); - } + @Override + public boolean isEmpty() { + return !this.iterator().hasNext(); + } @Override public void add(final IAEItemStack itemStack) { @@ -74,8 +77,8 @@ import appeng.util.item.AESharedItemStack.Bounds; return; } - return this.records.get( ( (AEItemStack) itemStack ).getSharedStack() ); - } + this.getOrCreateRecord(itemStack.getItem()).add(itemStack); + } @Override public void addStorage(final IAEItemStack itemStack) { @@ -85,7 +88,8 @@ import appeng.util.item.AESharedItemStack.Bounds; return; } - final AEItemStack ais = (AEItemStack) filter; + this.getOrCreateRecord(itemStack.getItem()).addStorage(itemStack); + } @Override public void addCrafting(final IAEItemStack itemStack) { @@ -95,11 +99,8 @@ import appeng.util.item.AESharedItemStack.Bounds; return; } - return this.findFuzzyDamage( is, fuzzy, is.getItemDamage() == OreDictionary.WILDCARD_VALUE ); - } - else - { - final Collection output = new ArrayList<>(); + this.getOrCreateRecord(itemStack.getItem()).addCrafting(itemStack); + } @Override public void addRequestable(final IAEItemStack itemStack) { @@ -109,24 +110,17 @@ import appeng.util.item.AESharedItemStack.Bounds; return; } - return output; - } - } ).orElse( this.findFuzzyDamage( ais, fuzzy, false ) ); - } + this.getOrCreateRecord(itemStack.getItem()).addRequestable(itemStack); + } - @Override - public boolean isEmpty() - { - return !this.iterator().hasNext(); - } + @Override + public IAEItemStack getFirstItem() { + for (final IAEItemStack stackType : this) { + return stackType; + } - @Override - public void addStorage( final IAEItemStack option ) - { - if( option == null ) - { - return; - } + return null; + } @Override public int size() { @@ -135,19 +129,20 @@ import appeng.util.item.AESharedItemStack.Bounds; size += entry.size(); } - if( st != null ) - { - st.incStackSize( option.getStackSize() ); - return; - } + return size; + } @Override public Iterator iterator() { return new ChainedIterator(this.records.values().iterator(), version); } - this.putItemRecord( opt ); - } + @Override + public void resetStatus() { + for (final IAEItemStack i : this) { + i.reset(); + } + } private ItemVariantList getOrCreateRecord(Item item) { return this.records.computeIfAbsent(item, this::makeRecordMap); diff --git a/src/main/java/appeng/util/item/MeaningfulItemIterator.java b/src/main/java/appeng/util/item/MeaningfulItemIterator.java index 310d23fb3..2d84f7933 100644 --- a/src/main/java/appeng/util/item/MeaningfulItemIterator.java +++ b/src/main/java/appeng/util/item/MeaningfulItemIterator.java @@ -43,13 +43,11 @@ public class MeaningfulItemIterator implements Iterator< return this.next != null; } - @Override - public T next() - { - if( this.next == null ) - { - throw new NoSuchElementException(); - } + @Override + public T next() { + if (this.next == null) { + throw new NoSuchElementException(); + } T result = this.next; this.next = this.seekNext();