com.teamdman_9201.flow.TileFloodGate.java Source code

Java tutorial

Introduction

Here is the source code for com.teamdman_9201.flow.TileFloodGate.java

Source

package com.teamdman_9201.flow;

/**
 * Created by TeamDman on 2015-07-26.
 */
/**
 * Copyright (c) 2011-2015, SpaceToad and the BuildCraft Team
 * http://www.mod-buildcraft.com
 *
 * BuildCraft is distributed under the terms of the Minecraft Mod Public
 * License 1.0, or MMPL. Please check the contents of the license located in
 * http://www.mod-buildcraft.com/MMPL-1.0.txt
 */

import net.minecraft.block.Block;
import net.minecraft.block.BlockStaticLiquid;
import net.minecraft.init.Blocks;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.BlockFluidBase;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidTankInfo;
import net.minecraftforge.fluids.IFluidBlock;
import net.minecraftforge.fluids.IFluidHandler;

import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.TreeMap;

import io.netty.buffer.ByteBuf;

public class TileFloodGate extends TileEntity implements IFluidHandler {
    public static final int[] REBUILD_DELAY = new int[8];
    public static final int MAX_LIQUID = FluidContainerRegistry.BUCKET_VOLUME * 2;
    private final TreeMap<Integer, Deque<BlockIndex>> pumpLayerQueues = new TreeMap<Integer, Deque<BlockIndex>>();
    private final Set<BlockIndex> visitedBlocks = new HashSet<BlockIndex>();
    private Deque<BlockIndex> fluidsFound = new LinkedList<BlockIndex>();
    private final Tank tank = new Tank("tank", MAX_LIQUID, this);
    private int rebuildDelay;
    private int tick = 4; //rolled a dice //Utils.RANDOM.nextInt();
    private boolean powered = false;
    private boolean[] blockedSides = new boolean[6];

    static {
        REBUILD_DELAY[0] = 128;
        REBUILD_DELAY[1] = 256;
        REBUILD_DELAY[2] = 512;
        REBUILD_DELAY[3] = 1024;
        REBUILD_DELAY[4] = 2048;
        REBUILD_DELAY[5] = 4096;
        REBUILD_DELAY[6] = 8192;
        REBUILD_DELAY[7] = 16384;
    }

    public TileFloodGate() {
    }

    @Override
    public void updateEntity() {
        super.updateEntity();

        if (worldObj.isRemote) {
            return;
        }

        //redstone control temp disabled
        //        if (powered) {
        //            return;
        //        }

        tick++;
        if (tick % 16 == 0) {
            FluidStack fluidtoFill = tank.drain(FluidContainerRegistry.BUCKET_VOLUME, false);
            if (fluidtoFill != null && fluidtoFill.amount == FluidContainerRegistry.BUCKET_VOLUME) {
                Fluid fluid = fluidtoFill.getFluid();
                if (fluid == null || !fluid.canBePlacedInWorld()) {
                    return;
                }

                if (fluid == FluidRegistry.WATER && worldObj.provider.dimensionId == -1) {
                    tank.drain(FluidContainerRegistry.BUCKET_VOLUME, true);
                    return;
                }

                if (tick % REBUILD_DELAY[rebuildDelay] == 0) {
                    rebuildDelay++;
                    if (rebuildDelay >= REBUILD_DELAY.length) {
                        rebuildDelay = REBUILD_DELAY.length - 1;
                    }
                    rebuildQueue();
                }
                BlockIndex index = getNextIndexToFill(true);

                if (index != null && placeFluid(index.x, index.y, index.z, fluid)) {
                    tank.drain(FluidContainerRegistry.BUCKET_VOLUME, true);
                    rebuildDelay = 0;
                }
            }
        }
    }

    private boolean placeFluid(int x, int y, int z, Fluid fluid) {
        Block block = BlockUtils.getBlock(worldObj, x, y, z);

        if (canPlaceFluidAt(block, x, y, z)) {
            boolean placed;
            Block b = TankUtils.getFluidBlock(fluid, true);

            if (b instanceof BlockFluidBase) {
                BlockFluidBase blockFluid = (BlockFluidBase) b;
                placed = worldObj.setBlock(x, y, z, b, blockFluid.getMaxRenderHeightMeta(), 3);
            } else {
                placed = worldObj.setBlock(x, y, z, b);
            }

            if (placed) {
                queueAdjacent(x, y, z);
                expandQueue();
            }

            return placed;
        }

        return false;
    }

    private BlockIndex getNextIndexToFill(boolean remove) {
        if (pumpLayerQueues.isEmpty()) {
            return null;
        }

        Deque<BlockIndex> bottomLayer = pumpLayerQueues.firstEntry().getValue();

        if (bottomLayer != null) {
            if (bottomLayer.isEmpty()) {
                pumpLayerQueues.pollFirstEntry();
            }
            if (remove) {
                BlockIndex index = bottomLayer.pollFirst();
                return index;
            }
            return bottomLayer.peekFirst();
        }

        return null;
    }

    private Deque<BlockIndex> getLayerQueue(int layer) {
        Deque<BlockIndex> pumpQueue = pumpLayerQueues.get(layer);
        if (pumpQueue == null) {
            pumpQueue = new LinkedList<BlockIndex>();
            pumpLayerQueues.put(layer, pumpQueue);
        }
        return pumpQueue;
    }

    public boolean[] getBlocked() {
        return blockedSides;
    }

    /**
     * Nasty expensive function, don't call if you don't have to.
     */
    void rebuildQueue() {
        pumpLayerQueues.clear();
        visitedBlocks.clear();
        fluidsFound.clear();

        queueAdjacent(xCoord, yCoord, zCoord);

        expandQueue();
    }

