com.builtbroken.atomic.content.machines.processing.TileEntityProcessingMachine.java Source code

Java tutorial

Introduction

Here is the source code for com.builtbroken.atomic.content.machines.processing.TileEntityProcessingMachine.java

Source

package com.builtbroken.atomic.content.machines.processing;

import com.builtbroken.atomic.content.items.wrench.WrenchColor;
import com.builtbroken.atomic.content.items.wrench.WrenchMode;
import com.builtbroken.atomic.content.machines.TileEntityPowerInvMachine;
import com.builtbroken.atomic.content.machines.processing.recipes.ProcessingRecipe;
import com.builtbroken.atomic.content.machines.processing.recipes.ProcessingRecipeList;
import com.builtbroken.atomic.lib.power.PowerSystem;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import io.netty.buffer.ByteBuf;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.*;

import java.util.List;
import java.util.function.Function;

/**
 * @see <a href="https://github.com/BuiltBrokenModding/VoltzEngine/blob/development/license.md">License</a> for what you can and can't do with the code.
 * Created by Dark(DarkGuardsman, Robert) on 5/22/2018.
 */
public abstract class TileEntityProcessingMachine extends TileEntityPowerInvMachine {
    boolean processing = false;
    public int processTimer = 0;

    ForgeDirection _facingDirectionCache;

    float _processingAnimationRotationPrev = 0;
    float _processingAnimationRotation = 0;

    @Override
    public void update(int ticks) {
        super.update(ticks);
        if (isServer()) {
            preProcess(ticks);
            process(ticks);
            postProcess(ticks);
        } else if (processTimer > 0) {
            doAnimation(ticks);
            doEffects(ticks);
        }
    }

    protected void doAnimation(int ticks) {
        _processingAnimationRotation += 5f; //TODO move to val
        if (_processingAnimationRotation > 360) {
            _processingAnimationRotation -= 360;
            _processingAnimationRotationPrev -= 360;
        }
    }

    protected void doEffects(int ticks) {

    }

    public void onWrench(WrenchMode type, WrenchColor color, ForgeDirection side, EntityPlayer player) {

    }

    //-----------------------------------------------
    //--------Recipe Handling -----------------------
    //-----------------------------------------------

    /**
     * Called before recipe/process is run
     * <p>
     * Good chance to input fluids and items
     *
     * @param ticks - time in ticks since alive
     */
    protected void preProcess(int ticks) {

    }

    /**
     * Called to do the process checks
     *
     * @param ticks - time in ticks since alive
     */
    protected void process(int ticks) {
        if (processing) {
            if (processTimer++ >= getProcessingTime()) {
                processTimer = 0;
                doProcess();
                checkRecipe();
            }
        } else if (ticks % 20 == 0) {
            checkRecipe();
        }
    }

    /**
     * Called when we finish a recipe
     */
    protected void onProcessed() {

    }

    /**
     * How long each process cycle takes before running
     */
    protected abstract int getProcessingTime();

    /**
     * Called to do the process
     * <p>
     * E.g. consume items and resources
     */
    protected void doProcess() {
        ProcessingRecipe recipe = getRecipeList().getMatchingRecipe(this);
        if (recipe != null) {
            if (recipe.applyRecipe(this)) {
                onProcessed();
            }
        }
    }

    /**
     * Called to check if the recipe works
     * <p>
     * Sets {@link #processing} to true to
     * avoid checking recipe every tick
     */
    protected void checkRecipe() {
        processing = canProcess();
        if (!processing) {
            processTimer = 0;
        }
        //Set to 1 for client sync
        else if (processTimer == 0) {
            processTimer = 1;
        }
        syncClientNextTick();
    }

    /**
     * Checks if the process and recipe work
     *
     * @return true if machine has a valid recipe and can function
     */
    protected boolean canProcess() {
        return getRecipeList().getMatchingRecipe(this) != null; //TODO store recipe
    }

    /**
     * Gets the list of recipes supported by this machine
     *
     * @return
     */
    protected abstract ProcessingRecipeList getRecipeList();

    /**
     * Called after the process has run
     * <p>
     * Good chance to output fluids and items
     *
     * @param ticks
     */
    protected void postProcess(int ticks) {

    }

