de.sanandrew.mods.turretmod.tileentity.assembly.TileEntityTurretAssembly.java Source code

Java tutorial

Introduction

Here is the source code for de.sanandrew.mods.turretmod.tileentity.assembly.TileEntityTurretAssembly.java

Source

/*
 * ****************************************************************************************************************
 * Authors:   SanAndreasP
 * Copyright: SanAndreasP
 * License:   Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
 * http://creativecommons.org/licenses/by-nc-sa/4.0/
 * *****************************************************************************************************************
 */
package de.sanandrew.mods.turretmod.tileentity.assembly;

import de.sanandrew.mods.sanlib.lib.Tuple;
import de.sanandrew.mods.sanlib.lib.util.ItemStackUtils;
import de.sanandrew.mods.sanlib.lib.util.MiscUtils;
import de.sanandrew.mods.turretmod.api.TmrConstants;
import de.sanandrew.mods.turretmod.network.PacketSyncTileEntity;
import de.sanandrew.mods.turretmod.network.TileClientSync;
import de.sanandrew.mods.turretmod.registry.assembly.TurretAssemblyRegistry;
import de.sanandrew.mods.turretmod.util.EnumParticle;
import de.sanandrew.mods.turretmod.util.TurretModRebirth;
import io.netty.buffer.ByteBuf;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
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.NonNullList;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.energy.CapabilityEnergy;
import net.minecraftforge.fml.common.network.ByteBufUtils;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.wrapper.SidedInvWrapper;

import java.util.UUID;

public class TileEntityTurretAssembly extends TileEntity implements TileClientSync, ITickable {
    public static final int MAX_FLUX_STORAGE = 75_000;
    public static final int MAX_FLUX_INSERT = 500;

    public float robotArmX;
    public float robotArmY;
    public float prevRobotArmX;
    public float prevRobotArmY;
    public float robotMotionX;
    public float robotMotionY;
    public float robotEndX;
    public float robotEndY;
    public Tuple spawnParticle;

    private boolean prevActive;
    boolean automate;
    public boolean isActive;
    private boolean isActiveClient;

    public Tuple currCrafting;
    int ticksCrafted;
    int maxTicksCrafted;
    int fluxConsumption;

    boolean doSync = false;

    private long ticksExisted;
    private String customName;

    final AssemblyEnergyStorage energyStorage;
    final AssemblyInventoryHandler invHandler;
    final IItemHandler itemHandlerBottom;
    final IItemHandler itemHandlerSide;

    public TileEntityTurretAssembly() {
        this.robotArmX = 2.0F;
        this.robotArmY = -9.0F;
        this.robotMotionX = 0.0F;
        this.robotMotionY = 0.0F;
        this.fluxConsumption = 0;
        this.ticksCrafted = 0;
        this.maxTicksCrafted = 0;
        this.ticksExisted = 0L;

        this.energyStorage = new AssemblyEnergyStorage();
        this.invHandler = new AssemblyInventoryHandler(this);
        this.itemHandlerBottom = new SidedInvWrapper(this.invHandler, EnumFacing.DOWN);
        this.itemHandlerSide = new SidedInvWrapper(this.invHandler, EnumFacing.WEST);
    }

    public void beginCrafting(UUID recipe, int count) {
        if (this.currCrafting != null && recipe.equals(this.currCrafting.getValue(0)) && !this.automate) {
            ItemStack result = TurretAssemblyRegistry.INSTANCE.getRecipeResult(recipe);
            ItemStack currCrfStack = this.currCrafting.getValue(1);
            if (currCrfStack.getCount() + count < 1) {
                this.cancelCrafting();
            } else if (ItemStackUtils.isValid(result)
                    && currCrfStack.getCount() + count * result.getCount() <= currCrfStack.getMaxStackSize()) {
                currCrfStack.grow(count);
                this.doSync = true;
            } else {
                currCrfStack.setCount(currCrfStack.getMaxStackSize());
                this.doSync = true;
            }
        } else if (this.currCrafting == null) {
            ItemStack stackRes = TurretAssemblyRegistry.INSTANCE.getRecipeResult(recipe);
            TurretAssemblyRegistry.RecipeEntry entry = TurretAssemblyRegistry.INSTANCE.getRecipeEntry(recipe);
            if (entry != null && ItemStackUtils.isValid(stackRes)) {
                stackRes = stackRes.copy();
                stackRes.setCount(this.automate ? 1 : count);
                this.currCrafting = new Tuple(recipe, stackRes);
                this.maxTicksCrafted = entry.ticksProcessing;
                this.doSync = true;
            }
        }
    }

