From 94d73aec7c80920a3af8be1021c043969d4b1a8c Mon Sep 17 00:00:00 2001 From: PrototypeTrousers Date: Thu, 9 Dec 2021 23:08:26 -0300 Subject: [PATCH] wwww --- gradle.properties | 2 +- .../fluids/helper/DualityFluidInterface.java | 12 +- .../fluids/parts/PartFluidStorageBus.java | 996 +++++++------ .../appeng/me/cache/GridStorageCache.java | 13 +- .../java/appeng/me/cache/NetworkMonitor.java | 14 +- .../parts/misc/PartSharedStorageBus.java | 231 --- .../appeng/parts/misc/PartStorageBus.java | 1250 ++++++++--------- .../java/appeng/tile/storage/TileChest.java | 2 +- .../java/appeng/tile/storage/TileDrive.java | 2 +- 9 files changed, 1164 insertions(+), 1358 deletions(-) delete mode 100644 src/main/java/appeng/parts/misc/PartSharedStorageBus.java diff --git a/gradle.properties b/gradle.properties index 900f981ef..b0cc7cf87 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ aechannel=stable aebuild=7 aegroup=appeng aebasename=appliedenergistics2 -trousers=omni-fixes-v49j +trousers=omni-fixes-v49k ######################################################### # Versions # diff --git a/src/main/java/appeng/fluids/helper/DualityFluidInterface.java b/src/main/java/appeng/fluids/helper/DualityFluidInterface.java index 56b706e8b..37f9bf812 100644 --- a/src/main/java/appeng/fluids/helper/DualityFluidInterface.java +++ b/src/main/java/appeng/fluids/helper/DualityFluidInterface.java @@ -93,7 +93,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable private final MEMonitorPassThrough items = new MEMonitorPassThrough<>( new NullInventory(), AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); private final MEMonitorPassThrough fluids = new MEMonitorPassThrough<>( new NullInventory(), AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ); - private boolean resetConfigCache; + private boolean resetConfigCache = true; private IMEMonitor configCachedHandler; public DualityFluidInterface( final AENetworkProxy networkProxy, final IFluidInterfaceHost ih ) @@ -117,15 +117,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable public IUpgradeableHost getHost() { - if( this.iHost instanceof IUpgradeableHost ) - { - return this.iHost; - } - if( this.iHost instanceof IUpgradeableHost ) - { - return this.iHost; - } - return null; + return this.iHost; } @Override diff --git a/src/main/java/appeng/fluids/parts/PartFluidStorageBus.java b/src/main/java/appeng/fluids/parts/PartFluidStorageBus.java index 30889ed16..effa3abf4 100644 --- a/src/main/java/appeng/fluids/parts/PartFluidStorageBus.java +++ b/src/main/java/appeng/fluids/parts/PartFluidStorageBus.java @@ -19,17 +19,54 @@ package appeng.fluids.parts; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - import javax.annotation.Nonnull; - +import javax.annotation.Nullable; +import appeng.api.AEApi; +import appeng.api.config.*; +import appeng.api.networking.IGridNode; +import appeng.api.networking.events.MENetworkCellArrayUpdate; +import appeng.api.networking.events.MENetworkChannelsChanged; +import appeng.api.networking.events.MENetworkEventSubscribe; +import appeng.api.networking.events.MENetworkPowerStatusChange; +import appeng.api.networking.security.IActionSource; +import appeng.api.networking.storage.IBaseMonitor; import appeng.api.networking.storage.IStorageGrid; -import appeng.api.storage.channels.IItemStorageChannel; +import appeng.api.networking.ticking.IGridTickable; +import appeng.api.networking.ticking.ITickManager; +import appeng.api.networking.ticking.TickRateModulation; +import appeng.api.networking.ticking.TickingRequest; +import appeng.api.parts.IPart; +import appeng.api.parts.IPartCollisionHelper; +import appeng.api.parts.IPartModel; +import appeng.api.storage.*; +import appeng.api.storage.channels.IFluidStorageChannel; +import appeng.api.storage.data.IAEFluidStack; +import appeng.api.storage.data.IItemList; +import appeng.api.util.AECableType; +import appeng.api.util.IConfigManager; +import appeng.capabilities.Capabilities; +import appeng.core.AppEng; +import appeng.core.settings.TickRates; +import appeng.core.sync.GuiBridge; import appeng.fluids.helper.IConfigurableFluidInventory; +import appeng.fluids.tile.TileFluidInterface; +import appeng.fluids.util.AEFluidInventory; +import appeng.fluids.util.IAEFluidInventory; +import appeng.fluids.util.IAEFluidTank; +import appeng.helpers.IPriorityHost; +import appeng.items.parts.PartModels; +import appeng.me.GridAccessException; import appeng.me.cache.GridStorageCache; +import appeng.me.helpers.MachineSource; +import appeng.me.storage.ITickingMonitor; +import appeng.me.storage.MEInventoryHandler; +import appeng.parts.PartModel; +import appeng.parts.automation.PartUpgradeable; +import appeng.tile.networking.TileCableBus; import appeng.util.ConfigManager; +import appeng.util.Platform; +import appeng.util.prioritylist.FuzzyPriorityList; +import appeng.util.prioritylist.PrecisePriorityList; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -37,54 +74,15 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; +import net.minecraft.world.IBlockAccess; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; -import appeng.api.AEApi; -import appeng.api.config.AccessRestriction; -import appeng.api.config.FuzzyMode; -import appeng.api.config.IncludeExclude; -import appeng.api.config.Settings; -import appeng.api.config.StorageFilter; -import appeng.api.config.Upgrades; -import appeng.api.networking.IGridNode; -import appeng.api.networking.events.MENetworkCellArrayUpdate; -import appeng.api.networking.security.IActionSource; -import appeng.api.networking.storage.IBaseMonitor; -import appeng.api.networking.ticking.ITickManager; -import appeng.api.networking.ticking.TickRateModulation; -import appeng.api.networking.ticking.TickingRequest; -import appeng.api.parts.IPartHost; -import appeng.api.parts.IPartModel; -import appeng.api.storage.IMEInventory; -import appeng.api.storage.IMEInventoryHandler; -import appeng.api.storage.IMEMonitorHandlerReceiver; -import appeng.api.storage.IStorageChannel; -import appeng.api.storage.IStorageMonitorable; -import appeng.api.storage.IStorageMonitorableAccessor; -import appeng.api.storage.channels.IFluidStorageChannel; -import appeng.api.storage.data.IAEFluidStack; -import appeng.api.storage.data.IItemList; -import appeng.api.util.AEPartLocation; -import appeng.capabilities.Capabilities; -import appeng.core.AppEng; -import appeng.core.settings.TickRates; -import appeng.core.sync.GuiBridge; -import appeng.fluids.util.AEFluidInventory; -import appeng.fluids.util.IAEFluidInventory; -import appeng.fluids.util.IAEFluidTank; -import appeng.helpers.IInterfaceHost; -import appeng.items.parts.PartModels; -import appeng.me.GridAccessException; -import appeng.me.helpers.MachineSource; -import appeng.me.storage.ITickingMonitor; -import appeng.me.storage.MEInventoryHandler; -import appeng.parts.PartModel; -import appeng.parts.misc.PartSharedStorageBus; -import appeng.util.Platform; -import appeng.util.prioritylist.FuzzyPriorityList; -import appeng.util.prioritylist.PrecisePriorityList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; /** @@ -92,463 +90,559 @@ import appeng.util.prioritylist.PrecisePriorityList; * @version rv6 - 22/05/2018 * @since rv6 22/05/2018 */ -public class PartFluidStorageBus extends PartSharedStorageBus implements IMEMonitorHandlerReceiver, IAEFluidInventory, IConfigurableFluidInventory +public class PartFluidStorageBus extends PartUpgradeable implements IGridTickable, ICellContainer, IMEMonitorHandlerReceiver, IAEFluidInventory, IConfigurableFluidInventory, IPriorityHost { - public static final ResourceLocation MODEL_BASE = new ResourceLocation( AppEng.MOD_ID, "part/fluid_storage_bus_base" ); - @PartModels - public static final IPartModel MODELS_OFF = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/fluid_storage_bus_off" ) ); - @PartModels - public static final IPartModel MODELS_ON = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/fluid_storage_bus_on" ) ); - @PartModels - public static final IPartModel MODELS_HAS_CHANNEL = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/fluid_storage_bus_has_channel" ) ); + public static final ResourceLocation MODEL_BASE = new ResourceLocation( AppEng.MOD_ID, "part/fluid_storage_bus_base" ); + @PartModels + public static final IPartModel MODELS_OFF = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/fluid_storage_bus_off" ) ); + @PartModels + public static final IPartModel MODELS_ON = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/fluid_storage_bus_on" ) ); + @PartModels + public static final IPartModel MODELS_HAS_CHANNEL = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/fluid_storage_bus_has_channel" ) ); - private final IActionSource source; - private final AEFluidInventory config = new AEFluidInventory( this, 63 ); - private boolean cached = false; - private ITickingMonitor monitor = null; - private MEInventoryHandler handler = null; - private int handlerHash = 0; - private byte resetCacheLogic = 0; + private final IActionSource source; + private final AEFluidInventory config = new AEFluidInventory( this, 63 ); + private int priority = 0; + private boolean cached = false; + private ITickingMonitor monitor = null; + private MEInventoryHandler handler = null; + private int handlerHash = 0; + private boolean wasActive = false; + private byte resetCacheLogic = 0; + private boolean accessChanged; + private boolean readOncePass; - public PartFluidStorageBus( ItemStack is ) - { - super( is ); - this.getConfigManager().registerSetting( Settings.ACCESS, AccessRestriction.READ_WRITE ); - this.getConfigManager().registerSetting( Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL ); - this.getConfigManager().registerSetting( Settings.STORAGE_FILTER, StorageFilter.EXTRACTABLE_ONLY ); - this.source = new MachineSource( this ); - } + public PartFluidStorageBus( ItemStack is ) + { + super( is ); + this.getConfigManager().registerSetting( Settings.ACCESS, AccessRestriction.READ_WRITE ); + this.getConfigManager().registerSetting( Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL ); + this.getConfigManager().registerSetting( Settings.STORAGE_FILTER, StorageFilter.EXTRACTABLE_ONLY ); + this.source = new MachineSource( this ); + } - private IMEInventory getInventoryWrapper( TileEntity target ) - { - EnumFacing targetSide = this.getSide().getFacing().getOpposite(); - // Prioritize a handler to directly link to another ME network - IStorageMonitorableAccessor accessor = target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ); - if( accessor != null ) - { - IStorageMonitorable inventory = accessor.getInventory( this.source ); - if( inventory != null ) - { - return inventory.getInventory( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ); - } + @Override + @MENetworkEventSubscribe + public void powerRender( final MENetworkPowerStatusChange c ) + { + this.updateStatus(); + } - // So this could / can be a design decision. If the tile does support our custom capability, - // but it does not return an inventory for the action source, we do NOT fall back to using - // IItemHandler's, as that might circumvent the security setings, and might also cause - // performance issues. - return null; - } + protected void updateStatus() + { + final boolean currentActive = this.getProxy().isActive(); + if( this.wasActive != currentActive ) + { + this.wasActive = currentActive; + try + { + this.getProxy().getGrid().postEvent( new MENetworkCellArrayUpdate() ); + this.getHost().markForUpdate(); + } + catch( final GridAccessException e ) + { + // :P + } + } + } - // Check via cap for IItemHandler - IFluidHandler handlerExt = target.getCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, targetSide ); - if( handlerExt != null ) - { - return new FluidHandlerAdapter( handlerExt, this ); - } + @Override + @MENetworkEventSubscribe + public void chanRender( final MENetworkChannelsChanged changedChannels ) + { + this.updateStatus(); + } - return null; - } + @Override + protected int getUpgradeSlots() + { + return 5; + } - @Override - public TickRateModulation tickingRequest( IGridNode node, int ticksSinceLastCall ) - { - if( this.resetCacheLogic != 0 ) - { - this.resetCache(); - } + @Override + public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue ) + { + if( settingName.name().equals( "ACCESS" ) ) + { + this.accessChanged = true; + } + this.resetCache( true ); + this.getHost().markForSave(); + } - if( this.monitor != null ) - { - return this.monitor.onTick(); - } + @Override + public void onFluidInventoryChanged( IAEFluidTank inv, int slot ) + { + if( inv == this.config ) + { + this.resetCache( true ); + } + } - return TickRateModulation.SLEEP; - } + @Override + public void upgradesChanged() + { + super.upgradesChanged(); + this.resetCache( true ); + } - @Override - protected void resetCache() - { - final boolean fullReset = this.resetCacheLogic == 2; - this.resetCacheLogic = 0; + @Override + public void readFromNBT( final NBTTagCompound data ) + { + super.readFromNBT( data ); + this.config.readFromNBT( data, "config" ); + this.priority = data.getInteger( "priority" ); + this.accessChanged = false; + } - final MEInventoryHandler in = this.getInternalHandler(); - IItemList before = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList(); - if( in != null ) - { - if( accessChanged ) - { - AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ); - AccessRestriction oldAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getOldSetting( Settings.ACCESS ); - if( oldAccess.hasPermission( AccessRestriction.READ ) && !currentAccess.hasPermission( AccessRestriction.READ ) ) - { - readOncePass = true; - } - in.setBaseAccess( oldAccess ); - before = in.getAvailableItems( before ); - in.setBaseAccess( currentAccess ); - accessChanged = false; - } - else - { - before = in.getAvailableItems( before ); - } - } + @Override + public void writeToNBT( final NBTTagCompound data ) + { + super.writeToNBT( data ); + this.config.writeToNBT( data, "config" ); + data.setInteger( "priority", this.priority ); + } - this.cached = false; - if( fullReset ) - { - this.handlerHash = 0; - } + @Override + public IFluidHandler getFluidInventoryByName( final String name ) + { + if( name.equals( "config" ) ) + { + return this.config; + } + return null; + } - final MEInventoryHandler out = this.getInternalHandler(); - IItemList after = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList(); + protected void resetCache( final boolean fullReset ) + { + if( this.getHost() == null || this.getHost().getTile() == null || this.getHost().getTile().getWorld() == null || this.getHost().getTile().getWorld().isRemote ) + { + return; + } - if( in != out ) - { - if( out != null ) - { - after = out.getAvailableItems( after ); - } - Platform.postListChanges( before, after, this, this.source ); - } - } + if( fullReset ) + { + this.resetCacheLogic = 2; + } + else if( this.resetCacheLogic < 2 ) + { + this.resetCacheLogic = 1; + } - @Override - protected void resetCache( final boolean fullReset ) - { - if( this.getHost() == null || this.getHost().getTile() == null || this.getHost().getTile().getWorld() == null || this.getHost() - .getTile() - .getWorld().isRemote ) - { - return; - } + try + { + this.getProxy().getTick().alertDevice( this.getProxy().getNode() ); + } + catch( final GridAccessException e ) + { + // :P + } + } - if( fullReset ) - { - this.resetCacheLogic = 2; - } - else if( this.resetCacheLogic < 2 ) - { - this.resetCacheLogic = 1; - } + @Override + public boolean isValid( final Object verificationToken ) + { + return this.handler == verificationToken; + } - try - { - this.getProxy().getTick().alertDevice( this.getProxy().getNode() ); - } - catch( final GridAccessException e ) - { - // :P - } - } + @Override + public void postChange( final IBaseMonitor monitor, final Iterable change, final IActionSource source ) + { + if( this.getProxy().isActive() ) + { + AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ); + if( readOncePass ) + { + readOncePass = false; + try + { + this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ), change, this.source ); + } + catch( final GridAccessException e ) + { + // :( + } + return; + } + if( !currentAccess.hasPermission( AccessRestriction.READ ) ) + { + return; + } + try + { + this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ), change, source ); + } + catch( final GridAccessException e ) + { + // :( + } + } + } - @Override - public boolean onPartActivate( final EntityPlayer player, final EnumHand hand, final Vec3d pos ) - { - if( Platform.isServer() ) - { - Platform.openGUI( player, this.getHost().getTile(), this.getSide(), GuiBridge.GUI_STORAGEBUS_FLUID ); - } - return true; - } + @Override + public void onListUpdate() + { + // not used here. + } - @Override - public void onFluidInventoryChanged( IAEFluidTank inv, int slot ) - { - if( inv == this.config ) - { - this.resetCache( true ); - } - } + @Override + public void getBoxes( final IPartCollisionHelper bch ) + { + bch.addBox( 3, 3, 15, 13, 13, 16 ); + bch.addBox( 2, 2, 14, 14, 14, 15 ); + bch.addBox( 5, 5, 12, 11, 11, 14 ); + } - @Override - public void readFromNBT( final NBTTagCompound data ) - { - super.readFromNBT( data ); - this.config.readFromNBT( data, "config" ); - } + @Override + public void onNeighborChanged( IBlockAccess w, BlockPos pos, BlockPos neighbor ) + { + if( pos.offset( this.getSide().getFacing() ).equals( neighbor ) ) + { - @Override - public void writeToNBT( final NBTTagCompound data ) - { - super.writeToNBT( data ); - this.config.writeToNBT( data, "config" ); - } + final TileEntity te = w.getTileEntity( neighbor ); - @Override - public boolean isValid( final Object verificationToken ) - { - return this.handler == verificationToken; - } + // In case the TE was destroyed, we have to do a full reset immediately. + if( te instanceof TileCableBus ) + { + IPart iPart = ( (TileCableBus) te ).getPart( this.getSide().getOpposite() ); + if( iPart == null || iPart instanceof PartFluidInterface ) + { + this.resetCache( true ); + this.resetCache(); + } + } + else if( te == null || te instanceof TileFluidInterface ) + { + this.resetCache( true ); + this.resetCache(); + } + else + { + this.resetCache( false ); + } + } + } - @Override - public void postChange( final IBaseMonitor monitor, final Iterable change, final IActionSource source ) - { - if( this.getProxy().isActive() ) - { - AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ); - if( readOncePass ) - { - readOncePass = false; - try - { - this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ), change, source ); - } - catch( final GridAccessException e ) - { - // :( - } - return; - } - if( !currentAccess.hasPermission( AccessRestriction.READ ) ) - { - return; - } - try - { - this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ), change, source ); - } - catch( final GridAccessException e ) - { - // :( - } - } - } + @Override + public float getCableConnectionLength( AECableType cable ) + { + return 4; + } - public MEInventoryHandler getInternalHandler() - { - if( this.cached ) - { - return this.handler; - } + @Override + public boolean onPartActivate( final EntityPlayer player, final EnumHand hand, final Vec3d pos ) + { + if( Platform.isServer() ) + { + Platform.openGUI( player, this.getHost().getTile(), this.getSide(), GuiBridge.GUI_STORAGEBUS_FLUID ); + } + return true; + } - final boolean wasSleeping = this.monitor == null; + @Override + public TickingRequest getTickingRequest( IGridNode node ) + { + return new TickingRequest( TickRates.FluidStorageBus.getMin(), TickRates.FluidStorageBus.getMax(), monitor == null, true ); + } - this.cached = true; - final TileEntity self = this.getHost().getTile(); - final TileEntity target = self.getWorld().getTileEntity( self.getPos().offset( this.getSide().getFacing() ) ); - final int newHandlerHash = this.createHandlerHash( target ); + @Override + public TickRateModulation tickingRequest( IGridNode node, int ticksSinceLastCall ) + { + if( this.resetCacheLogic != 0 ) + { + this.resetCache(); + } - if( newHandlerHash != 0 && newHandlerHash == this.handlerHash ) - { - return this.handler; - } + if( this.monitor != null ) + { + return this.monitor.onTick(); + } - this.handlerHash = newHandlerHash; - this.handler = null; - if( this.monitor != null ) - { - ( (IBaseMonitor) monitor ).removeListener( this ); - } - this.monitor = null; - if( target != null ) - { - IMEInventory inv = this.getInventoryWrapper( target ); - if( inv instanceof ITickingMonitor ) - { - this.monitor = (ITickingMonitor) inv; - this.monitor.setActionSource( this.source ); - this.monitor.setMode( (StorageFilter) this.getConfigManager().getSetting( Settings.STORAGE_FILTER ) ); - } + return TickRateModulation.SLEEP; + } - if( inv != null ) - { - this.checkInterfaceVsStorageBus( target, this.getSide().getOpposite() ); + protected void resetCache() + { + final boolean fullReset = this.resetCacheLogic == 2; + this.resetCacheLogic = 0; - this.handler = new MEInventoryHandler<>( inv, AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ); + final MEInventoryHandler in = this.getInternalHandler(); + IItemList before = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList(); + if( in != null ) + { + if( accessChanged ) + { + AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ); + AccessRestriction oldAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getOldSetting( Settings.ACCESS ); + if( oldAccess.hasPermission( AccessRestriction.READ ) && !currentAccess.hasPermission( AccessRestriction.READ ) ) + { + readOncePass = true; + } + in.setBaseAccess( oldAccess ); + before = in.getAvailableItems( before ); + in.setBaseAccess( currentAccess ); + accessChanged = false; + } + else + { + before = in.getAvailableItems( before ); + } + } - this.handler.setBaseAccess( (AccessRestriction) this.getConfigManager().getSetting( Settings.ACCESS ) ); - this.handler.setWhitelist( this.getInstalledUpgrades( Upgrades.INVERTER ) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST ); - this.handler.setPriority( this.getPriority() ); + this.cached = false; + if( fullReset ) + { + this.handlerHash = 0; + } - final IItemList priorityList = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList(); + final MEInventoryHandler out = this.getInternalHandler(); + IItemList after = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList(); - final int slotsToUse = 18 + this.getInstalledUpgrades( Upgrades.CAPACITY ) * 9; - for( int x = 0; x < this.config.getSlots() && x < slotsToUse; x++ ) - { - final IAEFluidStack is = this.config.getFluidInSlot( x ); - if( is != null ) - { - priorityList.add( is ); - } - } + if( in != out ) + { + if( out != null ) + { + after = out.getAvailableItems( after ); + } + Platform.postListChanges( before, after, this, this.source ); + } + } - if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) - { - this.handler.setPartitionList( - new FuzzyPriorityList( priorityList, (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE ) ) ); - } - else - { - this.handler.setPartitionList( new PrecisePriorityList( priorityList ) ); - } + private IMEInventory getInventoryWrapper( TileEntity target ) + { + EnumFacing targetSide = this.getSide().getFacing().getOpposite(); + // Prioritize a handler to directly link to another ME network + IStorageMonitorableAccessor accessor = target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ); + if( accessor != null ) + { + IStorageMonitorable inventory = accessor.getInventory( this.source ); + if( inventory != null ) + { + return inventory.getInventory( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ); + } - if( inv instanceof IBaseMonitor ) - { - if( ( (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ) ).hasPermission( AccessRestriction.READ ) ) - { - ( (IBaseMonitor) inv ).addListener( this, this.handler ); - } - } - } - } + // So this could / can be a design decision. If the tile does support our custom capability, + // but it does not return an inventory for the action source, we do NOT fall back to using + // IItemHandler's, as that might circumvent the security setings, and might also cause + // performance issues. + return null; + } - // update sleep state... - if( wasSleeping != ( this.monitor == null ) ) - { - try - { - final ITickManager tm = this.getProxy().getTick(); - if( this.monitor == null ) - { - tm.sleepDevice( this.getProxy().getNode() ); - } - else - { - tm.wakeDevice( this.getProxy().getNode() ); - } - } - catch( final GridAccessException ignore ) - { - // :( - } - } + // Check via cap for IItemHandler + IFluidHandler handlerExt = target.getCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, targetSide ); + if( handlerExt != null ) + { + return new FluidHandlerAdapter( handlerExt, this ); + } - try - { - // force grid to update handlers... - (( GridStorageCache ) this.getProxy().getGrid().getCache( IStorageGrid.class )).cellUpdate( null ); - } - catch( final GridAccessException ignore ) - { - // :3 - } + return null; + } - return this.handler; - } + private int createHandlerHash( TileEntity target ) + { + if( target == null ) + { + return 0; + } - private void checkInterfaceVsStorageBus( final TileEntity target, final AEPartLocation side ) - { - IInterfaceHost achievement = null; + final EnumFacing targetSide = this.getSide().getFacing().getOpposite(); - if( target instanceof IInterfaceHost ) - { - achievement = (IInterfaceHost) target; - } + if( target.hasCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) ) + { + return Objects.hash( target, target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) ); + } - if( target instanceof IPartHost ) - { - final Object part = ( (IPartHost) target ).getPart( side ); - if( part instanceof IInterfaceHost ) - { - achievement = (IInterfaceHost) part; - } - } + final IFluidHandler fluidHandler = target.getCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, targetSide ); - if( achievement != null && achievement.getActionableNode() != null ) - { - // Platform.addStat( achievement.getActionableNode().getPlayerID(), Achievements.Recursive.getAchievement() - // ); - // Platform.addStat( getActionableNode().getPlayerID(), Achievements.Recursive.getAchievement() ); - } - } + if( fluidHandler != null ) + { + return Objects.hash( target, fluidHandler, fluidHandler.getTankProperties().length ); + } - @Override - public List getCellArray( final IStorageChannel channel ) - { - if( channel == this.getStorageChannel() ) - { - final IMEInventoryHandler out = this.getInternalHandler(); - if( out != null ) - { - return Collections.singletonList( out ); - } - } - return super.getCellArray( channel ); - } + return 0; + } - private int createHandlerHash( TileEntity target ) - { - if( target == null ) - { - return 0; - } + public MEInventoryHandler getInternalHandler() + { + if( this.cached ) + { + return this.handler; + } - final EnumFacing targetSide = this.getSide().getFacing().getOpposite(); + final boolean wasSleeping = this.monitor == null; - if( target.hasCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) ) - { - return Objects.hash( target, target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) ); - } + this.cached = true; + final TileEntity self = this.getHost().getTile(); + final TileEntity target = self.getWorld().getTileEntity( self.getPos().offset( this.getSide().getFacing() ) ); + final int newHandlerHash = this.createHandlerHash( target ); - final IFluidHandler fluidHandler = target.getCapability( CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, targetSide ); + if( newHandlerHash != 0 && newHandlerHash == this.handlerHash ) + { + return this.handler; + } - if( fluidHandler != null ) - { - return Objects.hash( target, fluidHandler, fluidHandler.getTankProperties().length ); - } + this.handlerHash = newHandlerHash; + this.handler = null; + if( this.monitor != null ) + { + ( (IBaseMonitor) monitor ).removeListener( this ); + } + this.monitor = null; + if( target != null ) + { + IMEInventory inv = this.getInventoryWrapper( target ); + if( inv instanceof ITickingMonitor ) + { + this.monitor = (ITickingMonitor) inv; + this.monitor.setActionSource( this.source ); + this.monitor.setMode( (StorageFilter) this.getConfigManager().getSetting( Settings.STORAGE_FILTER ) ); + } - return 0; - } + if( inv != null ) + { + this.handler = new MEInventoryHandler<>( inv, AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ); - @Override - public TickingRequest getTickingRequest( IGridNode node ) - { - return new TickingRequest( TickRates.FluidStorageBus.getMin(), TickRates.FluidStorageBus.getMax(), this.isSleeping(), true ); - } + this.handler.setBaseAccess( (AccessRestriction) this.getConfigManager().getSetting( Settings.ACCESS ) ); + this.handler.setWhitelist( this.getInstalledUpgrades( Upgrades.INVERTER ) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST ); + this.handler.setPriority( this.getPriority() ); - @Override - public void onListUpdate() - { - // not used here. - } + final IItemList priorityList = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList(); - @Override - public IStorageChannel getStorageChannel() - { - return AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ); - } + final int slotsToUse = 18 + this.getInstalledUpgrades( Upgrades.CAPACITY ) * 9; + for( int x = 0; x < this.config.getSlots() && x < slotsToUse; x++ ) + { + final IAEFluidStack is = this.config.getFluidInSlot( x ); + if( is != null ) + { + priorityList.add( is ); + } + } - public IAEFluidTank getConfig() - { - return this.config; - } + if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) + { + this.handler.setPartitionList( new FuzzyPriorityList( priorityList, (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE ) ) ); + } + else + { + this.handler.setPartitionList( new PrecisePriorityList( priorityList ) ); + } - @Override - public IFluidHandler getFluidInventoryByName(final String name) { - if (name.equals("config")) { - return this.config; - } - return null; - } + if( inv instanceof IBaseMonitor ) + { + if( ( (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ) ).hasPermission( AccessRestriction.READ ) ) + { + ( (IBaseMonitor) inv ).addListener( this, this.handler ); + } + } + } + } - @Nonnull - @Override - public IPartModel getStaticModels() - { - if( this.isActive() && this.isPowered() ) - { - return MODELS_HAS_CHANNEL; - } - else if( this.isPowered() ) - { - return MODELS_ON; - } - else - { - return MODELS_OFF; - } - } + // update sleep state... + if( wasSleeping != ( this.monitor == null ) ) + { + try + { + final ITickManager tm = this.getProxy().getTick(); + if( this.monitor == null ) + { + tm.sleepDevice( this.getProxy().getNode() ); + } + else + { + tm.wakeDevice( this.getProxy().getNode() ); + } + } + catch( final GridAccessException ignore ) + { + // :( + } + } - @Override - public ItemStack getItemStackRepresentation() - { - return AEApi.instance().definitions().parts().fluidStorageBus().maybeStack( 1 ).orElse( ItemStack.EMPTY ); - } + try + { + // force grid to update handlers... + ( (GridStorageCache) this.getProxy().getGrid().getCache( IStorageGrid.class ) ).cellUpdate( null ); + } + catch( final GridAccessException e ) + { + // :3 + } - @Override - public GuiBridge getGuiBridge() - { - return GuiBridge.GUI_STORAGEBUS_FLUID; - } + return this.handler; + } + + @Override + public List getCellArray( final IStorageChannel channel ) + { + if( channel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ) + { + final IMEInventoryHandler out = this.getInternalHandler(); + if( out != null ) + { + return Collections.singletonList( out ); + } + } + return Collections.emptyList(); + } + + @Override + public int getPriority() + { + return this.priority; + } + + @Override + public void setPriority( int newValue ) + { + this.priority = newValue; + this.getHost().markForSave(); + this.resetCache( true ); + } + + @Override + public void blinkCell( int slot ) + { + + } + + @Override + public void saveChanges( @Nullable ICellInventory cellInventory ) + { + + } + + public IAEFluidTank getConfig() + { + return this.config; + } + + @Nonnull + @Override + public IPartModel getStaticModels() + { + if( this.isActive() && this.isPowered() ) + { + return MODELS_HAS_CHANNEL; + } + else if( this.isPowered() ) + { + return MODELS_ON; + } + else + { + return MODELS_OFF; + } + } + + @Override + public ItemStack getItemStackRepresentation() + { + return AEApi.instance().definitions().parts().fluidStorageBus().maybeStack( 1 ).orElse( ItemStack.EMPTY ); + } + + @Override + public GuiBridge getGuiBridge() + { + return GuiBridge.GUI_STORAGEBUS_FLUID; + } } diff --git a/src/main/java/appeng/me/cache/GridStorageCache.java b/src/main/java/appeng/me/cache/GridStorageCache.java index c0b8564b3..30e0105f8 100644 --- a/src/main/java/appeng/me/cache/GridStorageCache.java +++ b/src/main/java/appeng/me/cache/GridStorageCache.java @@ -170,15 +170,14 @@ public class GridStorageCache implements IStorageGrid private CellChangeTracker addCellProvider( final ICellProvider cc, final CellChangeTracker tracker ) { - if( this.inactiveCellProviders.contains( cc ) && !this.activeCellProviders.contains( cc )) + if( this.inactiveCellProviders.contains( cc ) ) { this.inactiveCellProviders.remove( cc ); this.activeCellProviders.add( cc ); final IActionSource actionSrc = cc instanceof IActionHost ? new MachineSource( (IActionHost) cc ) : new BaseActionSource(); - this.storageMonitors.forEach( ( channel, monitor ) -> - { + this.storageMonitors.forEach( ( channel, monitor ) -> { for( final IMEInventoryHandler h : cc.getCellArray( channel ) ) { tracker.postChanges( channel, 1, h, actionSrc ); @@ -223,7 +222,7 @@ public class GridStorageCache implements IStorageGrid for( final ICellProvider cc : ll ) { - boolean active = true; + boolean active = false; if( cc instanceof IActionHost ) { @@ -232,10 +231,6 @@ public class GridStorageCache implements IStorageGrid { active = true; } - else - { - active = false; - } } if( active ) @@ -249,7 +244,7 @@ public class GridStorageCache implements IStorageGrid } tracker.applyChanges(); - this.storageMonitors.forEach( ( channel, monitor ) -> monitor.forceUpdate() ); + this.storageMonitors.forEach( ( channel, monitor ) -> monitor.setForceUpdate( true ) ); } private , C extends IStorageChannel> void postChangesToNetwork( final C chan, final int upOrDown, final IItemList availableItems, final IActionSource src ) diff --git a/src/main/java/appeng/me/cache/NetworkMonitor.java b/src/main/java/appeng/me/cache/NetworkMonitor.java index 54ad910e2..0b2ef7bbe 100644 --- a/src/main/java/appeng/me/cache/NetworkMonitor.java +++ b/src/main/java/appeng/me/cache/NetworkMonitor.java @@ -63,6 +63,7 @@ public class NetworkMonitor> implements IMEMonitor private boolean sendEvent = false; private long gridItemCount; private long gridFluidCount; + public boolean forceUpdate; public NetworkMonitor( final GridStorageCache cache, final IStorageChannel chan ) { @@ -232,7 +233,6 @@ public class NetworkMonitor> implements IMEMonitor return; } src2MonitorsMap.get( src ).add( this ); - isNested = false; this.sendEvent = true; @@ -285,7 +285,7 @@ public class NetworkMonitor> implements IMEMonitor if( networkMonitor.isNested != networkMonitor.wasNested ) { networkMonitor.wasNested = networkMonitor.isNested; - networkMonitor.forceUpdate(); + networkMonitor.setForceUpdate( true ); } } ); src2MonitorsMap.remove( src ); @@ -293,8 +293,14 @@ public class NetworkMonitor> implements IMEMonitor } } + public void setForceUpdate( boolean forceUpdate ) + { + this.forceUpdate = forceUpdate; + } + void forceUpdate() { + forceUpdate = false; this.cachedList.resetStatus(); this.getAvailableItems( this.cachedList ); @@ -357,6 +363,10 @@ public class NetworkMonitor> implements IMEMonitor void onTick() { + if( forceUpdate ) + { + forceUpdate(); + } if( this.sendEvent ) { this.sendEvent = false; diff --git a/src/main/java/appeng/parts/misc/PartSharedStorageBus.java b/src/main/java/appeng/parts/misc/PartSharedStorageBus.java deleted file mode 100644 index 594133c04..000000000 --- a/src/main/java/appeng/parts/misc/PartSharedStorageBus.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * This file is part of Applied Energistics 2. - * Copyright (c) 2013 - 2018, 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.parts.misc; - - -import java.util.Collections; -import java.util.List; - -import appeng.api.config.AccessRestriction; -import appeng.api.parts.IPart; -import appeng.fluids.parts.PartFluidInterface; -import appeng.fluids.tile.TileFluidInterface; -import appeng.tile.misc.TileInterface; -import appeng.tile.networking.TileCableBus; -import net.minecraft.item.ItemStack; -import net.minecraft.nbt.NBTTagCompound; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.math.BlockPos; -import net.minecraft.world.IBlockAccess; - -import appeng.api.AEApi; -import appeng.api.networking.events.MENetworkCellArrayUpdate; -import appeng.api.networking.events.MENetworkChannelsChanged; -import appeng.api.networking.events.MENetworkEventSubscribe; -import appeng.api.networking.events.MENetworkPowerStatusChange; -import appeng.api.networking.ticking.IGridTickable; -import appeng.api.parts.IPartCollisionHelper; -import appeng.api.storage.ICellContainer; -import appeng.api.storage.ICellInventory; -import appeng.api.storage.IMEInventoryHandler; -import appeng.api.storage.IStorageChannel; -import appeng.api.storage.channels.IItemStorageChannel; -import appeng.api.util.AECableType; -import appeng.api.util.IConfigManager; -import appeng.helpers.IPriorityHost; -import appeng.me.GridAccessException; -import appeng.parts.automation.PartUpgradeable; - - -/** - * @author BrockWS - * @version rv6 - 22/05/2018 - * @since rv6 22/05/2018 - */ -public abstract class PartSharedStorageBus extends PartUpgradeable implements IGridTickable, ICellContainer, IPriorityHost -{ - private boolean wasActive = false; - private int priority = 0; - protected boolean accessChanged; - protected boolean readOncePass; - - public PartSharedStorageBus( ItemStack is ) - { - super( is ); - } - - protected void updateStatus() - { - final boolean currentActive = this.getProxy().isActive(); - if( this.wasActive != currentActive ) - { - this.wasActive = currentActive; - try - { - this.getProxy().getGrid().postEvent( new MENetworkCellArrayUpdate() ); - this.getHost().markForUpdate(); - } - catch( final GridAccessException ignore ) - { - // :P - } - } - } - - @Override - @MENetworkEventSubscribe - public void chanRender( final MENetworkChannelsChanged changedChannels ) - { - this.updateStatus(); - } - - /** - * Helper method to get this parts storage channel - * - * @return Storage channel - */ - public IStorageChannel getStorageChannel() - { - return AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ); - } - - protected abstract void resetCache(); - - protected abstract void resetCache( boolean fullReset ); - - @Override - public List getCellArray( final IStorageChannel channel ) - { - return Collections.emptyList(); - } - - @Override - public void blinkCell( int slot ) - { - } - - @Override - public void saveChanges( ICellInventory cellInventory ) - { - } - - @Override - public int getPriority() - { - return this.priority; - } - - @Override - public void setPriority( final int newValue ) - { - this.priority = newValue; - this.getHost().markForSave(); - this.resetCache( true ); - } - - @Override - @MENetworkEventSubscribe - public void powerRender( final MENetworkPowerStatusChange c ) - { - this.updateStatus(); - } - - @Override - public void upgradesChanged() - { - super.upgradesChanged(); - this.resetCache( true ); - } - - @Override - public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue ) - { - if( settingName.name().equals( "ACCESS" ) ) - { - this.accessChanged = true; - } - this.resetCache( true ); - this.getHost().markForSave(); - } - - @Override - public void onNeighborChanged( IBlockAccess w, BlockPos pos, BlockPos neighbor ) - { - if( pos.offset( this.getSide().getFacing() ).equals( neighbor ) ) - { - - final TileEntity te = w.getTileEntity( neighbor ); - - // In case the TE was destroyed, we have to do a full reset immediately. - if( te instanceof TileCableBus ) - { - IPart iPart = ( (TileCableBus) te ).getPart( this.getSide().getOpposite() ); - if( iPart == null || iPart instanceof PartFluidInterface ) - { - this.resetCache( true ); - this.resetCache(); - } - } - else if( te == null || te instanceof TileFluidInterface ) - { - this.resetCache( true ); - this.resetCache(); - } - else - { - this.resetCache( false ); - } - } - } - - @Override - public void readFromNBT( final NBTTagCompound data ) - { - super.readFromNBT( data ); - this.priority = data.getInteger( "priority" ); - this.accessChanged = false; - } - - @Override - public void writeToNBT( final NBTTagCompound data ) - { - super.writeToNBT( data ); - data.setInteger( "priority", this.priority ); - } - - @Override - public void getBoxes( final IPartCollisionHelper bch ) - { - bch.addBox( 3, 3, 15, 13, 13, 16 ); - bch.addBox( 2, 2, 14, 14, 14, 15 ); - bch.addBox( 5, 5, 12, 11, 11, 14 ); - } - - @Override - protected int getUpgradeSlots() - { - return 5; - } - - @Override - public float getCableConnectionLength( AECableType cable ) - { - return 4; - } -} diff --git a/src/main/java/appeng/parts/misc/PartStorageBus.java b/src/main/java/appeng/parts/misc/PartStorageBus.java index 1dcf6f1fd..ef2848635 100644 --- a/src/main/java/appeng/parts/misc/PartStorageBus.java +++ b/src/main/java/appeng/parts/misc/PartStorageBus.java @@ -19,16 +19,51 @@ package appeng.parts.misc; -import java.util.Collections; -import java.util.List; -import java.util.Objects; - +import appeng.api.AEApi; +import appeng.api.config.*; +import appeng.api.networking.IGridNode; +import appeng.api.networking.events.MENetworkCellArrayUpdate; +import appeng.api.networking.events.MENetworkChannelsChanged; +import appeng.api.networking.events.MENetworkEventSubscribe; +import appeng.api.networking.events.MENetworkPowerStatusChange; +import appeng.api.networking.security.IActionSource; +import appeng.api.networking.storage.IBaseMonitor; import appeng.api.networking.storage.IStorageGrid; +import appeng.api.networking.ticking.IGridTickable; +import appeng.api.networking.ticking.ITickManager; +import appeng.api.networking.ticking.TickRateModulation; +import appeng.api.networking.ticking.TickingRequest; import appeng.api.parts.IPart; +import appeng.api.parts.IPartCollisionHelper; +import appeng.api.parts.IPartModel; +import appeng.api.storage.*; +import appeng.api.storage.channels.IItemStorageChannel; +import appeng.api.storage.data.IAEItemStack; +import appeng.api.storage.data.IItemList; +import appeng.api.util.AECableType; +import appeng.api.util.IConfigManager; +import appeng.capabilities.Capabilities; +import appeng.core.AppEng; +import appeng.core.settings.TickRates; +import appeng.core.sync.GuiBridge; +import appeng.helpers.IPriorityHost; +import appeng.helpers.Reflected; +import appeng.items.parts.PartModels; +import appeng.me.GridAccessException; import appeng.me.cache.GridStorageCache; +import appeng.me.helpers.MachineSource; +import appeng.me.storage.ITickingMonitor; +import appeng.me.storage.MEInventoryHandler; +import appeng.parts.PartModel; +import appeng.parts.automation.PartUpgradeable; +import appeng.tile.inventory.AppEngInternalAEInventory; import appeng.tile.misc.TileInterface; import appeng.tile.networking.TileCableBus; import appeng.util.ConfigManager; +import appeng.util.Platform; +import appeng.util.inv.InvOperation; +import appeng.util.prioritylist.FuzzyPriorityList; +import appeng.util.prioritylist.PrecisePriorityList; import com.jaquadro.minecraft.storagedrawers.api.capabilities.IItemRepository; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.item.ItemStack; @@ -45,561 +80,498 @@ import net.minecraftforge.common.capabilities.CapabilityInject; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandler; -import appeng.api.AEApi; -import appeng.api.config.AccessRestriction; -import appeng.api.config.FuzzyMode; -import appeng.api.config.IncludeExclude; -import appeng.api.config.Settings; -import appeng.api.config.StorageFilter; -import appeng.api.config.Upgrades; -import appeng.api.networking.IGridNode; -import appeng.api.networking.events.MENetworkCellArrayUpdate; -import appeng.api.networking.events.MENetworkChannelsChanged; -import appeng.api.networking.events.MENetworkEventSubscribe; -import appeng.api.networking.events.MENetworkPowerStatusChange; -import appeng.api.networking.security.IActionSource; -import appeng.api.networking.storage.IBaseMonitor; -import appeng.api.networking.ticking.IGridTickable; -import appeng.api.networking.ticking.ITickManager; -import appeng.api.networking.ticking.TickRateModulation; -import appeng.api.networking.ticking.TickingRequest; -import appeng.api.parts.IPartCollisionHelper; -import appeng.api.parts.IPartHost; -import appeng.api.parts.IPartModel; -import appeng.api.storage.ICellContainer; -import appeng.api.storage.ICellInventory; -import appeng.api.storage.IMEInventory; -import appeng.api.storage.IMEInventoryHandler; -import appeng.api.storage.IMEMonitorHandlerReceiver; -import appeng.api.storage.IStorageChannel; -import appeng.api.storage.IStorageMonitorable; -import appeng.api.storage.IStorageMonitorableAccessor; -import appeng.api.storage.channels.IItemStorageChannel; -import appeng.api.storage.data.IAEItemStack; -import appeng.api.storage.data.IItemList; -import appeng.api.util.AECableType; -import appeng.api.util.AEPartLocation; -import appeng.api.util.IConfigManager; -import appeng.capabilities.Capabilities; -import appeng.core.AppEng; -import appeng.core.settings.TickRates; -import appeng.core.sync.GuiBridge; -import appeng.helpers.IInterfaceHost; -import appeng.helpers.IPriorityHost; -import appeng.helpers.Reflected; -import appeng.items.parts.PartModels; -import appeng.me.GridAccessException; -import appeng.me.helpers.MachineSource; -import appeng.me.storage.ITickingMonitor; -import appeng.me.storage.MEInventoryHandler; -import appeng.parts.PartModel; -import appeng.parts.automation.PartUpgradeable; -import appeng.tile.inventory.AppEngInternalAEInventory; -import appeng.util.Platform; -import appeng.util.inv.InvOperation; -import appeng.util.prioritylist.FuzzyPriorityList; -import appeng.util.prioritylist.PrecisePriorityList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; public class PartStorageBus extends PartUpgradeable implements IGridTickable, ICellContainer, IMEMonitorHandlerReceiver, IPriorityHost { - @CapabilityInject(IItemRepository.class) - public static Capability ITEM_REPOSITORY_CAPABILITY = null; - - public static final ResourceLocation MODEL_BASE = new ResourceLocation( AppEng.MOD_ID, "part/storage_bus_base" ); - - @PartModels - public static final IPartModel MODELS_OFF = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/storage_bus_off" ) ); - - @PartModels - public static final IPartModel MODELS_ON = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/storage_bus_on" ) ); - - @PartModels - public static final IPartModel MODELS_HAS_CHANNEL = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/storage_bus_has_channel" ) ); - - private final IActionSource mySrc; - private final AppEngInternalAEInventory Config = new AppEngInternalAEInventory( this, 63 ); - private int priority = 0; - private boolean cached = false; - private ITickingMonitor monitor = null; - private MEInventoryHandler handler = null; - private int handlerHash = 0; - private boolean wasActive = false; - private byte resetCacheLogic = 0; - private boolean accessChanged; - private boolean readOncePass; - - @Reflected - public PartStorageBus( final ItemStack is ) - { - super( is ); - this.getConfigManager().registerSetting( Settings.ACCESS, AccessRestriction.READ_WRITE ); - this.getConfigManager().registerSetting( Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL ); - this.getConfigManager().registerSetting( Settings.STORAGE_FILTER, StorageFilter.EXTRACTABLE_ONLY ); - this.mySrc = new MachineSource( this ); - } - - @Override - @MENetworkEventSubscribe - public void powerRender( final MENetworkPowerStatusChange c ) - { - this.updateStatus(); - } - - private void updateStatus() - { - final boolean currentActive = this.getProxy().isActive(); - if( this.wasActive != currentActive ) - { - this.wasActive = currentActive; - try - { - this.getProxy().getGrid().postEvent( new MENetworkCellArrayUpdate() ); - this.getHost().markForUpdate(); - } - catch( final GridAccessException e ) - { - // :P - } - } - } - - @Override - @MENetworkEventSubscribe - public void chanRender( final MENetworkChannelsChanged changedChannels ) - { - this.updateStatus(); - } - - @Override - protected int getUpgradeSlots() - { - return 5; - } - - @Override - public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue ) - { - if( settingName.name().equals( "ACCESS" ) ) - { - this.accessChanged = true; - } - this.resetCache( true ); - this.getHost().markForSave(); - } - - @Override - public void onChangeInventory( final IItemHandler inv, final int slot, final InvOperation mc, final ItemStack removedStack, final ItemStack newStack ) - { - super.onChangeInventory( inv, slot, mc, removedStack, newStack ); - - if( inv == this.Config ) - { - this.resetCache( true ); - } - } - - @Override - public void upgradesChanged() - { - super.upgradesChanged(); - this.resetCache( true ); - } - - @Override - public void readFromNBT( final NBTTagCompound data ) - { - super.readFromNBT( data ); - this.Config.readFromNBT( data, "config" ); - this.priority = data.getInteger( "priority" ); - this.accessChanged = false; - } - - @Override - public void writeToNBT( final NBTTagCompound data ) - { - super.writeToNBT( data ); - this.Config.writeToNBT( data, "config" ); - data.setInteger( "priority", this.priority ); - } - - @Override - public IItemHandler getInventoryByName( final String name ) - { - if( name.equals( "config" ) ) - { - return this.Config; - } - - return super.getInventoryByName( name ); - } - - private void resetCache( final boolean fullReset ) - { - if( this.getHost() == null || this.getHost().getTile() == null || this.getHost().getTile().getWorld() == null || this.getHost() - .getTile() - .getWorld().isRemote ) - { - return; - } - - if( fullReset ) - { - this.resetCacheLogic = 2; - } - else if( this.resetCacheLogic < 2 ) - { - this.resetCacheLogic = 1; - } - - try - { - this.getProxy().getTick().alertDevice( this.getProxy().getNode() ); - } - catch( final GridAccessException e ) - { - // :P - } - } - - @Override - public boolean isValid( final Object verificationToken ) - { - return this.handler == verificationToken; - } - - @Override - public void postChange( final IBaseMonitor monitor, final Iterable change, final IActionSource source ) - { - if( this.getProxy().isActive() ) - { - AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ); - if( readOncePass ) - { - readOncePass = false; - try - { - this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), change, source ); - } - catch( final GridAccessException e ) - { - // :( - } - return; - } - if( !currentAccess.hasPermission( AccessRestriction.READ ) ) - { - return; - } - try - { - this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), change, source ); - } - catch( final GridAccessException e ) - { - // :( - } - } - } - - @Override - public void onListUpdate() - { - // not used here. - } - - @Override - public void getBoxes( final IPartCollisionHelper bch ) - { - bch.addBox( 3, 3, 15, 13, 13, 16 ); - bch.addBox( 2, 2, 14, 14, 14, 15 ); - bch.addBox( 5, 5, 12, 11, 11, 14 ); - } - - @Override - public void onNeighborChanged( IBlockAccess w, BlockPos pos, BlockPos neighbor ) - { - if( pos.offset( this.getSide().getFacing() ).equals( neighbor ) ) - { - - final TileEntity te = w.getTileEntity( neighbor ); - - // In case the TE was destroyed, we have to do a full reset immediately. - if( te instanceof TileCableBus ) - { - IPart iPart = ( (TileCableBus) te ).getPart( this.getSide().getOpposite() ); - if( iPart == null || iPart instanceof PartInterface ) - { - this.resetCache( true ); - this.resetCache(); - } - } - else if( te == null || te instanceof TileInterface ) - { - this.resetCache( true ); - this.resetCache(); - } - else - { - this.resetCache( false ); - } - } - } - - @Override - public float getCableConnectionLength( AECableType cable ) - { - return 4; - } - - @Override - public boolean onPartActivate( final EntityPlayer player, final EnumHand hand, final Vec3d pos ) - { - if( Platform.isServer() ) - { - Platform.openGUI( player, this.getHost().getTile(), this.getSide(), GuiBridge.GUI_STORAGEBUS ); - } - return true; - } - - @Override - public TickingRequest getTickingRequest( final IGridNode node ) - { - return new TickingRequest( TickRates.StorageBus.getMin(), TickRates.StorageBus.getMax(), this.monitor == null, true ); - } - - @Override - public TickRateModulation tickingRequest( final IGridNode node, final int ticksSinceLastCall ) - { - if( this.resetCacheLogic != 0 ) - { - this.resetCache(); - } - - if( this.monitor != null ) - { - return this.monitor.onTick(); - } - - return TickRateModulation.SLEEP; - } - - private void resetCache() - { - final boolean fullReset = this.resetCacheLogic == 2; - this.resetCacheLogic = 0; - - final MEInventoryHandler in = this.getInternalHandler(); - - IItemList before = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); - if( in != null ) - { - if( accessChanged ) - { - AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ); - AccessRestriction oldAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getOldSetting( Settings.ACCESS ); - if( oldAccess.hasPermission( AccessRestriction.READ ) && !currentAccess.hasPermission( AccessRestriction.READ ) ) - { - readOncePass = true; - } - in.setBaseAccess( oldAccess ); - before = in.getAvailableItems( before ); - in.setBaseAccess( currentAccess ); - accessChanged = false; - } - else - { - before = in.getAvailableItems( before ); - } - } - - this.cached = false; - if( fullReset ) - { - this.handlerHash = 0; - } - - final MEInventoryHandler out = this.getInternalHandler(); - - IItemList after = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); - - if( in != out ) - { - if( out != null ) - { - after = out.getAvailableItems( after ); - } - Platform.postListChanges( before, after, this, this.mySrc ); - } - } - - private IMEInventory getInventoryWrapper( TileEntity target ) - { - - EnumFacing targetSide = this.getSide().getFacing().getOpposite(); - - // Prioritize a handler to directly link to another ME network - IStorageMonitorableAccessor accessor = target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ); - - if( accessor != null ) - { - IStorageMonitorable inventory = accessor.getInventory( this.mySrc ); - if( inventory != null ) - { - return inventory.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); - } - - // So this could / can be a design decision. If the tile does support our custom capability, - // but it does not return an inventory for the action source, we do NOT fall back to using - // IItemHandler's, as that might circumvent the security setings, and might also cause - // performance issues. - return null; - } - - // Check via cap for IItemRepository - if (ITEM_REPOSITORY_CAPABILITY != null && target.hasCapability( ITEM_REPOSITORY_CAPABILITY, targetSide )) - { - IItemRepository handlerRepo = target.getCapability( ITEM_REPOSITORY_CAPABILITY, targetSide ); - if( handlerRepo != null ) - { - return new ItemRepositoryAdapter( handlerRepo, this ); - } - } - // Check via cap for IItemHandler - IItemHandler handlerExt = target.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, targetSide ); - if( handlerExt != null ) - { - return new ItemHandlerAdapter( handlerExt, this ); - } - - return null; - - } - - private int createHandlerHash( TileEntity target ) - { - if( target == null ) - { - return 0; - } - - final EnumFacing targetSide = this.getSide().getFacing().getOpposite(); - - if( target.hasCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) ) - { - return Objects.hash( target, target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) ); - } - - final IItemHandler itemHandler = target.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, targetSide ); - - if( itemHandler != null ) - { - return Objects.hash( target, itemHandler, itemHandler.getSlots() ); - } - - return 0; - } - - public MEInventoryHandler getInternalHandler() - { - if( this.cached ) - { - return this.handler; - } - - final boolean wasSleeping = this.monitor == null; - - this.cached = true; - final TileEntity self = this.getHost().getTile(); - final TileEntity target = self.getWorld().getTileEntity( self.getPos().offset( this.getSide().getFacing() ) ); - final int newHandlerHash = this.createHandlerHash( target ); - - if( newHandlerHash != 0 && newHandlerHash == this.handlerHash ) - { - return this.handler; - } - - this.handlerHash = newHandlerHash; - this.handler = null; - if( this.monitor != null ) - { - ( (IBaseMonitor) monitor ).removeListener( this ); - } - this.monitor = null; - if( target != null ) - { - IMEInventory inv = this.getInventoryWrapper( target ); - - if( inv instanceof ITickingMonitor ) - { - this.monitor = (ITickingMonitor) inv; - this.monitor.setActionSource( mySrc ); - this.monitor.setMode( (StorageFilter) this.getConfigManager().getSetting( Settings.STORAGE_FILTER ) ); - } - - if( inv != null ) - { - this.checkInterfaceVsStorageBus( target, this.getSide().getOpposite() ); - - this.handler = new MEInventoryHandler( inv, AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); - - this.handler.setBaseAccess( (AccessRestriction) this.getConfigManager().getSetting( Settings.ACCESS ) ); - this.handler.setWhitelist( this.getInstalledUpgrades( Upgrades.INVERTER ) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST ); - this.handler.setPriority( this.priority ); - - final IItemList priorityList = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); - - final int slotsToUse = 18 + this.getInstalledUpgrades( Upgrades.CAPACITY ) * 9; - for( int x = 0; x < this.Config.getSlots() && x < slotsToUse; x++ ) - { - final IAEItemStack is = this.Config.getAEStackInSlot( x ); - if( is != null ) - { - priorityList.add( is ); - } - } - - if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) - { - this.handler - .setPartitionList( new FuzzyPriorityList( priorityList, (FuzzyMode) this.getConfigManager() - .getSetting( Settings.FUZZY_MODE ) ) ); - } - else - { - this.handler.setPartitionList( new PrecisePriorityList( priorityList ) ); - } - - if( inv instanceof IBaseMonitor ) - { - if( ( (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ) ).hasPermission( AccessRestriction.READ ) ) - { - ( (IBaseMonitor) inv ).addListener( this, this.handler ); - } - } - } - } - - // update sleep state... - if( wasSleeping != ( this.monitor == null ) ) - { - try - { - final ITickManager tm = this.getProxy().getTick(); - if( this.monitor == null ) - { - tm.sleepDevice( this.getProxy().getNode() ); - } - else - { - tm.wakeDevice( this.getProxy().getNode() ); - } - } - catch( final GridAccessException e ) - { - // :( - } - } + public static final ResourceLocation MODEL_BASE = new ResourceLocation( AppEng.MOD_ID, "part/storage_bus_base" ); + @PartModels + public static final IPartModel MODELS_OFF = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/storage_bus_off" ) ); + @PartModels + public static final IPartModel MODELS_ON = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/storage_bus_on" ) ); + @PartModels + public static final IPartModel MODELS_HAS_CHANNEL = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/storage_bus_has_channel" ) ); + @CapabilityInject( IItemRepository.class ) + public static Capability ITEM_REPOSITORY_CAPABILITY = null; + private final IActionSource mySrc; + private final AppEngInternalAEInventory Config = new AppEngInternalAEInventory( this, 63 ); + private int priority = 0; + private boolean cached = false; + private ITickingMonitor monitor = null; + private MEInventoryHandler handler = null; + private int handlerHash = 0; + private boolean wasActive = false; + private byte resetCacheLogic = 0; + private boolean accessChanged; + private boolean readOncePass; + + @Reflected + public PartStorageBus( final ItemStack is ) + { + super( is ); + this.getConfigManager().registerSetting( Settings.ACCESS, AccessRestriction.READ_WRITE ); + this.getConfigManager().registerSetting( Settings.FUZZY_MODE, FuzzyMode.IGNORE_ALL ); + this.getConfigManager().registerSetting( Settings.STORAGE_FILTER, StorageFilter.EXTRACTABLE_ONLY ); + this.mySrc = new MachineSource( this ); + } + + @Override + @MENetworkEventSubscribe + public void powerRender( final MENetworkPowerStatusChange c ) + { + this.updateStatus(); + } + + private void updateStatus() + { + final boolean currentActive = this.getProxy().isActive(); + if( this.wasActive != currentActive ) + { + this.wasActive = currentActive; + try + { + this.getProxy().getGrid().postEvent( new MENetworkCellArrayUpdate() ); + this.getHost().markForUpdate(); + } + catch( final GridAccessException e ) + { + // :P + } + } + } + + @Override + @MENetworkEventSubscribe + public void chanRender( final MENetworkChannelsChanged changedChannels ) + { + this.updateStatus(); + } + + @Override + protected int getUpgradeSlots() + { + return 5; + } + + @Override + public void updateSetting( final IConfigManager manager, final Enum settingName, final Enum newValue ) + { + if( settingName.name().equals( "ACCESS" ) ) + { + this.accessChanged = true; + } + this.resetCache( true ); + this.getHost().markForSave(); + } + + @Override + public void onChangeInventory( final IItemHandler inv, final int slot, final InvOperation mc, final ItemStack removedStack, final ItemStack newStack ) + { + super.onChangeInventory( inv, slot, mc, removedStack, newStack ); + + if( inv == this.Config ) + { + this.resetCache( true ); + } + } + + @Override + public void upgradesChanged() + { + super.upgradesChanged(); + this.resetCache( true ); + } + + @Override + public void readFromNBT( final NBTTagCompound data ) + { + super.readFromNBT( data ); + this.Config.readFromNBT( data, "config" ); + this.priority = data.getInteger( "priority" ); + this.accessChanged = false; + } + + @Override + public void writeToNBT( final NBTTagCompound data ) + { + super.writeToNBT( data ); + this.Config.writeToNBT( data, "config" ); + data.setInteger( "priority", this.priority ); + } + + @Override + public IItemHandler getInventoryByName( final String name ) + { + if( name.equals( "config" ) ) + { + return this.Config; + } + + return super.getInventoryByName( name ); + } + + private void resetCache( final boolean fullReset ) + { + if( this.getHost() == null || this.getHost().getTile() == null || this.getHost().getTile().getWorld() == null || this.getHost().getTile().getWorld().isRemote ) + { + return; + } + + if( fullReset ) + { + this.resetCacheLogic = 2; + } + else if( this.resetCacheLogic < 2 ) + { + this.resetCacheLogic = 1; + } + + try + { + this.getProxy().getTick().alertDevice( this.getProxy().getNode() ); + } + catch( final GridAccessException e ) + { + // :P + } + } + + @Override + public boolean isValid( final Object verificationToken ) + { + return this.handler == verificationToken; + } + + @Override + public void postChange( final IBaseMonitor monitor, final Iterable change, final IActionSource source ) + { + if( this.getProxy().isActive() ) + { + AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ); + if( readOncePass ) + { + readOncePass = false; + try + { + this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), change, mySrc ); + } + catch( final GridAccessException e ) + { + // :( + } + return; + } + if( !currentAccess.hasPermission( AccessRestriction.READ ) ) + { + return; + } + try + { + this.getProxy().getStorage().postAlterationOfStoredItems( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ), change, source ); + } + catch( final GridAccessException e ) + { + // :( + } + } + } + + @Override + public void onListUpdate() + { + // not used here. + } + + @Override + public void getBoxes( final IPartCollisionHelper bch ) + { + bch.addBox( 3, 3, 15, 13, 13, 16 ); + bch.addBox( 2, 2, 14, 14, 14, 15 ); + bch.addBox( 5, 5, 12, 11, 11, 14 ); + } + + @Override + public void onNeighborChanged( IBlockAccess w, BlockPos pos, BlockPos neighbor ) + { + if( pos.offset( this.getSide().getFacing() ).equals( neighbor ) ) + { + final TileEntity te = w.getTileEntity( neighbor ); + + // In case the TE was destroyed, we have to do a full reset immediately. + if( te instanceof TileCableBus ) + { + IPart iPart = ( (TileCableBus) te ).getPart( this.getSide().getOpposite() ); + if( iPart == null || iPart instanceof PartInterface ) + { + this.resetCache( true ); + this.resetCache(); + } + } + else if( te == null || te instanceof TileInterface ) + { + this.resetCache( true ); + this.resetCache(); + } + else + { + this.resetCache( false ); + } + } + } + + @Override + public float getCableConnectionLength( AECableType cable ) + { + return 4; + } + + @Override + public boolean onPartActivate( final EntityPlayer player, final EnumHand hand, final Vec3d pos ) + { + if( Platform.isServer() ) + { + Platform.openGUI( player, this.getHost().getTile(), this.getSide(), GuiBridge.GUI_STORAGEBUS ); + } + return true; + } + + @Override + public TickingRequest getTickingRequest( final IGridNode node ) + { + return new TickingRequest( TickRates.StorageBus.getMin(), TickRates.StorageBus.getMax(), this.monitor == null, true ); + } + + @Override + public TickRateModulation tickingRequest( final IGridNode node, final int ticksSinceLastCall ) + { + if( this.resetCacheLogic != 0 ) + { + this.resetCache(); + } + + if( this.monitor != null ) + { + return this.monitor.onTick(); + } + + return TickRateModulation.SLEEP; + } + + private void resetCache() + { + final boolean fullReset = this.resetCacheLogic == 2; + this.resetCacheLogic = 0; + + final MEInventoryHandler in = this.getInternalHandler(); + + IItemList before = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + if( in != null ) + { + if( accessChanged ) + { + AccessRestriction currentAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ); + AccessRestriction oldAccess = (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getOldSetting( Settings.ACCESS ); + if( oldAccess.hasPermission( AccessRestriction.READ ) && !currentAccess.hasPermission( AccessRestriction.READ ) ) + { + readOncePass = true; + } + in.setBaseAccess( oldAccess ); + before = in.getAvailableItems( before ); + in.setBaseAccess( currentAccess ); + accessChanged = false; + } + else + { + before = in.getAvailableItems( before ); + } + } + + this.cached = false; + if( fullReset ) + { + this.handlerHash = 0; + } + + final MEInventoryHandler out = this.getInternalHandler(); + + IItemList after = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + + if( in != out ) + { + if( out != null ) + { + after = out.getAvailableItems( after ); + } + Platform.postListChanges( before, after, this, this.mySrc ); + } + } + + private IMEInventory getInventoryWrapper( TileEntity target ) + { + + EnumFacing targetSide = this.getSide().getFacing().getOpposite(); + + // Prioritize a handler to directly link to another ME network + IStorageMonitorableAccessor accessor = target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ); + + if( accessor != null ) + { + IStorageMonitorable inventory = accessor.getInventory( this.mySrc ); + if( inventory != null ) + { + return inventory.getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); + } + + // So this could / can be a design decision. If the tile does support our custom capability, + // but it does not return an inventory for the action source, we do NOT fall back to using + // IItemHandler's, as that might circumvent the security setings, and might also cause + // performance issues. + return null; + } + + // Check via cap for IItemRepository + if( ITEM_REPOSITORY_CAPABILITY != null && target.hasCapability( ITEM_REPOSITORY_CAPABILITY, targetSide ) ) + { + IItemRepository handlerRepo = target.getCapability( ITEM_REPOSITORY_CAPABILITY, targetSide ); + if( handlerRepo != null ) + { + return new ItemRepositoryAdapter( handlerRepo, this ); + } + } + // Check via cap for IItemHandler + IItemHandler handlerExt = target.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, targetSide ); + if( handlerExt != null ) + { + return new ItemHandlerAdapter( handlerExt, this ); + } + + return null; + + } + + private int createHandlerHash( TileEntity target ) + { + if( target == null ) + { + return 0; + } + + final EnumFacing targetSide = this.getSide().getFacing().getOpposite(); + + if( target.hasCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) ) + { + return Objects.hash( target, target.getCapability( Capabilities.STORAGE_MONITORABLE_ACCESSOR, targetSide ) ); + } + + final IItemHandler itemHandler = target.getCapability( CapabilityItemHandler.ITEM_HANDLER_CAPABILITY, targetSide ); + + if( itemHandler != null ) + { + return Objects.hash( target, itemHandler, itemHandler.getSlots() ); + } + + return 0; + } + + public MEInventoryHandler getInternalHandler() + { + if( this.cached ) + { + return this.handler; + } + + final boolean wasSleeping = this.monitor == null; + + this.cached = true; + final TileEntity self = this.getHost().getTile(); + final TileEntity target = self.getWorld().getTileEntity( self.getPos().offset( this.getSide().getFacing() ) ); + final int newHandlerHash = this.createHandlerHash( target ); + + if( newHandlerHash != 0 && newHandlerHash == this.handlerHash ) + { + return this.handler; + } + + this.handlerHash = newHandlerHash; + this.handler = null; + if( this.monitor != null ) + { + ( (IBaseMonitor) monitor ).removeListener( this ); + } + this.monitor = null; + if( target != null ) + { + IMEInventory inv = this.getInventoryWrapper( target ); + + if( inv instanceof ITickingMonitor ) + { + this.monitor = (ITickingMonitor) inv; + this.monitor.setActionSource( mySrc ); + this.monitor.setMode( (StorageFilter) this.getConfigManager().getSetting( Settings.STORAGE_FILTER ) ); + } + + if( inv != null ) + { + this.handler = new MEInventoryHandler<>( inv, AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ); + + this.handler.setBaseAccess( (AccessRestriction) this.getConfigManager().getSetting( Settings.ACCESS ) ); + this.handler.setWhitelist( this.getInstalledUpgrades( Upgrades.INVERTER ) > 0 ? IncludeExclude.BLACKLIST : IncludeExclude.WHITELIST ); + this.handler.setPriority( this.priority ); + + final IItemList priorityList = AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ).createList(); + + final int slotsToUse = 18 + this.getInstalledUpgrades( Upgrades.CAPACITY ) * 9; + for( int x = 0; x < this.Config.getSlots() && x < slotsToUse; x++ ) + { + final IAEItemStack is = this.Config.getAEStackInSlot( x ); + if( is != null ) + { + priorityList.add( is ); + } + } + + if( this.getInstalledUpgrades( Upgrades.FUZZY ) > 0 ) + { + this.handler.setPartitionList( new FuzzyPriorityList<>( priorityList, (FuzzyMode) this.getConfigManager().getSetting( Settings.FUZZY_MODE ) ) ); + } + else + { + this.handler.setPartitionList( new PrecisePriorityList<>( priorityList ) ); + } + + if( inv instanceof IBaseMonitor ) + { + if( ( (AccessRestriction) ( (ConfigManager) this.getConfigManager() ).getSetting( Settings.ACCESS ) ).hasPermission( AccessRestriction.READ ) ) + { + ( (IBaseMonitor) inv ).addListener( this, this.handler ); + } + } + } + } + + // update sleep state... + if( wasSleeping != ( this.monitor == null ) ) + { + try + { + final ITickManager tm = this.getProxy().getTick(); + if( this.monitor == null ) + { + tm.sleepDevice( this.getProxy().getNode() ); + } + else + { + tm.wakeDevice( this.getProxy().getNode() ); + } + } + catch( final GridAccessException e ) + { + // :( + } + } try { @@ -611,109 +583,83 @@ public class PartStorageBus extends PartUpgradeable implements IGridTickable, IC // :3 } - return this.handler; - } + return this.handler; + } - private void checkInterfaceVsStorageBus( final TileEntity target, final AEPartLocation side ) - { - IInterfaceHost achievement = null; + @Override + public List getCellArray( final IStorageChannel channel ) + { + if( channel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) + { + final IMEInventoryHandler out = this.getInternalHandler(); + if( out != null ) + { + return Collections.singletonList( out ); + } + } + return Collections.emptyList(); + } - if( target instanceof IInterfaceHost ) - { - achievement = (IInterfaceHost) target; - } + @Override + public int getPriority() + { + return this.priority; + } - if( target instanceof IPartHost ) - { - final Object part = ( (IPartHost) target ).getPart( side ); - if( part instanceof IInterfaceHost ) - { - achievement = (IInterfaceHost) part; - } - } + @Override + public void setPriority( final int newValue ) + { + this.priority = newValue; + this.getHost().markForSave(); + this.resetCache( true ); + } - if( achievement != null && achievement.getActionableNode() != null ) - { - // Platform.addStat( achievement.getActionableNode().getPlayerID(), Achievements.Recursive.getAchievement() - // ); - // Platform.addStat( getActionableNode().getPlayerID(), Achievements.Recursive.getAchievement() ); - } - } + @Override + public void blinkCell( final int slot ) + { + } - @Override - public List getCellArray( final IStorageChannel channel ) - { - if( channel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) - { - final IMEInventoryHandler out = this.getInternalHandler(); - if( out != null ) - { - return Collections.singletonList( out ); - } - } - return Collections.emptyList(); - } + // TODO: BC PIPE INTEGRATION + /* + * @Override + * @Method( iname = IntegrationType.BuildCraftTransport ) + * public ConnectOverride overridePipeConnection( PipeType type, ForgeDirection with ) + * { + * return type == PipeType.ITEM && with == this.getSide() ? ConnectOverride.CONNECT : ConnectOverride.DISCONNECT; + * } + */ + @Override + public void saveChanges( final ICellInventory cellInventory ) + { + // nope! + } - @Override - public int getPriority() - { - return this.priority; - } + @Override + public IPartModel getStaticModels() + { + if( this.isActive() && this.isPowered() ) + { + return MODELS_HAS_CHANNEL; + } + else if( this.isPowered() ) + { + return MODELS_ON; + } + else + { + return MODELS_OFF; + } + } - @Override - public void setPriority( final int newValue ) - { - this.priority = newValue; - this.getHost().markForSave(); - this.resetCache( true ); - } + @Override + public ItemStack getItemStackRepresentation() + { + return AEApi.instance().definitions().parts().storageBus().maybeStack( 1 ).orElse( ItemStack.EMPTY ); + } - @Override - public void blinkCell( final int slot ) - { - } - - // TODO: BC PIPE INTEGRATION - /* - * @Override - * @Method( iname = IntegrationType.BuildCraftTransport ) - * public ConnectOverride overridePipeConnection( PipeType type, ForgeDirection with ) - * { - * return type == PipeType.ITEM && with == this.getSide() ? ConnectOverride.CONNECT : ConnectOverride.DISCONNECT; - * } - */ - @Override - public void saveChanges( final ICellInventory cellInventory ) - { - // nope! - } - - @Override - public IPartModel getStaticModels() - { - if( this.isActive() && this.isPowered() ) - { - return MODELS_HAS_CHANNEL; - } - else if( this.isPowered() ) - { - return MODELS_ON; - } - else - { - return MODELS_OFF; - } - } - - @Override - public ItemStack getItemStackRepresentation() - { - return AEApi.instance().definitions().parts().storageBus().maybeStack( 1 ).orElse( ItemStack.EMPTY ); - } - - @Override - public GuiBridge getGuiBridge() - { - return GuiBridge.GUI_STORAGEBUS; - } + @Override + public GuiBridge getGuiBridge() + { + return GuiBridge.GUI_STORAGEBUS; + } } diff --git a/src/main/java/appeng/tile/storage/TileChest.java b/src/main/java/appeng/tile/storage/TileChest.java index d2bad8df9..7b15b76d6 100644 --- a/src/main/java/appeng/tile/storage/TileChest.java +++ b/src/main/java/appeng/tile/storage/TileChest.java @@ -495,12 +495,12 @@ public class TileChest extends AENetworkPowerTile implements IMEChest, ITerminal try { - this.getProxy().getGrid().postEvent( new MENetworkCellArrayUpdate() ); if( this.getProxy().isActive() ) { final IStorageGrid gs = this.getProxy().getStorage(); Platform.postChanges( gs, removed, added, this.mySrc ); } + this.getProxy().getGrid().postEvent( new MENetworkCellArrayUpdate() ); } catch( final GridAccessException ignored ) { diff --git a/src/main/java/appeng/tile/storage/TileDrive.java b/src/main/java/appeng/tile/storage/TileDrive.java index 9d472ee8a..afa5a5008 100644 --- a/src/main/java/appeng/tile/storage/TileDrive.java +++ b/src/main/java/appeng/tile/storage/TileDrive.java @@ -263,12 +263,12 @@ public class TileDrive extends AENetworkInvTile implements IChestOrDrive, IPrior try { - this.getProxy().getGrid().postEvent( new MENetworkCellArrayUpdate() ); if( this.getProxy().isActive() ) { final IStorageGrid gs = this.getProxy().getStorage(); Platform.postChanges( gs, removed, added, this.mySrc ); } + this.getProxy().getGrid().postEvent( new MENetworkCellArrayUpdate() ); } catch( final GridAccessException ignored ) {