    //-----------------------------------------------
    //--------Inventory handling ---------------------------
    //-----------------------------------------------

    protected void drainBattery(int slot) {
        ItemStack itemStack = getStackInSlot(slot);
        int power = PowerSystem.getEnergyStored(itemStack);
        if (power > 0) {
            power = PowerSystem.removePower(itemStack, power, false);
            int added = addEnergy(power, true);
            PowerSystem.removePower(itemStack, added, true);
            setInventorySlotContents(slot, itemStack);
        }
    }

    public boolean hasSpaceInOutput(ItemStack insertStack, int slot) {
        if (insertStack != null) {
            ItemStack stackInSlot = getStackInSlot(slot);
            if (stackInSlot == null) {
                return true;
            } else if (stackInSlot.getItem() == insertStack.getItem()
                    && stackInSlot.getItemDamage() == insertStack.getItemDamage()) {
                return getInventoryStackLimit() - stackInSlot.stackSize >= insertStack.stackSize;
            }
        }
        return false;
    }

    public void addToOutput(ItemStack insertStack, int slot) {
        ItemStack stackInSlot = getStackInSlot(slot);
        if (stackInSlot == null) {
            setInventorySlotContents(slot, insertStack);
        } else if (stackInSlot.getItem() == insertStack.getItem()
                && stackInSlot.getItemDamage() == insertStack.getItemDamage()) {
            stackInSlot.stackSize += insertStack.stackSize;
            stackInSlot.stackSize = Math.min(stackInSlot.stackSize, stackInSlot.getMaxStackSize());
            stackInSlot.stackSize = Math.min(stackInSlot.stackSize, getInventoryStackLimit());
        }
    }

    //-----------------------------------------------
    //--------Fluid Handling ------------------------
    //-----------------------------------------------

    protected boolean containsFluid(final int slot) {
        return getFluid(slot) != null;
    }

    protected boolean containsFluid(final int slot, Fluid fluid) {
        FluidStack fluidStack = getFluid(slot);
        if (fluidStack != null) {
            return fluidStack.getFluid() == fluid;
        }
        return false;
    }

    protected boolean isInputFluid(final int slot) {
        return isInputFluid(getStackInSlot(slot));
    }

    protected boolean isInputFluid(ItemStack stack) {
        FluidStack fluidStack = getFluid(stack);
        if (fluidStack != null) {
            return getRecipeList().isComponent(this, fluidStack.getFluid());
        }
        return false;
    }

    protected FluidStack getFluid(final int slot) {
        return getFluid(getStackInSlot(slot));
    }

    protected FluidStack getFluid(ItemStack itemStack) {
        if (itemStack != null) {
            if (itemStack.getItem() instanceof IFluidContainerItem) {
                return ((IFluidContainerItem) itemStack.getItem()).getFluid(itemStack);
            } else if (FluidContainerRegistry.isFilledContainer(itemStack)) {
                return FluidContainerRegistry.getFluidForFilledItem(itemStack);
            }
        }
        return null;
    }

    protected boolean isEmptyFluidContainer(final int slot) {
        return isEmptyFluidContainer(getStackInSlot(slot));
    }

    protected boolean isEmptyFluidContainer(ItemStack itemStack) {
        if (itemStack != null) {
            if (itemStack.getItem() instanceof IFluidContainerItem) {
                return ((IFluidContainerItem) itemStack.getItem()).getFluid(itemStack) == null;
            }
            return FluidContainerRegistry.isEmptyContainer(itemStack) || itemStack.getItem() == Items.bucket;
        }
        return false;
    }