    public void cancelCrafting() {
        this.currCrafting = null;
        this.ticksCrafted = 0;
        this.fluxConsumption = 0;
        this.maxTicksCrafted = 0;
        this.isActive = false;
        this.isActiveClient = false;
        this.doSync = true;
        this.markDirty();
    }

    private void initCrafting() {
        if (this.currCrafting != null && this.invHandler.canFillOutput()) {
            UUID currCrfUUID = this.currCrafting.getValue(0);
            ItemStack addStacks = this.currCrafting.<ItemStack>getValue(1).copy();
            ItemStack recipe = TurretAssemblyRegistry.INSTANCE.getRecipeResult(currCrfUUID);
            if (ItemStackUtils.isValid(recipe)) {
                addStacks.setCount(recipe.getCount());
                if (this.invHandler.canFillOutput(addStacks)
                        && TurretAssemblyRegistry.INSTANCE.checkAndConsumeResources(this.invHandler, currCrfUUID)) {
                    TurretAssemblyRegistry.RecipeEntry currentlyCrafted = TurretAssemblyRegistry.INSTANCE
                            .getRecipeEntry(currCrfUUID);
                    if (currentlyCrafted != null) {
                        this.maxTicksCrafted = currentlyCrafted.ticksProcessing;
                        this.fluxConsumption = MathHelper
                                .ceil(currentlyCrafted.fluxPerTick * (this.hasSpeedUpgrade() ? 1.1F : 1.0F));
                        this.ticksCrafted = 0;
                        this.isActive = true;
                        this.doSync = true;
                    }
                }
            } else {
                this.cancelCrafting();
            }
        }
    }

    public boolean hasAutoUpgrade() {
        return this.invHandler.hasAutoUpgrade();
    }

    public boolean hasSpeedUpgrade() {
        return this.invHandler.hasSpeedUpgrade();
    }

    public boolean hasFilterUpgrade() {
        return this.invHandler.hasFilterUpgrade();
    }

    public NonNullList<ItemStack> getFilterStacks() {
        return this.invHandler.getFilterStacks();
    }

    @Override
    public void update() {
        if (!this.world.isRemote) {
            if (this.automate && !this.hasAutoUpgrade()) {
                this.automate = false;
                this.cancelCrafting();
            }

            if (this.energyStorage.hasFluxChanged()) {
                this.doSync = true;
            }
            this.energyStorage.updatePrevFlux();

            int maxLoop = this.hasSpeedUpgrade() ? 4 : 1;
            boolean markDirty = false;

            this.isActiveClient = this.isActive;
            if (this.isActive && this.currCrafting != null) {
                for (int i = 0; i < maxLoop; i++) {
                    if (this.energyStorage.fluxAmount >= this.fluxConsumption
                            && this.world.isBlockIndirectlyGettingPowered(this.pos) == 0) {
                        this.energyStorage.fluxAmount -= this.fluxConsumption;
                        if (++this.ticksCrafted >= this.maxTicksCrafted) {
                            ItemStack stack = TurretAssemblyRegistry.INSTANCE
                                    .getRecipeResult(this.currCrafting.getValue(0));
                            if (!ItemStackUtils.isValid(stack)) {
                                this.cancelCrafting();
                                return;
                            }

                            this.invHandler.fillOutput(stack);

                            if (!this.invHandler.canFillOutput(stack)) {
                                this.isActive = false;
                                this.isActiveClient = false;
                            }

                            if (this.currCrafting.<ItemStack>getValue(1).getCount() > 1 || this.automate) {
                                if (!this.automate) {
                                    this.currCrafting.<ItemStack>getValue(1).shrink(1);
                                }

                                if (!TurretAssemblyRegistry.INSTANCE.checkAndConsumeResources(this.invHandler,
                                        this.currCrafting.getValue(0))) {
                                    this.isActive = false;
                                    this.isActiveClient = false;
                                }
                            } else if (!this.automate) {
                                this.cancelCrafting();
                                return;
                            }
                            this.ticksCrafted = 0;

                            markDirty = true;
                        }

                        this.doSync = true;
                    } else {
                        this.isActiveClient = false;
                        this.doSync = true;
                    }

                    if (!this.isActive || this.currCrafting == null) {
                        break;
                    }
                }
            } else {
                this.initCrafting();
                this.isActiveClient = false;
            }

            if (markDirty) {
                this.markDirty();
            }

            if (this.doSync) {
                PacketSyncTileEntity.sync(this);
                this.doSync = false;
            }
        } else {
            this.processRobotArm();
        }

        this.prevActive = this.isActive;
        this.ticksExisted++;
    }

