Added ME Fluid Interface (#3564)

* Fixed fluid storage bus json recipe
* Added part version and recipes
* Added rudimentary gui
This commit is contained in:
fscan
2018-06-27 20:04:30 +02:00
committed by yueh
parent 046a27bf4c
commit c2d18ce013
31 changed files with 2200 additions and 7 deletions
@@ -0,0 +1,66 @@
/*
* 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.block;
import javax.annotation.Nullable;
import net.minecraft.block.material.Material;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import appeng.api.util.AEPartLocation;
import appeng.block.AEBaseTileBlock;
import appeng.core.sync.GuiBridge;
import appeng.fluids.tile.TileFluidInterface;
import appeng.util.Platform;
public class BlockFluidInterface extends AEBaseTileBlock
{
public BlockFluidInterface()
{
super( Material.IRON );
}
@Override
public boolean onActivated( final World w, final BlockPos pos, final EntityPlayer p, final EnumHand hand, final @Nullable ItemStack heldItem, final EnumFacing side, final float hitX, final float hitY, final float hitZ )
{
if( p.isSneaking() )
{
return false;
}
final TileEntity tg = this.getTileEntity( w, pos );
if( tg instanceof TileFluidInterface )
{
if( Platform.isServer() )
{
Platform.openGUI( p, tg, AEPartLocation.fromFacing( side ), GuiBridge.GUI_FLUID_INTERFACE );
}
return true;
}
return false;
}
}
@@ -0,0 +1,92 @@
/*
* 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.client.gui;
import java.io.IOException;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.entity.player.InventoryPlayer;
import appeng.client.gui.AEBaseGui;
import appeng.client.gui.widgets.GuiFluidTank;
import appeng.client.gui.widgets.GuiTabButton;
import appeng.core.localization.GuiText;
import appeng.core.sync.GuiBridge;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketSwitchGuis;
import appeng.fluids.container.ContainerFluidInterface;
import appeng.fluids.helper.DualityFluidInterface;
import appeng.fluids.helper.IFluidInterfaceHost;
public class GuiFluidInterface extends AEBaseGui
{
public final static int ID_BUTTON_TANK = 222;
private final IFluidInterfaceHost host;
private GuiTabButton priority;
public GuiFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te )
{
super( new ContainerFluidInterface( ip, te ) );
this.ySize = 231;
this.host = te;
}
@Override
public void initGui()
{
super.initGui();
for( int i = 0; i < DualityFluidInterface.NUMBER_OF_TANKS; ++i )
{
this.buttonList.add( new GuiFluidTank( ID_BUTTON_TANK + i, this.host.getDualityFluidInterface()
.getTank( i ), this.getGuiLeft() + 7 + 18 * i, this.getGuiTop() + 16 + 8, 16, 80 ) );
}
this.priority = new GuiTabButton( this.getGuiLeft() + 154, this.getGuiTop(), 2 + 4 * 16, GuiText.Priority.getLocal(), this.itemRender );
this.buttonList.add( this.priority );
}
@Override
public void drawFG( int offsetX, int offsetY, int mouseX, int mouseY )
{
this.fontRenderer.drawString( this.getGuiDisplayName( GuiText.FluidInterface.getLocal() ), 8, 6, 4210752 );
this.fontRenderer.drawString( GuiText.inventory.getLocal(), 8, this.ySize - 96 + 3, 4210752 );
}
@Override
public void drawBG( int offsetX, int offsetY, int mouseX, int mouseY )
{
this.bindTexture( "guis/interfacefluid.png" );
this.drawTexturedModalRect( offsetX, offsetY, 0, 0, this.xSize, this.ySize );
}
@Override
protected void actionPerformed( final GuiButton btn ) throws IOException
{
super.actionPerformed( btn );
if( btn == this.priority )
{
NetworkHandler.instance().sendToServer( new PacketSwitchGuis( GuiBridge.GUI_PRIORITY ) );
}
}
}
@@ -0,0 +1,122 @@
/*
* 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.container;
import java.util.HashMap;
import java.util.Map;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.IContainerListener;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import appeng.api.config.SecurityPermissions;
import appeng.api.parts.IPart;
import appeng.container.AEBaseContainer;
import appeng.core.sync.network.NetworkHandler;
import appeng.core.sync.packets.PacketFluidTank;
import appeng.fluids.container.slots.SlotFakeFluid;
import appeng.fluids.helper.DualityFluidInterface;
import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.util.Platform;
public class ContainerFluidInterface extends AEBaseContainer
{
private final DualityFluidInterface myDuality;
public ContainerFluidInterface( final InventoryPlayer ip, final IFluidInterfaceHost te )
{
super( ip, (TileEntity) ( te instanceof TileEntity ? te : null ), (IPart) ( te instanceof IPart ? te : null ) );
this.myDuality = te.getDualityFluidInterface();
for( int x = 0; x < DualityFluidInterface.NUMBER_OF_TANKS; x++ )
{
this.addSlotToContainer( new SlotFakeFluid( this.myDuality.getConfig(), x, 8 + 18 * x, 115 ) );
}
this.bindPlayerInventory( ip, 0, 231 - /* height of player inventory */82 );
}
@Override
public void detectAndSendChanges()
{
this.verifyPermissions( SecurityPermissions.BUILD, false );
if( Platform.isServer() )
{
this.sendTankUpdate();
}
super.detectAndSendChanges();
}
@Override
public void addListener( IContainerListener listener )
{
super.addListener( listener );
this.sendTankInfo( listener );
}
private void sendTankUpdate( final IContainerListener l, final HashMap<Integer, NBTTagCompound> updateMap )
{
if( l instanceof EntityPlayerMP )
{
NetworkHandler.instance().sendTo( new PacketFluidTank( updateMap ), (EntityPlayerMP) l );
}
}
private void sendTankUpdate()
{
final HashMap<Integer, NBTTagCompound> updateMap = new HashMap<>();
if( this.myDuality.writeTankInfo( updateMap, false ) )
{
for( final IContainerListener listener : this.listeners )
{
this.sendTankUpdate( listener, updateMap );
}
}
}
private void sendTankInfo( final IContainerListener l )
{
final HashMap<Integer, NBTTagCompound> updateMap = new HashMap<>();
if( this.myDuality.writeTankInfo( updateMap, true ) )
{
this.sendTankUpdate( l, updateMap );
}
}
public void receiveTankInfo( final Map<Integer, NBTTagCompound> tankTags )
{
this.myDuality.readTankInfo( tankTags );
}
@Override
public boolean isValidForSlot( Slot s, ItemStack i )
{
return s instanceof SlotFakeFluid ? i.hasCapability( CapabilityFluidHandler.FLUID_HANDLER_ITEM_CAPABILITY, null ) : super.isValidForSlot( s, i );
}
}
@@ -0,0 +1,45 @@
/*
* 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();
}
}
@@ -0,0 +1,662 @@
/*
* 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 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.networking.GridFlags;
import appeng.api.networking.IGridNode;
import appeng.api.networking.energy.IEnergySource;
import appeng.api.networking.security.IActionHost;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.ticking.IGridTickable;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.storage.IMEInventory;
import appeng.api.storage.IMEMonitor;
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.channels.IItemStorageChannel;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IAEItemStack;
import appeng.api.storage.data.IAEStack;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.api.util.DimensionalCoord;
import appeng.capabilities.Capabilities;
import appeng.core.settings.TickRates;
import appeng.helpers.IPriorityHost;
import appeng.me.GridAccessException;
import appeng.me.helpers.AENetworkProxy;
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.Platform;
import appeng.util.inv.IAEAppEngInventory;
import appeng.util.inv.InvOperation;
public class DualityFluidInterface implements IGridTickable, IStorageMonitorable, IAEFluidInventory, IAEAppEngInventory, IPriorityHost
{
public static final int NUMBER_OF_TANKS = 9;
public static final int TANK_CAPACITY = Fluid.BUCKET_VOLUME * 4;
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 IAEFluidStack[] requireWork;
private final boolean[] tankChanged;
private int isWorking = -1;
private int priority;
private final MEMonitorPassThrough<IAEItemStack> items = new MEMonitorPassThrough<>( new NullInventory<IAEItemStack>(), AEApi.instance()
.storage()
.getStorageChannel( IItemStorageChannel.class ) );
private final MEMonitorPassThrough<IAEFluidStack> fluids = new MEMonitorPassThrough<>( new NullInventory<IAEFluidStack>(), AEApi.instance()
.storage()
.getStorageChannel( IFluidStorageChannel.class ) );
public DualityFluidInterface( final AENetworkProxy networkProxy, final IFluidInterfaceHost ih )
{
this.gridProxy = networkProxy;
this.gridProxy.setFlags( GridFlags.REQUIRE_CHANNEL );
this.iHost = ih;
this.mySource = new MachineSource( this.iHost );
this.interfaceRequestSource = new InterfaceRequestSource( this.iHost );
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 );
}
@Override
public <T extends IAEStack<T>> IMEMonitor<T> getInventory( IStorageChannel<T> channel )
{
if( channel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) )
{
if( this.hasConfig() )
{
return null;
}
return (IMEMonitor<T>) this.items;
}
else if( channel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) )
{
if( this.hasConfig() )
{
return (IMEMonitor<T>) new InterfaceInventory( this );
}
return (IMEMonitor<T>) this.fluids;
}
return null;
}
public IStorageMonitorable getMonitorable( final IActionSource src )
{
if( Platform.canAccess( this.gridProxy, src ) )
{
return this;
}
return null;
}
@Override
public TickingRequest getTickingRequest( final IGridNode node )
{
return new TickingRequest( TickRates.Interface.getMin(), TickRates.Interface.getMax(), !this.hasWorkToDo(), true );
}
@Override
public TickRateModulation tickingRequest( final IGridNode node, final int ticksSinceLastCall )
{
if( !this.gridProxy.isActive() )
{
return TickRateModulation.SLEEP;
}
final boolean couldDoWork = this.updateStorage();
return this.hasWorkToDo() ? ( couldDoWork ? TickRateModulation.URGENT : TickRateModulation.SLOWER ) : TickRateModulation.SLEEP;
}
public void notifyNeighbors()
{
if( this.gridProxy.isActive() )
{
try
{
this.gridProxy.getTick().wakeDevice( this.gridProxy.getNode() );
}
catch( final GridAccessException e )
{
// :P
}
}
final TileEntity te = this.iHost.getTileEntity();
if( te != null && te.getWorld() != null )
{
Platform.notifyBlocksOfNeighbors( te.getWorld(), te.getPos() );
}
}
public void gridChanged()
{
try
{
this.items.setInternal( this.gridProxy.getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) );
this.fluids.setInternal( this.gridProxy.getStorage().getInventory( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ) );
}
catch( final GridAccessException gae )
{
this.items.setInternal( new NullInventory<IAEItemStack>() );
this.fluids.setInternal( new NullInventory<IAEFluidStack>() );
}
this.notifyNeighbors();
}
public AECableType getCableConnectionType( final AEPartLocation dir )
{
return AECableType.SMART;
}
public DimensionalCoord getLocation()
{
return new DimensionalCoord( this.iHost.getTileEntity() );
}
public boolean hasCapability( Capability<?> capabilityClass, EnumFacing facing )
{
return capabilityClass == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY || capabilityClass == Capabilities.STORAGE_MONITORABLE_ACCESSOR;
}
@SuppressWarnings( "unchecked" )
public <T> T getCapability( Capability<T> capabilityClass, EnumFacing facing )
{
if( capabilityClass == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY )
{
return (T) this.storage;
}
else if( capabilityClass == Capabilities.STORAGE_MONITORABLE_ACCESSOR )
{
return (T) this.accessor;
}
return null;
}
private boolean hasConfig()
{
return this.hasConfig;
}
private void readConfig()
{
final boolean had = this.hasWorkToDo();
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 );
}
final boolean has = this.hasWorkToDo();
if( had != has )
{
try
{
if( has )
{
this.gridProxy.getTick().alertDevice( this.gridProxy.getNode() );
}
else
{
this.gridProxy.getTick().sleepDevice( this.gridProxy.getNode() );
}
}
catch( final GridAccessException e )
{
// :P
}
}
this.notifyNeighbors();
}
private boolean updateStorage()
{
boolean didSomething = false;
for( int x = 0; x < NUMBER_OF_TANKS; x++ )
{
if( this.requireWork[x] != null )
{
didSomething = this.usePlan( x ) || didSomething;
}
}
return didSomething;
}
private boolean hasWorkToDo()
{
for( final IAEFluidStack requiredWork : this.requireWork )
{
if( requiredWork != null )
{
return true;
}
}
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 );
if( req == null && ( stored != null && stored.amount > 0 ) )
{
final IAEFluidStack work = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createStack( stored );
this.requireWork[slot] = work.setStackSize( -work.getStackSize() );
return;
}
else if( req != null )
{
if( stored == null || stored.amount == 0 ) // need to add stuff!
{
this.requireWork[slot] = req.copy();
return;
}
else if( req.getFluid().equals( stored.getFluid() ) ) // same type ( qty different? )!
{
if( stored.amount < TANK_CAPACITY )
{
this.requireWork[slot] = req.copy();
this.requireWork[slot].setStackSize( TANK_CAPACITY - stored.amount );
return;
}
}
else
// Stored != null; dispose!
{
final IAEFluidStack work = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createStack( stored );
this.requireWork[slot] = work.setStackSize( -work.getStackSize() );
return;
}
}
this.requireWork[slot] = null;
}
private boolean usePlan( final int slot )
{
IFluidHandler tank = this.tanks[slot];
IAEFluidStack work = this.requireWork[slot];
this.isWorking = slot;
boolean changed = false;
try
{
final IMEInventory<IAEFluidStack> dest = this.gridProxy.getStorage()
.getInventory( AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) );
final IEnergySource src = this.gridProxy.getEnergy();
if( work.getStackSize() > 0 )
{
// make sure strange things didn't happen...
if( tank.fill( work.getFluidStack(), false ) != work.getStackSize() )
{
changed = true;
}
else
{
final IAEFluidStack acquired = Platform.poweredExtraction( src, dest, work, this.interfaceRequestSource );
if( acquired != null )
{
changed = true;
final int filled = tank.fill( acquired.getFluidStack(), true );
if( filled != acquired.getStackSize() )
{
throw new IllegalStateException( "bad attempt at managing tanks. ( fill )" );
}
}
}
}
else if( work.getStackSize() < 0 )
{
IAEFluidStack toStore = work.copy();
toStore.setStackSize( -toStore.getStackSize() );
// make sure strange things didn't happen...
final FluidStack canExtract = tank.drain( toStore.getFluidStack(), false );
if( canExtract == null || canExtract.amount != toStore.getStackSize() )
{
changed = true;
}
else
{
IAEFluidStack notStored = Platform.poweredInsert( src, dest, toStore, this.interfaceRequestSource );
toStore.setStackSize( toStore.getStackSize() - ( notStored == null ? 0 : notStored.getStackSize() ) );
if( toStore.getStackSize() > 0 )
{
// extract items!
changed = true;
final FluidStack removed = tank.drain( toStore.getFluidStack(), true );
if( removed == null || toStore.getStackSize() != removed.amount )
{
throw new IllegalStateException( "bad attempt at managing tanks. ( drain )" );
}
}
}
}
}
catch( final GridAccessException e )
{
// :P
}
if( changed )
{
this.updatePlan( slot );
}
this.isWorking = -1;
return changed;
}
@Override
public void onFluidInventoryChanged( final IFluidHandler inventory )
{
final int slot = 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 )
{
if( this.isWorking == slot )
{
return;
}
if( inv == this.config )
{
this.readConfig();
}
}
@Override
public int getPriority()
{
return this.priority;
}
@Override
public void setPriority( final int newValue )
{
this.priority = newValue;
}
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.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.priority = data.getInteger( "priority" );
this.readConfig();
}
public IItemHandler getConfig()
{
return this.config;
}
public AEFluidTank getTank( final int i )
{
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;
}
private class InterfaceRequestSource extends MachineSource
{
private final InterfaceRequestContext context;
InterfaceRequestSource( IActionHost v )
{
super( v );
this.context = new InterfaceRequestContext();
}
@Override
public <T> Optional<T> context( Class<T> key )
{
if( key == InterfaceRequestContext.class )
{
return (Optional<T>) Optional.of( this.context );
}
return super.context( key );
}
}
private class InterfaceRequestContext implements Comparable<Integer>
{
@Override
public int compareTo( Integer o )
{
return Integer.compare( DualityFluidInterface.this.priority, o );
}
}
private class InterfaceInventory extends MEMonitorIFluidHandler
{
InterfaceInventory( final DualityFluidInterface tileInterface )
{
super( tileInterface.storage );
this.setActionSource( new MachineSource( tileInterface.iHost ) );
}
@Override
public IAEFluidStack injectItems( final IAEFluidStack input, final Actionable type, final IActionSource src )
{
final Optional<InterfaceRequestContext> context = src.context( InterfaceRequestContext.class );
final boolean isInterface = context.isPresent();
if( isInterface )
{
return input;
}
return super.injectItems( input, type, src );
}
@Override
public IAEFluidStack extractItems( final IAEFluidStack request, final Actionable type, final IActionSource src )
{
final Optional<InterfaceRequestContext> context = src.context( InterfaceRequestContext.class );
final boolean hasLowerOrEqualPriority = context.map( c -> c.compareTo( DualityFluidInterface.this.priority ) <= 0 ).orElse( false );
if( hasLowerOrEqualPriority )
{
return null;
}
return super.extractItems( request, type, src );
}
}
@Override
public void saveChanges()
{
this.iHost.getTileEntity().markDirty();
}
}
@@ -0,0 +1,29 @@
/*
* 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 );
}
@@ -0,0 +1,38 @@
/*
* 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 java.util.EnumSet;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import appeng.api.networking.security.IActionHost;
import appeng.me.helpers.IGridProxyable;
public interface IFluidInterfaceHost extends IActionHost, IGridProxyable
{
DualityFluidInterface getDualityFluidInterface();
EnumSet<EnumFacing> getTargets();
TileEntity getTileEntity();
}
@@ -0,0 +1,219 @@
/*
* 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.parts;
import java.util.EnumSet;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
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.Vec3d;
import net.minecraftforge.common.capabilities.Capability;
import appeng.api.networking.IGridNode;
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.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.parts.IPartCollisionHelper;
import appeng.api.parts.IPartModel;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.IStorageMonitorable;
import appeng.api.storage.data.IAEStack;
import appeng.api.util.AECableType;
import appeng.core.AppEng;
import appeng.core.sync.GuiBridge;
import appeng.fluids.helper.DualityFluidInterface;
import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.helpers.IPriorityHost;
import appeng.helpers.Reflected;
import appeng.items.parts.PartModels;
import appeng.parts.PartBasicState;
import appeng.parts.PartModel;
import appeng.util.Platform;
public class PartFluidInterface extends PartBasicState implements IGridTickable, IStorageMonitorable, IFluidInterfaceHost, IPriorityHost
{
public static final ResourceLocation MODEL_BASE = new ResourceLocation( AppEng.MOD_ID, "part/interface_base" );
@PartModels
public static final PartModel MODELS_OFF = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/interface_off" ) );
@PartModels
public static final PartModel MODELS_ON = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/interface_on" ) );
@PartModels
public static final PartModel MODELS_HAS_CHANNEL = new PartModel( MODEL_BASE, new ResourceLocation( AppEng.MOD_ID, "part/interface_has_channel" ) );
private final DualityFluidInterface duality = new DualityFluidInterface( this.getProxy(), this );
@Reflected
public PartFluidInterface( final ItemStack is )
{
super( is );
}
@Override
public DualityFluidInterface getDualityFluidInterface()
{
return duality;
}
@MENetworkEventSubscribe
public void stateChange( final MENetworkChannelsChanged c )
{
this.duality.notifyNeighbors();
}
@MENetworkEventSubscribe
public void stateChange( final MENetworkPowerStatusChange c )
{
this.duality.notifyNeighbors();
}
@Override
public void getBoxes( final IPartCollisionHelper bch )
{
bch.addBox( 2, 2, 14, 14, 14, 16 );
bch.addBox( 5, 5, 12, 11, 11, 14 );
}
@Override
public void gridChanged()
{
this.duality.gridChanged();
}
@Override
public void readFromNBT( final NBTTagCompound data )
{
super.readFromNBT( data );
this.duality.readFromNBT( data );
}
@Override
public void writeToNBT( final NBTTagCompound data )
{
super.writeToNBT( data );
this.duality.writeToNBT( data );
}
@Override
public float getCableConnectionLength( AECableType cable )
{
return 4;
}
@Override
public boolean onPartActivate( final EntityPlayer p, final EnumHand hand, final Vec3d pos )
{
if( p.isSneaking() )
{
return false;
}
if( Platform.isServer() )
{
Platform.openGUI( p, this.getTileEntity(), this.getSide(), GuiBridge.GUI_FLUID_INTERFACE );
}
return true;
}
@Override
public <T extends IAEStack<T>> IMEMonitor<T> getInventory( IStorageChannel<T> channel )
{
return this.duality.getInventory( channel );
}
@Override
public TickingRequest getTickingRequest( final IGridNode node )
{
return this.duality.getTickingRequest( node );
}
@Override
public TickRateModulation tickingRequest( final IGridNode node, final int ticksSinceLastCall )
{
return this.duality.tickingRequest( node, ticksSinceLastCall );
}
@Override
public EnumSet<EnumFacing> getTargets()
{
return EnumSet.of( this.getSide().getFacing() );
}
@Override
public TileEntity getTileEntity()
{
return super.getHost().getTile();
}
@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 int getPriority()
{
return this.duality.getPriority();
}
@Override
public void setPriority( final int newValue )
{
this.duality.setPriority( newValue );
}
@Override
public boolean hasCapability( Capability<?> capabilityClass )
{
return this.duality.hasCapability( capabilityClass, this.getSide().getFacing() );
}
@Override
public <T> T getCapability( Capability<T> capabilityClass )
{
return this.duality.getCapability( capabilityClass, this.getSide().getFacing() );
}
}
@@ -0,0 +1,154 @@
/*
* 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.tile;
import java.util.EnumSet;
import javax.annotation.Nullable;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraftforge.common.capabilities.Capability;
import appeng.api.networking.IGridNode;
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.networking.ticking.TickRateModulation;
import appeng.api.networking.ticking.TickingRequest;
import appeng.api.util.AECableType;
import appeng.api.util.AEPartLocation;
import appeng.api.util.DimensionalCoord;
import appeng.fluids.helper.DualityFluidInterface;
import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.helpers.IPriorityHost;
import appeng.tile.grid.AENetworkTile;
public class TileFluidInterface extends AENetworkTile implements IGridTickable, IFluidInterfaceHost, IPriorityHost
{
private final DualityFluidInterface duality = new DualityFluidInterface( this.getProxy(), this );
@MENetworkEventSubscribe
public void stateChange( final MENetworkChannelsChanged c )
{
this.duality.notifyNeighbors();
}
@MENetworkEventSubscribe
public void stateChange( final MENetworkPowerStatusChange c )
{
this.duality.notifyNeighbors();
}
@Override
public TickingRequest getTickingRequest( IGridNode node )
{
return this.duality.getTickingRequest( node );
}
@Override
public TickRateModulation tickingRequest( IGridNode node, int ticksSinceLastCall )
{
return this.duality.tickingRequest( node, ticksSinceLastCall );
}
@Override
public DualityFluidInterface getDualityFluidInterface()
{
return this.duality;
}
@Override
public TileEntity getTileEntity()
{
return this;
}
@Override
public void gridChanged()
{
this.duality.gridChanged();
}
@Override
public NBTTagCompound writeToNBT( final NBTTagCompound data )
{
super.writeToNBT( data );
this.duality.writeToNBT( data );
return data;
}
@Override
public void readFromNBT( final NBTTagCompound data )
{
super.readFromNBT( data );
this.duality.readFromNBT( data );
}
@Override
public AECableType getCableConnectionType( final AEPartLocation dir )
{
return this.duality.getCableConnectionType( dir );
}
@Override
public DimensionalCoord getLocation()
{
return this.duality.getLocation();
}
@Override
public EnumSet<EnumFacing> getTargets()
{
return EnumSet.allOf( EnumFacing.class );
}
@Override
public int getPriority()
{
return this.duality.getPriority();
}
@Override
public void setPriority( final int newValue )
{
this.duality.setPriority( newValue );
}
@Override
public boolean hasCapability( Capability<?> capability, @Nullable EnumFacing facing )
{
return this.duality.hasCapability( capability, facing ) || super.hasCapability( capability, facing );
}
@Override
public <T> T getCapability( Capability<T> capability, @Nullable EnumFacing facing )
{
T result = this.duality.getCapability( capability, facing );
if( result != null )
{
return result;
}
return super.getCapability( capability, facing );
}
}