    /**
     * Pulls fluids from container and insert into tank
     */
    protected void fillTank(final int slot, final IFluidTank inputTank) {
        final ItemStack itemStack = getStackInSlot(slot);
        if (itemStack != null) {
            if (itemStack.getItem() instanceof IFluidContainerItem) {
                IFluidContainerItem fluidContainerItem = (IFluidContainerItem) itemStack.getItem();

                FluidStack fluidStack = fluidContainerItem.getFluid(itemStack);
                if (fluidStack != null && getRecipeList().isComponent(this, fluidStack.getFluid())) {
                    fluidStack = fluidContainerItem.drain(itemStack,
                            inputTank.getCapacity() - inputTank.getFluidAmount(), false);
                    int amount = inputTank.fill(fluidStack, true);
                    fluidContainerItem.drain(itemStack, amount, true);
                    setInventorySlotContents(slot, itemStack);
                }
            } else if (FluidContainerRegistry.isFilledContainer(itemStack)) {
                FluidStack stack = FluidContainerRegistry.getFluidForFilledItem(itemStack);
                if (stack != null && getRecipeList().isComponent(this, stack.getFluid())) {
                    inputTank.fill(stack, true);
                    decrStackSize(slot, 1);

                    ItemStack container = itemStack.getItem().getContainerItem(itemStack);
                    if (container != null) {
                        if (getStackInSlot(slot) == null) {
                            setInventorySlotContents(slot, container);
                        } else {
                            //TODO add fluid container output slot
                            EntityItem item = new EntityItem(worldObj);
                            item.setPosition(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5);
                            item.setEntityItemStack(container);
                            worldObj.spawnEntityInWorld(item);
                        }
                    }
                }
            }
        }
    }

    /**
     * Outputs fluids to container in slot
     *
     * @param slot       - slot with container
     * @param outputTank - tank to drain
     */
    protected void outputFluids(final int slot, final IFluidTank outputTank) {
        final ItemStack itemStack = getStackInSlot(slot);
        if (itemStack != null && outputTank.getFluid() != null) {
            if (itemStack.getItem() instanceof IFluidContainerItem) {
                //Copy stack (fix for containers that can stack when empty)
                final ItemStack fluidContainer = itemStack.copy();
                fluidContainer.stackSize = 1;

                IFluidContainerItem fluidContainerItem = (IFluidContainerItem) fluidContainer.getItem();
                FluidStack fluidStack = fluidContainerItem.getFluid(fluidContainer);
                if (fluidStack == null || fluidStack.getFluid() == outputTank.getFluid().getFluid()) {
                    int filled = fluidContainerItem.fill(fluidContainer, outputTank.getFluid(), true);
                    outputTank.drain(filled, true);

                    if (itemStack.stackSize == 1) {
                        setInventorySlotContents(slot, fluidContainer);
                    } else {
                        decrStackSize(slot, 1);

                        //TODO add fluid container output slot
                        EntityItem item = new EntityItem(worldObj);
                        item.setPosition(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5);
                        item.setEntityItemStack(fluidContainer);
                        worldObj.spawnEntityInWorld(item);
                    }
                }
            } else if (FluidContainerRegistry.isEmptyContainer(itemStack)) {
                ItemStack filledContainer = FluidContainerRegistry.fillFluidContainer(outputTank.getFluid(),
                        itemStack);
                if (filledContainer != null) {
                    FluidStack fluidStack = FluidContainerRegistry.getFluidForFilledItem(filledContainer);
                    if (fluidStack.getFluid() == outputTank.getFluid().getFluid()
                            && fluidStack.amount <= outputTank.getFluidAmount()) {
                        outputTank.drain(fluidStack.amount, true);
                        decrStackSize(slot, 1);

                        if (getStackInSlot(slot) == null) {
                            setInventorySlotContents(slot, filledContainer);
                        } else {
                            //TODO add fluid container output slot
                            EntityItem item = new EntityItem(worldObj);
                            item.setPosition(xCoord + 0.5, yCoord + 0.5, zCoord + 0.5);
                            item.setEntityItemStack(filledContainer);
                            worldObj.spawnEntityInWorld(item);
                        }
                    }
                }
            }
        }
    }

