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
@@ -148,6 +148,8 @@ public interface IBlocks
ITileDefinition iface(); ITileDefinition iface();
ITileDefinition fluidIface();
ITileDefinition cellWorkbench(); ITileDefinition cellWorkbench();
ITileDefinition iOPort(); ITileDefinition iOPort();
@@ -64,6 +64,8 @@ public interface IParts
IItemDefinition iface(); IItemDefinition iface();
IItemDefinition fluidIface();
IItemDefinition levelEmitter(); IItemDefinition levelEmitter();
IItemDefinition annihilationPlane(); IItemDefinition annihilationPlane();
@@ -751,6 +751,7 @@ public abstract class AEBaseGui extends GuiContainer
if( fs != null && this.isPowered() ) if( fs != null && this.isPowered() )
{ {
GlStateManager.disableLighting(); GlStateManager.disableLighting();
GlStateManager.disableBlend();
Fluid fluid = fs.getFluid(); Fluid fluid = fs.getFluid();
Minecraft.getMinecraft().getTextureManager().bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ); Minecraft.getMinecraft().getTextureManager().bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( fluid.getStill().toString() ); TextureAtlasSprite sprite = Minecraft.getMinecraft().getTextureMapBlocks().getAtlasSprite( fluid.getStill().toString() );
@@ -764,6 +765,7 @@ public abstract class AEBaseGui extends GuiContainer
this.drawTexturedModalRect( s.xPos, s.yPos, sprite, 16, 16 ); this.drawTexturedModalRect( s.xPos, s.yPos, sprite, 16, 16 );
GlStateManager.enableLighting(); GlStateManager.enableLighting();
GlStateManager.enableBlend();
if( s instanceof IMEFluidSlot ) if( s instanceof IMEFluidSlot )
{ {
@@ -0,0 +1,128 @@
/*
* 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.client.gui.widgets;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.texture.TextureMap;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.IFluidTank;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import appeng.api.util.AEColor;
@SideOnly( Side.CLIENT )
public class GuiFluidTank extends GuiButton implements ITooltip
{
private final IFluidTank tank;
public GuiFluidTank( int buttonId, IFluidTank tank, int x, int y, int w, int h )
{
super( buttonId, x, y, w, h, "" );
this.tank = tank;
}
@Override
public void drawButton( final Minecraft mc, final int mouseX, final int mouseY, final float partialTicks )
{
if( this.visible )
{
GlStateManager.disableBlend();
GlStateManager.disableLighting();
drawRect( this.x, this.y, this.x + this.width, this.y + this.height, AEColor.GRAY.blackVariant | 0xFF000000 );
if( this.tank != null )
{
final FluidStack fluid = this.tank.getFluid();
if( fluid != null && fluid.amount > 0 )
{
mc.getTextureManager().bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE );
float red = ( fluid.getFluid().getColor() >> 16 & 255 ) / 255.0F;
float green = ( fluid.getFluid().getColor() >> 8 & 255 ) / 255.0F;
float blue = ( fluid.getFluid().getColor() & 255 ) / 255.0F;
GlStateManager.color( red, green, blue );
TextureAtlasSprite sprite = mc.getTextureMapBlocks().getAtlasSprite( fluid.getFluid().getStill().toString() );
final int scaledHeight = (int) ( this.height * ( (float) fluid.amount / this.tank.getCapacity() ) );
int iconHeightRemainder = scaledHeight % 16;
if( iconHeightRemainder > 0 )
{
drawTexturedModalRect( this.x, this.y + this.height - iconHeightRemainder, sprite, 16, iconHeightRemainder );
}
for( int i = 0; i < scaledHeight / 16; i++ )
{
drawTexturedModalRect( this.x, this.y + this.height - iconHeightRemainder - ( i + 1 ) * 16, sprite, 16, 16 );
}
}
}
}
}
@Override
public String getMessage()
{
if( this.tank != null && this.tank.getFluid() != null && this.tank.getFluid().amount > 0 )
{
String desc = this.tank.getFluid().getFluid().getLocalizedName( this.tank.getFluid() );
String amountToText = this.tank.getFluid().amount + "mB";
return desc + "\n" + amountToText;
}
return null;
}
@Override
public int xPos()
{
return this.x - 2;
}
@Override
public int yPos()
{
return this.y - 2;
}
@Override
public int getWidth()
{
return this.width + 4;
}
@Override
public int getHeight()
{
return this.height + 4;
}
@Override
public boolean isVisible()
{
return true;
}
}
@@ -126,6 +126,8 @@ import appeng.decorative.solid.BlockQuartzPillar;
import appeng.decorative.solid.BlockSkyStone; import appeng.decorative.solid.BlockSkyStone;
import appeng.decorative.solid.BlockSkyStone.SkystoneType; import appeng.decorative.solid.BlockSkyStone.SkystoneType;
import appeng.decorative.stair.BlockStairCommon; import appeng.decorative.stair.BlockStairCommon;
import appeng.fluids.block.BlockFluidInterface;
import appeng.fluids.tile.TileFluidInterface;
import appeng.hooks.DispenserBehaviorTinyTNT; import appeng.hooks.DispenserBehaviorTinyTNT;
import appeng.tile.crafting.TileCraftingMonitorTile; import appeng.tile.crafting.TileCraftingMonitorTile;
import appeng.tile.crafting.TileCraftingStorageTile; import appeng.tile.crafting.TileCraftingStorageTile;
@@ -197,6 +199,7 @@ public final class ApiBlocks implements IBlocks
private final ITileDefinition drive; private final ITileDefinition drive;
private final ITileDefinition chest; private final ITileDefinition chest;
private final ITileDefinition iface; private final ITileDefinition iface;
private final ITileDefinition fluidIface;
private final ITileDefinition cellWorkbench; private final ITileDefinition cellWorkbench;
private final ITileDefinition iOPort; private final ITileDefinition iOPort;
private final ITileDefinition condenser; private final ITileDefinition condenser;
@@ -390,6 +393,10 @@ public final class ApiBlocks implements IBlocks
.features( AEFeature.INTERFACE ) .features( AEFeature.INTERFACE )
.tileEntity( new TileEntityDefinition( TileInterface.class ) ) .tileEntity( new TileEntityDefinition( TileInterface.class ) )
.build(); .build();
this.fluidIface = registry.block( "fluid_interface", BlockFluidInterface::new )
.features( AEFeature.FLUID_INTERFACE )
.tileEntity( new TileEntityDefinition( TileFluidInterface.class ) )
.build();
this.cellWorkbench = registry.block( "cell_workbench", BlockCellWorkbench::new ) this.cellWorkbench = registry.block( "cell_workbench", BlockCellWorkbench::new )
.features( AEFeature.STORAGE_CELLS ) .features( AEFeature.STORAGE_CELLS )
.tileEntity( new TileEntityDefinition( TileCellWorkbench.class ) ) .tileEntity( new TileEntityDefinition( TileCellWorkbench.class ) )
@@ -893,6 +900,12 @@ public final class ApiBlocks implements IBlocks
return this.iface; return this.iface;
} }
@Override
public ITileDefinition fluidIface()
{
return this.fluidIface;
}
@Override @Override
public ITileDefinition cellWorkbench() public ITileDefinition cellWorkbench()
{ {
@@ -55,6 +55,7 @@ public final class ApiParts implements IParts
private final IItemDefinition importBus; private final IItemDefinition importBus;
private final IItemDefinition exportBus; private final IItemDefinition exportBus;
private final IItemDefinition iface; private final IItemDefinition iface;
private final IItemDefinition fluidIface;
private final IItemDefinition levelEmitter; private final IItemDefinition levelEmitter;
private final IItemDefinition annihilationPlane; private final IItemDefinition annihilationPlane;
private final IItemDefinition identityAnnihilationPlane; private final IItemDefinition identityAnnihilationPlane;
@@ -111,10 +112,11 @@ public final class ApiParts implements IParts
this.importBus = new DamagedItemDefinition( "part.bus.import", itemPart.createPart( PartType.IMPORT_BUS ) ); this.importBus = new DamagedItemDefinition( "part.bus.import", itemPart.createPart( PartType.IMPORT_BUS ) );
this.exportBus = new DamagedItemDefinition( "part.bus.export", itemPart.createPart( PartType.EXPORT_BUS ) ); this.exportBus = new DamagedItemDefinition( "part.bus.export", itemPart.createPart( PartType.EXPORT_BUS ) );
this.iface = new DamagedItemDefinition( "part.interface", itemPart.createPart( PartType.INTERFACE ) ); this.iface = new DamagedItemDefinition( "part.interface", itemPart.createPart( PartType.INTERFACE ) );
this.fluidIface = new DamagedItemDefinition( "part.fluid_interface", itemPart.createPart( PartType.FLUID_INTERFACE ) );
this.levelEmitter = new DamagedItemDefinition( "part.level_emitter", itemPart.createPart( PartType.LEVEL_EMITTER ) ); this.levelEmitter = new DamagedItemDefinition( "part.level_emitter", itemPart.createPart( PartType.LEVEL_EMITTER ) );
this.annihilationPlane = new DamagedItemDefinition( "part.plane.annihilation", itemPart.createPart( PartType.ANNIHILATION_PLANE ) ); this.annihilationPlane = new DamagedItemDefinition( "part.plane.annihilation", itemPart.createPart( PartType.ANNIHILATION_PLANE ) );
this.identityAnnihilationPlane = new DamagedItemDefinition( "part.plane.annihiliation.identity", this.identityAnnihilationPlane = new DamagedItemDefinition( "part.plane.annihiliation.identity", itemPart
itemPart.createPart( PartType.IDENTITY_ANNIHILATION_PLANE ) ); .createPart( PartType.IDENTITY_ANNIHILATION_PLANE ) );
this.formationPlane = new DamagedItemDefinition( "part.plane.formation", itemPart.createPart( PartType.FORMATION_PLANE ) ); this.formationPlane = new DamagedItemDefinition( "part.plane.formation", itemPart.createPart( PartType.FORMATION_PLANE ) );
this.p2PTunnelME = new DamagedItemDefinition( "part.tunnel.me", itemPart.createPart( PartType.P2P_TUNNEL_ME ) ); this.p2PTunnelME = new DamagedItemDefinition( "part.tunnel.me", itemPart.createPart( PartType.P2P_TUNNEL_ME ) );
this.p2PTunnelRedstone = new DamagedItemDefinition( "part.tunnel.redstone", itemPart.createPart( PartType.P2P_TUNNEL_REDSTONE ) ); this.p2PTunnelRedstone = new DamagedItemDefinition( "part.tunnel.redstone", itemPart.createPart( PartType.P2P_TUNNEL_REDSTONE ) );
@@ -255,6 +257,12 @@ public final class ApiParts implements IParts
return this.iface; return this.iface;
} }
@Override
public IItemDefinition fluidIface()
{
return this.fluidIface;
}
@Override @Override
public IItemDefinition levelEmitter() public IItemDefinition levelEmitter()
{ {
@@ -75,6 +75,7 @@ public enum AEFeature
CHANNELS( "Channels", Constants.CATEGORY_NETWORK_FEATURES ), CHANNELS( "Channels", Constants.CATEGORY_NETWORK_FEATURES ),
INTERFACE( "Interface", Constants.CATEGORY_NETWORK_BUSES ), INTERFACE( "Interface", Constants.CATEGORY_NETWORK_BUSES ),
FLUID_INTERFACE( "FluidInterface", Constants.CATEGORY_NETWORK_BUSES ),
LEVEL_EMITTER( "LevelEmitter", Constants.CATEGORY_NETWORK_BUSES ), LEVEL_EMITTER( "LevelEmitter", Constants.CATEGORY_NETWORK_BUSES ),
FLUID_TERMINAL( "FluidTerminal", Constants.CATEGORY_NETWORK_BUSES ), FLUID_TERMINAL( "FluidTerminal", Constants.CATEGORY_NETWORK_BUSES ),
CRAFTING_TERMINAL( "CraftingTerminal", Constants.CATEGORY_NETWORK_BUSES ), CRAFTING_TERMINAL( "CraftingTerminal", Constants.CATEGORY_NETWORK_BUSES ),
@@ -40,6 +40,7 @@ public enum GuiText
Terminal, Terminal,
Interface, Interface,
FluidInterface,
Config, Config,
StoredItems, StoredItems,
Patterns, Patterns,
@@ -39,8 +39,6 @@ import appeng.core.sync.network.NetworkHandler;
public abstract class AppEngPacket implements Packet public abstract class AppEngPacket implements Packet
{ {
private AppEngPacketHandlerBase.PacketTypes id;
private PacketBuffer p; private PacketBuffer p;
private PacketCallState caller; private PacketCallState caller;
@@ -33,6 +33,7 @@ import appeng.core.sync.packets.PacketCompassResponse;
import appeng.core.sync.packets.PacketCompressedNBT; import appeng.core.sync.packets.PacketCompressedNBT;
import appeng.core.sync.packets.PacketConfigButton; import appeng.core.sync.packets.PacketConfigButton;
import appeng.core.sync.packets.PacketCraftRequest; import appeng.core.sync.packets.PacketCraftRequest;
import appeng.core.sync.packets.PacketFluidTank;
import appeng.core.sync.packets.PacketInventoryAction; import appeng.core.sync.packets.PacketInventoryAction;
import appeng.core.sync.packets.PacketJEIRecipe; import appeng.core.sync.packets.PacketJEIRecipe;
import appeng.core.sync.packets.PacketLightning; import appeng.core.sync.packets.PacketLightning;
@@ -104,7 +105,9 @@ public class AppEngPacketHandlerBase
PACKET_COMPRESSED_NBT( PacketCompressedNBT.class ), PACKET_COMPRESSED_NBT( PacketCompressedNBT.class ),
PACKET_PAINTED_ENTITY( PacketPaintedEntity.class ); PACKET_PAINTED_ENTITY( PacketPaintedEntity.class ),
PACKET_FLUID_TANK( PacketFluidTank.class );
private final Class<? extends AppEngPacket> packetClass; private final Class<? extends AppEngPacket> packetClass;
private final Constructor<? extends AppEngPacket> packetConstructor; private final Constructor<? extends AppEngPacket> packetConstructor;
@@ -87,8 +87,10 @@ import appeng.container.implementations.ContainerVibrationChamber;
import appeng.container.implementations.ContainerWireless; import appeng.container.implementations.ContainerWireless;
import appeng.container.implementations.ContainerWirelessTerm; import appeng.container.implementations.ContainerWirelessTerm;
import appeng.fluids.container.ContainerFluidIO; import appeng.fluids.container.ContainerFluidIO;
import appeng.fluids.container.ContainerFluidInterface;
import appeng.fluids.container.ContainerFluidStorageBus; import appeng.fluids.container.ContainerFluidStorageBus;
import appeng.fluids.container.ContainerFluidTerminal; import appeng.fluids.container.ContainerFluidTerminal;
import appeng.fluids.helper.IFluidInterfaceHost;
import appeng.fluids.parts.PartFluidStorageBus; import appeng.fluids.parts.PartFluidStorageBus;
import appeng.fluids.parts.PartFluidTerminal; import appeng.fluids.parts.PartFluidTerminal;
import appeng.fluids.parts.PartSharedFluidBus; import appeng.fluids.parts.PartSharedFluidBus;
@@ -156,6 +158,8 @@ public enum GuiBridge implements IGuiHandler
GUI_INTERFACE( ContainerInterface.class, IInterfaceHost.class, GuiHostType.WORLD, SecurityPermissions.BUILD ), GUI_INTERFACE( ContainerInterface.class, IInterfaceHost.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_FLUID_INTERFACE( ContainerFluidInterface.class, IFluidInterfaceHost.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_BUS( ContainerUpgradeable.class, IUpgradeableHost.class, GuiHostType.WORLD, SecurityPermissions.BUILD ), GUI_BUS( ContainerUpgradeable.class, IUpgradeableHost.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
GUI_BUS_FLUID( ContainerFluidIO.class, PartSharedFluidBus.class, GuiHostType.WORLD, SecurityPermissions.BUILD ), GUI_BUS_FLUID( ContainerFluidIO.class, PartSharedFluidBus.class, GuiHostType.WORLD, SecurityPermissions.BUILD ),
@@ -0,0 +1,83 @@
/*
* 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.core.sync.packets;
import java.util.HashMap;
import java.util.Map;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import appeng.core.sync.AppEngPacket;
import appeng.core.sync.network.INetworkInfo;
import appeng.fluids.container.ContainerFluidInterface;
public class PacketFluidTank extends AppEngPacket
{
private final Map<Integer, NBTTagCompound> updateMap;
public PacketFluidTank( final ByteBuf stream )
{
this.updateMap = new HashMap<>();
NBTTagCompound tags = ByteBufUtils.readTag( stream );
for( final String key : tags.getKeySet() )
{
updateMap.put( Integer.parseInt( key ), tags.getCompoundTag( key ) );
}
}
// api
public PacketFluidTank( final Map<Integer, NBTTagCompound> updateMap )
{
this.updateMap = updateMap;
final NBTTagCompound tag = new NBTTagCompound();
for( Map.Entry<Integer, NBTTagCompound> e : updateMap.entrySet() )
{
tag.setTag( e.getKey().toString(), e.getValue() );
}
final ByteBuf data = Unpooled.buffer();
data.writeInt( this.getPacketID() );
ByteBufUtils.writeTag( data, tag );
this.configureWrite( data );
}
public Map<Integer, NBTTagCompound> getUpdateMap()
{
return this.updateMap;
}
@Override
public void clientPacketData( final INetworkInfo manager, final AppEngPacket packet, final EntityPlayer player )
{
final Container c = player.openContainer;
if( c instanceof ContainerFluidInterface )
{
( (ContainerFluidInterface) c ).receiveTankInfo( this.updateMap );
}
}
}
@@ -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 );
}
}
@@ -43,6 +43,7 @@ import appeng.core.features.AEFeature;
import appeng.core.localization.GuiText; import appeng.core.localization.GuiText;
import appeng.fluids.parts.PartFluidExportBus; import appeng.fluids.parts.PartFluidExportBus;
import appeng.fluids.parts.PartFluidImportBus; import appeng.fluids.parts.PartFluidImportBus;
import appeng.fluids.parts.PartFluidInterface;
import appeng.fluids.parts.PartFluidStorageBus; import appeng.fluids.parts.PartFluidStorageBus;
import appeng.fluids.parts.PartFluidTerminal; import appeng.fluids.parts.PartFluidTerminal;
import appeng.integration.IntegrationRegistry; import appeng.integration.IntegrationRegistry;
@@ -195,7 +196,8 @@ public enum PartType
DARK_MONITOR( 200, "dark_monitor", EnumSet.of( AEFeature.PANELS ), EnumSet.noneOf( IntegrationType.class ), PartDarkPanel.class, "itemIlluminatedPanel" ), DARK_MONITOR( 200, "dark_monitor", EnumSet.of( AEFeature.PANELS ), EnumSet.noneOf( IntegrationType.class ), PartDarkPanel.class, "itemIlluminatedPanel" ),
STORAGE_BUS( 220, "storage_bus", EnumSet.of( AEFeature.STORAGE_BUS ), EnumSet.noneOf( IntegrationType.class ), PartStorageBus.class ), STORAGE_BUS( 220, "storage_bus", EnumSet.of( AEFeature.STORAGE_BUS ), EnumSet.noneOf( IntegrationType.class ), PartStorageBus.class ),
FLUID_STORAGE_BUS( 221, "fluid_storage_bus", EnumSet.of( AEFeature.FLUID_STORAGE_BUS ), EnumSet.noneOf( IntegrationType.class ), PartFluidStorageBus.class ), FLUID_STORAGE_BUS( 221, "fluid_storage_bus", EnumSet.of( AEFeature.FLUID_STORAGE_BUS ), EnumSet
.noneOf( IntegrationType.class ), PartFluidStorageBus.class ),
IMPORT_BUS( 240, "import_bus", EnumSet.of( AEFeature.IMPORT_BUS ), EnumSet.noneOf( IntegrationType.class ), PartImportBus.class ), IMPORT_BUS( 240, "import_bus", EnumSet.of( AEFeature.IMPORT_BUS ), EnumSet.noneOf( IntegrationType.class ), PartImportBus.class ),
@@ -228,6 +230,7 @@ public enum PartType
.noneOf( IntegrationType.class ), PartConversionMonitor.class ), .noneOf( IntegrationType.class ), PartConversionMonitor.class ),
INTERFACE( 440, "interface", EnumSet.of( AEFeature.INTERFACE ), EnumSet.noneOf( IntegrationType.class ), PartInterface.class ), INTERFACE( 440, "interface", EnumSet.of( AEFeature.INTERFACE ), EnumSet.noneOf( IntegrationType.class ), PartInterface.class ),
FLUID_INTERFACE( 441, "fluid_interface", EnumSet.of( AEFeature.FLUID_INTERFACE ), EnumSet.noneOf( IntegrationType.class ), PartFluidInterface.class ),
P2P_TUNNEL_ME( 460, "p2p_tunnel_me", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_ME ), EnumSet P2P_TUNNEL_ME( 460, "p2p_tunnel_me", EnumSet.of( AEFeature.P2P_TUNNEL, AEFeature.P2P_TUNNEL_ME ), EnumSet
.noneOf( IntegrationType.class ), PartP2PTunnelME.class, GuiText.METunnel ) .noneOf( IntegrationType.class ), PartP2PTunnelME.class, GuiText.METunnel )
@@ -0,0 +1,349 @@
/*
* 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.me.storage;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.concurrent.ConcurrentSkipListMap;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidTankProperties;
import appeng.api.AEApi;
import appeng.api.config.AccessRestriction;
import appeng.api.config.Actionable;
import appeng.api.config.StorageFilter;
import appeng.api.networking.security.IActionSource;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.api.storage.IMEMonitor;
import appeng.api.storage.IMEMonitorHandlerReceiver;
import appeng.api.storage.IStorageChannel;
import appeng.api.storage.channels.IFluidStorageChannel;
import appeng.api.storage.data.IAEFluidStack;
import appeng.api.storage.data.IItemList;
public class MEMonitorIFluidHandler implements IMEMonitor<IAEFluidStack>, ITickingMonitor
{
private final IFluidHandler handler;
private final IItemList<IAEFluidStack> list = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList();
private final HashMap<IMEMonitorHandlerReceiver<IAEFluidStack>, Object> listeners = new HashMap<>();
private final NavigableMap<Integer, CachedFluidStack> memory;
private IActionSource mySource;
private StorageFilter mode = StorageFilter.EXTRACTABLE_ONLY;
public MEMonitorIFluidHandler( final IFluidHandler handler )
{
this.handler = handler;
this.memory = new ConcurrentSkipListMap<>();
}
@Override
public void addListener( final IMEMonitorHandlerReceiver<IAEFluidStack> l, final Object verificationToken )
{
this.listeners.put( l, verificationToken );
}
@Override
public void removeListener( final IMEMonitorHandlerReceiver<IAEFluidStack> l )
{
this.listeners.remove( l );
}
@Override
public IAEFluidStack injectItems( final IAEFluidStack input, final Actionable type, final IActionSource src )
{
final int filled = this.handler.fill( input.getFluidStack(), type == Actionable.MODULATE );
if( filled == 0 )
{
return input.copy();
}
if( type == Actionable.MODULATE )
{
this.onTick();
}
if( filled == input.getStackSize() )
{
return null;
}
final IAEFluidStack o = input.copy();
o.setStackSize( input.getStackSize() - filled );
return o;
}
@Override
public IAEFluidStack extractItems( final IAEFluidStack request, final Actionable type, final IActionSource src )
{
final FluidStack removed = this.handler.drain( request.getFluidStack(), type == Actionable.MODULATE );
if( removed == null || removed.amount == 0 )
{
return null;
}
if( type == Actionable.MODULATE )
{
this.onTick();
}
final IAEFluidStack o = request.copy();
o.setStackSize( removed.amount );
return o;
}
@Override
public IStorageChannel getChannel()
{
return AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class );
}
@Override
public TickRateModulation onTick()
{
final List<IAEFluidStack> changes = new ArrayList<>();
this.list.resetStatus();
int high = 0;
boolean changed = false;
final IFluidTankProperties[] props = this.handler.getTankProperties();
for( int slot = 0; slot < this.handler.getTankProperties().length; ++slot )
{
final CachedFluidStack old = this.memory.get( slot );
high = Math.max( high, slot );
final FluidStack newIS = !props[slot].canDrain() && this.getMode() == StorageFilter.EXTRACTABLE_ONLY ? null : props[slot].getContents();
final FluidStack oldIS = old == null ? null : old.fluidStack;
if( isDifferent( newIS, oldIS ) )
{
final CachedFluidStack cis = new CachedFluidStack( newIS );
this.memory.put( slot, cis );
if( old != null && old.aeStack != null )
{
old.aeStack.setStackSize( -old.aeStack.getStackSize() );
changes.add( old.aeStack );
}
if( cis.aeStack != null )
{
changes.add( cis.aeStack );
this.list.add( cis.aeStack );
}
changed = true;
}
else
{
final int newSize = newIS == null ? 0 : newIS.amount;
final int diff = newSize - ( oldIS == null ? 0 : oldIS.amount );
IAEFluidStack stack = null;
if( newIS != null )
{
stack = ( old == null || old.aeStack == null ? AEApi.instance()
.storage()
.getStorageChannel( IFluidStorageChannel.class )
.createStack( newIS ) : old.aeStack.copy() );
}
if( stack != null )
{
stack.setStackSize( newSize );
this.list.add( stack );
}
if( diff != 0 && stack != null )
{
final CachedFluidStack cis = new CachedFluidStack( newIS );
this.memory.put( slot, cis );
final IAEFluidStack a = stack.copy();
a.setStackSize( diff );
changes.add( a );
changed = true;
}
}
}
// detect dropped items; should fix non IISided Inventory Changes.
final NavigableMap<Integer, CachedFluidStack> end = this.memory.tailMap( high, false );
if( !end.isEmpty() )
{
for( final CachedFluidStack cis : end.values() )
{
if( cis != null && cis.aeStack != null )
{
final IAEFluidStack a = cis.aeStack.copy();
a.setStackSize( -a.getStackSize() );
changes.add( a );
changed = true;
}
}
end.clear();
}
if( !changes.isEmpty() )
{
this.postDifference( changes );
}
return changed ? TickRateModulation.URGENT : TickRateModulation.SLOWER;
}
private static boolean isDifferent( FluidStack a, FluidStack b )
{
if( a == b )
{
return false;
}
if( a == null || b == null )
{
return true;
}
return !a.getFluid().equals( b.getFluid() );
}
private void postDifference( final Iterable<IAEFluidStack> a )
{
if( a != null )
{
final Iterator<Entry<IMEMonitorHandlerReceiver<IAEFluidStack>, Object>> i = this.listeners.entrySet().iterator();
while( i.hasNext() )
{
final Entry<IMEMonitorHandlerReceiver<IAEFluidStack>, Object> l = i.next();
final IMEMonitorHandlerReceiver<IAEFluidStack> key = l.getKey();
if( key.isValid( l.getValue() ) )
{
key.postChange( this, a, this.getActionSource() );
}
else
{
i.remove();
}
}
}
}
@Override
public AccessRestriction getAccess()
{
return AccessRestriction.READ_WRITE;
}
@Override
public boolean isPrioritized( final IAEFluidStack input )
{
return false;
}
@Override
public boolean canAccept( final IAEFluidStack input )
{
return true;
}
@Override
public int getPriority()
{
return 0;
}
@Override
public int getSlot()
{
return 0;
}
@Override
public boolean validForPass( final int i )
{
return true;
}
@Override
public IItemList<IAEFluidStack> getAvailableItems( final IItemList out )
{
for( final CachedFluidStack is : this.memory.values() )
{
out.addStorage( is.aeStack );
}
return out;
}
@Override
public IItemList<IAEFluidStack> getStorageList()
{
return this.list;
}
private StorageFilter getMode()
{
return this.mode;
}
public void setMode( final StorageFilter mode )
{
this.mode = mode;
}
private IActionSource getActionSource()
{
return this.mySource;
}
@Override
public void setActionSource( final IActionSource mySource )
{
this.mySource = mySource;
}
private static class CachedFluidStack
{
private final FluidStack fluidStack;
private final IAEFluidStack aeStack;
CachedFluidStack( final FluidStack is )
{
if( is == null )
{
this.fluidStack = null;
this.aeStack = null;
}
else
{
this.fluidStack = is.copy();
this.aeStack = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createStack( is );
}
}
}
}
@@ -0,0 +1,7 @@
{
"variants": {
"normal": {
"model": "appliedenergistics2:interface"
}
}
}
@@ -16,6 +16,7 @@ tile.appliedenergistics2.matrix_frame.name=Matrix Frame
tile.appliedenergistics2.io_port.name=ME IO Port tile.appliedenergistics2.io_port.name=ME IO Port
tile.appliedenergistics2.inscriber.name=Inscriber tile.appliedenergistics2.inscriber.name=Inscriber
tile.appliedenergistics2.interface.name=ME Interface tile.appliedenergistics2.interface.name=ME Interface
tile.appliedenergistics2.fluid_interface.name=ME Fluid Interface
tile.appliedenergistics2.quantum_link.name=ME Quantum Link Chamber tile.appliedenergistics2.quantum_link.name=ME Quantum Link Chamber
tile.appliedenergistics2.quantum_ring.name=ME Quantum Ring tile.appliedenergistics2.quantum_ring.name=ME Quantum Ring
tile.appliedenergistics2.fluix_block.name=Fluix Block tile.appliedenergistics2.fluix_block.name=Fluix Block
@@ -152,6 +153,7 @@ gui.appliedenergistics2.GrindStone=Grindstone
gui.appliedenergistics2.ImportBus=ME Import Bus gui.appliedenergistics2.ImportBus=ME Import Bus
gui.appliedenergistics2.ImportBusFluids=ME Fluid Import Bus gui.appliedenergistics2.ImportBusFluids=ME Fluid Import Bus
gui.appliedenergistics2.Interface=ME Interface gui.appliedenergistics2.Interface=ME Interface
gui.appliedenergistics2.FluidInterface=ME Fluid Interface
gui.appliedenergistics2.LevelEmitter=ME Level Emitter gui.appliedenergistics2.LevelEmitter=ME Level Emitter
gui.appliedenergistics2.Of=of gui.appliedenergistics2.Of=of
gui.appliedenergistics2.Patterns=Patterns gui.appliedenergistics2.Patterns=Patterns
@@ -495,6 +497,7 @@ item.appliedenergistics2.multi_part.formation_plane.name=ME Formation Plane
item.appliedenergistics2.multi_part.import_bus.name=ME Import Bus item.appliedenergistics2.multi_part.import_bus.name=ME Import Bus
item.appliedenergistics2.multi_part.fluid_import_bus.name=ME Fluid Import Bus item.appliedenergistics2.multi_part.fluid_import_bus.name=ME Fluid Import Bus
item.appliedenergistics2.multi_part.interface.name=ME Interface item.appliedenergistics2.multi_part.interface.name=ME Interface
item.appliedenergistics2.multi_part.fluid_interface.name=ME Fluid Interface
item.appliedenergistics2.multi_part.level_emitter.name=ME Level Emitter item.appliedenergistics2.multi_part.level_emitter.name=ME Level Emitter
item.appliedenergistics2.multi_part.p2p_tunnel.name=P2P Tunnel item.appliedenergistics2.multi_part.p2p_tunnel.name=P2P Tunnel
item.appliedenergistics2.multi_part.pattern_terminal.name=ME Pattern Terminal item.appliedenergistics2.multi_part.pattern_terminal.name=ME Pattern Terminal
@@ -0,0 +1,106 @@
{
"parent": "appliedenergistics2:item/part/part",
"textures": {
"sides": "appliedenergistics2:parts/monitor_sides",
"back": "appliedenergistics2:parts/monitor_back",
"front": "appliedenergistics2:items/part/interface"
},
"elements": [
{
"from": [
2,
2,
7
],
"to": [
14,
14,
9
],
"faces": {
"north": {
"texture": "#front"
},
"south": {
"texture": "#back"
},
"east": {
"texture": "#sides"
},
"west": {
"texture": "#sides"
},
"up": {
"texture": "#sides"
},
"down": {
"texture": "#sides"
}
}
},
{
"from": [
5,
5,
10
],
"to": [
11,
11,
11
],
"faces": {
"north": {
"texture": "#front"
},
"south": {
"texture": "#back"
},
"east": {
"texture": "#sides"
},
"west": {
"texture": "#sides"
},
"up": {
"texture": "#sides"
},
"down": {
"texture": "#sides"
}
}
},
{
"from": [
5,
5,
9
],
"to": [
11,
11,
10
],
"faces": {
"north": {
"texture": "#front"
},
"south": {
"texture": "#back"
},
"east": {
"texture": "#sides"
},
"west": {
"texture": "#sides"
},
"up": {
"texture": "#sides"
},
"down": {
"texture": "#sides"
}
}
}
]
}
@@ -0,0 +1,29 @@
{
"result": {
"item": "appliedenergistics2:fluid_interface"
},
"type": "forge:ore_shaped",
"pattern": [
"aba",
"c d",
"aba"
],
"key": {
"d": {
"type": "appliedenergistics2:part",
"part": "material.formation_core"
},
"b": {
"type": "forge:ore_dict",
"ore": "dyeBlue"
},
"a": {
"type": "forge:ore_dict",
"ore": "ingotIron"
},
"c": {
"type": "appliedenergistics2:part",
"part": "material.annihilation_core"
}
}
}
@@ -0,0 +1,12 @@
{
"result": {
"item": "appliedenergistics2:fluid_interface"
},
"type": "forge:ore_shapeless",
"ingredients": [
{
"type": "appliedenergistics2:part",
"part": "part.fluid_interface"
}
]
}
@@ -0,0 +1,12 @@
{
"result": {
"type": "appliedenergistics2:part",
"part": "part.fluid_interface"
},
"type": "appliedenergistics2:part_shapeless",
"ingredients": [
{
"item": "appliedenergistics2:fluid_interface"
}
]
}
@@ -1,7 +1,7 @@
{ {
"result": { "result": {
"type": "appliedenergistics2:part", "type": "appliedenergistics2:part",
"part": "part.storage_bus_fluid" "part": "part.fluid_storage_bus"
}, },
"type": "appliedenergistics2:part_shapeless", "type": "appliedenergistics2:part_shapeless",
"ingredients": [ "ingredients": [
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB