From c2d18ce0133a27d54a16d95a4f89f38dbc1a1bb1 Mon Sep 17 00:00:00 2001 From: fscan Date: Wed, 27 Jun 2018 20:04:30 +0200 Subject: [PATCH] Added ME Fluid Interface (#3564) * Fixed fluid storage bus json recipe * Added part version and recipes * Added rudimentary gui --- .../java/appeng/api/definitions/IBlocks.java | 2 + .../java/appeng/api/definitions/IParts.java | 2 + .../java/appeng/client/gui/AEBaseGui.java | 2 + .../client/gui/widgets/GuiFluidTank.java | 128 ++++ .../core/api/definitions/ApiBlocks.java | 13 + .../appeng/core/api/definitions/ApiParts.java | 12 +- .../java/appeng/core/features/AEFeature.java | 1 + .../appeng/core/localization/GuiText.java | 1 + .../java/appeng/core/sync/AppEngPacket.java | 2 - .../core/sync/AppEngPacketHandlerBase.java | 5 +- src/main/java/appeng/core/sync/GuiBridge.java | 4 + .../core/sync/packets/PacketFluidTank.java | 83 +++ .../fluids/block/BlockFluidInterface.java | 66 ++ .../fluids/client/gui/GuiFluidInterface.java | 92 +++ .../container/ContainerFluidInterface.java | 122 ++++ .../appeng/fluids/helper/AEFluidTank.java | 45 ++ .../fluids/helper/DualityFluidInterface.java | 662 ++++++++++++++++++ .../fluids/helper/IAEFluidInventory.java | 29 + .../fluids/helper/IFluidInterfaceHost.java | 38 + .../fluids/parts/PartFluidInterface.java | 219 ++++++ .../fluids/tile/TileFluidInterface.java | 154 ++++ .../java/appeng/items/parts/PartType.java | 5 +- .../me/storage/MEMonitorIFluidHandler.java | 349 +++++++++ .../blockstates/fluid_interface.json | 7 + .../appliedenergistics2/lang/en_us.lang | 3 + .../models/item/part/fluid_interface.json | 106 +++ .../blocks/fluid_interfaces_interface.json | 29 + .../fluid_interfaces_interface_alt.json | 12 + .../fluid_interfaces_interface_part.json | 12 + .../network/parts/storage_bus_fluid.json | 2 +- .../textures/guis/interfacefluid.png | Bin 0 -> 1271 bytes 31 files changed, 2200 insertions(+), 7 deletions(-) create mode 100644 src/main/java/appeng/client/gui/widgets/GuiFluidTank.java create mode 100644 src/main/java/appeng/core/sync/packets/PacketFluidTank.java create mode 100644 src/main/java/appeng/fluids/block/BlockFluidInterface.java create mode 100644 src/main/java/appeng/fluids/client/gui/GuiFluidInterface.java create mode 100644 src/main/java/appeng/fluids/container/ContainerFluidInterface.java create mode 100644 src/main/java/appeng/fluids/helper/AEFluidTank.java create mode 100644 src/main/java/appeng/fluids/helper/DualityFluidInterface.java create mode 100644 src/main/java/appeng/fluids/helper/IAEFluidInventory.java create mode 100644 src/main/java/appeng/fluids/helper/IFluidInterfaceHost.java create mode 100644 src/main/java/appeng/fluids/parts/PartFluidInterface.java create mode 100644 src/main/java/appeng/fluids/tile/TileFluidInterface.java create mode 100644 src/main/java/appeng/me/storage/MEMonitorIFluidHandler.java create mode 100644 src/main/resources/assets/appliedenergistics2/blockstates/fluid_interface.json create mode 100644 src/main/resources/assets/appliedenergistics2/models/item/part/fluid_interface.json create mode 100644 src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface.json create mode 100644 src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface_alt.json create mode 100644 src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface_part.json create mode 100644 src/main/resources/assets/appliedenergistics2/textures/guis/interfacefluid.png diff --git a/src/api/java/appeng/api/definitions/IBlocks.java b/src/api/java/appeng/api/definitions/IBlocks.java index 714d11d4b..66a0b8a7b 100644 --- a/src/api/java/appeng/api/definitions/IBlocks.java +++ b/src/api/java/appeng/api/definitions/IBlocks.java @@ -148,6 +148,8 @@ public interface IBlocks ITileDefinition iface(); + ITileDefinition fluidIface(); + ITileDefinition cellWorkbench(); ITileDefinition iOPort(); diff --git a/src/api/java/appeng/api/definitions/IParts.java b/src/api/java/appeng/api/definitions/IParts.java index 3491500cf..00da98641 100644 --- a/src/api/java/appeng/api/definitions/IParts.java +++ b/src/api/java/appeng/api/definitions/IParts.java @@ -64,6 +64,8 @@ public interface IParts IItemDefinition iface(); + IItemDefinition fluidIface(); + IItemDefinition levelEmitter(); IItemDefinition annihilationPlane(); diff --git a/src/main/java/appeng/client/gui/AEBaseGui.java b/src/main/java/appeng/client/gui/AEBaseGui.java index 22b8f6c95..c147644e9 100644 --- a/src/main/java/appeng/client/gui/AEBaseGui.java +++ b/src/main/java/appeng/client/gui/AEBaseGui.java @@ -751,6 +751,7 @@ public abstract class AEBaseGui extends GuiContainer if( fs != null && this.isPowered() ) { GlStateManager.disableLighting(); + GlStateManager.disableBlend(); Fluid fluid = fs.getFluid(); Minecraft.getMinecraft().getTextureManager().bindTexture( TextureMap.LOCATION_BLOCKS_TEXTURE ); 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 ); GlStateManager.enableLighting(); + GlStateManager.enableBlend(); if( s instanceof IMEFluidSlot ) { diff --git a/src/main/java/appeng/client/gui/widgets/GuiFluidTank.java b/src/main/java/appeng/client/gui/widgets/GuiFluidTank.java new file mode 100644 index 000000000..5f3760c19 --- /dev/null +++ b/src/main/java/appeng/client/gui/widgets/GuiFluidTank.java @@ -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 . + */ + +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; + } + +} diff --git a/src/main/java/appeng/core/api/definitions/ApiBlocks.java b/src/main/java/appeng/core/api/definitions/ApiBlocks.java index 55a07c2b9..e9831ba49 100644 --- a/src/main/java/appeng/core/api/definitions/ApiBlocks.java +++ b/src/main/java/appeng/core/api/definitions/ApiBlocks.java @@ -126,6 +126,8 @@ import appeng.decorative.solid.BlockQuartzPillar; import appeng.decorative.solid.BlockSkyStone; import appeng.decorative.solid.BlockSkyStone.SkystoneType; import appeng.decorative.stair.BlockStairCommon; +import appeng.fluids.block.BlockFluidInterface; +import appeng.fluids.tile.TileFluidInterface; import appeng.hooks.DispenserBehaviorTinyTNT; import appeng.tile.crafting.TileCraftingMonitorTile; import appeng.tile.crafting.TileCraftingStorageTile; @@ -197,6 +199,7 @@ public final class ApiBlocks implements IBlocks private final ITileDefinition drive; private final ITileDefinition chest; private final ITileDefinition iface; + private final ITileDefinition fluidIface; private final ITileDefinition cellWorkbench; private final ITileDefinition iOPort; private final ITileDefinition condenser; @@ -390,6 +393,10 @@ public final class ApiBlocks implements IBlocks .features( AEFeature.INTERFACE ) .tileEntity( new TileEntityDefinition( TileInterface.class ) ) .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 ) .features( AEFeature.STORAGE_CELLS ) .tileEntity( new TileEntityDefinition( TileCellWorkbench.class ) ) @@ -893,6 +900,12 @@ public final class ApiBlocks implements IBlocks return this.iface; } + @Override + public ITileDefinition fluidIface() + { + return this.fluidIface; + } + @Override public ITileDefinition cellWorkbench() { diff --git a/src/main/java/appeng/core/api/definitions/ApiParts.java b/src/main/java/appeng/core/api/definitions/ApiParts.java index 3f52c438d..d370c7026 100644 --- a/src/main/java/appeng/core/api/definitions/ApiParts.java +++ b/src/main/java/appeng/core/api/definitions/ApiParts.java @@ -55,6 +55,7 @@ public final class ApiParts implements IParts private final IItemDefinition importBus; private final IItemDefinition exportBus; private final IItemDefinition iface; + private final IItemDefinition fluidIface; private final IItemDefinition levelEmitter; private final IItemDefinition annihilationPlane; 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.exportBus = new DamagedItemDefinition( "part.bus.export", itemPart.createPart( PartType.EXPORT_BUS ) ); 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.annihilationPlane = new DamagedItemDefinition( "part.plane.annihilation", itemPart.createPart( PartType.ANNIHILATION_PLANE ) ); - this.identityAnnihilationPlane = new DamagedItemDefinition( "part.plane.annihiliation.identity", - itemPart.createPart( PartType.IDENTITY_ANNIHILATION_PLANE ) ); + this.identityAnnihilationPlane = new DamagedItemDefinition( "part.plane.annihiliation.identity", itemPart + .createPart( PartType.IDENTITY_ANNIHILATION_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.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; } + @Override + public IItemDefinition fluidIface() + { + return this.fluidIface; + } + @Override public IItemDefinition levelEmitter() { diff --git a/src/main/java/appeng/core/features/AEFeature.java b/src/main/java/appeng/core/features/AEFeature.java index a80f63d45..40b730d9a 100644 --- a/src/main/java/appeng/core/features/AEFeature.java +++ b/src/main/java/appeng/core/features/AEFeature.java @@ -75,6 +75,7 @@ public enum AEFeature CHANNELS( "Channels", Constants.CATEGORY_NETWORK_FEATURES ), INTERFACE( "Interface", Constants.CATEGORY_NETWORK_BUSES ), + FLUID_INTERFACE( "FluidInterface", Constants.CATEGORY_NETWORK_BUSES ), LEVEL_EMITTER( "LevelEmitter", Constants.CATEGORY_NETWORK_BUSES ), FLUID_TERMINAL( "FluidTerminal", Constants.CATEGORY_NETWORK_BUSES ), CRAFTING_TERMINAL( "CraftingTerminal", Constants.CATEGORY_NETWORK_BUSES ), diff --git a/src/main/java/appeng/core/localization/GuiText.java b/src/main/java/appeng/core/localization/GuiText.java index 092eec89c..4eafbdc71 100644 --- a/src/main/java/appeng/core/localization/GuiText.java +++ b/src/main/java/appeng/core/localization/GuiText.java @@ -40,6 +40,7 @@ public enum GuiText Terminal, Interface, + FluidInterface, Config, StoredItems, Patterns, diff --git a/src/main/java/appeng/core/sync/AppEngPacket.java b/src/main/java/appeng/core/sync/AppEngPacket.java index dd8557c80..6bbb52e16 100644 --- a/src/main/java/appeng/core/sync/AppEngPacket.java +++ b/src/main/java/appeng/core/sync/AppEngPacket.java @@ -39,8 +39,6 @@ import appeng.core.sync.network.NetworkHandler; public abstract class AppEngPacket implements Packet { - - private AppEngPacketHandlerBase.PacketTypes id; private PacketBuffer p; private PacketCallState caller; diff --git a/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java b/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java index 321fb3776..f5a68d5e6 100644 --- a/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java +++ b/src/main/java/appeng/core/sync/AppEngPacketHandlerBase.java @@ -33,6 +33,7 @@ import appeng.core.sync.packets.PacketCompassResponse; import appeng.core.sync.packets.PacketCompressedNBT; import appeng.core.sync.packets.PacketConfigButton; import appeng.core.sync.packets.PacketCraftRequest; +import appeng.core.sync.packets.PacketFluidTank; import appeng.core.sync.packets.PacketInventoryAction; import appeng.core.sync.packets.PacketJEIRecipe; import appeng.core.sync.packets.PacketLightning; @@ -104,7 +105,9 @@ public class AppEngPacketHandlerBase PACKET_COMPRESSED_NBT( PacketCompressedNBT.class ), - PACKET_PAINTED_ENTITY( PacketPaintedEntity.class ); + PACKET_PAINTED_ENTITY( PacketPaintedEntity.class ), + + PACKET_FLUID_TANK( PacketFluidTank.class ); private final Class packetClass; private final Constructor packetConstructor; diff --git a/src/main/java/appeng/core/sync/GuiBridge.java b/src/main/java/appeng/core/sync/GuiBridge.java index f058e0662..ecf75e639 100644 --- a/src/main/java/appeng/core/sync/GuiBridge.java +++ b/src/main/java/appeng/core/sync/GuiBridge.java @@ -87,8 +87,10 @@ import appeng.container.implementations.ContainerVibrationChamber; import appeng.container.implementations.ContainerWireless; import appeng.container.implementations.ContainerWirelessTerm; import appeng.fluids.container.ContainerFluidIO; +import appeng.fluids.container.ContainerFluidInterface; import appeng.fluids.container.ContainerFluidStorageBus; import appeng.fluids.container.ContainerFluidTerminal; +import appeng.fluids.helper.IFluidInterfaceHost; import appeng.fluids.parts.PartFluidStorageBus; import appeng.fluids.parts.PartFluidTerminal; 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_FLUID_INTERFACE( ContainerFluidInterface.class, IFluidInterfaceHost.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 ), diff --git a/src/main/java/appeng/core/sync/packets/PacketFluidTank.java b/src/main/java/appeng/core/sync/packets/PacketFluidTank.java new file mode 100644 index 000000000..b3d7a8b3b --- /dev/null +++ b/src/main/java/appeng/core/sync/packets/PacketFluidTank.java @@ -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 . + */ + +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 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 updateMap ) + { + this.updateMap = updateMap; + + final NBTTagCompound tag = new NBTTagCompound(); + for( Map.Entry 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 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 ); + } + } +} diff --git a/src/main/java/appeng/fluids/block/BlockFluidInterface.java b/src/main/java/appeng/fluids/block/BlockFluidInterface.java new file mode 100644 index 000000000..4eabf1efd --- /dev/null +++ b/src/main/java/appeng/fluids/block/BlockFluidInterface.java @@ -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 . + */ + +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; + } +} diff --git a/src/main/java/appeng/fluids/client/gui/GuiFluidInterface.java b/src/main/java/appeng/fluids/client/gui/GuiFluidInterface.java new file mode 100644 index 000000000..d950fbc5c --- /dev/null +++ b/src/main/java/appeng/fluids/client/gui/GuiFluidInterface.java @@ -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 . + */ + +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 ) ); + } + } +} diff --git a/src/main/java/appeng/fluids/container/ContainerFluidInterface.java b/src/main/java/appeng/fluids/container/ContainerFluidInterface.java new file mode 100644 index 000000000..14ba7fa46 --- /dev/null +++ b/src/main/java/appeng/fluids/container/ContainerFluidInterface.java @@ -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 . + */ + +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 updateMap ) + { + if( l instanceof EntityPlayerMP ) + { + NetworkHandler.instance().sendTo( new PacketFluidTank( updateMap ), (EntityPlayerMP) l ); + } + } + + private void sendTankUpdate() + { + final HashMap 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 updateMap = new HashMap<>(); + if( this.myDuality.writeTankInfo( updateMap, true ) ) + { + this.sendTankUpdate( l, updateMap ); + } + } + + public void receiveTankInfo( final Map 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 ); + } +} diff --git a/src/main/java/appeng/fluids/helper/AEFluidTank.java b/src/main/java/appeng/fluids/helper/AEFluidTank.java new file mode 100644 index 000000000..23086e951 --- /dev/null +++ b/src/main/java/appeng/fluids/helper/AEFluidTank.java @@ -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 . + */ + +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(); + } + +} diff --git a/src/main/java/appeng/fluids/helper/DualityFluidInterface.java b/src/main/java/appeng/fluids/helper/DualityFluidInterface.java new file mode 100644 index 000000000..926a594a0 --- /dev/null +++ b/src/main/java/appeng/fluids/helper/DualityFluidInterface.java @@ -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 . + */ + +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 items = new MEMonitorPassThrough<>( new NullInventory(), AEApi.instance() + .storage() + .getStorageChannel( IItemStorageChannel.class ) ); + private final MEMonitorPassThrough fluids = new MEMonitorPassThrough<>( new NullInventory(), AEApi.instance() + .storage() + .getStorageChannel( IFluidStorageChannel.class ) ); + + 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 > IMEMonitor getInventory( IStorageChannel channel ) + { + if( channel == AEApi.instance().storage().getStorageChannel( IItemStorageChannel.class ) ) + { + if( this.hasConfig() ) + { + return null; + } + + return (IMEMonitor) this.items; + } + else if( channel == AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ) ) + { + if( this.hasConfig() ) + { + return (IMEMonitor) new InterfaceInventory( this ); + } + + return (IMEMonitor) 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() ); + this.fluids.setInternal( new NullInventory() ); + } + + 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 getCapability( Capability 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 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 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 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 Optional context( Class key ) + { + if( key == InterfaceRequestContext.class ) + { + return (Optional) Optional.of( this.context ); + } + + return super.context( key ); + } + } + + private class InterfaceRequestContext implements Comparable + { + @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 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 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(); + } + +} diff --git a/src/main/java/appeng/fluids/helper/IAEFluidInventory.java b/src/main/java/appeng/fluids/helper/IAEFluidInventory.java new file mode 100644 index 000000000..7cbc17c2a --- /dev/null +++ b/src/main/java/appeng/fluids/helper/IAEFluidInventory.java @@ -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 . + */ + +package appeng.fluids.helper; + + +import net.minecraftforge.fluids.capability.IFluidHandler; + + +@FunctionalInterface +public interface IAEFluidInventory +{ + void onFluidInventoryChanged( IFluidHandler inventory ); +} diff --git a/src/main/java/appeng/fluids/helper/IFluidInterfaceHost.java b/src/main/java/appeng/fluids/helper/IFluidInterfaceHost.java new file mode 100644 index 000000000..5009473b5 --- /dev/null +++ b/src/main/java/appeng/fluids/helper/IFluidInterfaceHost.java @@ -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 . + */ + +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 getTargets(); + + TileEntity getTileEntity(); +} diff --git a/src/main/java/appeng/fluids/parts/PartFluidInterface.java b/src/main/java/appeng/fluids/parts/PartFluidInterface.java new file mode 100644 index 000000000..72b29a6f7 --- /dev/null +++ b/src/main/java/appeng/fluids/parts/PartFluidInterface.java @@ -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 . + */ + +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 > IMEMonitor getInventory( IStorageChannel 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 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 getCapability( Capability capabilityClass ) + { + return this.duality.getCapability( capabilityClass, this.getSide().getFacing() ); + } + +} diff --git a/src/main/java/appeng/fluids/tile/TileFluidInterface.java b/src/main/java/appeng/fluids/tile/TileFluidInterface.java new file mode 100644 index 000000000..e1d1978a1 --- /dev/null +++ b/src/main/java/appeng/fluids/tile/TileFluidInterface.java @@ -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 . + */ + +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 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 getCapability( Capability capability, @Nullable EnumFacing facing ) + { + T result = this.duality.getCapability( capability, facing ); + if( result != null ) + { + return result; + } + return super.getCapability( capability, facing ); + } +} diff --git a/src/main/java/appeng/items/parts/PartType.java b/src/main/java/appeng/items/parts/PartType.java index 1fbae9b74..bf702dbac 100644 --- a/src/main/java/appeng/items/parts/PartType.java +++ b/src/main/java/appeng/items/parts/PartType.java @@ -43,6 +43,7 @@ import appeng.core.features.AEFeature; import appeng.core.localization.GuiText; import appeng.fluids.parts.PartFluidExportBus; import appeng.fluids.parts.PartFluidImportBus; +import appeng.fluids.parts.PartFluidInterface; import appeng.fluids.parts.PartFluidStorageBus; import appeng.fluids.parts.PartFluidTerminal; 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" ), 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 ), @@ -228,6 +230,7 @@ public enum PartType .noneOf( IntegrationType.class ), PartConversionMonitor.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 .noneOf( IntegrationType.class ), PartP2PTunnelME.class, GuiText.METunnel ) diff --git a/src/main/java/appeng/me/storage/MEMonitorIFluidHandler.java b/src/main/java/appeng/me/storage/MEMonitorIFluidHandler.java new file mode 100644 index 000000000..2a3a9dc4a --- /dev/null +++ b/src/main/java/appeng/me/storage/MEMonitorIFluidHandler.java @@ -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 . + */ + +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, ITickingMonitor +{ + private final IFluidHandler handler; + private final IItemList list = AEApi.instance().storage().getStorageChannel( IFluidStorageChannel.class ).createList(); + private final HashMap, Object> listeners = new HashMap<>(); + private final NavigableMap 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 l, final Object verificationToken ) + { + this.listeners.put( l, verificationToken ); + } + + @Override + public void removeListener( final IMEMonitorHandlerReceiver 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 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 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 a ) + { + if( a != null ) + { + final Iterator, Object>> i = this.listeners.entrySet().iterator(); + while( i.hasNext() ) + { + final Entry, Object> l = i.next(); + final IMEMonitorHandlerReceiver 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 getAvailableItems( final IItemList out ) + { + for( final CachedFluidStack is : this.memory.values() ) + { + out.addStorage( is.aeStack ); + } + + return out; + } + + @Override + public IItemList 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 ); + } + } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/blockstates/fluid_interface.json b/src/main/resources/assets/appliedenergistics2/blockstates/fluid_interface.json new file mode 100644 index 000000000..ebd072327 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/blockstates/fluid_interface.json @@ -0,0 +1,7 @@ +{ + "variants": { + "normal": { + "model": "appliedenergistics2:interface" + } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/lang/en_us.lang b/src/main/resources/assets/appliedenergistics2/lang/en_us.lang index 353c37e05..ffb801c1f 100644 --- a/src/main/resources/assets/appliedenergistics2/lang/en_us.lang +++ b/src/main/resources/assets/appliedenergistics2/lang/en_us.lang @@ -16,6 +16,7 @@ tile.appliedenergistics2.matrix_frame.name=Matrix Frame tile.appliedenergistics2.io_port.name=ME IO Port tile.appliedenergistics2.inscriber.name=Inscriber 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_ring.name=ME Quantum Ring tile.appliedenergistics2.fluix_block.name=Fluix Block @@ -152,6 +153,7 @@ gui.appliedenergistics2.GrindStone=Grindstone gui.appliedenergistics2.ImportBus=ME Import Bus gui.appliedenergistics2.ImportBusFluids=ME Fluid Import Bus gui.appliedenergistics2.Interface=ME Interface +gui.appliedenergistics2.FluidInterface=ME Fluid Interface gui.appliedenergistics2.LevelEmitter=ME Level Emitter gui.appliedenergistics2.Of=of 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.fluid_import_bus.name=ME Fluid Import Bus 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.p2p_tunnel.name=P2P Tunnel item.appliedenergistics2.multi_part.pattern_terminal.name=ME Pattern Terminal diff --git a/src/main/resources/assets/appliedenergistics2/models/item/part/fluid_interface.json b/src/main/resources/assets/appliedenergistics2/models/item/part/fluid_interface.json new file mode 100644 index 000000000..8810a7578 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/models/item/part/fluid_interface.json @@ -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" + } + } + } + ] +} diff --git a/src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface.json b/src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface.json new file mode 100644 index 000000000..816170e68 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface.json @@ -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" + } + } +} diff --git a/src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface_alt.json b/src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface_alt.json new file mode 100644 index 000000000..d634987f9 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface_alt.json @@ -0,0 +1,12 @@ +{ + "result": { + "item": "appliedenergistics2:fluid_interface" + }, + "type": "forge:ore_shapeless", + "ingredients": [ + { + "type": "appliedenergistics2:part", + "part": "part.fluid_interface" + } + ] +} diff --git a/src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface_part.json b/src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface_part.json new file mode 100644 index 000000000..6cce7e4d4 --- /dev/null +++ b/src/main/resources/assets/appliedenergistics2/recipes/network/blocks/fluid_interfaces_interface_part.json @@ -0,0 +1,12 @@ +{ + "result": { + "type": "appliedenergistics2:part", + "part": "part.fluid_interface" + }, + "type": "appliedenergistics2:part_shapeless", + "ingredients": [ + { + "item": "appliedenergistics2:fluid_interface" + } + ] +} diff --git a/src/main/resources/assets/appliedenergistics2/recipes/network/parts/storage_bus_fluid.json b/src/main/resources/assets/appliedenergistics2/recipes/network/parts/storage_bus_fluid.json index 10dc4a50c..58cac00a6 100644 --- a/src/main/resources/assets/appliedenergistics2/recipes/network/parts/storage_bus_fluid.json +++ b/src/main/resources/assets/appliedenergistics2/recipes/network/parts/storage_bus_fluid.json @@ -1,7 +1,7 @@ { "result": { "type": "appliedenergistics2:part", - "part": "part.storage_bus_fluid" + "part": "part.fluid_storage_bus" }, "type": "appliedenergistics2:part_shapeless", "ingredients": [ diff --git a/src/main/resources/assets/appliedenergistics2/textures/guis/interfacefluid.png b/src/main/resources/assets/appliedenergistics2/textures/guis/interfacefluid.png new file mode 100644 index 0000000000000000000000000000000000000000..29492e3e825745a2d8a4326ac6571bdd4b09c1a5 GIT binary patch literal 1271 zcmeAS@N?(olHy`uVBq!ia0y~yU}OMc4rT@hhU_&FAq)&mzXE(hT%9e985kJM&COjb zja{rvTx?A185lxCL%GT>ba!`8nKI?rv19-L|7RElqaiT7LSWha=N~|Mq9n*Kn8D%M zjWiG^$=lt9p@UV{gMop8v%n*=n1O-s5C}7hYIrp;Ffg!}c>21s-)9sM)iH2C;P8fl zfw9cf#WAGf*4x{LT!#$=To2wgar5|YzkYJq1ho{$?&njrn4}C^`eg-gE?=P$KL69h z@A1aj3~AHXX=^j64P1~~h&*