    private void processRobotArm() {
        this.prevRobotArmX = this.robotArmX;
        this.prevRobotArmY = this.robotArmY;

        this.robotArmX += this.robotMotionX;
        this.robotArmY += this.robotMotionY;

        if (this.robotArmX > this.robotEndX && this.robotMotionX > 0.0F) {
            this.robotArmX = this.robotEndX;
            this.robotMotionX = 0.0F;
        } else if (this.robotArmX < this.robotEndX && this.robotMotionX < 0.0F) {
            this.robotArmX = this.robotEndX;
            this.robotMotionX = 0.0F;
        }

        if (this.robotArmY > this.robotEndY && this.robotMotionY > 0.0F) {
            this.robotArmY = this.robotEndY;
            this.robotMotionY = 0.0F;
        } else if (this.robotArmY < this.robotEndY && this.robotMotionY < 0.0F) {
            this.robotArmY = this.robotEndY;
            this.robotMotionY = 0.0F;
        }

        if (this.isActiveClient && (!this.prevActive || this.ticksExisted % 20 == 0)) {
            this.animateRobotArmRng();
        } else if (this.prevActive && !this.isActiveClient) {
            this.animateRobotArmReset();
            this.spawnParticle = null;
        }

        if (this.isActiveClient && this.spawnParticle != null) {
            TurretModRebirth.proxy.spawnParticle(EnumParticle.ASSEMBLY_SPARK, spawnParticle.getValue(0),
                    spawnParticle.<Double>getValue(1) + 0.05D, spawnParticle.getValue(2), null);
            this.spawnParticle = null;
        }
    }

    private void animateRobotArmRng() {
        float endX = 4.0F + MiscUtils.RNG.randomFloat() * 6.0F;
        float endY = -3.5F + MiscUtils.RNG.randomFloat() * -6.0F;

        this.robotMotionX = (0.1F + MiscUtils.RNG.randomFloat() * 0.1F) * (endX > this.robotArmX ? 1.0F : -1.0F);
        this.robotMotionY = (0.1F + MiscUtils.RNG.randomFloat() * 0.1F) * (endY > this.robotArmY ? 1.0F : -1.0F);
        this.robotEndX = endX;
        this.robotEndY = endY;
    }

    private void animateRobotArmReset() {
        float endX = 2.0F;
        float endY = -9.0F;

        this.robotMotionX = (0.1F + MiscUtils.RNG.randomFloat() * 0.1F) * (endX > this.robotArmX ? 1.0F : -1.0F);
        this.robotMotionY = (0.1F + MiscUtils.RNG.randomFloat() * 0.1F) * (endY > this.robotArmY ? 1.0F : -1.0F);
        this.robotEndX = endX;
        this.robotEndY = endY;
    }

    public IInventory getInventory() {
        return this.invHandler;
    }

    @Override
    @SideOnly(Side.CLIENT)
    public void onDataPacket(NetworkManager net, SPacketUpdateTileEntity pkt) {
        this.readNBT(pkt.getNbtCompound());
    }

    @Override
    public NBTTagCompound getUpdateTag() {
        return this.writeNBT(super.getUpdateTag());
    }

    @Override
    public void handleUpdateTag(NBTTagCompound tag) {
        super.handleUpdateTag(tag);
        this.readFromNBT(tag);
    }

    @Override
    public SPacketUpdateTileEntity getUpdatePacket() {
        return new SPacketUpdateTileEntity(this.pos, 0, this.writeNBT(new NBTTagCompound()));
    }

    @Override
    public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
        super.writeToNBT(nbt);

        this.writeNBT(nbt);

