diff --git a/src/main/java/appeng/fluids/util/AEFluidStack.java b/src/main/java/appeng/fluids/util/AEFluidStack.java index 430e2c613..7082f4578 100644 --- a/src/main/java/appeng/fluids/util/AEFluidStack.java +++ b/src/main/java/appeng/fluids/util/AEFluidStack.java @@ -19,7 +19,6 @@ package appeng.fluids.util; -import java.io.IOException; import javax.annotation.Nonnull; import net.minecraft.fluid.Fluid; @@ -40,6 +39,10 @@ import appeng.util.item.AEStack; public final class AEFluidStack extends AEStack implements IAEFluidStack, Comparable { + private static final String NBT_STACKSIZE = "cnt"; + private static final String NBT_REQUESTABLE = "req"; + private static final String NBT_CRAFTABLE = "craft"; + private static final String NBT_FLUIDSTACK = "fs"; private final Fluid fluid; private CompoundNBT tagCompound; @@ -90,7 +93,7 @@ public final class AEFluidStack extends AEStack implements IAEFlu public static IAEFluidStack fromNBT( final CompoundNBT data ) { - final FluidStack fluidStack = FluidStack.loadFluidStackFromNBT( data ); + final FluidStack fluidStack = FluidStack.loadFluidStackFromNBT( data.getCompound( NBT_FLUIDSTACK ) ); if( fluidStack == null ) { @@ -98,9 +101,9 @@ public final class AEFluidStack extends AEStack implements IAEFlu } final AEFluidStack fluid = AEFluidStack.fromFluidStack( fluidStack ); - fluid.setStackSize( data.getLong( "Cnt" ) ); - fluid.setCountRequestable( data.getLong( "Req" ) ); - fluid.setCraftable( data.getBoolean( "Craft" ) ); + fluid.setStackSize( data.getLong( NBT_STACKSIZE ) ); + fluid.setCountRequestable( data.getLong( NBT_REQUESTABLE ) ); + fluid.setCraftable( data.getBoolean( NBT_CRAFTABLE ) ); if( fluid.hasTagCompound() ) { @@ -125,20 +128,20 @@ public final class AEFluidStack extends AEStack implements IAEFlu @Override public void writeToNBT( final CompoundNBT data ) { - data.putString( "FluidName", this.fluid.getRegistryName().toString() ); - data.putByte( "Count", (byte) 0 ); - data.putLong( "Cnt", this.getStackSize() ); - data.putLong( "Req", this.getCountRequestable() ); - data.putBoolean( "Craft", this.isCraftable() ); - + data.getCompound( NBT_FLUIDSTACK ).putString( "FluidName", this.fluid.getRegistryName().toString() ); + data.getCompound( NBT_FLUIDSTACK ).putInt( "Amount", 0 ); if( this.hasTagCompound() ) { - data.put( "Tag", this.tagCompound ); + data.getCompound( NBT_FLUIDSTACK ).put( "Tag", this.tagCompound ); } else { - data.remove( "Tag" ); + data.getCompound( NBT_FLUIDSTACK ).remove( "Tag" ); } + + data.putLong( NBT_STACKSIZE, this.getStackSize() ); + data.putLong( NBT_REQUESTABLE, this.getCountRequestable() ); + data.putBoolean( NBT_CRAFTABLE, this.isCraftable() ); } @Override @@ -264,27 +267,11 @@ public final class AEFluidStack extends AEStack implements IAEFlu public static IAEFluidStack fromPacket( final PacketBuffer buffer ) { - final byte mask = buffer.readByte(); - final byte stackType = (byte) ( ( mask & 0x0C ) >> 2 ); - final byte countReqType = (byte) ( ( mask & 0x30 ) >> 4 ); - final boolean isCraftable = ( mask & 0x40 ) > 0; - final boolean hasTagCompound = ( mask & 0x80 ) > 0; + final boolean isCraftable = buffer.readBoolean(); + final FluidStack fluidStack = buffer.readFluidStack(); - // don't send this... - final CompoundNBT d = new CompoundNBT(); - - d.putString( "FluidName", buffer.readString() ); - d.putByte( "Amount", (byte) 0 ); - - if( hasTagCompound ) - { - d.put( "Tag", buffer.readCompoundTag() ); - } - - final long stackSize = getPacketValue( stackType, buffer ); - final long countRequestable = getPacketValue( countReqType, buffer ); - - final FluidStack fluidStack = FluidStack.loadFluidStackFromNBT( d ); + final long stackSize = buffer.readVarLong(); + final long countRequestable = buffer.readVarLong(); if( fluidStack == null ) { @@ -292,7 +279,6 @@ public final class AEFluidStack extends AEStack implements IAEFlu } final AEFluidStack fluid = AEFluidStack.fromFluidStack( fluidStack ); - // fluid.priority = (int) priority; fluid.setStackSize( stackSize ); fluid.setCountRequestable( countRequestable ); fluid.setCraftable( isCraftable ); @@ -302,23 +288,9 @@ public final class AEFluidStack extends AEStack implements IAEFlu @Override public void writeToPacket( final PacketBuffer buffer ) { - 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 ); - - this.writeToStream( buffer ); - - this.putPacketValue( buffer, this.getStackSize() ); - this.putPacketValue( buffer, this.getCountRequestable() ); - } - - private void writeToStream( final PacketBuffer buffer ) - { - buffer.writeString( fluid.getRegistryName().toString() ); - if( this.hasTagCompound() ) - { - buffer.writeCompoundTag( tagCompound ); - } + buffer.writeBoolean( this.isCraftable() ); + buffer.writeFluidStack( this.getFluidStack() ); + buffer.writeVarLong( this.getStackSize() ); + buffer.writeVarLong( this.getCountRequestable() ); } } diff --git a/src/main/java/appeng/util/item/AEItemStack.java b/src/main/java/appeng/util/item/AEItemStack.java index 49224baa3..9ac69083d 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 @@ -19,19 +19,16 @@ package appeng.util.item; -import java.util.EnumSet; import java.util.List; import java.util.Objects; import javax.annotation.Nonnull; import javax.annotation.Nullable; - import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.PacketBuffer; -import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; @@ -47,14 +44,17 @@ import appeng.util.Platform; public final class AEItemStack extends AEStack implements IAEItemStack { - private AESharedItemStack sharedStack; + private static final String NBT_STACKSIZE = "cnt"; + private static final String NBT_REQUESTABLE = "req"; + private static final String NBT_CRAFTABLE = "craft"; + private static final String NBT_ITEMSTACK = "is"; + + private final AESharedItemStack sharedStack; @OnlyIn( Dist.CLIENT ) private ITextComponent displayName; @OnlyIn( Dist.CLIENT ) private List tooltip; - @OnlyIn( Dist.CLIENT ) - private ResourceLocation uniqueID; private AEItemStack( final AEItemStack is ) { @@ -90,38 +90,37 @@ public final class AEItemStack extends AEStack implements IAEItemS return null; } - final ItemStack itemstack = ItemStack.read( i ); + final ItemStack itemstack = ItemStack.read( i.getCompound( NBT_ITEMSTACK ) ); 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" ) ); + item.setStackSize( i.getLong( NBT_STACKSIZE ) ); + item.setCountRequestable( i.getLong( NBT_REQUESTABLE ) ); + item.setCraftable( i.getBoolean( NBT_CRAFTABLE ) ); return item; } @Override public void writeToNBT( final CompoundNBT i ) { - this.getDefinition().write( i ); - i.putLong( "Cnt", this.getStackSize() ); - i.putLong( "Req", this.getCountRequestable() ); - i.putBoolean( "Craft", this.isCraftable() ); + final CompoundNBT itemStack = new CompoundNBT(); + this.getDefinition().write( itemStack ); + + i.put( NBT_ITEMSTACK, itemStack ); + i.putLong( NBT_STACKSIZE, this.getStackSize() ); + i.putLong( NBT_REQUESTABLE, this.getCountRequestable() ); + i.putBoolean( NBT_CRAFTABLE, this.isCraftable() ); } - public static AEItemStack fromPacket( final PacketBuffer data ) + public static AEItemStack fromPacket( final PacketBuffer buffer ) { - 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 = data.readItemStack(); - final long stackSize = getPacketValue( stackType, data ); - final long countRequestable = getPacketValue( countReqType, data ); + final boolean isCraftable = buffer.readBoolean(); + final long stackSize = buffer.readVarLong(); + final long countRequestable = buffer.readVarLong(); + final ItemStack itemstack = buffer.readItemStack(); if( itemstack.isEmpty() ) { @@ -135,15 +134,12 @@ public final class AEItemStack extends AEStack implements IAEItemS } @Override - public void writeToPacket( final PacketBuffer i ) + public void writeToPacket( final PacketBuffer buffer ) { - final byte mask = (byte) ( ( this.getType( this.getStackSize() ) << 2 ) | ( this - .getType( this.getCountRequestable() ) << 4 ) | ( (byte) ( this.isCraftable() ? 1 : 0 ) << 6 ) ); - - i.writeByte( mask ); - i.writeItemStack(getDefinition()); - this.putPacketValue( i, this.getStackSize() ); - this.putPacketValue( i, this.getCountRequestable() ); + buffer.writeBoolean( this.isCraftable() ); + buffer.writeVarLong( this.getStackSize() ); + buffer.writeVarLong( this.getCountRequestable() ); + buffer.writeItemStack( getDefinition() ); } @Override diff --git a/src/main/java/appeng/util/item/AESharedItemStack.java b/src/main/java/appeng/util/item/AESharedItemStack.java index 553605077..8dcedef92 100644 --- a/src/main/java/appeng/util/item/AESharedItemStack.java +++ b/src/main/java/appeng/util/item/AESharedItemStack.java @@ -32,9 +32,6 @@ import appeng.api.config.FuzzyMode; final class AESharedItemStack implements Comparable { - private static final CompoundNBT LOW_TAG = new CompoundNBT(); - private static final CompoundNBT HIGH_TAG = new CompoundNBT(); - private final ItemStack itemStack; private final int itemId; private final int itemDamage; @@ -48,9 +45,9 @@ final class AESharedItemStack implements Comparable this.hashCode = this.makeHashCode(); } - Bounds getBounds( final FuzzyMode fuzzy, final boolean ignoreMeta ) + Bounds getBounds( final FuzzyMode fuzzy ) { - return new Bounds( this.itemStack, fuzzy, ignoreMeta ); + return new Bounds( this.itemStack, fuzzy ); } ItemStack getDefinition() @@ -116,36 +113,9 @@ final class AESharedItemStack implements Comparable return damageValue; } - final int nbt = this.compareNBT( b.getDefinition() ); - if( nbt != 0 ) - { - return nbt; - } - - if( !this.itemStack.areCapsCompatible( b.getDefinition() ) ) - { - return System.identityHashCode( this.itemStack ) - System.identityHashCode( b.getDefinition() ); - } return 0; } - private int compareNBT( final ItemStack b ) - { - if( this.itemStack.getTag() == b.getTag() ) - { - return 0; - } - if( this.itemStack.getTag() == LOW_TAG || b.getTag() == HIGH_TAG ) - { - return -1; - } - if( this.itemStack.getTag() == HIGH_TAG || b.getTag() == LOW_TAG ) - { - return 1; - } - return System.identityHashCode( this.itemStack.getTag() ) - System.identityHashCode( b.getTag() ); - } - private int makeHashCode() { return Objects.hash( this.itemId, this.itemDamage, this.itemStack.hasTag() ? this.itemStack.getTag() : 0 ); @@ -160,20 +130,20 @@ final class AESharedItemStack implements Comparable * Bounds enforced by {@link ItemStack#isEmpty()} */ private static final int MIN_DAMAGE_VALUE = 0; - private static final int MAX_DAMAGE_VALUE = 65535; + private static final int MAX_DAMAGE_VALUE = Short.MAX_VALUE; private final AESharedItemStack lower; private final AESharedItemStack upper; - public Bounds( final ItemStack stack, final FuzzyMode fuzzy, final boolean ignoreMeta ) + public Bounds( final ItemStack stack, final FuzzyMode fuzzy ) { Preconditions.checkState( !stack.isEmpty(), "ItemStack#isEmpty() has to be false" ); Preconditions.checkState( stack.getCount() == 1, "ItemStack#getCount() has to be 1" ); final CompoundNBT tag = stack.hasTag() ? stack.getTag() : null; - this.lower = this.makeLowerBound( stack, tag, fuzzy, ignoreMeta ); - this.upper = this.makeUpperBound( stack, tag, fuzzy, ignoreMeta ); + this.lower = this.makeLowerBound( stack, tag, fuzzy ); + this.upper = this.makeUpperBound( stack, tag, fuzzy ); } public AESharedItemStack lower() @@ -186,83 +156,65 @@ final class AESharedItemStack implements Comparable return this.upper; } - private AESharedItemStack makeLowerBound( final ItemStack itemStack, final CompoundNBT tag, final FuzzyMode fuzzy, final boolean ignoreMeta ) + private AESharedItemStack makeLowerBound( final ItemStack itemStack, final CompoundNBT tag, final FuzzyMode fuzzy ) { final ItemStack newDef = itemStack.copy(); - if( ignoreMeta ) + if( newDef.getItem().isDamageable() ) { - newDef.setDamage( MIN_DAMAGE_VALUE ); - newDef.setTag( tag ); - } - else - { - if( newDef.getItem().isDamageable() ) + if( fuzzy == FuzzyMode.IGNORE_ALL ) { - if( fuzzy == FuzzyMode.IGNORE_ALL ) + newDef.setDamage( MIN_DAMAGE_VALUE ); + } + else if( fuzzy == FuzzyMode.PERCENT_99 ) + { + if( itemStack.getDamage() == MIN_DAMAGE_VALUE ) { newDef.setDamage( MIN_DAMAGE_VALUE ); } - else if( fuzzy == FuzzyMode.PERCENT_99 ) - { - if( itemStack.getDamage() == MIN_DAMAGE_VALUE ) - { - newDef.setDamage( MIN_DAMAGE_VALUE ); - } - else - { - newDef.setDamage( MIN_DAMAGE_VALUE + 1 ); - } - } else { - final int breakpoint = fuzzy.calculateBreakPoint( itemStack.getMaxDamage() ); - final int damage = breakpoint <= itemStack.getDamage() ? breakpoint : 0; - newDef.setDamage( damage ); + newDef.setDamage( MIN_DAMAGE_VALUE + 1 ); } } - newDef.setTag( LOW_TAG ); + else + { + final int breakpoint = fuzzy.calculateBreakPoint( itemStack.getMaxDamage() ); + final int damage = breakpoint <= itemStack.getDamage() ? breakpoint : 0; + newDef.setDamage( damage ); + } } return new AESharedItemStack( newDef ); } - private AESharedItemStack makeUpperBound( final ItemStack itemStack, final CompoundNBT tag, final FuzzyMode fuzzy, final boolean ignoreMeta ) + private AESharedItemStack makeUpperBound( final ItemStack itemStack, final CompoundNBT tag, final FuzzyMode fuzzy ) { final ItemStack newDef = itemStack.copy(); - if( ignoreMeta ) + if( newDef.getItem().isDamageable() ) { - newDef.setDamage( MAX_DAMAGE_VALUE ); - newDef.setTag( tag ); - } - else - { - if( newDef.getItem().isDamageable() ) + if( fuzzy == FuzzyMode.IGNORE_ALL ) { - if( fuzzy == FuzzyMode.IGNORE_ALL ) + newDef.setDamage( itemStack.getMaxDamage() + 1 ); + } + else if( fuzzy == FuzzyMode.PERCENT_99 ) + { + if( itemStack.getDamage() == MIN_DAMAGE_VALUE ) { - newDef.setDamage( itemStack.getMaxDamage() + 1 ); - } - else if( fuzzy == FuzzyMode.PERCENT_99 ) - { - if( itemStack.getDamage() == MIN_DAMAGE_VALUE ) - { - newDef.setDamage( MIN_DAMAGE_VALUE ); - } - else - { - newDef.setDamage( itemStack.getMaxDamage() + 1 ); - } + newDef.setDamage( MIN_DAMAGE_VALUE ); } else { - final int breakpoint = fuzzy.calculateBreakPoint( itemStack.getMaxDamage() ); - final int damage = itemStack.getDamage() < breakpoint ? breakpoint - 1 : itemStack.getMaxDamage() + 1; - newDef.setDamage( damage ); + newDef.setDamage( itemStack.getMaxDamage() + 1 ); } } - newDef.setTag( HIGH_TAG ); + else + { + final int breakpoint = fuzzy.calculateBreakPoint( itemStack.getMaxDamage() ); + final int damage = itemStack.getDamage() < breakpoint ? breakpoint - 1 : itemStack.getMaxDamage() + 1; + newDef.setDamage( damage ); + } } return new AESharedItemStack( newDef ); diff --git a/src/main/java/appeng/util/item/AEStack.java b/src/main/java/appeng/util/item/AEStack.java index c7551d60c..0c05bbe16 100644 --- a/src/main/java/appeng/util/item/AEStack.java +++ b/src/main/java/appeng/util/item/AEStack.java @@ -19,42 +19,16 @@ package appeng.util.item; -import net.minecraft.network.PacketBuffer; - 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; - protected static long getPacketValue( final byte type, final PacketBuffer 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; - } - - return tag.readLong(); - } - @Override public long getStackSize() { @@ -62,10 +36,10 @@ public abstract class AEStack> implements } @Override - public StackType setStackSize( final long ss ) + public T setStackSize( final long ss ) { this.stackSize = ss; - return (StackType) this; + return (T) this; } @Override @@ -75,10 +49,10 @@ public abstract class AEStack> implements } @Override - public StackType setCountRequestable( final long countRequestable ) + public T setCountRequestable( final long countRequestable ) { this.countRequestable = countRequestable; - return (StackType) this; + return (T) this; } @Override @@ -88,26 +62,25 @@ public abstract class AEStack> implements } @Override - public StackType setCraftable( final boolean isCraftable ) + public T setCraftable( final boolean isCraftable ) { this.isCraftable = isCraftable; - return (StackType) this; + return (T) this; } @Override - public StackType reset() + public T reset() { this.stackSize = 0; - // priority = Integer.MIN_VALUE; this.setCountRequestable( 0 ); this.setCraftable( false ); - return (StackType) this; + return (T) this; } @Override - public StackType empty() + public T empty() { - final StackType dup = this.copy(); + final T dup = this.copy(); dup.reset(); return dup; } @@ -142,45 +115,5 @@ public abstract class AEStack> implements this.countRequestable -= i; } - 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 abstract boolean hasTagCompound(); - - protected void putPacketValue( final PacketBuffer 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 ); - } - } } diff --git a/src/main/java/appeng/util/item/AbstractItemList.java b/src/main/java/appeng/util/item/AbstractItemList.java new file mode 100644 index 000000000..f3726a6d2 --- /dev/null +++ b/src/main/java/appeng/util/item/AbstractItemList.java @@ -0,0 +1,200 @@ +/* + * This file is part of Applied Energistics 2. + * 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 + * 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.item; + + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.Map; + +import appeng.api.config.FuzzyMode; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; + + +abstract class AbstractItemList implements IItemList +{ + + @Override + public void add( final IAEItemStack option ) + { + if( option == null ) + { + return; + } + + final IAEItemStack st = this.getRecords().get( ( (AEItemStack) option ).getSharedStack() ); + + if( st != null ) + { + st.add( option ); + return; + } + + final IAEItemStack opt = option.copy(); + + this.putItemRecord( opt ); + } + + @Override + public IAEItemStack findPrecise( final IAEItemStack itemStack ) + { + if( itemStack == null ) + { + return null; + } + + return this.getRecords().get( ( (AEItemStack) itemStack ).getSharedStack() ); + } + + @Override + public Collection findFuzzy( final IAEItemStack filter, final FuzzyMode fuzzy ) + { + if( filter == null ) + { + return Collections.emptyList(); + } + + return this.getRecords().values(); + } + + @Override + public boolean isEmpty() + { + return !this.iterator().hasNext(); + } + + @Override + public void addStorage( final IAEItemStack option ) + { + if( option == null ) + { + return; + } + + final IAEItemStack st = this.getRecords().get( ( (AEItemStack) option ).getSharedStack() ); + + if( st != null ) + { + st.incStackSize( option.getStackSize() ); + return; + } + + final IAEItemStack opt = option.copy(); + + this.putItemRecord( opt ); + } + + @Override + public void addCrafting( final IAEItemStack option ) + { + if( option == null ) + { + return; + } + + final IAEItemStack st = this.getRecords().get( ( (AEItemStack) option ).getSharedStack() ); + + if( st != null ) + { + st.setCraftable( true ); + return; + } + + final IAEItemStack opt = option.copy(); + opt.setStackSize( 0 ); + opt.setCraftable( true ); + + this.putItemRecord( opt ); + } + + @Override + public void addRequestable( final IAEItemStack option ) + { + if( option == null ) + { + return; + } + + final IAEItemStack st = this.getRecords().get( ( (AEItemStack) option ).getSharedStack() ); + + if( st != null ) + { + st.setCountRequestable( st.getCountRequestable() + option.getCountRequestable() ); + return; + } + + final IAEItemStack opt = option.copy(); + opt.setStackSize( 0 ); + opt.setCraftable( false ); + opt.setCountRequestable( option.getCountRequestable() ); + + this.putItemRecord( opt ); + } + + @Override + public IAEItemStack getFirstItem() + { + for( final IAEItemStack stackType : this ) + { + return stackType; + } + + return null; + } + + @Override + public int size() + { + int size = 0; + for( IAEItemStack entry : getRecords().values() ) + { + if( entry.isMeaningful() ) + { + size++; + } + } + + return size; + } + + @Override + public Iterator iterator() + { + return new MeaningfulItemIterator<>( this.getRecords().values() ); + } + + @Override + public void resetStatus() + { + for( final IAEItemStack i : this ) + { + i.reset(); + } + } + + abstract Map getRecords(); + + private IAEItemStack putItemRecord( final IAEItemStack itemStack ) + { + return this.getRecords().put( ( (AEItemStack) itemStack ).getSharedStack(), itemStack ); + } + +} diff --git a/src/main/java/appeng/util/item/FuzzyItemList.java b/src/main/java/appeng/util/item/FuzzyItemList.java new file mode 100644 index 000000000..947631773 --- /dev/null +++ b/src/main/java/appeng/util/item/FuzzyItemList.java @@ -0,0 +1,62 @@ +/* + * This file is part of Applied Energistics 2. + * 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 + * 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.item; + + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; +import java.util.NavigableMap; +import java.util.TreeMap; + +import appeng.api.config.FuzzyMode; +import appeng.api.storage.data.IAEItemStack; +import appeng.util.item.AESharedItemStack.Bounds; + + +class FuzzyItemList extends AbstractItemList +{ + private final NavigableMap records = new TreeMap<>(); + + @Override + public Collection findFuzzy( final IAEItemStack filter, final FuzzyMode fuzzy ) + { + if( filter == null ) + { + return Collections.emptyList(); + } + + return this.findFuzzyDamage( filter, fuzzy ); + } + + @Override + Map getRecords() + { + return this.records; + } + + private Collection findFuzzyDamage( final IAEItemStack filter, final FuzzyMode fuzzy ) + { + final AEItemStack itemStack = (AEItemStack) filter; + final Bounds bounds = itemStack.getSharedStack().getBounds( fuzzy ); + + return this.records.subMap( bounds.lower(), true, bounds.upper(), true ).descendingMap().values(); + } + +} diff --git a/src/main/java/appeng/util/item/ItemList.java b/src/main/java/appeng/util/item/ItemList.java index 87e927e5c..0e0892e01 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 @@ -21,41 +21,24 @@ package appeng.util.item; import java.util.Collection; import java.util.Collections; +import java.util.IdentityHashMap; import java.util.Iterator; -import java.util.NavigableMap; -import java.util.concurrent.ConcurrentSkipListMap; +import java.util.Map; +import java.util.NoSuchElementException; + +import net.minecraft.item.Item; 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 NavigableMap records = new ConcurrentSkipListMap<>(); + private final static IItemList NULL_ITEMLIST = new NullItemList(); - @Override - public void add( final IAEItemStack option ) - { - if( option == null ) - { - return; - } - - final IAEItemStack st = this.records.get( ( (AEItemStack) option ).getSharedStack() ); - - if( st != null ) - { - st.add( option ); - return; - } - - final IAEItemStack opt = option.copy(); - - this.putItemRecord( opt ); - } + private final Map> records = new IdentityHashMap<>(); @Override public IAEItemStack findPrecise( final IAEItemStack itemStack ) @@ -65,7 +48,7 @@ public final class ItemList implements IItemList return null; } - return this.records.get( ( (AEItemStack) itemStack ).getSharedStack() ); + return this.getRecord( itemStack.getItem() ).findPrecise( itemStack ); } @Override @@ -76,9 +59,7 @@ public final class ItemList implements IItemList return Collections.emptyList(); } - final AEItemStack ais = (AEItemStack) filter; - - return this.findFuzzyDamage( ais, fuzzy, false ); + return this.getRecord( filter.getItem() ).findFuzzy( filter, fuzzy ); } @Override @@ -88,76 +69,47 @@ public final class ItemList implements IItemList } @Override - public void addStorage( final IAEItemStack option ) + public void add( final IAEItemStack itemStack ) { - if( option == null ) + if( itemStack == null ) { return; } - final IAEItemStack st = this.records.get( ( (AEItemStack) option ).getSharedStack() ); - - if( st != null ) - { - st.incStackSize( option.getStackSize() ); - return; - } - - final IAEItemStack opt = option.copy(); - - this.putItemRecord( opt ); - } - - /* - * public void clean() { Iterator i = iterator(); while (i.hasNext()) { StackType AEI = - * i.next(); if ( !AEI.isMeaningful() ) i.remove(); } } - */ - - @Override - public void addCrafting( final IAEItemStack option ) - { - if( option == null ) - { - return; - } - - final IAEItemStack st = this.records.get( ( (AEItemStack) option ).getSharedStack() ); - - if( st != null ) - { - st.setCraftable( true ); - return; - } - - final IAEItemStack opt = option.copy(); - opt.setStackSize( 0 ); - opt.setCraftable( true ); - - this.putItemRecord( opt ); + this.getOrCreateRecord( itemStack.getItem() ).add( itemStack ); } @Override - public void addRequestable( final IAEItemStack option ) + public void addStorage( final IAEItemStack itemStack ) { - if( option == null ) + if( itemStack == null ) { return; } - final IAEItemStack st = this.records.get( ( (AEItemStack) option ).getSharedStack() ); + this.getOrCreateRecord( itemStack.getItem() ).addStorage( itemStack ); + } - if( st != null ) + @Override + public void addCrafting( final IAEItemStack itemStack ) + { + if( itemStack == null ) { - st.setCountRequestable( st.getCountRequestable() + option.getCountRequestable() ); return; } - final IAEItemStack opt = option.copy(); - opt.setStackSize( 0 ); - opt.setCraftable( false ); - opt.setCountRequestable( option.getCountRequestable() ); + this.getOrCreateRecord( itemStack.getItem() ).addCrafting( itemStack ); + } - this.putItemRecord( opt ); + @Override + public void addRequestable( final IAEItemStack itemStack ) + { + if( itemStack == null ) + { + return; + } + + this.getOrCreateRecord( itemStack.getItem() ).addRequestable( itemStack ); } @Override @@ -174,13 +126,19 @@ public final class ItemList implements IItemList @Override public int size() { - return this.records.size(); + int size = 0; + for( IItemList entry : records.values() ) + { + size += entry.size(); + } + + return size; } @Override public Iterator iterator() { - return new MeaningfulItemIterator<>( this.records.values().iterator() ); + return new ChainedIterator( this.records.values().iterator() ); } @Override @@ -192,16 +150,76 @@ public final class ItemList implements IItemList } } - private IAEItemStack putItemRecord( final IAEItemStack itemStack ) + private IItemList getRecord( Item item ) { - return this.records.put( ( (AEItemStack) itemStack ).getSharedStack(), itemStack ); + return this.records.getOrDefault( item, NULL_ITEMLIST ); } - private Collection findFuzzyDamage( final IAEItemStack filter, final FuzzyMode fuzzy, final boolean ignoreMeta ) + private IItemList getOrCreateRecord( Item item ) { - final AEItemStack itemStack = (AEItemStack) filter; - final Bounds bounds = itemStack.getSharedStack().getBounds( fuzzy, ignoreMeta ); + return this.records.computeIfAbsent( item, this::makeRecordMap ); + } + + private IItemList makeRecordMap( Item item ) + { + if( item.isDamageable() ) + { + return new FuzzyItemList(); + } + else + { + return new StrictItemList(); + } + } + + private class ChainedIterator implements Iterator + { + + private final Iterator> parent; + private Iterator next; + + public ChainedIterator( Iterator> iterator ) + { + this.parent = iterator; + if( this.parent.hasNext() ) + { + this.next = this.parent.next().iterator(); + } + } + + @Override + public boolean hasNext() + { + while( this.next != null ) + { + if( this.next.hasNext() ) + { + return true; + } + + if( this.parent.hasNext() ) + { + this.next = this.parent.next().iterator(); + } + else + { + this.next = null; + } + } + + return false; + } + + @Override + public IAEItemStack next() + { + if( this.next == null ) + { + throw new NoSuchElementException(); + } + + return this.next.next(); + } - return this.records.subMap( bounds.lower(), true, bounds.upper(), true ).descendingMap().values(); } } diff --git a/src/main/java/appeng/util/item/MeaningfulItemIterator.java b/src/main/java/appeng/util/item/MeaningfulItemIterator.java index 7d7c8b016..e795ef3e8 100644 --- a/src/main/java/appeng/util/item/MeaningfulItemIterator.java +++ b/src/main/java/appeng/util/item/MeaningfulItemIterator.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 @@ -19,6 +19,8 @@ package appeng.util.item; +import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; @@ -28,12 +30,15 @@ import appeng.api.storage.data.IAEItemStack; public class MeaningfulItemIterator implements Iterator { + private final Collection collection; private final Iterator parent; private T next; + private final Collection toRemove = new ArrayList<>(); - public MeaningfulItemIterator( final Iterator iterator ) + public MeaningfulItemIterator( final Collection collection ) { - this.parent = iterator; + this.collection = collection; + this.parent = collection.iterator(); } @Override @@ -49,10 +54,15 @@ public class MeaningfulItemIterator implements Iterator< } else { - this.parent.remove(); // self cleaning :3 + // TODO: Avoid if possible + this.toRemove.add( this.next ); + // this.parent.remove(); // self cleaning :3 } } + // Cleanup afterwards to avoid CMEs + this.toRemove.forEach( entry -> this.collection.remove( entry ) ); + this.next = null; return false; } diff --git a/src/main/java/appeng/util/item/NullItemList.java b/src/main/java/appeng/util/item/NullItemList.java new file mode 100644 index 000000000..0499f1801 --- /dev/null +++ b/src/main/java/appeng/util/item/NullItemList.java @@ -0,0 +1,95 @@ +/* + * This file is part of Applied Energistics 2. + * 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 + * 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.item; + + +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +import appeng.api.config.FuzzyMode; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; + + +public class NullItemList implements IItemList +{ + + @Override + public void add( IAEItemStack option ) + { + } + + @Override + public IAEItemStack findPrecise( IAEItemStack i ) + { + return null; + } + + @Override + public Collection findFuzzy( IAEItemStack input, FuzzyMode fuzzy ) + { + return Collections.emptyList(); + } + + @Override + public boolean isEmpty() + { + return true; + } + + @Override + public void addStorage( IAEItemStack option ) + { + } + + @Override + public void addCrafting( IAEItemStack option ) + { + } + + @Override + public void addRequestable( IAEItemStack option ) + { + } + + @Override + public IAEItemStack getFirstItem() + { + return null; + } + + @Override + public int size() + { + return 0; + } + + @Override + public Iterator iterator() + { + return Collections.emptyIterator(); + } + + @Override + public void resetStatus() + { + } + +} diff --git a/src/main/java/appeng/util/item/StrictItemList.java b/src/main/java/appeng/util/item/StrictItemList.java new file mode 100644 index 000000000..952d7b119 --- /dev/null +++ b/src/main/java/appeng/util/item/StrictItemList.java @@ -0,0 +1,39 @@ +/* + * This file is part of Applied Energistics 2. + * 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 + * 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.item; + + +import java.util.IdentityHashMap; +import java.util.Map; + +import appeng.api.storage.data.IAEItemStack; + + +class StrictItemList extends AbstractItemList +{ + + private final Map records = new IdentityHashMap<>(); + + @Override + Map getRecords() + { + return this.records; + } + +}