/*
* This file is part of Project-Zed. Project-Zed is free software: you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version. Project-Zed is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should
* have received a copy of the GNU General Public License along with Project-Zed. If not, see <http://www.gnu
* .org/licenses/>
*/
package com.projectzed.mod.tileentity.machine;
import com.hockeyhurd.hcorelib.api.math.Rect;
import com.hockeyhurd.hcorelib.api.math.Vector2;
import com.hockeyhurd.hcorelib.api.math.Vector3;
import com.hockeyhurd.hcorelib.api.math.VectorHelper;
import com.hockeyhurd.hcorelib.api.util.BlockUtils;
import com.projectzed.api.item.IItemUpgradeComponent;
import com.projectzed.api.tileentity.machine.AbstractTileEntityMachine;
import com.projectzed.api.util.Sound;
import com.projectzed.mod.ProjectZed;
import com.projectzed.mod.item.upgrades.ItemRadialUpgrade;
import net.minecraft.block.Block;
import net.minecraft.block.BlockCrops;
import net.minecraft.block.BlockLeaves;
import net.minecraft.block.BlockLog;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import java.util.ArrayList;
import java.util.List;
/**
* TileEntity class for industrialHarvester.
*
* @author hockeyhurd
* @version 9/10/2015.
*/
public class TileEntityIndustrialHarvester extends AbstractTileEntityMachine {
private Vector3<Integer> currentCheckingVec;
private Rect<Integer> boundedRect;
private int currentSize = 1;
public static final int DEFAULT_RECT_SIZE = 3;
public static final int DEFAULT_NORMALIZED_RECT_SIZE = 1;
public TileEntityIndustrialHarvester() {
super("industrialHarvester");
}
public Rect<Integer> getBoundedRect() {
return boundedRect;
}
public void setBoundedRect(Rect<Integer> boundedRect) {
this.boundedRect = boundedRect;
}
@Override
public int getSizeInventory() {
return slots.length;
}
@Override
public int getInventoryStackLimit() {
return 0x40;
}
@Override
protected void initContentsArray() {
}
@Override
protected void initSlotsArray() {
this.slots = new ItemStack[2 * 9 + getSizeUpgradeSlots()];
}
@Override
public boolean isItemValidForSlot(int slot, ItemStack stack) {
if (stack == null || stack.stackSize == 0) return false;
if (stack.getItem() instanceof IItemUpgradeComponent && slot < getSizeInventory() &&
slot >= getSizeInventory() - getSizeUpgradeSlots() - 1) {
// System.out.println("Testing!");
return canInsertItemUpgrade((IItemUpgradeComponent) stack.getItem(), stack);
}
return true;
}
@Override
protected boolean canSmelt() {
return false;
}
@Override
public void smeltItem() {
}
/**
* Method used to increment current coordinate checker.
*/
private void incrementVector() {
if (currentCheckingVec.x < boundedRect.max.x) currentCheckingVec.x++;
else {
currentCheckingVec.x = boundedRect.min.x;
if (currentCheckingVec.z < boundedRect.max.y) currentCheckingVec.z++;
else currentCheckingVec.z = boundedRect.min.y;
}
}
@Override
public Sound getSound() {
return null;
}
private void addStackToContainer(ItemStack stack) {
if (stack == null || stack.stackSize <= 0) return;
ItemStack currentStack;
int amountCanTransfer, amountToTransfer;
// first pass, check for merge.
for (int i = 0; i < getSizeInventory() - getSizeUpgradeSlots(); i++) {
currentStack = slots[i];
if (currentStack != null && currentStack.isItemEqual(stack)) {
amountCanTransfer = currentStack.getMaxStackSize() - currentStack.stackSize;
if (amountCanTransfer <= 0) continue;
amountToTransfer = Math.min(amountCanTransfer, stack.stackSize);
currentStack.stackSize += amountToTransfer;
stack.stackSize -= amountToTransfer;
}
if (stack.stackSize == 0) return;
}
for (int i = 0; i < getSizeInventory() - getSizeUpgradeSlots(); i++) {
if (slots[i] == null) {
slots[i] = stack;
break;
}
}
}
/**
* Method to create and return a 'chop list' of blocks/trees to chop.
*
* @param currentList current list container.
* @param currentCheckingVec current checking vector3i.
* @return list of blocks to chop.
*/
@SuppressWarnings("unchecked")
private List<Vector3<Integer>> createChopList(List<Vector3<Integer>> currentList, Vector3<Integer> currentCheckingVec) {
Vector3<Integer> copy = currentCheckingVec.copy();
Vector3<Integer> min = new Vector3<Integer>(copy.x - 5, copy.y.intValue(), copy.z - 5);
Vector3<Integer> max = new Vector3<Integer>(copy.x + 5, copy.y + 32, copy.z + 5);
Vector3<Integer> bufferVec = Vector3.zero.getVector3i();
Block currentBlock;
for (int y = min.y; y < max.y; y++) {
for (int x = min.x; x < max.x; x++) {
for (int z = min.z; z < max.z; z++) {
bufferVec.x = x;
bufferVec.y = y;
bufferVec.z = z;
currentBlock = BlockUtils.getBlock(worldObj, bufferVec).getBlock();
if (currentBlock == Blocks.AIR) continue;
if (currentBlock instanceof BlockLog || currentBlock instanceof BlockLeaves || currentBlock instanceof BlockCrops) {
currentList.add(bufferVec.copy());
}
}
}
}
return currentList;
}
/**
* Method to perform action of checking and chopping tress.
*/
private void chopTree() {
Vector3<Integer> currentVec = currentCheckingVec.copy();
int volume = getVolume();
List<Vector3<Integer>> chopList = new ArrayList<Vector3<Integer>>(volume);
createChopList(chopList, currentVec);
if (!chopList.isEmpty()) {
IBlockState block;
List<ItemStack> dropsList;
for (Vector3<Integer> vec : chopList) {
/*if (vec != null) {
ProjectZed.logHelper.info(vec, BlockUtils.getBlock(worldObj, vec).getLocalizedName());
continue;
}*/
block = BlockUtils.getBlock(worldObj, vec);
dropsList = block.getBlock().getDrops(worldObj, VectorHelper.toBlockPos(vec), block, 0);
if (dropsList != null && !dropsList.isEmpty()) {
for (ItemStack stack : dropsList) {
if (stack != null && stack.stackSize > 0) {
addStackToContainer(stack);
// BlockUtils.destroyBlock(worldObj, vec);
}
}
}
BlockUtils.destroyBlock(worldObj, vec, false);
}
}
else ProjectZed.logHelper.warn("Empty chop list, is empty!!");
}
/**
* Calculates volume of cubic area.
*
* @return volume.
*/
private int getVolume() {
return Math.abs(Math.abs(boundedRect.max.x) + 5 - Math.abs(boundedRect.min.x) - 5) * (Math.abs(boundedRect.max.y) + 5 - Math.abs(boundedRect.min.y) - 5) * (32);
}
@Override
protected void calculateDataFromUpgrades() {
super.calculateDataFromUpgrades();
// checks once per second or every 20th tick for updating upgrade info.
if (!worldObj.isRemote && worldObj.getTotalWorldTime() % 20L == 0 && getSizeUpgradeSlots() > 0) {
final ItemStack[] upgrades = getCurrentUpgrades();
final int lastSize = currentSize;
int max = Integer.MIN_VALUE;
for (ItemStack upgradeComp : upgrades) {
if (upgradeComp != null && upgradeComp.getItem() instanceof ItemRadialUpgrade) {
max = Math.max(max, upgradeComp.getMetadata() + 1);
}
}
if (max > 0) max++;
currentSize = Math.max(max, 1);
// We need to update the bounded box:
if (lastSize != currentSize) {
final int dif = currentSize - lastSize;
// Expand boundedRect:
boundedRect.min.x -= dif;
boundedRect.min.y -= dif;
boundedRect.max.x += dif;
boundedRect.max.y += dif;
// Translate boundedRect such that the boundedRect is in-front of the harvester:
switch (getCurrentFacing()) {
case NORTH:
// boundedRect.translate(new Vector2<Integer>(0, -dif));
boundedRect.min.y += dif;
boundedRect.max.y += dif;
break;
case SOUTH:
// boundedRect.translate(new Vector2<Integer>(0, dif));
boundedRect.min.y -= dif;
boundedRect.max.y -= dif;
break;
case EAST:
// boundedRect.translate(new Vector2<Integer>(dif, 0));
boundedRect.min.x -= dif;
boundedRect.max.x -= dif;
break;
case WEST:
// boundedRect.translate(new Vector2<Integer>(-dif, 0));
boundedRect.min.x += dif;
boundedRect.max.x += dif;
break;
default:
ProjectZed.logHelper.severe("Unknown error has occurred on boundedRect translation! Current facing:", getCurrentFacing());
}
}
}
}
@Override
public void update() {
super.update();
if (!worldObj.isRemote && boundedRect != null && worldObj.getTotalWorldTime() % 20L == 0) {
if (currentCheckingVec == null)
currentCheckingVec = new Vector3<Integer>(boundedRect.min.x.intValue(), pos.getY(), boundedRect.min.y.intValue());
// ProjectZed.logHelper.info("boundedRect", boundedRect, "currentCheckingVec", currentCheckingVec, getCurrentFacing());
final Block currentBlock = BlockUtils.getBlock(worldObj, currentCheckingVec).getBlock();
final int currentMeta = BlockUtils.getBlockMetadata(worldObj, currentCheckingVec);
if (currentBlock instanceof BlockLog || (currentBlock instanceof BlockCrops && currentMeta >= 7)) {
// chopTree((BlockLog) currentBlock);
chopTree();
return;
}
incrementVector();
}
}
@Override
public void readNBT(NBTTagCompound comp) {
super.readNBT(comp);
if (currentCheckingVec == null) currentCheckingVec = Vector3.zero.getVector3i();
if (comp.getBoolean("HasBoundedRect")) {
int qX0 = comp.getInteger("BoundedMinX");
int qY0 = comp.getInteger("BoundedMinY");
int qX1 = comp.getInteger("BoundedMaxX");
int qY1= comp.getInteger("BoundedMaxY");
boundedRect = new Rect<Integer>(new Vector2<Integer>(qX0, qY0), new Vector2<Integer>(qX1, qY1));
currentCheckingVec.x = comp.getInteger("CurrentCheckingVecX");
currentCheckingVec.y = comp.getInteger("CurrentCheckingVecY");
currentCheckingVec.z = comp.getInteger("CurrentCheckingVecZ");
}
}
@Override
public void saveNBT(NBTTagCompound comp) {
super.saveNBT(comp);
comp.setBoolean("HasBoundedRect", boundedRect != null);
if (boundedRect != null) {
comp.setInteger("BoundedMinX", boundedRect.min.x);
comp.setInteger("BoundedMinY", boundedRect.min.y);
comp.setInteger("BoundedMaxX", boundedRect.max.x);
comp.setInteger("BoundedMaxY", boundedRect.max.y);
if (currentCheckingVec == null)
currentCheckingVec = new Vector3<Integer>(boundedRect.min.x.intValue(), pos.getY(), boundedRect.min.y.intValue());
comp.setInteger("CurrentCheckingVecX", currentCheckingVec.x);
comp.setInteger("CurrentCheckingVecY", currentCheckingVec.y);
comp.setInteger("CurrentCheckingVecZ", currentCheckingVec.z);
}
}
}