        return nbt;
    }

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

        this.readNBT(nbt);

        this.doSync = true;
    }

    private NBTTagCompound writeNBT(NBTTagCompound nbt) {
        nbt.setTag("inventory", this.invHandler.serializeNBT());

        if (this.currCrafting != null) {
            nbt.setString("craftingUUID", this.currCrafting.getValue(0).toString());
            ItemStackUtils.writeStackToTag(this.currCrafting.getValue(1), nbt, "craftingStack");
        }

        nbt.setTag("cap_energy", this.energyStorage.serializeNBT());

        nbt.setBoolean("isActive", this.isActive);
        nbt.setInteger("ticksCrafted", this.ticksCrafted);
        nbt.setInteger("maxTicksCrafted", this.maxTicksCrafted);
        nbt.setInteger("fluxConsumption", this.fluxConsumption);
        nbt.setBoolean("automate", this.automate);

        if (this.hasCustomName()) {
            nbt.setString("customName", this.customName);
        }

        return nbt;
    }

    private void readNBT(NBTTagCompound nbt) {
        this.invHandler.deserializeNBT(nbt.getCompoundTag("inventory"));

        if (nbt.hasKey("craftingUUID") && nbt.hasKey("craftingStack")) {
            this.currCrafting = new Tuple(UUID.fromString(nbt.getString("craftingUUID")),
                    new ItemStack(nbt.getCompoundTag("craftingStack")));
        }

        this.energyStorage.deserializeNBT(nbt.getCompoundTag("cap_energy"));

        this.isActive = nbt.getBoolean("isActive");
        this.ticksCrafted = nbt.getInteger("ticksCrafted");
        this.maxTicksCrafted = nbt.getInteger("maxTicksCrafted");
        this.fluxConsumption = nbt.getInteger("fluxConsumption");
        this.automate = nbt.getBoolean("automate");

        if (nbt.hasKey("customName")) {
            this.customName = nbt.getString("customName");
        }
    }

    public ITextComponent getDisplayName() {
        return this.hasCustomName() ? new TextComponentString(this.getCustomName())
                : new TextComponentTranslation(this.getCustomName());
    }

    public int getTicksCrafted() {
        return this.ticksCrafted;
    }

    public int getMaxTicksCrafted() {
        return this.maxTicksCrafted;
    }

    public int getFluxConsumption() {
        return this.fluxConsumption;
    }

    @Override
    public void toBytes(ByteBuf buf) {
        buf.writeInt(this.energyStorage.fluxAmount);
        buf.writeInt(this.fluxConsumption);
        buf.writeBoolean(this.isActive);
        buf.writeInt(this.ticksCrafted);
        buf.writeInt(this.maxTicksCrafted);
        buf.writeBoolean(this.automate);
        buf.writeBoolean(this.isActiveClient);
        if (this.currCrafting != null) {
            ByteBufUtils.writeItemStack(buf, this.currCrafting.getValue(1));
            ByteBufUtils.writeUTF8String(buf, this.currCrafting.getValue(0).toString());
        } else {
            ByteBufUtils.writeItemStack(buf, ItemStackUtils.getEmpty());
        }
    }

    @Override
    public void fromBytes(ByteBuf buf) {
        this.energyStorage.fluxAmount = buf.readInt();
        this.fluxConsumption = buf.readInt();
        this.isActive = buf.readBoolean();
        this.ticksCrafted = buf.readInt();
        this.maxTicksCrafted = buf.readInt();
        this.automate = buf.readBoolean();
        this.isActiveClient = buf.readBoolean();
        ItemStack crfStack = ByteBufUtils.readItemStack(buf);
        if (ItemStackUtils.isValid(crfStack)) {
            this.currCrafting = new Tuple(UUID.fromString(ByteBufUtils.readUTF8String(buf)), crfStack);
        } else {
            this.currCrafting = null;
        }
    }

    public void setAutomated(boolean b) {
        if (this.currCrafting == null) {
            this.automate = b;
            this.doSync = true;
        }
    }

    public boolean isAutomated() {
        return this.automate;
    }

    @Override
    public TileEntity getTile() {
        return this;
    }

    @Override
    @SuppressWarnings({ "unchecked", "ConstantConditions" })
    public <T> T getCapability(Capability<T> capability, EnumFacing facing) {
        if (capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) {
            if (facing == EnumFacing.DOWN) {
                return (T) itemHandlerBottom;
            } else if (facing != EnumFacing.UP) {
                return (T) itemHandlerSide;
            }
        } else if (facing != EnumFacing.UP && capability == CapabilityEnergy.ENERGY) {
            return (T) energyStorage;
        }

        return null;
    }

    @Override
    public boolean hasCapability(Capability<?> capability, EnumFacing facing) {
        if (facing != EnumFacing.UP) {
            return capability == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY
                    || capability == CapabilityEnergy.ENERGY || super.hasCapability(capability, facing);
        }

        return super.hasCapability(capability, facing);
    }

    public void setCustomName(String customName) {
        this.customName = customName;
    }

    public String getCustomName() {
        return this.hasCustomName() ? this.customName : TmrConstants.ID + ".container.assembly";
    }

    public boolean hasCustomName() {
        return this.customName != null;
    }
}