    private void expandQueue() {
        if (tank.getFluidType() == null) {
            return;
        }
        while (!fluidsFound.isEmpty()) {
            Deque<BlockIndex> fluidsToExpand = fluidsFound;
            fluidsFound = new LinkedList<BlockIndex>();

            for (BlockIndex index : fluidsToExpand) {
                queueAdjacent(index.x, index.y, index.z);
            }
        }
    }

    public void queueAdjacent(int x, int y, int z) {
        if (tank.getFluidType() == null) {
            return;
        }
        for (int i = 0; i < 6; i++) {
            if (i != 1 && !blockedSides[i]) {
                ForgeDirection dir = ForgeDirection.getOrientation(i);
                queueForFilling(x + dir.offsetX, y + dir.offsetY, z + dir.offsetZ);
            }
        }
    }

    public void queueForFilling(int x, int y, int z) {
        if (y < 0 || y > 255) {
            return;
        }
        BlockIndex index = new BlockIndex(x, y, z);
        if (visitedBlocks.add(index)) {
            if ((x - xCoord) * (x - xCoord) + (z - zCoord) * (z - zCoord) > 64 * 64) {
                return;
            }

            Block block = BlockUtils.getBlock(worldObj, x, y, z);
            if (BlockUtils.getFluid(block) == tank.getFluidType()) {
                fluidsFound.add(index);
            }
            if (canPlaceFluidAt(block, x, y, z)) {
                getLayerQueue(y).addLast(index);
            }
        }
    }

    private boolean canPlaceFluidAt(Block block, int x, int y, int z) {
        if (block == Blocks.air)
            return true;
        if (block instanceof IFluidBlock || block instanceof BlockStaticLiquid)
            return worldObj.getBlockMetadata(x, y, z) != 0;
        return false;
        //BlockUtils.isFullFluidBlock(block, worldObj, x, y, z) || block == Blocks.air;
        //BuildCraftAPI.isSoftBlock(worldObj, x, y, z) && !
        //worldProperties.get("soft").get(world, x, y, z);
    }

    public void onNeighborBlockChange(Block block) {
        boolean p = worldObj.isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord);
        if (powered != p) {
            powered = p;
            if (!p) {
                rebuildQueue();
            }
        }
    }

    @Override
    public void readFromNBT(NBTTagCompound data) {
        super.readFromNBT(data);
        tank.readFromNBT(data);
        rebuildDelay = data.getByte("rebuildDelay");
        powered = data.getBoolean("powered");
        for (int i = 0; i < 6; i++) {
            blockedSides[i] = data.getBoolean("blocked[" + i + "]");
        }
    }

    @Override
    public void writeToNBT(NBTTagCompound data) {
        super.writeToNBT(data);
        tank.writeToNBT(data);
        data.setByte("rebuildDelay", (byte) rebuildDelay);
        data.setBoolean("powered", powered);
        for (int i = 0; i < 6; i++) {
            if (blockedSides[i]) {
                data.setBoolean("blocked[" + i + "]", true);
            }
        }
    }

    // TODO: fit in single byte

    public void readData(ByteBuf stream) {
        for (int i = 0; i < 6; i++) {
            blockedSides[i] = stream.readBoolean();
        }
    }

    public void writeData(ByteBuf stream) {
        for (int i = 0; i < 6; i++) {
            stream.writeBoolean(blockedSides[i]);
        }
    }

    public void switchSide(ForgeDirection side) {
        System.out.println("Csides=" + side.ordinal() + "=" + blockedSides[side.ordinal()]);
        if (side.ordinal() != 1) {
            blockedSides[side.ordinal()] = !blockedSides[side.ordinal()];
            System.out.println("Ssides=" + side.ordinal() + "=" + blockedSides[side.ordinal()]);

            rebuildQueue();
            //            sendNetworkUpdate(); //idk what to put here instead .-.
            worldObj.markBlockRangeForRenderUpdate(xCoord, yCoord, zCoord, xCoord, yCoord, zCoord);
        }
    }

    //    public void switchSide(ForgeDirection side) {
    //        if (side.ordinal() != 1) {
    //            blockedSides[side.ordinal()] = !blockedSides[side.ordinal()];
    //
    //            rebuildQueue();
    //            sendNetworkUpdate();
    //            worldObj.markBlockRangeForRenderUpdate(xCoord, yCoord, zCoord, xCoord, yCoord, zCoord);
    //        }
    //    }

    @Override
    public void invalidate() {
        super.invalidate();
        destroy();
    }

    public void destroy() {
        pumpLayerQueues.clear();
    }

    // IFluidHandler implementation.
    @Override
    public int fill(ForgeDirection from, FluidStack resource, boolean doFill) {
        return tank.fill(resource, doFill);
    }

    @Override
    public FluidStack drain(ForgeDirection from, int maxDrain, boolean doDrain) {
        return null;
    }

    @Override
    public FluidStack drain(ForgeDirection from, FluidStack resource, boolean doDrain) {
        return null;
    }

    @Override
    public boolean canFill(ForgeDirection from, Fluid fluid) {
        return true;
    }

    @Override
    public boolean canDrain(ForgeDirection from, Fluid fluid) {
        return false;
    }

    @Override
    public FluidTankInfo[] getTankInfo(ForgeDirection from) {
        return new FluidTankInfo[] { tank.getInfo() };
    }

    public boolean isSideBlocked(int side) {
        return blockedSides[side];
    }

}