    /**
     * Outputs fluids to connected tiles
     *
     * @param outputTank - tank to drain
     */
    protected void outputFluidToTiles(IFluidTank outputTank, Function<ForgeDirection, Boolean> canUseSideFunction) {
        if (outputTank.getFluid() != null) {
            for (ForgeDirection direction : ForgeDirection.VALID_DIRECTIONS) {
                if (canUseSideFunction == null || canUseSideFunction.apply(direction)) {
                    int x = xCoord + direction.offsetX;
                    int y = yCoord + direction.offsetY;
                    int z = zCoord + direction.offsetZ;

                    if (worldObj.blockExists(x, y, z)) {
                        TileEntity tile = worldObj.getTileEntity(x, y, z);
                        if (tile instanceof IFluidHandler && outputTank.getFluid() != null && ((IFluidHandler) tile)
                                .canFill(direction.getOpposite(), outputTank.getFluid().getFluid())) {
                            int fill = ((IFluidHandler) tile).fill(direction.getOpposite(), outputTank.getFluid(),
                                    true);
                            outputTank.drain(fill, true);
                        }
                    }
                }
            }
        }
    }

    /**
     * Checks if the tank has fluids
     *
     * @param tank   - tank to check
     * @param fluid  - fluid to match
     * @param amount - fluid volume to match >=
     * @return true if enough fluid exists
     */
    public boolean hasInputFluid(IFluidTank tank, Fluid fluid, int amount) {
        FluidStack inputFluidStack = tank.getFluid();
        return inputFluidStack != null && inputFluidStack.getFluid() == fluid && inputFluidStack.amount >= amount;
    }

    /**
     * Checks if there is enough fluid to output
     *
     * @param tank   - tank to drain
     * @param fluid  - fluid to drain
     * @param amount - amount to drain
     * @return true if enough fluid
     */
    public boolean canOutputFluid(IFluidTank tank, Fluid fluid, int amount) {
        if (fluid != null && amount > 0) {
            if (tank.getFluid() != null) {
                //Space left in tank
                final int room = tank.getCapacity() - tank.getFluid().amount;
                return room >= amount && fluid == tank.getFluid().getFluid();
            } else {
                return tank.getCapacity() >= amount;
            }
        }
        return false;
    }

    public boolean tankMatch(IFluidTank tank, FluidStack fluidStack) {
        if (fluidStack != null) {
            return tank.getFluid() != null && tank.getFluid().getFluid() == fluidStack.getFluid();
        }
        return false;
    }

    public boolean tankMatch(IFluidTank tank, Fluid fluid) {
        return tank.getFluid() != null && tank.getFluid().getFluid() == fluid;
    }

    //-----------------------------------------------
    //--------Props ---------------------------------
    //-----------------------------------------------

    public ForgeDirection getFacingDirection() {
        if (_facingDirectionCache == null) {
            _facingDirectionCache = ForgeDirection.getOrientation(getBlockMetadata());
        }
        return _facingDirectionCache;
    }

    @Override
    public void markDirty() {
        if (isServer()) {
            _facingDirectionCache = null;
        }
    }

    @SideOnly(Side.CLIENT)
    public float rotate(float delta) {
        _processingAnimationRotationPrev = _processingAnimationRotation
                + (_processingAnimationRotation - _processingAnimationRotationPrev) * delta;
        return _processingAnimationRotationPrev;
    }

    //-----------------------------------------------
    //--------GUI Handler ---------------------------
    //-----------------------------------------------

    @Override
    protected void writeGuiPacket(List<Object> dataList, EntityPlayer player) {
        super.writeGuiPacket(dataList, player);
        dataList.add(processTimer);
    }

    @Override
    protected void readGuiPacket(ByteBuf buf, EntityPlayer player) {
        super.readGuiPacket(buf, player);
        processTimer = buf.readInt();
    }

    //-----------------------------------------------
    //--------Save/Load -----------------------------
    //-----------------------------------------------

    @Override
    public void writeToNBT(NBTTagCompound nbt) {
        super.writeToNBT(nbt);
        nbt.setInteger("processingProgress", processTimer);
    }

    @Override
    public void readFromNBT(NBTTagCompound nbt) {
        super.readFromNBT(nbt);
        processTimer = nbt.getInteger("processingProgress");
    }

    @Override
    protected void writeDescPacket(List<Object> dataList, EntityPlayer player) {
        super.writeGuiPacket(dataList, player);
        dataList.add(processTimer);
    }

    @Override
    protected void readDescPacket(ByteBuf buf, EntityPlayer player) {
        super.readGuiPacket(buf, player);
        processTimer = buf.readInt();
    }
}