buildcraft.core.lib.engines.TileEngineBase.java Source code

Java tutorial

Introduction

Here is the source code for buildcraft.core.lib.engines.TileEngineBase.java

Source

/**
 * Copyright (c) 2011-2015, SpaceToad and the BuildCraft Team
 * http://www.mod-buildcraft.com
 * <p/>
 * 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
 */
package buildcraft.core.lib.engines;

import io.netty.buffer.ByteBuf;

import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.ICrafting;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;

import net.minecraftforge.common.util.ForgeDirection;

import cofh.api.energy.IEnergyConnection;
import cofh.api.energy.IEnergyHandler;
import cofh.api.energy.IEnergyReceiver;
import buildcraft.BuildCraftCore;
import buildcraft.api.power.IEngine;
import buildcraft.api.tiles.IHeatable;
import buildcraft.api.tools.IToolWrench;
import buildcraft.api.transport.IPipeConnection;
import buildcraft.api.transport.IPipeTile;
import buildcraft.core.CompatHooks;
import buildcraft.core.lib.block.TileBuildCraft;
import buildcraft.core.lib.utils.MathUtils;
import buildcraft.core.lib.utils.ResourceUtils;
import buildcraft.core.lib.utils.Utils;

public abstract class TileEngineBase extends TileBuildCraft
        implements IPipeConnection, IEnergyHandler, IEngine, IHeatable {
    // TEMP
    public static final ResourceLocation TRUNK_BLUE_TEXTURE = new ResourceLocation(
            "buildcraftcore:textures/blocks/engine/trunk_blue.png");
    public static final ResourceLocation TRUNK_GREEN_TEXTURE = new ResourceLocation(
            "buildcraftcore:textures/blocks/engine/trunk_green.png");
    public static final ResourceLocation TRUNK_YELLOW_TEXTURE = new ResourceLocation(
            "buildcraftcore:textures/blocks/engine/trunk_yellow.png");
    public static final ResourceLocation TRUNK_RED_TEXTURE = new ResourceLocation(
            "buildcraftcore:textures/blocks/engine/trunk_red.png");
    public static final ResourceLocation TRUNK_OVERHEAT_TEXTURE = new ResourceLocation(
            "buildcraftcore:textures/blocks/engine/trunk_overheat.png");

    public enum EnergyStage {
        BLUE, GREEN, YELLOW, RED, OVERHEAT;
        public static final EnergyStage[] VALUES = values();
    }

    public static final float MIN_HEAT = 20;
    public static final float IDEAL_HEAT = 100;
    public static final float MAX_HEAT = 250;
    public int currentOutput = 0;
    public boolean isRedstonePowered = false;
    public float progress;
    public int energy;
    public float heat = MIN_HEAT;
    public EnergyStage energyStage = EnergyStage.BLUE;
    public ForgeDirection orientation = ForgeDirection.UP;

    protected int progressPart = 0;

    private boolean checkOrientation = false;

    private boolean isPumping = false; // Used for SMP synch

    public TileEngineBase() {
    }

    @Override
    public void initialize() {
        if (!worldObj.isRemote) {
            checkRedstonePower();
        }
    }

    private String getTexturePrefix() {
        if (!(blockType instanceof BlockEngineBase)) {
            Block engineBase = worldObj.getBlock(xCoord, yCoord, zCoord);
            if (engineBase instanceof BlockEngineBase) {
                blockType = engineBase;
                getBlockMetadata();
            } else {
                return null;
            }
        }

        return ((BlockEngineBase) blockType).getTexturePrefix(getBlockMetadata(), true);
    }

    public ResourceLocation getBaseTexture() {
        if (getTexturePrefix() != null) {
            return new ResourceLocation(getTexturePrefix() + "/base.png");
        } else {
            return new ResourceLocation("missingno");
        }
    }

    public ResourceLocation getChamberTexture() {
        if (getTexturePrefix() != null) {
            return new ResourceLocation(getTexturePrefix() + "/chamber.png");
        } else {
            return new ResourceLocation("missingno");
        }
    }

    public ResourceLocation getTrunkTexture(EnergyStage stage) {
        if (getTexturePrefix() == null) {
            return TRUNK_OVERHEAT_TEXTURE;
        }

        if (ResourceUtils.resourceExists(getTexturePrefix() + "/trunk.png")) {
            return new ResourceLocation(getTexturePrefix() + "/trunk.png");
        }

        switch (stage) {
        case BLUE:
            return TRUNK_BLUE_TEXTURE;
        case GREEN:
            return TRUNK_GREEN_TEXTURE;
        case YELLOW:
            return TRUNK_YELLOW_TEXTURE;
        case RED:
            return TRUNK_RED_TEXTURE;
        case OVERHEAT:
            return TRUNK_OVERHEAT_TEXTURE;
        default:
            return TRUNK_RED_TEXTURE;
        }
    }

    public boolean onBlockActivated(EntityPlayer player, ForgeDirection side) {
        if (!player.worldObj.isRemote && player.getCurrentEquippedItem() != null
                && player.getCurrentEquippedItem().getItem() instanceof IToolWrench) {
            IToolWrench wrench = (IToolWrench) player.getCurrentEquippedItem().getItem();
            if (wrench.canWrench(player, xCoord, yCoord, zCoord)) {
                if (getEnergyStage() == EnergyStage.OVERHEAT && !Utils.isFakePlayer(player)) {
                    energyStage = computeEnergyStage();
                    sendNetworkUpdate();
                }
                checkOrientation = true;

                wrench.wrenchUsed(player, xCoord, yCoord, zCoord);
                return true;
            }
        }
        return false;
    }

    public double getEnergyLevel() {
        return ((double) energy) / getMaxEnergy();
    }

    protected EnergyStage computeEnergyStage() {
        float energyLevel = getHeatLevel();
        if (energyLevel < 0.25f) {
            return EnergyStage.BLUE;
        } else if (energyLevel < 0.5f) {
            return EnergyStage.GREEN;
        } else if (energyLevel < 0.75f) {
            return EnergyStage.YELLOW;
        } else if (energyLevel < 1f) {
            return EnergyStage.RED;
        } else {
            return EnergyStage.OVERHEAT;
        }
    }

    public final EnergyStage getEnergyStage() {
        if (!worldObj.isRemote) {
            if (energyStage == EnergyStage.OVERHEAT) {
                return energyStage;
            }

            EnergyStage newStage = computeEnergyStage();

            if (energyStage != newStage) {
                energyStage = newStage;
                if (energyStage == EnergyStage.OVERHEAT) {
                    overheat();
                }
                sendNetworkUpdate();
            }
        }

        return energyStage;
    }

    public void overheat() {
        this.isPumping = false;
        if (BuildCraftCore.canEnginesExplode) {
            worldObj.createExplosion(null, xCoord, yCoord, zCoord, 3, true);
            worldObj.setBlockToAir(xCoord, yCoord, zCoord);
        }
    }

    public void updateHeat() {
        heat = (float) ((MAX_HEAT - MIN_HEAT) * getEnergyLevel()) + MIN_HEAT;
    }

    public float getHeatLevel() {
        return (heat - MIN_HEAT) / (MAX_HEAT - MIN_HEAT);
    }

    public float getPistonSpeed() {
        if (!worldObj.isRemote) {
            return Math.max(0.16f * getHeatLevel(), 0.01f);
        }

        switch (getEnergyStage()) {
        case BLUE:
            return 0.02F;
        case GREEN:
            return 0.04F;
        case YELLOW:
            return 0.08F;
        case RED:
            return 0.16F;
        default:
            return 0;
        }
    }

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

        if (worldObj.isRemote) {
            if (progressPart != 0) {
                progress += getPistonSpeed();

                if (progress > 1) {
                    progressPart = 0;
                    progress = 0;
                }
            } else if (this.isPumping) {
                progressPart = 1;
            }

            return;
        }

        if (checkOrientation) {
            checkOrientation = false;

            if (!isOrientationValid()) {
                switchOrientation(true);
            }
        }

        updateHeat();
        getEnergyStage();

        if (getEnergyStage() == EnergyStage.OVERHEAT) {
            this.energy = Math.max(this.energy - 50, 0);
            return;
        }

        engineUpdate();

        Object tile = getEnergyProvider(orientation);

        if (progressPart != 0) {
            progress += getPistonSpeed();

            if (progress > 0.5 && progressPart == 1) {
                progressPart = 2;
            } else if (progress >= 1) {
                progress = 0;
                progressPart = 0;
            }
        } else if (isRedstonePowered && isActive()) {
            if (isPoweredTile(tile, orientation)) {
                progressPart = 1;
                setPumping(true);
                if (getPowerToExtract() > 0) {
                    progressPart = 1;
                    setPumping(true);
                } else {
                    setPumping(false);
                }
            } else {
                setPumping(false);
            }
        } else {
            setPumping(false);
        }

        burn();

        if (!isRedstonePowered) {
            currentOutput = 0;
        } else if (isRedstonePowered && isActive()) {
            sendPower();
        }
    }

    public Object getEnergyProvider(ForgeDirection orientation) {
        return CompatHooks.INSTANCE.getEnergyProvider(getTile(orientation));
    }

    private int getPowerToExtract() {
        Object tile = getEnergyProvider(orientation);

        if (tile instanceof IEngine) {
            IEngine engine = (IEngine) tile;

            int maxEnergy = engine.receiveEnergyFromEngine(orientation.getOpposite(), this.energy, true);
            return extractEnergy(maxEnergy, false);
        } else if (tile instanceof IEnergyHandler) {
            IEnergyHandler handler = (IEnergyHandler) tile;

            int maxEnergy = handler.receiveEnergy(orientation.getOpposite(), this.energy, true);
            return extractEnergy(maxEnergy, false);
        } else if (tile instanceof IEnergyReceiver) {
            IEnergyReceiver handler = (IEnergyReceiver) tile;

            int maxEnergy = handler.receiveEnergy(orientation.getOpposite(), this.energy, true);
            return extractEnergy(maxEnergy, false);
        } else {
            return 0;
        }
    }

    protected void sendPower() {
        Object tile = getEnergyProvider(orientation);
        if (isPoweredTile(tile, orientation)) {
            int extracted = getPowerToExtract();
            if (extracted <= 0) {
                setPumping(false);
                return;
            }

            setPumping(true);

            if (tile instanceof IEngine) {
                IEngine engine = (IEngine) tile;
                int neededRF = engine.receiveEnergyFromEngine(orientation.getOpposite(), extracted, false);

                extractEnergy(neededRF, true);
            } else if (tile instanceof IEnergyHandler) {
                IEnergyHandler handler = (IEnergyHandler) tile;
                int neededRF = handler.receiveEnergy(orientation.getOpposite(), extracted, false);

                extractEnergy(neededRF, true);
            } else if (tile instanceof IEnergyReceiver) {
                IEnergyReceiver handler = (IEnergyReceiver) tile;
                int neededRF = handler.receiveEnergy(orientation.getOpposite(), extracted, false);

                extractEnergy(neededRF, true);
            }
        }
    }

    protected void burn() {
    }

    protected void engineUpdate() {
        if (!isRedstonePowered) {
            if (energy >= 10) {
                energy -= 10;
            } else if (energy < 10) {
                energy = 0;
            }
        }
    }

    public boolean isActive() {
        return true;
    }

    protected final void setPumping(boolean isActive) {
        if (this.isPumping == isActive) {
            return;
        }

        this.isPumping = isActive;
        sendNetworkUpdate();
    }

    public boolean isOrientationValid() {
        Object tile = getEnergyProvider(orientation);

        return isPoweredTile(tile, orientation);
    }

    public boolean switchOrientation(boolean preferPipe) {
        if (preferPipe && switchOrientationDo(true)) {
            return true;
        } else {
            return switchOrientationDo(false);
        }
    }

    private boolean switchOrientationDo(boolean pipesOnly) {
        for (int i = orientation.ordinal() + 1; i <= orientation.ordinal() + 6; ++i) {
            ForgeDirection o = ForgeDirection.VALID_DIRECTIONS[i % 6];

            Object tile = getEnergyProvider(o);

            if ((!pipesOnly || tile instanceof IPipeTile) && isPoweredTile(tile, o)) {
                orientation = o;
                worldObj.markBlockForUpdate(xCoord, yCoord, zCoord);
                worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord,
                        worldObj.getBlock(xCoord, yCoord, zCoord));

                return true;
            }
        }

        return false;
    }

    @Override
    public void invalidate() {
        super.invalidate();
        checkOrientation = true;
    }

    @Override
    public void validate() {
        super.validate();
        checkOrientation = true;
    }

    @Override
    public void readFromNBT(NBTTagCompound data) {
        super.readFromNBT(data);

        orientation = ForgeDirection.getOrientation(data.getByte("orientation"));
        progress = data.getFloat("progress");
        energy = data.getInteger("energy");
        heat = data.getFloat("heat");
    }

    @Override
    public void writeToNBT(NBTTagCompound data) {
        super.writeToNBT(data);

        data.setByte("orientation", (byte) orientation.ordinal());
        data.setFloat("progress", progress);
        data.setInteger("energy", energy);
        data.setFloat("heat", heat);
    }

    @Override
    public void readData(ByteBuf stream) {
        int flags = stream.readUnsignedByte();
        energyStage = EnergyStage.values()[flags & 0x07];
        isPumping = (flags & 0x08) != 0;
        orientation = ForgeDirection.getOrientation(stream.readByte());
    }

    @Override
    public void writeData(ByteBuf stream) {
        stream.writeByte(energyStage.ordinal() | (isPumping ? 8 : 0));
        stream.writeByte(orientation.ordinal());
    }

    public void getGUINetworkData(int id, int value) {
        switch (id) {
        case 0:
            energy = (energy & 0xffff0000) | (value & 0xffff);
            break;
        case 1:
            energy = (energy & 0xffff) | ((value & 0xffff) << 16);
            break;
        case 2:
            currentOutput = value;
            break;
        case 3:
            heat = value / 100F;
            break;
        }
    }

    public void sendGUINetworkData(Container container, ICrafting iCrafting) {
        iCrafting.sendProgressBarUpdate(container, 0, energy & 0xffff);
        iCrafting.sendProgressBarUpdate(container, 1, (energy & 0xffff0000) >> 16);
        iCrafting.sendProgressBarUpdate(container, 2, currentOutput);
        iCrafting.sendProgressBarUpdate(container, 3, Math.round(heat * 100));
    }

    /* STATE INFORMATION */
    public abstract boolean isBurning();

    public void addEnergy(int addition) {
        if (getEnergyStage() == EnergyStage.OVERHEAT) {
            return;
        }

        energy += addition;

        if (energy > getMaxEnergy()) {
            energy = getMaxEnergy();
        }
    }

    public int extractEnergy(int energyMax, boolean doExtract) {
        int max = Math.min(energyMax, getCurrentOutputLimit());

        int extracted;

        if (energy >= max) {
            extracted = max;

            if (doExtract) {
                energy -= max;
            }
        } else {
            extracted = energy;

            if (doExtract) {
                energy = 0;
            }
        }

        return extracted;
    }

    public boolean isPoweredTile(Object tile, ForgeDirection side) {
        if (tile == null) {
            return false;
        } else if (tile instanceof IEngine) {
            return ((IEngine) tile).canReceiveFromEngine(side.getOpposite());
        } else if (tile instanceof IEnergyHandler || tile instanceof IEnergyReceiver) {
            return ((IEnergyConnection) tile).canConnectEnergy(side.getOpposite());
        } else {
            return false;
        }
    }

    public abstract int getMaxEnergy();

    public int getEnergyStored() {
        return energy;
    }

    public abstract int getIdealOutput();

    public int getCurrentOutputLimit() {
        return Integer.MAX_VALUE;
    }

    @Override
    public ConnectOverride overridePipeConnection(IPipeTile.PipeType type, ForgeDirection with) {
        if (type == IPipeTile.PipeType.POWER) {
            return ConnectOverride.DEFAULT;
        } else if (with == orientation) {
            return ConnectOverride.DISCONNECT;
        } else {
            return ConnectOverride.DEFAULT;
        }
    }

    public void checkRedstonePower() {
        isRedstonePowered = worldObj.isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord);
    }

    public void onNeighborUpdate() {
        checkRedstonePower();
        checkOrientation = true;
    }
    // RF support

    @Override
    public int extractEnergy(ForgeDirection from, int maxExtract, boolean simulate) {
        return 0;
    }

    @Override
    public int getEnergyStored(ForgeDirection from) {
        if (!(from == orientation)) {
            return 0;
        }

        return energy;
    }

    @Override
    public int getMaxEnergyStored(ForgeDirection from) {
        return this.getMaxEnergy();
    }

    @Override
    public boolean canConnectEnergy(ForgeDirection from) {
        return from == orientation;
    }

    // IEngine

    @Override
    public boolean canReceiveFromEngine(ForgeDirection side) {
        return side == orientation.getOpposite();
    }

    @Override
    public int receiveEnergyFromEngine(ForgeDirection side, int amount, boolean simulate) {
        if (canReceiveFromEngine(side)) {
            int targetEnergy = Math.min(this.getMaxEnergy() - this.energy, amount);
            if (!simulate) {
                energy += targetEnergy;
            }
            return targetEnergy;
        } else {
            return 0;
        }
    }

    // IHeatable

    @Override
    public double getMinHeatValue() {
        return MIN_HEAT;
    }

    @Override
    public double getIdealHeatValue() {
        return IDEAL_HEAT;
    }

    @Override
    public double getMaxHeatValue() {
        return MAX_HEAT;
    }

    @Override
    public double getCurrentHeatValue() {
        return heat;
    }

    @Override
    public double setHeatValue(double value) {
        heat = (float) MathUtils.clamp(value, MIN_HEAT, MAX_HEAT);
        return heat;
    }
}