package slimeknights.tconstruct.smeltery.tileentity; import net.minecraft.block.state.IBlockState; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.network.NetworkManager; import net.minecraft.network.play.server.SPacketUpdateTileEntity; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.EnumFacing; import net.minecraft.util.ITickable; import net.minecraft.util.math.BlockPos; import net.minecraft.world.WorldServer; import net.minecraftforge.fluids.FluidStack; import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.fluids.capability.IFluidHandler; import javax.annotation.Nonnull; import slimeknights.tconstruct.common.TinkerNetwork; import slimeknights.tconstruct.library.materials.Material; import slimeknights.tconstruct.smeltery.block.BlockFaucet; import slimeknights.tconstruct.smeltery.network.FaucetActivationPacket; public class TileFaucet extends TileEntity implements ITickable { public static final int LIQUID_TRANSFER = 6; // how much liquid is transferred per operation public static final int TRANSACTION_AMOUNT = Material.VALUE_Ingot; // direction we're pulling liquid from. cached so we don't have to query the world every time. set on pour-begin public EnumFacing direction; // used to continue draining and for rendering public boolean isPouring; public boolean stopPouring; public FluidStack drained; // fluid is drained instantly and distributed over time. how much is left public boolean lastRedstoneState; public TileFaucet() { reset(); } // begin pouring public boolean activate() { IBlockState state = getWorld().getBlockState(pos); // invalid state if(!state.getPropertyKeys().contains(BlockFaucet.FACING)) { return false; } // already pouring? we want to stop then if(isPouring) { stopPouring = true; return true; } direction = getWorld().getBlockState(pos).getValue(BlockFaucet.FACING); doTransfer(); return isPouring; } public void handleRedstone(boolean hasSignal) { if(hasSignal != lastRedstoneState) { lastRedstoneState = hasSignal; if(hasSignal) { activate(); } } } @Override public void update() { if(getWorld().isRemote) { return; } // nothing to do if not pouring if(!isPouring) { return; } if(drained != null) { // done draining if(drained.amount <= 0) { drained = null; // pour me another, if we want to. if(!stopPouring) { doTransfer(); } else { reset(); } } else { // reduce amount (cooldown) pour(); } } } protected void doTransfer() { // still got content left if(drained != null) { return; } IFluidHandler toDrain = getFluidHandler(pos.offset(direction), direction); IFluidHandler toFill = getFluidHandler(pos.down(), EnumFacing.UP); if(toDrain != null && toFill != null) { // can we drain? FluidStack drained = toDrain.drain(TRANSACTION_AMOUNT, false); if(drained != null) { // can we fill? int filled = toFill.fill(drained, false); if(filled > 0) { // drain the liquid and transfer it, buffer the amount for delay this.drained = toDrain.drain(filled, true); this.isPouring = true; pour(); // sync to clients if(!getWorld().isRemote && getWorld() instanceof WorldServer) { TinkerNetwork.sendToClients((WorldServer) getWorld(), pos, new FaucetActivationPacket(pos, drained)); } return; } } } // draining unsuccessful reset(); } // takes the liquid inside and executes one pouring step protected void pour() { if(drained == null) { return; } IFluidHandler toFill = getFluidHandler(pos.down(), EnumFacing.UP); if(toFill != null) { FluidStack fillStack = drained.copy(); fillStack.amount = Math.min(drained.amount, LIQUID_TRANSFER); // can we fill? int filled = toFill.fill(fillStack, false); if(filled > 0) { // transfer it this.drained.amount -= filled; fillStack.amount = filled; toFill.fill(fillStack, true); } } else { // filling TE got lost. reset. all liquid buffered is lost. reset(); } } protected void reset() { isPouring = false; stopPouring = false; drained = null; direction = EnumFacing.DOWN; // invalid direction lastRedstoneState = false; // sync to clients if(getWorld() != null && !getWorld().isRemote && getWorld() instanceof WorldServer) { TinkerNetwork.sendToClients((WorldServer) getWorld(), pos, new FaucetActivationPacket(pos, null)); } } protected IFluidHandler getFluidHandler(BlockPos pos, EnumFacing direction) { TileEntity te = getWorld().getTileEntity(pos); if(te != null && te.hasCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, direction)) { return te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, direction); } return null; } /* Load & Save */ @Nonnull @Override public NBTTagCompound writeToNBT(NBTTagCompound compound) { compound = super.writeToNBT(compound); if(drained != null) { drained.writeToNBT(compound); compound.setInteger("direction", direction.getIndex()); //compound.setString("direction", direction.getName()); compound.setBoolean("stop", stopPouring); } return compound; } @Override public void readFromNBT(NBTTagCompound compound) { super.readFromNBT(compound); drained = FluidStack.loadFluidStackFromNBT(compound); if(drained != null) { isPouring = true; direction = EnumFacing.values()[compound.getInteger("direction")]; //direction = EnumFacing.valueOf(compound.getString("direction")); stopPouring = compound.getBoolean("stop"); } else { reset(); } } public void onActivationPacket(FluidStack fluid) { if(fluid == null) { reset(); } else { drained = fluid; isPouring = true; direction = getWorld().getBlockState(pos).getValue(BlockFaucet.FACING); } } @Override public SPacketUpdateTileEntity getUpdatePacket() { NBTTagCompound tag = new NBTTagCompound(); writeToNBT(tag); return new SPacketUpdateTileEntity(this.getPos(), this.getBlockMetadata(), tag); } @Override public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) { super.onDataPacket(net, pkt); readFromNBT(pkt.getNbtCompound()); } @Nonnull @Override public NBTTagCompound getUpdateTag() { // new tag instead of super since default implementation calls the super of writeToNBT return writeToNBT(new NBTTagCompound()); } @Override public void handleUpdateTag(@Nonnull NBTTagCompound tag) { readFromNBT(tag); } }