Fluid cleanup and performance improvements (#3581)

Use custom gui widget with custom synchronization for rendering fake fluid slots.
This commit is contained in:
fscan
2018-07-04 19:12:12 +02:00
committed by GitHub
parent 979531afb7
commit 5d26b98ab8
40 changed files with 1499 additions and 777 deletions
@@ -1,45 +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 <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.fluids.helper;
import net.minecraftforge.fluids.FluidTank;
public class AEFluidTank extends FluidTank
{
private final IAEFluidInventory host;
public AEFluidTank( IAEFluidInventory host, int capacity )
{
super( capacity );
this.host = host;
}
@Override
protected void onContentsChanged()
{
if( host != null )
{
host.onFluidInventoryChanged( this );
}
super.onContentsChanged();
}
}
@@ -19,25 +19,21 @@
package appeng.fluids.helper;
import java.util.Map;
import java.util.Optional;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandlerItem;
import net.minecraftforge.fluids.capability.templates.FluidHandlerConcatenate;
import net.minecraftforge.items.IItemHandler;
import appeng.api.AEApi;
import appeng.api.config.Actionable;
import appeng.api.config.Upgrades;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.networking.GridFlags;
import appeng.api.networking.IGridNode;
import appeng.api.networking.energy.IEnergySource;
@@ -59,8 +55,12 @@ import appeng.api.storage.data.IAEStack;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.api.util.DimensionalCoord;
import appeng.api.util.IConfigManager;
import appeng.capabilities.Capabilities;
import appeng.core.settings.TickRates;
import appeng.fluids.util.AEFluidInventory;
import appeng.fluids.util.IAEFluidInventory;
import appeng.fluids.util.IAEFluidTank;
import appeng.helpers.IPriorityHost;
import appeng.me.GridAccessException;
import appeng.me.helpers.AENetworkProxy;
@@ -68,29 +68,26 @@ import appeng.me.helpers.MachineSource;
import appeng.me.storage.MEMonitorIFluidHandler;
import appeng.me.storage.MEMonitorPassThrough;
import appeng.me.storage.NullInventory;
import appeng.tile.inventory.AppEngInternalAEInventory;
import appeng.util.ConfigManager;
import appeng.util.IConfigManagerHost;
import appeng.util.Platform;
import appeng.util.inv.IAEAppEngInventory;
import appeng.util.inv.InvOperation;
public class DualityFluidInterface implements IGridTickable, IStorageMonitorable, IAEFluidInventory, IAEAppEngInventory, IPriorityHost
public class DualityFluidInterface implements IGridTickable, IStorageMonitorable, IAEFluidInventory, IPriorityHost, IUpgradeableHost, IConfigManagerHost
{
public static final int NUMBER_OF_TANKS = 6;
public static final int TANK_CAPACITY = Fluid.BUCKET_VOLUME * 4;
private final ConfigManager cm = new ConfigManager( this );
private final AENetworkProxy gridProxy;
private final IFluidInterfaceHost iHost;
private final IActionSource mySource;
private final IActionSource interfaceRequestSource;
private boolean hasConfig = false;
private final IStorageMonitorableAccessor accessor = this::getMonitorable;
private final AEFluidTank[] tanks;
private final IFluidHandler storage;
private final AppEngInternalAEInventory config = new AppEngInternalAEInventory( this, NUMBER_OF_TANKS );
private final IAEFluidStack[] configStacks;
private final AEFluidInventory tanks = new AEFluidInventory( this, NUMBER_OF_TANKS, TANK_CAPACITY );
private final AEFluidInventory config = new AEFluidInventory( this, NUMBER_OF_TANKS );
private final IAEFluidStack[] requireWork;
private final boolean[] tankChanged;
private int isWorking = -1;
private int priority;
@@ -113,18 +110,24 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
this.fluids.setChangeSource( this.mySource );
this.items.setChangeSource( this.mySource );
this.tanks = new AEFluidTank[NUMBER_OF_TANKS];
this.requireWork = new IAEFluidStack[NUMBER_OF_TANKS];
this.configStacks = new IAEFluidStack[NUMBER_OF_TANKS];
this.tankChanged = new boolean[NUMBER_OF_TANKS];
for( int i = 0; i < NUMBER_OF_TANKS; ++i )
{
this.tanks[i] = new AEFluidTank( this, TANK_CAPACITY );
this.requireWork[i] = null;
this.configStacks[i] = null;
this.tankChanged[i] = false;
}
this.storage = new FluidHandlerConcatenate( this.tanks );
}
public IUpgradeableHost getHost()
{
if( this.iHost instanceof IUpgradeableHost )
{
return (IUpgradeableHost) this.iHost;
}
if( this.iHost instanceof IUpgradeableHost )
{
return (IUpgradeableHost) this.iHost;
}
return null;
}
@Override
@@ -237,7 +240,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
{
if( capabilityClass == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY )
{
return (T) this.storage;
return (T) this.tanks;
}
else if( capabilityClass == Capabilities.STORAGE_MONITORABLE_ACCESSOR )
{
@@ -257,20 +260,6 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
for( int x = 0; x < NUMBER_OF_TANKS; x++ )
{
this.configStacks[x] = null;
ItemStack is = this.config.getStackInSlot( x );
if( !is.isEmpty() )
{
IFluidHandlerItem fh = is.getCapability( CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null );
if( fh != null )
{
FluidStack fs = fh.drain( Fluid.BUCKET_VOLUME, false );
if( fs != null && fs.amount > 0 )
{
this.configStacks[x] = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createStack( fs );
}
}
}
this.updatePlan( x );
}
@@ -324,49 +313,38 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
return false;
}
private int getTankSlot( final IFluidHandler inventory )
{
for( int i = 0; i < NUMBER_OF_TANKS; ++i )
{
if( this.tanks[i] == inventory )
{
return i;
}
}
throw new IndexOutOfBoundsException();
}
private void updatePlan( final int slot )
{
final IAEFluidStack req = this.configStacks[slot];
final FluidStack stored = this.tanks[slot].drain( TANK_CAPACITY, false );
final IAEFluidStack req = this.config.getFluidInSlot( slot );
final IAEFluidStack stored = this.tanks.getFluidInSlot( slot );
if( req == null && ( stored != null && stored.amount > 0 ) )
if( req == null && ( stored != null && stored.getStackSize() > 0 ) )
{
final IAEFluidStack work = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createStack( stored );
final IAEFluidStack work = stored.copy();
this.requireWork[slot] = work.setStackSize( -work.getStackSize() );
return;
}
else if( req != null )
{
if( stored == null || stored.amount == 0 ) // need to add stuff!
if( stored == null || stored.getStackSize() == 0 ) // need to add stuff!
{
this.requireWork[slot] = req.copy();
this.requireWork[slot].setStackSize( TANK_CAPACITY );
return;
}
else if( req.getFluid().equals( stored.getFluid() ) ) // same type ( qty different? )!
else if( req.equals( stored ) ) // same type ( qty different? )!
{
if( stored.amount < TANK_CAPACITY )
if( stored.getStackSize() < TANK_CAPACITY )
{
this.requireWork[slot] = req.copy();
this.requireWork[slot].setStackSize( TANK_CAPACITY - stored.amount );
this.requireWork[slot].setStackSize( TANK_CAPACITY - stored.getStackSize() );
return;
}
}
else
// Stored != null; dispose!
{
final IAEFluidStack work = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createStack( stored );
final IAEFluidStack work = stored.copy();
this.requireWork[slot] = work.setStackSize( -work.getStackSize() );
return;
}
@@ -377,7 +355,6 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
private boolean usePlan( final int slot )
{
IFluidHandler tank = this.tanks[slot];
IAEFluidStack work = this.requireWork[slot];
this.isWorking = slot;
@@ -391,7 +368,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
if( work.getStackSize() > 0 )
{
// make sure strange things didn't happen...
if( tank.fill( work.getFluidStack(), false ) != work.getStackSize() )
if( this.tanks.fill( slot, work.getFluidStack(), false ) != work.getStackSize() )
{
changed = true;
}
@@ -401,7 +378,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
if( acquired != null )
{
changed = true;
final int filled = tank.fill( acquired.getFluidStack(), true );
final int filled = this.tanks.fill( slot, acquired.getFluidStack(), true );
if( filled != acquired.getStackSize() )
{
throw new IllegalStateException( "bad attempt at managing tanks. ( fill )" );
@@ -415,7 +392,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
toStore.setStackSize( -toStore.getStackSize() );
// make sure strange things didn't happen...
final FluidStack canExtract = tank.drain( toStore.getFluidStack(), false );
final FluidStack canExtract = this.tanks.drain( slot, toStore.getFluidStack(), false );
if( canExtract == null || canExtract.amount != toStore.getStackSize() )
{
changed = true;
@@ -429,7 +406,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
{
// extract items!
changed = true;
final FluidStack removed = tank.drain( toStore.getFluidStack(), true );
final FluidStack removed = this.tanks.drain( slot, toStore.getFluidStack(), true );
if( removed == null || toStore.getStackSize() != removed.amount )
{
throw new IllegalStateException( "bad attempt at managing tanks. ( drain )" );
@@ -453,56 +430,46 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
}
@Override
public void onFluidInventoryChanged( final IFluidHandler inventory )
{
final int slot = this.getTankSlot( inventory );
this.tankChanged[slot] = true;
this.saveChanges();
if( this.isWorking == slot )
{
return;
}
final boolean had = this.hasWorkToDo();
this.updatePlan( slot );
final boolean now = this.hasWorkToDo();
if( had != now )
{
try
{
if( now )
{
this.gridProxy.getTick().alertDevice( this.gridProxy.getNode() );
}
else
{
this.gridProxy.getTick().sleepDevice( this.gridProxy.getNode() );
}
}
catch( final GridAccessException e )
{
// :P
}
}
}
@Override
public void onChangeInventory( IItemHandler inv, int slot, InvOperation mc, ItemStack removedStack, ItemStack newStack )
public void onFluidInventoryChanged( final IAEFluidTank inventory, final int slot )
{
if( this.isWorking == slot )
{
return;
}
if( inv == this.config )
if( inventory == this.config )
{
this.readConfig();
}
else if( inventory == this.tanks )
{
this.saveChanges();
final boolean had = this.hasWorkToDo();
this.updatePlan( slot );
final boolean now = this.hasWorkToDo();
if( had != now )
{
try
{
if( now )
{
this.gridProxy.getTick().alertDevice( this.gridProxy.getNode() );
}
else
{
this.gridProxy.getTick().sleepDevice( this.gridProxy.getNode() );
}
}
catch( final GridAccessException e )
{
// :P
}
}
}
}
@Override
@@ -519,69 +486,27 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
public void writeToNBT( final NBTTagCompound data )
{
final NBTTagList tankContents = new NBTTagList();
for( int i = 0; i < NUMBER_OF_TANKS; ++i )
{
tankContents.appendTag( this.tanks[i].writeToNBT( new NBTTagCompound() ) );
}
data.setInteger( "priority", this.priority );
data.setTag( "storage", tankContents );
this.tanks.writeToNBT( data, "storage" );
this.config.writeToNBT( data, "config" );
}
public void readFromNBT( final NBTTagCompound data )
{
this.config.readFromNBT( data, "config" );
final NBTTagList tankContents = data.getTagList( "storage", 10 );
if( tankContents != null )
{
for( int i = 0; i < Math.min( NUMBER_OF_TANKS, tankContents.tagCount() ); ++i )
{
this.tanks[i].readFromNBT( tankContents.getCompoundTagAt( i ) );
}
}
this.tanks.readFromNBT( data, "storage" );
this.priority = data.getInteger( "priority" );
this.readConfig();
}
public IItemHandler getConfig()
public IAEFluidTank getConfig()
{
return this.config;
}
public AEFluidTank getTank( final int i )
public IAEFluidTank getTanks()
{
return this.tanks[i];
}
public boolean writeTankInfo( final Map<Integer, NBTTagCompound> tagMap, boolean all )
{
boolean empty = true;
for( int i = 0; i < NUMBER_OF_TANKS; ++i )
{
if( all || this.tankChanged[i] )
{
tagMap.put( i, this.tanks[i].writeToNBT( new NBTTagCompound() ) );
this.tankChanged[i] = !all;
empty = false;
}
}
return !empty;
}
public boolean readTankInfo( final Map<Integer, NBTTagCompound> tagMap )
{
boolean changed = false;
for( int i = 0; i < NUMBER_OF_TANKS; ++i )
{
if( tagMap.containsKey( i ) )
{
this.tanks[i].readFromNBT( tagMap.get( i ) );
changed = true;
}
}
return changed;
return this.tanks;
}
private class InterfaceRequestSource extends MachineSource
@@ -620,7 +545,7 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
InterfaceInventory( final DualityFluidInterface tileInterface )
{
super( tileInterface.storage );
super( tileInterface.tanks );
this.setActionSource( new MachineSource( tileInterface.iHost ) );
}
@@ -653,10 +578,37 @@ public class DualityFluidInterface implements IGridTickable, IStorageMonitorable
}
}
@Override
public void saveChanges()
{
this.iHost.getTileEntity().markDirty();
}
@Override
public IConfigManager getConfigManager()
{
return this.cm;
}
@Override
public IItemHandler getInventoryByName( String name )
{
return null;
}
@Override
public int getInstalledUpgrades( Upgrades u )
{
return 0;
}
@Override
public TileEntity getTile()
{
return (TileEntity) ( this.iHost instanceof TileEntity ? this.iHost : null );
}
@Override
public void updateSetting( IConfigManager manager, Enum settingName, Enum newValue )
{
}
}
@@ -0,0 +1,106 @@
/*
* 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 <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.fluids.helper;
import javax.annotation.Nonnull;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidUtil;
import appeng.core.Api;
import appeng.fluids.items.FluidDummyItem;
import appeng.items.contents.CellConfig;
/**
* @author DrummerMC
* @version rv6 - 2018-01-22
* @since rv6 2018-01-22
*/
public class FluidCellConfig extends CellConfig
{
public FluidCellConfig( ItemStack is )
{
super( is );
}
@Override
@Nonnull
public ItemStack insertItem( int slot, @Nonnull ItemStack stack, boolean simulate )
{
if( stack.isEmpty() || stack.getItem() instanceof FluidDummyItem )
{
super.insertItem( slot, stack, simulate );
}
FluidStack fluid = FluidUtil.getFluidContained( stack );
if( fluid == null || !Api.INSTANCE.definitions().items().dummyFluidItem().maybeStack( 1 ).isPresent() )
{
return stack;
}
fluid.amount = Fluid.BUCKET_VOLUME;
ItemStack is = Api.INSTANCE.definitions().items().dummyFluidItem().maybeStack( 1 ).get();
FluidDummyItem item = (FluidDummyItem) is.getItem();
item.setFluidStack( is, fluid );
return super.insertItem( slot, is, simulate );
}
@Override
public void setStackInSlot( int slot, @Nonnull ItemStack stack )
{
if( stack.isEmpty() || stack.getItem() instanceof FluidDummyItem )
{
super.setStackInSlot( slot, stack );
}
FluidStack fluid = FluidUtil.getFluidContained( stack );
if( fluid == null || !Api.INSTANCE.definitions().items().dummyFluidItem().maybeStack( 1 ).isPresent() )
{
return;
}
fluid.amount = Fluid.BUCKET_VOLUME;
ItemStack is = Api.INSTANCE.definitions().items().dummyFluidItem().maybeStack( 1 ).get();
FluidDummyItem item = (FluidDummyItem) is.getItem();
item.setFluidStack( is, fluid );
super.setStackInSlot( slot, is );
}
@Override
public boolean isItemValidForSlot( int slot, ItemStack stack )
{
if( stack.isEmpty() || stack.getItem() instanceof FluidDummyItem )
{
super.isItemValidForSlot( slot, stack );
}
FluidStack fluid = FluidUtil.getFluidContained( stack );
if( fluid == null || !Api.INSTANCE.definitions().items().dummyFluidItem().maybeStack( 1 ).isPresent() )
{
return false;
}
fluid.amount = Fluid.BUCKET_VOLUME;
ItemStack is = Api.INSTANCE.definitions().items().dummyFluidItem().maybeStack( 1 ).get();
FluidDummyItem item = (FluidDummyItem) is.getItem();
item.setFluidStack( is, fluid );
return super.isItemValidForSlot( slot, is );
}
}
@@ -0,0 +1,98 @@
package appeng.fluids.helper;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.IContainerListener;
import appeng.api.storage.data.IAEFluidStack;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketFluidSlot;
import appeng.fluids.util.AEFluidInventory;
import appeng.fluids.util.IAEFluidTank;
public class FluidSyncHelper
{
private final IAEFluidTank inv;
private final IAEFluidTank cache;
private final int idOffset;
public FluidSyncHelper( final IAEFluidTank inv, final int idOffset )
{
this.inv = inv;
this.cache = new AEFluidInventory( null, inv.getSlots() );
this.idOffset = idOffset;
}
public void sendFull( final Iterable<IContainerListener> listeners )
{
this.sendDiffMap( this.createDiffMap( true ), listeners );
}
public void sendDiff( final Iterable<IContainerListener> listeners )
{
this.sendDiffMap( this.createDiffMap( false ), listeners );
}
public void readPacket( final Map<Integer, IAEFluidStack> data )
{
for( int i = 0; i < this.inv.getSlots(); ++i )
{
if( data.containsKey( i + this.idOffset ) )
{
this.inv.setFluidInSlot( i, data.get( i + this.idOffset ) );
}
}
}
private void sendDiffMap( final Map<Integer, IAEFluidStack> data, final Iterable<IContainerListener> listeners )
{
if( data.isEmpty() )
{
return;
}
for( final IContainerListener l : listeners )
{
if( l instanceof EntityPlayerMP )
{
NetworkHandler.instance().sendTo( new PacketFluidSlot( data ), (EntityPlayerMP) l );
}
}
}
private final Map<Integer, IAEFluidStack> createDiffMap( final boolean full )
{
final Map<Integer, IAEFluidStack> ret = new HashMap<>();
for( int i = 0; i < this.inv.getSlots(); ++i )
{
if( full || !this.equalsSlot( i ) )
{
ret.put( i + this.idOffset, this.inv.getFluidInSlot( i ) );
}
if( !full )
{
this.cache.setFluidInSlot( i, this.inv.getFluidInSlot( i ) );
}
}
return ret;
}
private final boolean equalsSlot( int slot )
{
final IAEFluidStack stackA = this.inv.getFluidInSlot( slot );
final IAEFluidStack stackB = this.cache.getFluidInSlot( slot );
if( !Objects.equals( stackA, stackB ) )
{
return false;
}
return stackA == null || stackA.getStackSize() == stackB.getStackSize();
}
}
@@ -1,29 +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 <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.fluids.helper;
import net.minecraftforge.fluids.capability.IFluidHandler;
@FunctionalInterface
public interface IAEFluidInventory
{
void onFluidInventoryChanged( IFluidHandler inventory );
}
@@ -24,11 +24,12 @@ import java.util.EnumSet;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import appeng.api.implementations.IUpgradeableHost;
import appeng.api.networking.security.IActionHost;
import appeng.me.helpers.IGridProxyable;
public interface IFluidInterfaceHost extends IActionHost, IGridProxyable
public interface IFluidInterfaceHost extends IActionHost, IGridProxyable, IUpgradeableHost
{
DualityFluidInterface getDualityFluidInterface();