blob: 57c5d384907b13847ae0a75d2b7e938fb3bd99f0 [file] [log] [blame] [raw]
package mekanism.common.tile;
import io.netty.buffer.ByteBuf;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import mekanism.api.Chunk3D;
import mekanism.api.Coord4D;
import mekanism.api.MekanismConfig.usage;
import mekanism.api.Range4D;
import mekanism.api.util.CapabilityUtils;
import mekanism.common.HashList;
import mekanism.common.Mekanism;
import mekanism.common.Upgrade;
import mekanism.common.base.IActiveState;
import mekanism.common.base.IAdvancedBoundingBlock;
import mekanism.common.base.IRedstoneControl;
import mekanism.common.base.ISustainedData;
import mekanism.common.base.IUpgradeTile;
import mekanism.common.block.states.BlockStateMachine;
import mekanism.common.capabilities.Capabilities;
import mekanism.common.chunkloading.IChunkLoader;
import mekanism.common.content.miner.MItemStackFilter;
import mekanism.common.content.miner.MOreDictFilter;
import mekanism.common.content.miner.MinerFilter;
import mekanism.common.content.miner.ThreadMinerSearch;
import mekanism.common.content.miner.ThreadMinerSearch.State;
import mekanism.common.content.transporter.InvStack;
import mekanism.common.content.transporter.TransporterManager;
import mekanism.common.inventory.container.ContainerFilter;
import mekanism.common.inventory.container.ContainerNull;
import mekanism.common.network.PacketTileEntity.TileEntityMessage;
import mekanism.common.tile.component.TileComponentChunkLoader;
import mekanism.common.tile.component.TileComponentSecurity;
import mekanism.common.tile.component.TileComponentUpgrade;
import mekanism.common.util.ChargeUtils;
import mekanism.common.util.InventoryUtils;
import mekanism.common.util.ItemDataUtils;
import mekanism.common.util.MekanismUtils;
import mekanism.common.util.MinerUtils;
import mekanism.common.util.TransporterUtils;
import net.minecraft.block.Block;
import net.minecraft.block.BlockBush;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.ChunkPos;
import net.minecraft.world.WorldServer;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.Constants.NBT;
import net.minecraftforge.event.world.BlockEvent;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class TileEntityDigitalMiner extends TileEntityElectricBlock implements IUpgradeTile, IRedstoneControl, IActiveState, ISustainedData, IChunkLoader, IAdvancedBoundingBlock
{
public static int[] EJECT_INV;
public Map<Chunk3D, BitSet> oresToMine = new HashMap<Chunk3D, BitSet>();
public Map<Integer, MinerFilter> replaceMap = new HashMap<Integer, MinerFilter>();
public HashList<MinerFilter> filters = new HashList<MinerFilter>();
public ThreadMinerSearch searcher = new ThreadMinerSearch(this);
public final double BASE_ENERGY_USAGE = usage.digitalMinerUsage;
public double energyUsage = usage.digitalMinerUsage;
public int radius;
public boolean inverse;
public int minY = 0;
public int maxY = 60;
public boolean doEject = false;
public boolean doPull = false;
public ItemStack missingStack = null;
public int BASE_DELAY = 80;
public int delay;
public int delayLength = BASE_DELAY;
public int clientToMine;
public boolean isActive;
public boolean clientActive;
public boolean silkTouch;
public boolean running;
public double prevEnergy;
public int delayTicks;
public boolean initCalc = false;
public int numPowering;
public boolean clientRendering = false;
/** This machine's current RedstoneControl type. */
public RedstoneControl controlType = RedstoneControl.DISABLED;
public TileComponentUpgrade upgradeComponent = new TileComponentUpgrade(this, 28);
public TileComponentSecurity securityComponent = new TileComponentSecurity(this);
public TileComponentChunkLoader chunkLoaderComponent = new TileComponentChunkLoader(this);
public TileEntityDigitalMiner()
{
super("DigitalMiner", BlockStateMachine.MachineType.DIGITAL_MINER.baseEnergy);
inventory = NonNullList.withSize(29, ItemStack.EMPTY);
radius = 10;
upgradeComponent.setSupported(Upgrade.ANCHOR);
}
@Override
public void onUpdate()
{
super.onUpdate();
if(getActive())
{
for(EntityPlayer player : (HashSet<EntityPlayer>)playersUsing.clone())
{
if(player.openContainer instanceof ContainerNull || player.openContainer instanceof ContainerFilter)
{
player.closeScreen();
}
}
}
if(!world.isRemote)
{
if(!initCalc)
{
if(searcher.state == State.FINISHED)
{
boolean prevRunning = running;
reset();
start();
running = prevRunning;
}
initCalc = true;
}
ChargeUtils.discharge(27, this);
if(MekanismUtils.canFunction(this) && running && getEnergy() >= getPerTick() && searcher.state == State.FINISHED && oresToMine.size() > 0)
{
setActive(true);
if(delay > 0)
{
delay--;
}
setEnergy(getEnergy()-getPerTick());
if(delay == 0)
{
Set<Chunk3D> toRemove = new HashSet<Chunk3D>();
boolean did = false;
for(Chunk3D chunk : oresToMine.keySet())
{
BitSet set = oresToMine.get(chunk);
int next = 0;
while(true)
{
int index = set.nextSetBit(next);
Coord4D coord = getCoordFromIndex(index);
if(index == -1)
{
toRemove.add(chunk);
break;
}
if(!coord.exists(world))
{
set.clear(index);
if(set.cardinality() == 0)
{
toRemove.add(chunk);
}
next = index + 1;
continue;
}
IBlockState state = coord.getBlockState(world);
Block block = state.getBlock();
int meta = block.getMetaFromState(state);
if(block == null || coord.isAirBlock(world))
{
set.clear(index);
if(set.cardinality() == 0)
{
toRemove.add(chunk);
}
next = index + 1;
continue;
}
boolean hasFilter = false;
for(MinerFilter filter : filters)
{
if(filter.canFilter(new ItemStack(block, 1, meta)))
{
hasFilter = true;
break;
}
}
if(inverse == hasFilter)
{
set.clear(index);
if(set.cardinality() == 0)
{
toRemove.add(chunk);
break;
}
next = index + 1;
continue;
}
List<ItemStack> drops = MinerUtils.getDrops(world, coord, silkTouch);
if(canInsert(drops) && setReplace(coord, index))
{
did = true;
add(drops);
set.clear(index);
if(set.cardinality() == 0)
{
toRemove.add(chunk);
}
world.playEvent(null, 2001, coord.getPos(), Block.getStateId(state));
missingStack = null;
}
break;
}
if(did)
{
break;
}
}
for(Chunk3D chunk : toRemove)
{
oresToMine.remove(chunk);
}
delay = getDelay();
}
}
else {
if(prevEnergy >= getEnergy())
{
setActive(false);
}
}
if(doEject && delayTicks == 0 && getTopEject(false, null) != null && getEjectInv() != null && getEjectTile() != null)
{
if(getEjectInv() instanceof IInventory)
{
ItemStack remains = InventoryUtils.putStackInInventory((IInventory)getEjectInv(), getTopEject(false, null), facing.getOpposite(), false);
getTopEject(true, remains);
}
else if(CapabilityUtils.hasCapability(getEjectInv(), Capabilities.LOGISTICAL_TRANSPORTER_CAPABILITY, facing.getOpposite()))
{
ItemStack rejected = TransporterUtils.insert(getEjectTile(), CapabilityUtils.getCapability(getEjectInv(), Capabilities.LOGISTICAL_TRANSPORTER_CAPABILITY, facing.getOpposite()), getTopEject(false, null), null, true, 0);
if(TransporterManager.didEmit(getTopEject(false, null), rejected))
{
getTopEject(true, rejected);
}
}
delayTicks = 10;
}
else if(delayTicks > 0)
{
delayTicks--;
}
if(playersUsing.size() > 0)
{
for(EntityPlayer player : playersUsing)
{
Mekanism.packetHandler.sendTo(new TileEntityMessage(Coord4D.get(this), getSmallPacket(new ArrayList<Object>())), (EntityPlayerMP)player);
}
}
prevEnergy = getEnergy();
}
}
public double getPerTick()
{
double ret = energyUsage;
if(silkTouch)
{
ret *= 6F;
}
int baseRad = Math.max(radius-10, 0);
ret *= (1 + ((float)baseRad/22F));
int baseHeight = Math.max((maxY-minY)-60, 0);
ret *= (1 + ((float)baseHeight/195F));
return ret;
}
public int getDelay()
{
return delayLength;
}
/*
* returns false if unsuccessful
*/
public boolean setReplace(Coord4D obj, int index)
{
IBlockState state = obj.getBlockState(world);
Block block = state.getBlock();
EntityPlayer dummy = Mekanism.proxy.getDummyPlayer((WorldServer)world, obj.xCoord, obj.yCoord, obj.zCoord).get();
BlockEvent.BreakEvent event = new BlockEvent.BreakEvent(world, obj.getPos(), state, dummy);
MinecraftForge.EVENT_BUS.post(event);
if(!event.isCanceled())
{
ItemStack stack = getReplace(index);
if(stack != null)
{
world.setBlockState(obj.getPos(), Block.getBlockFromItem(stack.getItem()).getStateFromMeta(stack.getItemDamage()), 3);
IBlockState s = obj.getBlockState(world);
if(s.getBlock() instanceof BlockBush && !((BlockBush)s.getBlock()).canBlockStay(world, obj.getPos(), s))
{
s.getBlock().dropBlockAsItem(world, obj.getPos(), s, 1);
world.setBlockToAir(obj.getPos());
}
return true;
}
else {
MinerFilter filter = replaceMap.get(index);
if(filter == null || (filter.replaceStack == null || !filter.requireStack))
{
world.setBlockToAir(obj.getPos());
return true;
}
missingStack = filter.replaceStack;
return false;
}
}
return false;
}
public ItemStack getReplace(int index)
{
MinerFilter filter = replaceMap.get(index);
if(filter == null || filter.replaceStack == null)
{
return null;
}
for(int i = 0; i < 27; i++)
{
if(!inventory.get(i).isEmpty() && inventory.get(i).isItemEqual(filter.replaceStack))
{
inventory.get(i).shrink(1);
return MekanismUtils.size(filter.replaceStack, 1);
}
}
if(doPull && getPullInv() instanceof IInventory)
{
InvStack stack = InventoryUtils.takeDefinedItem((IInventory)getPullInv(), EnumFacing.UP, filter.replaceStack.copy(), 1, 1);
if(stack != null)
{
stack.use();
return MekanismUtils.size(filter.replaceStack, 1);
}
}
return null;
}
public NonNullList<ItemStack> copy(NonNullList<ItemStack> stacks)
{
NonNullList<ItemStack> toReturn = NonNullList.withSize(stacks.size(), ItemStack.EMPTY);
for(int i = 0; i < stacks.size(); i++)
{
toReturn.set(i, !stacks.get(i).isEmpty() ? stacks.get(i).copy() : ItemStack.EMPTY);
}
return toReturn;
}
public ItemStack getTopEject(boolean remove, ItemStack reject)
{
for(int i = 27-1; i >= 0; i--)
{
ItemStack stack = inventory.get(i);
if(!stack.isEmpty())
{
if(isReplaceStack(stack))
{
continue;
}
if(remove)
{
inventory.set(i, reject);
}
return stack;
}
}
return null;
}
public boolean canInsert(List<ItemStack> stacks)
{
if(stacks.isEmpty())
{
return true;
}
NonNullList<ItemStack> testInv = copy(inventory);
int added = 0;
stacks:
for(ItemStack stack : stacks)
{
if(stack == null || stack.getItem() == null)
{
continue;
}
for(int i = 0; i < 27; i++)
{
if(!testInv.get(i).isEmpty() && testInv.get(i).getItem() == null)
{
testInv.set(i, ItemStack.EMPTY);
}
if(testInv.get(i).isEmpty())
{
testInv.set(i, stack);
added++;
continue stacks;
}
else if(testInv.get(i).isItemEqual(stack) && testInv.get(i).getCount()+stack.getCount() <= stack.getMaxStackSize())
{
testInv.get(i).grow(stack.getCount());
added++;
continue stacks;
}
}
}
if(added == stacks.size())
{
return true;
}
return false;
}
public TileEntity getPullInv()
{
return Coord4D.get(this).translate(0, 2, 0).getTileEntity(world);
}
public TileEntity getEjectInv()
{
EnumFacing side = facing.getOpposite();
return world.getTileEntity(getPos().up().offset(side, 2));
}
public void add(List<ItemStack> stacks)
{
if(stacks.isEmpty())
{
return;
}
stacks:
for(ItemStack stack : stacks)
{
for(int i = 0; i < 27; i++)
{
if(inventory.get(i).isEmpty())
{
inventory.set(i, stack);
continue stacks;
}
else if(inventory.get(i).isItemEqual(stack) && inventory.get(i).getCount()+stack.getCount() <= stack.getMaxStackSize())
{
inventory.get(i).grow(stack.getCount());
continue stacks;
}
}
}
}
public void start()
{
if(searcher.state == State.IDLE)
{
searcher.start();
}
running = true;
MekanismUtils.saveChunk(this);
}
public void stop()
{
if(searcher.state == State.SEARCHING)
{
searcher.interrupt();
reset();
return;
}
else if(searcher.state == State.FINISHED)
{
running = false;
}
MekanismUtils.saveChunk(this);
}
public void reset()
{
searcher = new ThreadMinerSearch(this);
running = false;
oresToMine.clear();
replaceMap.clear();
missingStack = null;
MekanismUtils.saveChunk(this);
}
public boolean isReplaceStack(ItemStack stack)
{
for(MinerFilter filter : filters)
{
if(filter.replaceStack != null && filter.replaceStack.isItemEqual(stack))
{
return true;
}
}
return false;
}
public int getSize()
{
int size = 0;
for(Chunk3D chunk : oresToMine.keySet())
{
size += oresToMine.get(chunk).cardinality();
}
return size;
}
@Override
public void openInventory(EntityPlayer player)
{
super.openInventory(player);
if(!world.isRemote)
{
Mekanism.packetHandler.sendTo(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList())), (EntityPlayerMP)player);
}
}
@Override
public void readFromNBT(NBTTagCompound nbtTags)
{
super.readFromNBT(nbtTags);
radius = nbtTags.getInteger("radius");
minY = nbtTags.getInteger("minY");
maxY = nbtTags.getInteger("maxY");
doEject = nbtTags.getBoolean("doEject");
doPull = nbtTags.getBoolean("doPull");
isActive = nbtTags.getBoolean("isActive");
running = nbtTags.getBoolean("running");
delay = nbtTags.getInteger("delay");
silkTouch = nbtTags.getBoolean("silkTouch");
numPowering = nbtTags.getInteger("numPowering");
searcher.state = State.values()[nbtTags.getInteger("state")];
controlType = RedstoneControl.values()[nbtTags.getInteger("controlType")];
inverse = nbtTags.getBoolean("inverse");
if(nbtTags.hasKey("filters"))
{
NBTTagList tagList = nbtTags.getTagList("filters", NBT.TAG_COMPOUND);
for(int i = 0; i < tagList.tagCount(); i++)
{
filters.add(MinerFilter.readFromNBT(tagList.getCompoundTagAt(i)));
}
}
}
@Override
public NBTTagCompound writeToNBT(NBTTagCompound nbtTags)
{
super.writeToNBT(nbtTags);
if(searcher.state == State.SEARCHING)
{
reset();
}
nbtTags.setInteger("radius", radius);
nbtTags.setInteger("minY", minY);
nbtTags.setInteger("maxY", maxY);
nbtTags.setBoolean("doEject", doEject);
nbtTags.setBoolean("doPull", doPull);
nbtTags.setBoolean("isActive", isActive);
nbtTags.setBoolean("running", running);
nbtTags.setInteger("delay", delay);
nbtTags.setBoolean("silkTouch", silkTouch);
nbtTags.setInteger("numPowering", numPowering);
nbtTags.setInteger("state", searcher.state.ordinal());
nbtTags.setInteger("controlType", controlType.ordinal());
nbtTags.setBoolean("inverse", inverse);
NBTTagList filterTags = new NBTTagList();
for(MinerFilter filter : filters)
{
filterTags.appendTag(filter.write(new NBTTagCompound()));
}
if(filterTags.tagCount() != 0)
{
nbtTags.setTag("filters", filterTags);
}
return nbtTags;
}
@Override
public void handlePacketData(ByteBuf dataStream)
{
if(FMLCommonHandler.instance().getEffectiveSide().isServer())
{
int type = dataStream.readInt();
switch(type)
{
case 0:
doEject = !doEject;
break;
case 1:
doPull = !doPull;
break;
case 3:
start();
break;
case 4:
stop();
break;
case 5:
reset();
break;
case 6:
radius = dataStream.readInt();
break;
case 7:
minY = dataStream.readInt();
break;
case 8:
maxY = dataStream.readInt();
break;
case 9:
silkTouch = !silkTouch;
break;
case 10:
inverse = !inverse;
break;
case 11:
{
// Move filter up
int filterIndex = dataStream.readInt();
filters.swap(filterIndex, filterIndex - 1);
for(EntityPlayer player : playersUsing)
{
openInventory(player);
}
break;
}
case 12:
{
// Move filter down
int filterIndex = dataStream.readInt();
filters.swap(filterIndex, filterIndex + 1);
for(EntityPlayer player : playersUsing)
{
openInventory(player);
}
break;
}
}
MekanismUtils.saveChunk(this);
for(EntityPlayer player : playersUsing)
{
Mekanism.packetHandler.sendTo(new TileEntityMessage(Coord4D.get(this), getGenericPacket(new ArrayList<Object>())), (EntityPlayerMP)player);
}
return;
}
super.handlePacketData(dataStream);
if(FMLCommonHandler.instance().getEffectiveSide().isClient())
{
int type = dataStream.readInt();
if(type == 0)
{
radius = dataStream.readInt();
minY = dataStream.readInt();
maxY = dataStream.readInt();
doEject = dataStream.readBoolean();
doPull = dataStream.readBoolean();
clientActive = dataStream.readBoolean();
running = dataStream.readBoolean();
silkTouch = dataStream.readBoolean();
numPowering = dataStream.readInt();
searcher.state = State.values()[dataStream.readInt()];
clientToMine = dataStream.readInt();
controlType = RedstoneControl.values()[dataStream.readInt()];
inverse = dataStream.readBoolean();
if(dataStream.readBoolean())
{
missingStack = new ItemStack(Item.getItemById(dataStream.readInt()), 1, dataStream.readInt());
}
else {
missingStack = null;
}
filters.clear();
int amount = dataStream.readInt();
for(int i = 0; i < amount; i++)
{
filters.add(MinerFilter.readFromPacket(dataStream));
}
}
else if(type == 1)
{
radius = dataStream.readInt();
minY = dataStream.readInt();
maxY = dataStream.readInt();
doEject = dataStream.readBoolean();
doPull = dataStream.readBoolean();
clientActive = dataStream.readBoolean();
running = dataStream.readBoolean();
silkTouch = dataStream.readBoolean();
numPowering = dataStream.readInt();
searcher.state = State.values()[dataStream.readInt()];
clientToMine = dataStream.readInt();
controlType = RedstoneControl.values()[dataStream.readInt()];
inverse = dataStream.readBoolean();
if(dataStream.readBoolean())
{
missingStack = new ItemStack(Item.getItemById(dataStream.readInt()), 1, dataStream.readInt());
}
else {
missingStack = null;
}
}
else if(type == 2)
{
filters.clear();
int amount = dataStream.readInt();
for(int i = 0; i < amount; i++)
{
filters.add(MinerFilter.readFromPacket(dataStream));
}
}
else if(type == 3)
{
clientActive = dataStream.readBoolean();
running = dataStream.readBoolean();
clientToMine = dataStream.readInt();
if(dataStream.readBoolean())
{
missingStack = new ItemStack(Item.getItemById(dataStream.readInt()), 1, dataStream.readInt());
}
else {
missingStack = null;
}
}
if(clientActive != isActive)
{
isActive = clientActive;
MekanismUtils.updateBlock(world, getPos());
}
}
}
@Override
public ArrayList<Object> getNetworkedData(ArrayList<Object> data)
{
super.getNetworkedData(data);
data.add(0);
data.add(radius);
data.add(minY);
data.add(maxY);
data.add(doEject);
data.add(doPull);
data.add(isActive);
data.add(running);
data.add(silkTouch);
data.add(numPowering);
data.add(searcher.state.ordinal());
if(searcher.state == State.SEARCHING)
{
data.add(searcher.found);
}
else {
data.add(getSize());
}
data.add(controlType.ordinal());
data.add(inverse);
if(missingStack != null)
{
data.add(true);
data.add(MekanismUtils.getID(missingStack));
data.add(missingStack.getItemDamage());
}
else {
data.add(false);
}
data.add(filters.size());
for(MinerFilter filter : filters)
{
filter.write(data);
}
return data;
}
public ArrayList<Object> getSmallPacket(ArrayList<Object> data)
{
super.getNetworkedData(data);
data.add(3);
data.add(isActive);
data.add(running);
if(searcher.state == State.SEARCHING)
{
data.add(searcher.found);
}
else {
data.add(getSize());
}
if(missingStack != null)
{
data.add(true);
data.add(MekanismUtils.getID(missingStack));
data.add(missingStack.getItemDamage());
}
else {
data.add(false);
}
return data;
}
public ArrayList<Object> getGenericPacket(ArrayList<Object> data)
{
super.getNetworkedData(data);
data.add(1);
data.add(radius);
data.add(minY);
data.add(maxY);
data.add(doEject);
data.add(doPull);
data.add(isActive);
data.add(running);
data.add(silkTouch);
data.add(numPowering);
data.add(searcher.state.ordinal());
if(searcher.state == State.SEARCHING)
{
data.add(searcher.found);
}
else {
data.add(getSize());
}
data.add(controlType.ordinal());
data.add(inverse);
if(missingStack != null)
{
data.add(true);
data.add(MekanismUtils.getID(missingStack));
data.add(missingStack.getItemDamage());
}
else {
data.add(false);
}
return data;
}
public ArrayList getFilterPacket(ArrayList<Object> data)
{
super.getNetworkedData(data);
data.add(2);
data.add(filters.size());
for(MinerFilter filter : filters)
{
filter.write(data);
}
return data;
}
public int getTotalSize()
{
return getDiameter()*getDiameter()*(maxY-minY+1);
}
public int getDiameter()
{
return (radius*2)+1;
}
public Coord4D getStartingCoord()
{
return new Coord4D(getPos().getX()-radius, minY, getPos().getZ()-radius, world.provider.getDimension());
}
public Coord4D getCoordFromIndex(int index)
{
int diameter = getDiameter();
Coord4D start = getStartingCoord();
int x = start.xCoord+index%diameter;
int y = start.yCoord+(index/diameter/diameter);
int z = start.zCoord+(index/diameter)%diameter;
return new Coord4D(x, y, z, world.provider.getDimension());
}
@Override
public boolean isPowered()
{
return redstone || numPowering > 0;
}
@Override
public boolean canPulse()
{
return false;
}
@Override
public RedstoneControl getControlType()
{
return controlType;
}
@Override
public void setControlType(RedstoneControl type)
{
controlType = type;
MekanismUtils.saveChunk(this);
}
@Override
public TileComponentUpgrade getComponent()
{
return upgradeComponent;
}
@Override
public void setActive(boolean active)
{
isActive = active;
if(clientActive != active)
{
Mekanism.packetHandler.sendToReceivers(new TileEntityMessage(Coord4D.get(this), getNetworkedData(new ArrayList<Object>())), new Range4D(Coord4D.get(this)));
clientActive = active;
}
}
@Override
public boolean getActive()
{
return isActive;
}
@Override
public boolean renderUpdate()
{
return false;
}
@Override
public boolean lightUpdate()
{
return false;
}
@Override
@SideOnly(Side.CLIENT)
public AxisAlignedBB getRenderBoundingBox()
{
return INFINITE_EXTENT_AABB;
}
@Override
public void onPlace()
{
for(int x = -1; x <= +1; x++)
{
for(int y = 0; y <= +1; y++)
{
for(int z = -1; z <= +1; z++)
{
if(x == 0 && y == 0 && z == 0)
{
continue;
}
BlockPos pos1 = getPos().add(x, y, z);
MekanismUtils.makeAdvancedBoundingBlock(world, pos1, Coord4D.get(this));
world.notifyNeighborsOfStateChange(pos1, getBlockType(), true);
}
}
}
}
@Override
public boolean canSetFacing(int side)
{
return side != 0 && side != 1;
}
@Override
public void onBreak()
{
for(int x = -1; x <= +1; x++)
{
for(int y = 0; y <= +1; y++)
{
for(int z = -1; z <= +1; z++)
{
world.setBlockToAir(getPos().add(x, y, z));
}
}
}
}
@Override
public int[] getSlotsForFace(EnumFacing side)
{
return InventoryUtils.EMPTY;
}
public TileEntity getEjectTile()
{
EnumFacing side = facing.getOpposite();
return world.getTileEntity(getPos().up().offset(side));
}
@Override
public int[] getBoundSlots(Coord4D location, EnumFacing side)
{
EnumFacing dir = facing.getOpposite();
BlockPos pull = getPos().up();
BlockPos eject = pull.offset(dir);
if((location.equals(eject) && side == dir) || (location.equals(pull) && side == EnumFacing.UP))
{
if(EJECT_INV == null)
{
EJECT_INV = new int[27];
for(int i = 0; i < EJECT_INV.length; i++)
{
EJECT_INV[i] = i;
}
}
return EJECT_INV;
}
return InventoryUtils.EMPTY;
}
@Override
public boolean canBoundInsert(Coord4D location, int i, ItemStack itemstack)
{
EnumFacing side = facing.getOpposite();
BlockPos pull = getPos().up();
BlockPos eject = pull.offset(side);
if(location.equals(eject))
{
return false;
}
else if(location.equals(pull))
{
if(itemstack != null && isReplaceStack(itemstack))
{
return true;
}
}
return false;
}
@Override
public boolean canBoundExtract(Coord4D location, int i, ItemStack itemstack, EnumFacing dir)
{
EnumFacing side = facing.getOpposite();
BlockPos pull = getPos().up();
BlockPos eject = pull.offset(side);
if(location.equals(eject))
{
if(itemstack != null && isReplaceStack(itemstack))
{
return false;
}
return true;
}
else if(location.equals(pull))
{
return false;
}
return false;
}
@Override
public void onPower()
{
numPowering++;
}
@Override
public void onNoPower()
{
numPowering--;
}
public String[] methods = {"setRadius", "setMin", "setMax", "addFilter", "removeFilter", "addOreFilter", "removeOreFilter", "reset", "start", "stop"};
@Override
public String[] getMethods()
{
return methods;
}
@Override
public Object[] invoke(int method, Object[] arguments) throws Exception
{
if(arguments.length > 0)
{
int num = 0;
if(arguments[0] instanceof Double)
{
num = ((Double)arguments[0]).intValue();
}
else if(arguments[0] instanceof String && (method != 5 && method != 6))
{
num = Integer.parseInt((String)arguments[0]);
}
if(num != 0)
{
if(method == 0)
{
radius = num;
}
else if(method == 1)
{
minY = num;
}
else if(method == 2)
{
maxY = num;
}
else if(method == 3)
{
int meta = 0;
if(arguments.length > 1)
{
if(arguments[1] instanceof Double)
{
meta = ((Double)arguments[1]).intValue();
}
else if(arguments[1] instanceof String)
{
meta = Integer.parseInt((String)arguments[1]);
}
}
filters.add(new MItemStackFilter(new ItemStack(Item.getItemById(num), 1, meta)));
}
else if(method == 4)
{
Iterator<MinerFilter> iter = filters.iterator();
while(iter.hasNext())
{
MinerFilter filter = iter.next();
if(filter instanceof MItemStackFilter)
{
if(MekanismUtils.getID(((MItemStackFilter)filter).itemType) == num)
{
iter.remove();
}
}
}
}
else if(method == 5)
{
String ore = (String)arguments[0];
MOreDictFilter filter = new MOreDictFilter();
filter.oreDictName = ore;
filters.add(filter);
}
else if(method == 6)
{
String ore = (String)arguments[0];
Iterator<MinerFilter> iter = filters.iterator();
while(iter.hasNext())
{
MinerFilter filter = iter.next();
if(filter instanceof MOreDictFilter)
{
if(((MOreDictFilter)filter).oreDictName.equals(ore))
{
iter.remove();
}
}
}
}
else if(method == 7)
{
reset();
}
else if(method == 8)
{
start();
}
else if(method == 9)
{
stop();
}
}
}
for(EntityPlayer player : playersUsing)
{
Mekanism.packetHandler.sendTo(new TileEntityMessage(Coord4D.get(this), getGenericPacket(new ArrayList<Object>())), (EntityPlayerMP)player);
}
return null;
}
@Override
public NBTTagCompound getConfigurationData(NBTTagCompound nbtTags)
{
nbtTags.setInteger("radius", radius);
nbtTags.setInteger("minY", minY);
nbtTags.setInteger("maxY", maxY);
nbtTags.setBoolean("doEject", doEject);
nbtTags.setBoolean("doPull", doPull);
nbtTags.setBoolean("silkTouch", silkTouch);
nbtTags.setBoolean("inverse", inverse);
NBTTagList filterTags = new NBTTagList();
for(MinerFilter filter : filters)
{
filterTags.appendTag(filter.write(new NBTTagCompound()));
}
if(filterTags.tagCount() != 0)
{
nbtTags.setTag("filters", filterTags);
}
return nbtTags;
}
@Override
public void setConfigurationData(NBTTagCompound nbtTags)
{
radius = nbtTags.getInteger("radius");
minY = nbtTags.getInteger("minY");
maxY = nbtTags.getInteger("maxY");
doEject = nbtTags.getBoolean("doEject");
doPull = nbtTags.getBoolean("doPull");
silkTouch = nbtTags.getBoolean("silkTouch");
inverse = nbtTags.getBoolean("inverse");
if(nbtTags.hasKey("filters"))
{
NBTTagList tagList = nbtTags.getTagList("filters", NBT.TAG_COMPOUND);
for(int i = 0; i < tagList.tagCount(); i++)
{
filters.add(MinerFilter.readFromNBT(tagList.getCompoundTagAt(i)));
}
}
}
@Override
public String getDataType()
{
return getBlockType().getUnlocalizedName() + "." + fullName + ".name";
}
public void writeSustainedData(ItemStack itemStack)
{
ItemDataUtils.setBoolean(itemStack, "hasMinerConfig", true);
ItemDataUtils.setInt(itemStack, "radius", radius);
ItemDataUtils.setInt(itemStack, "minY", minY);
ItemDataUtils.setInt(itemStack, "maxY", maxY);
ItemDataUtils.setBoolean(itemStack, "doEject", doEject);
ItemDataUtils.setBoolean(itemStack, "doPull", doPull);
ItemDataUtils.setBoolean(itemStack, "silkTouch", silkTouch);
ItemDataUtils.setBoolean(itemStack, "inverse", inverse);
NBTTagList filterTags = new NBTTagList();
for(MinerFilter filter : filters)
{
filterTags.appendTag(filter.write(new NBTTagCompound()));
}
if(filterTags.tagCount() != 0)
{
ItemDataUtils.setList(itemStack, "filters", filterTags);
}
}
@Override
public void readSustainedData(ItemStack itemStack)
{
if(ItemDataUtils.hasData(itemStack, "hasMinerConfig"))
{
radius = ItemDataUtils.getInt(itemStack, "radius");
minY = ItemDataUtils.getInt(itemStack, "minY");
maxY = ItemDataUtils.getInt(itemStack, "maxY");
doEject = ItemDataUtils.getBoolean(itemStack, "doEject");
doPull = ItemDataUtils.getBoolean(itemStack, "doPull");
silkTouch = ItemDataUtils.getBoolean(itemStack, "silkTouch");
inverse = ItemDataUtils.getBoolean(itemStack, "inverse");
if(ItemDataUtils.hasData(itemStack, "filters"))
{
NBTTagList tagList = ItemDataUtils.getList(itemStack, "filters");
for(int i = 0; i < tagList.tagCount(); i++)
{
filters.add(MinerFilter.readFromNBT((NBTTagCompound)tagList.getCompoundTagAt(i)));
}
}
}
}
@Override
public void recalculateUpgradables(Upgrade upgrade)
{
super.recalculateUpgradables(upgrade);
switch(upgrade)
{
case SPEED:
delayLength = MekanismUtils.getTicks(this, BASE_DELAY);
case ENERGY:
energyUsage = MekanismUtils.getEnergyPerTick(this, BASE_ENERGY_USAGE);
maxEnergy = MekanismUtils.getMaxEnergy(this, BASE_MAX_ENERGY);
default:
break;
}
}
@Override
public boolean canBoundReceiveEnergy(Coord4D coord, EnumFacing side)
{
EnumFacing left = MekanismUtils.getLeft(facing);
EnumFacing right = MekanismUtils.getRight(facing);
if(coord.equals(Coord4D.get(this).offset(left)))
{
return side == left;
}
else if(coord.equals(Coord4D.get(this).offset(right)))
{
return side == right;
}
return false;
}
@Override
public EnumSet<EnumFacing> getConsumingSides()
{
return EnumSet.of(MekanismUtils.getLeft(facing), MekanismUtils.getRight(facing), EnumFacing.DOWN);
}
@Override
public TileComponentSecurity getSecurity()
{
return securityComponent;
}
@Override
public boolean hasCapability(Capability<?> capability, EnumFacing side)
{
return capability == Capabilities.CONFIG_CARD_CAPABILITY || capability == Capabilities.SPECIAL_CONFIG_DATA_CAPABILITY
|| super.hasCapability(capability, side);
}
@Override
public <T> T getCapability(Capability<T> capability, EnumFacing side)
{
if(capability == Capabilities.CONFIG_CARD_CAPABILITY || capability == Capabilities.SPECIAL_CONFIG_DATA_CAPABILITY)
{
return (T)this;
}
return super.getCapability(capability, side);
}
@Override
public TileComponentChunkLoader getChunkLoader()
{
return chunkLoaderComponent;
}
@Override
public Set<ChunkPos> getChunkSet()
{
return new Range4D(Coord4D.get(this)).expandFromCenter(radius).getIntersectingChunks().stream().map(t -> t.getPos()).collect(Collectors.toSet());
}
}