package micdoodle8.mods.galacticraft.planets.asteroids.entities;
import io.netty.buffer.ByteBuf;
import micdoodle8.mods.galacticraft.api.entity.IAntiGrav;
import micdoodle8.mods.galacticraft.api.entity.IEntityNoisy;
import micdoodle8.mods.galacticraft.api.entity.ITelemetry;
import micdoodle8.mods.galacticraft.api.vector.BlockTuple;
import micdoodle8.mods.galacticraft.api.vector.BlockVec3;
import micdoodle8.mods.galacticraft.core.GCBlocks;
import micdoodle8.mods.galacticraft.core.GCItems;
import micdoodle8.mods.galacticraft.core.GalacticraftCore;
import micdoodle8.mods.galacticraft.core.entities.player.GCPlayerStats;
import micdoodle8.mods.galacticraft.core.inventory.IInventoryDefaults;
import micdoodle8.mods.galacticraft.core.network.IPacketReceiver;
import micdoodle8.mods.galacticraft.core.network.PacketDynamic;
import micdoodle8.mods.galacticraft.core.util.*;
import micdoodle8.mods.galacticraft.planets.asteroids.blocks.AsteroidBlocks;
import micdoodle8.mods.galacticraft.planets.asteroids.client.sounds.SoundUpdaterMiner;
import micdoodle8.mods.galacticraft.planets.asteroids.dimension.WorldProviderAsteroids;
import micdoodle8.mods.galacticraft.planets.asteroids.items.AsteroidsItems;
import micdoodle8.mods.galacticraft.planets.asteroids.tick.AsteroidsTickHandlerServer;
import micdoodle8.mods.galacticraft.planets.asteroids.tile.TileEntityMinerBase;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFlower;
import net.minecraft.block.BlockLiquid;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.audio.ISound;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Blocks;
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.*;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeHooks;
import net.minecraftforge.common.IPlantable;
import net.minecraftforge.fluids.IFluidBlock;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
import org.lwjgl.opengl.GL11;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.UUID;
public class EntityAstroMiner extends Entity implements IInventoryDefaults, IPacketReceiver, IEntityNoisy, IAntiGrav, ITelemetry
{
public static final int MINE_LENGTH = 24;
public static final int MINE_LENGTH_AST = 12;
private static final int MAXENERGY = 12000;
private static final int RETURNENERGY = 1000;
private static final int RETURNDROPS = 10;
private static final int INV_SIZE = 227;
private static final float cLENGTH = 2.6F;
private static final float cWIDTH = 1.8F;
private static final float cHEIGHT = 1.7F;
private static final double SPEEDUP = 2.5D;
public static final int AISTATE_OFFLINE = -1;
public static final int AISTATE_STUCK = 0;
public static final int AISTATE_ATBASE = 1;
public static final int AISTATE_TRAVELLING = 2;
public static final int AISTATE_MINING = 3;
public static final int AISTATE_RETURNING = 4;
public static final int AISTATE_DOCKING = 5;
public static final int FAIL_BASEDESTROYED = 3;
public static final int FAIL_OUTOFENERGY = 4;
public static final int FAIL_RETURNPATHBLOCKED = 5;
public static final int FAIL_ANOTHERWASLINKED = 8;
private boolean TEMPDEBUG = false;
private boolean TEMPFAST = false;
public ItemStack[] cargoItems;
public int energyLevel;
public int mineCount = 0;
public float targetYaw;
public float targetPitch;
public int AIstate;
public int timeInCurrentState = 0;
public EntityPlayerMP playerMP = null;
private UUID playerUUID;
private BlockVec3 posTarget;
private BlockVec3 posBase;
private BlockVec3 waypointBase;
private LinkedList<BlockVec3> wayPoints = new LinkedList();
private LinkedList<BlockVec3> minePoints = new LinkedList();
private BlockVec3 minePointCurrent = null;
private EnumFacing baseFacing;
public EnumFacing facing;
private EnumFacing facingAI;
private EnumFacing lastFacing;
private static BlockVec3[] headings = {
new BlockVec3(0, -1, 0),
new BlockVec3(0, 1, 0),
new BlockVec3(0, 0, -1),
new BlockVec3(0, 0, 1),
new BlockVec3(-1, 0, 0),
new BlockVec3(1, 0, 0) };
private static BlockVec3[] headings2 = {
new BlockVec3(0, -3, 0),
new BlockVec3(0, 2, 0),
new BlockVec3(0, 0, -3),
new BlockVec3(0, 0, 2),
new BlockVec3(-3, 0, 0),
new BlockVec3(2, 0, 0) };
private final int baseSafeRadius = 32;
private final double speedbase = TEMPFAST ? 0.16D : 0.022D;
private double speed = speedbase;
private final float rotSpeedBase = TEMPFAST ? 8F : 1.5F;
private float rotSpeed = rotSpeedBase;
private double speedup = SPEEDUP;
private boolean noSpeedup = false; //This stops the miner getting stuck at turning points
public float shipDamage;
public int currentDamage;
public int timeSinceHit;
private boolean flagLink = false;
private boolean flagCheckPlayer = false;
private boolean toAddToServer = AsteroidsTickHandlerServer.loadingSavedChunks.get();
//To do:
// break the entity drops it as an item
private int turnProgress;
private double minecartX;
private double minecartY;
private double minecartZ;
private double minecartYaw;
private double minecartPitch;
@SideOnly(Side.CLIENT)
private double velocityX;
@SideOnly(Side.CLIENT)
private double velocityY;
@SideOnly(Side.CLIENT)
private double velocityZ;
private int tryBlockLimit;
private int inventoryDrops;
public boolean stopForTurn;
private static ArrayList<Block> noMineList = new ArrayList();
public static BlockTuple blockingBlock = new BlockTuple(Blocks.air, 0);
private int givenFailMessage = 0;
private BlockVec3 mineLast = null;
private int mineCountDown = 0;
private int pathBlockedCount = 0;
public LinkedList<BlockVec3> laserBlocks = new LinkedList();
public LinkedList<Integer> laserTimes = new LinkedList();
public float retraction = 1F;
protected ITickable soundUpdater;
private boolean soundToStop = false;
private boolean spawnedInCreative = false;
private int serverIndex;
static
{
//Avoid:
// Overworld: avoid lava source blocks, mossy cobble, End Portal and Fortress blocks
// railtrack, levers, redstone dust, GC walkways,
//Anything with a tileEntity will also be avoided:
// spawners, chests, oxygen pipes, hydrogen pipes, wires
noMineList.add(Blocks.bedrock);
noMineList.add(Blocks.lava);
noMineList.add(Blocks.mossy_cobblestone);
noMineList.add(Blocks.end_portal);
noMineList.add(Blocks.end_portal_frame);
noMineList.add(Blocks.portal);
noMineList.add(Blocks.stonebrick);
noMineList.add(Blocks.farmland);
noMineList.add(Blocks.rail);
noMineList.add(Blocks.lever);
noMineList.add(Blocks.redstone_wire);
noMineList.add(AsteroidBlocks.blockWalkway);
//TODO:
//Add configurable blacklist
}
public EntityAstroMiner(World world, ItemStack[] cargo, int energy)
{
this(world);
this.toAddToServer = true;
this.cargoItems = cargo.clone();
this.energyLevel = energy;
}
public EntityAstroMiner(World world)
{
super(world);
this.facing = EnumFacing.NORTH;
this.preventEntitySpawning = true;
this.ignoreFrustumCheck = true;
this.isImmuneToFire = true;
this.renderDistanceWeight = 5.0D;
this.width = cLENGTH;
this.height = cWIDTH;
this.setSize(cLENGTH, cWIDTH);
// this.myEntitySize = Entity.EnumEntitySize.SIZE_6;
// this.dataWatcher.addObject(this.currentDamage, new Integer(0));
// this.dataWatcher.addObject(this.timeSinceHit, new Integer(0));
this.noClip = true;
if (world != null && world.isRemote)
{
GalacticraftCore.packetPipeline.sendToServer(new PacketDynamic(this));
}
}
@Override
protected void entityInit()
{
this.dataWatcher.addObject(19, new Float(0.0F));
}
@Override
public int getSizeInventory()
{
return this.cargoItems.length;
}
@Override
public ItemStack getStackInSlot(int var1)
{
return this.cargoItems[var1];
}
@Override
public ItemStack decrStackSize(int var1, int var2)
{
if (this.cargoItems[var1] != null)
{
ItemStack var3;
if (this.cargoItems[var1].stackSize <= var2)
{
var3 = this.cargoItems[var1];
this.cargoItems[var1] = null;
return var3;
}
else
{
var3 = this.cargoItems[var1].splitStack(var2);
if (this.cargoItems[var1].stackSize == 0)
{
this.cargoItems[var1] = null;
}
return var3;
}
}
else
{
return null;
}
}
@Override
public ItemStack removeStackFromSlot(int var1)
{
if (this.cargoItems[var1] != null)
{
final ItemStack var2 = this.cargoItems[var1];
this.cargoItems[var1] = null;
return var2;
}
else
{
return null;
}
}
@Override
public void setInventorySlotContents(int var1, ItemStack var2)
{
this.cargoItems[var1] = var2;
if (var2 != null && var2.stackSize > this.getInventoryStackLimit())
{
var2.stackSize = this.getInventoryStackLimit();
}
}
@Override
public String getName()
{
return "AstroMiner";
}
@Override
public int getInventoryStackLimit()
{
return 64;
}
@Override
public boolean isUseableByPlayer(EntityPlayer var1)
{
return !this.isDead && var1.getDistanceSqToEntity(this) <= 64.0D;
}
@Override
public void markDirty()
{
}
@Override
public boolean isItemValidForSlot(int i, ItemStack itemstack)
{
return false;
}
@Override
public boolean hasCustomName()
{
return true;
}
private boolean emptyInventory(TileEntityMinerBase minerBase)
{
boolean doneOne = false;
for (int i = 0; i < this.cargoItems.length; i++)
{
ItemStack stack = this.cargoItems[i];
if (stack == null)
{
continue;
}
if (stack.stackSize == 0)
{
this.cargoItems[i] = null;
continue;
}
int sizeprev = stack.stackSize;
minerBase.addToInventory(stack);
if (stack == null || stack.stackSize == 0)
{
this.cargoItems[i] = null;
this.markDirty();
return true;
}
else if (stack.stackSize < sizeprev)
{
this.cargoItems[i] = stack;
this.markDirty();
//Something was transferred although some stacks remaining
return true;
}
}
//No stacks were transferred
return false;
}
@Override
public void onChunkLoad()
{
}
@Override
public void onUpdate()
{
if (this.posY < -64.0D)
{
this.kill();
return;
}
if (this.getDamage() > 0.0F)
{
this.setDamage(this.getDamage() - 1.0F);
}
stopForTurn = !this.checkRotation();
this.facing = this.getFacingFromRotation();
this.setBoundingBoxForFacing();
if (this.worldObj.isRemote)
{
//CLIENT CODE
if (this.turnProgress == 0)
{
this.turnProgress++;
if (this.AIstate < AISTATE_TRAVELLING)
{
//It should be stationary, so this deals with the spooky movement (due to minor differences between server and client position)
this.posX = this.minecartX;
this.posY = this.minecartY;
this.posZ = this.minecartZ;
}
else
{
double diffX = this.minecartX - this.posX;
double diffY = this.minecartY - this.posY;
double diffZ = this.minecartZ - this.posZ;
if (Math.abs(diffX) > 1.0D || Math.abs(diffY) > 1.0D || Math.abs(diffZ) > 1.0D)
{
this.posX = this.minecartX;
this.posY = this.minecartY;
this.posZ = this.minecartZ;
}
else
{
if (Math.abs(diffX) > Math.abs(this.motionX))
{
this.motionX += diffX / 10D;
}
if (Math.abs(diffY) > Math.abs(this.motionY))
{
this.motionY += diffY / 10D;
}
if (Math.abs(diffZ) > Math.abs(this.motionZ))
{
this.motionZ += diffZ / 10D;
}
}
}
}
this.posX += this.motionX;
this.posY += this.motionY;
this.posZ += this.motionZ;
setEntityBoundingBox(getEntityBoundingBox().offset(this.motionX, this.motionY, this.motionZ));
this.setRotation(this.rotationYaw, this.rotationPitch);
if (this.AIstate == AISTATE_MINING && this.ticksExisted % 2 == 0)
{
this.prepareMoveClient(TEMPFAST ? 8 : 1, 2);
}
//Sound updates on client
if (this.AIstate < AISTATE_ATBASE)
{
this.stopRocketSound();
}
return;
}
if (this.toAddToServer)
{
this.toAddToServer = false;
this.serverIndex = AsteroidsTickHandlerServer.monitorMiner(this);
}
//SERVER CODE
if (this.ticksExisted % 10 == 0 || this.flagLink)
{
this.flagLink = false;
this.checkPlayer();
if (posBase.blockExists(worldObj))
{
TileEntity tileEntity = posBase.getTileEntity(this.worldObj);
if (tileEntity instanceof TileEntityMinerBase && ((TileEntityMinerBase) tileEntity).isMaster && !tileEntity.isInvalid())
{
//Create link with base on loading the EntityAstroMiner
UUID linker = ((TileEntityMinerBase) tileEntity).getLinkedMiner();
if (!this.getUniqueID().equals(linker))
{
if (linker == null)
{
((TileEntityMinerBase) tileEntity).linkMiner(this);
}
else
{
this.freeze(FAIL_ANOTHERWASLINKED);
return;
}
}
else if (((TileEntityMinerBase) tileEntity).linkedMiner != this)
{
((TileEntityMinerBase) tileEntity).linkMiner(this);
}
}
else
{
if (this.playerMP != null && (this.givenFailMessage & (1 << FAIL_BASEDESTROYED)) == 0)
{
this.playerMP.addChatMessage(new ChatComponentText(GCCoreUtil.translate("gui.message.astro_miner" + FAIL_BASEDESTROYED + ".fail")));
this.givenFailMessage += (1 << FAIL_BASEDESTROYED);
//Continue mining even though base was destroyed - maybe it will be replaced
}
}
}
}
else if (this.flagCheckPlayer)
{
this.checkPlayer();
}
if (this.playerMP == null)
{
//Go into dormant state if player is offline
//but do not actually set the dormant state on the server, so can resume immediately if player comes online
if (this.motionX != 0 || this.motionY != 0 || this.motionZ != 0)
{
this.motionX = 0;
this.motionY = 0;
this.motionZ = 0;
GalacticraftCore.packetPipeline.sendToDimension(new PacketDynamic(this), GCCoreUtil.getDimensionID(this.worldObj));
}
return;
}
if (this.lastFacing != this.facingAI)
{
this.lastFacing = this.facingAI;
this.prepareMove(12, 0);
this.prepareMove(12, 1);
this.prepareMove(12, 2);
}
this.lastTickPosX = this.posX;
this.lastTickPosY = this.posY;
this.lastTickPosZ = this.posZ;
this.prevPosX = this.posX;
this.prevPosY = this.posY;
this.prevPosZ = this.posZ;
this.prevRotationPitch = this.rotationPitch;
this.prevRotationYaw = this.rotationYaw;
if (this.AIstate > AISTATE_ATBASE)
{
if (this.energyLevel <= 0)
{
this.freeze(FAIL_OUTOFENERGY);
}
else if (!(this.worldObj.provider instanceof WorldProviderAsteroids) && this.ticksExisted % 2 == 0)
{
this.energyLevel--;
}
//No energy consumption when moving in space in Asteroids dimension (this reduces the risk of the Astro Miner becoming stranded!)
}
switch (this.AIstate)
{
case AISTATE_STUCK:
//TODO blinking distress light or something?
//Attempt to re-start every 30 seconds or so
if (this.ticksExisted % 600 == 0)
{
if ((this.givenFailMessage & 8) > 0)
{
//The base was destroyed - see if it has been replaced?
this.atBase();
}
else
{
//See if the return path has been unblocked, and give a small amount of backup energy to try to get home
this.AIstate = AISTATE_RETURNING;
if (this.energyLevel <= 0)
{
this.energyLevel = 20;
}
}
}
break;
case AISTATE_ATBASE:
this.atBase();
break;
case AISTATE_TRAVELLING:
if (!this.moveToTarget())
{
this.prepareMove(TEMPFAST ? 8 : 2, 2);
}
break;
case AISTATE_MINING:
if (!this.doMining() && this.ticksExisted % 2 == 0)
{
this.energyLevel--;
this.prepareMove(TEMPFAST ? 8 : 1, 2);
}
break;
case AISTATE_RETURNING:
this.moveToBase();
this.prepareMove(TEMPFAST ? 8 : 4, 1);
break;
case AISTATE_DOCKING:
if (this.waypointBase != null)
{
this.speed = speedbase / 1.6;
this.rotSpeed = rotSpeedBase / 1.6F;
if (this.moveToPos(this.waypointBase, true))
{
this.AIstate = AISTATE_ATBASE;
this.motionX = 0;
this.motionY = 0;
this.motionZ = 0;
this.speed = speedbase;
this.rotSpeed = rotSpeedBase;
}
}
else
{
GCLog.severe("AstroMiner missing base position: this is a bug.");
this.AIstate = AISTATE_STUCK;
}
break;
}
GalacticraftCore.packetPipeline.sendToDimension(new PacketDynamic(this), GCCoreUtil.getDimensionID(this.worldObj));
this.posX += this.motionX;
this.posY += this.motionY;
this.posZ += this.motionZ;
setEntityBoundingBox(getEntityBoundingBox().offset(this.motionX, this.motionY, this.motionZ));
/* if (this.dataWatcher.getWatchableObjectInt(this.timeSinceHit) > 0)
{
this.dataWatcher.updateObject(this.timeSinceHit, Integer.valueOf(this.dataWatcher.getWatchableObjectInt(this.timeSinceHit) - 1));
}
if (this.dataWatcher.getWatchableObjectInt(this.currentDamage) > 0)
{
this.dataWatcher.updateObject(this.currentDamage, Integer.valueOf(this.dataWatcher.getWatchableObjectInt(this.currentDamage) - 1));
}
*/
}
private void checkPlayer()
{
if (this.playerMP == null)
{
if (this.playerUUID != null)
{
this.playerMP = PlayerUtil.getPlayerByUUID(this.playerUUID);
}
}
else
{
if (!PlayerUtil.isPlayerOnline(this.playerMP))
{
this.playerMP = null;
}
}
}
private void freeze(int i)
{
this.AIstate = AISTATE_STUCK;
this.motionX = 0;
this.motionY = 0;
this.motionZ = 0;
if (this.playerMP != null && (this.givenFailMessage & (1 << i)) == 0)
{
this.playerMP.addChatMessage(new ChatComponentText(GCCoreUtil.translate("gui.message.astro_miner" + i + ".fail")));
this.givenFailMessage += (1 << i);
}
}
//packet with AIstate, energy, rotationP + Y, mining data count
@Override
public void decodePacketdata(ByteBuf buffer)
{
this.AIstate = buffer.readInt();
this.energyLevel = buffer.readInt();
this.targetPitch = buffer.readFloat();
this.targetYaw = buffer.readFloat();
this.mineCount = buffer.readInt();
int x = buffer.readInt();
int y = buffer.readInt();
int z = buffer.readInt();
BlockPos pos = new BlockPos(x, y, z);
if (this.worldObj.isBlockLoaded(pos))
{
TileEntity tile = this.worldObj.getTileEntity(pos);
if (tile instanceof TileEntityMinerBase)
{
((TileEntityMinerBase) tile).linkedMiner = this;
((TileEntityMinerBase) tile).linkCountDown = 20;
}
}
}
@Override
public void getNetworkedData(ArrayList<Object> list)
{
if (this.worldObj.isRemote)
{
return;
}
list.add(this.playerMP == null ? AISTATE_OFFLINE : this.AIstate);
list.add(this.energyLevel);
list.add(this.targetPitch);
list.add(this.targetYaw);
list.add(this.mineCount);
list.add(this.posBase.x);
list.add(this.posBase.y);
list.add(this.posBase.z);
}
public void recall()
{
if (this.AIstate > this.AISTATE_ATBASE && this.AIstate < this.AISTATE_RETURNING)
{
AIstate = AISTATE_RETURNING;
this.pathBlockedCount = 0;
}
}
private EnumFacing getFacingFromRotation()
{
if (this.rotationPitch > 45F)
{
return EnumFacing.UP;
}
if (this.rotationPitch < -45F)
{
return EnumFacing.DOWN;
}
float rY = this.rotationYaw % 360F;
//rotationYaw 5 90 4 270 2 180 3 0
if (rY < 45F || rY > 315F)
{
return EnumFacing.SOUTH;
}
if (rY < 135F)
{
return EnumFacing.EAST;
}
if (rY < 225F)
{
return EnumFacing.NORTH;
}
return EnumFacing.WEST;
}
private void atBase()
{
TileEntity tileEntity = posBase.getTileEntity(this.worldObj);
if (!(tileEntity instanceof TileEntityMinerBase) || tileEntity.isInvalid() || !((TileEntityMinerBase) tileEntity).isMaster)
{
this.freeze(FAIL_BASEDESTROYED);
return;
}
TileEntityMinerBase minerBase = (TileEntityMinerBase) tileEntity;
//If it's successfully reached its base, clear all fail messages except number 6, which is that all mining areas are finished (see below)
this.givenFailMessage &= 64;
this.wayPoints.clear();
boolean somethingTransferred = true;
if (this.ticksExisted % 5 == 0)
{
somethingTransferred = this.emptyInventory(minerBase);
}
this.inventoryDrops = 0;
// Recharge
if (minerBase.hasEnoughEnergyToRun && this.energyLevel < MAXENERGY)
{
this.energyLevel += 16;
minerBase.storage.extractEnergyGC(minerBase.storage.getMaxExtract(), false);
}
// When fully charged, set off again
if (this.energyLevel >= MAXENERGY && !somethingTransferred && this.hasHoldSpace())
{
this.energyLevel = MAXENERGY;
if (this.findNextTarget(minerBase))
{
this.AIstate = AISTATE_TRAVELLING;
this.wayPoints.add(this.waypointBase.clone());
this.mineCount = 0;
}
else
{
if (this.playerMP != null && (this.givenFailMessage & 64) == 0)
{
this.playerMP.addChatMessage(new ChatComponentText(GCCoreUtil.translate("gui.message.astro_miner6.fail")));
this.givenFailMessage += 64;
}
}
}
}
private boolean hasHoldSpace()
{
for (int i = 0; i < this.getSizeInventory(); i++)
{
if (this.cargoItems[i] == null)
{
return true;
}
if (this.cargoItems[i].stackSize == 0)
{
this.cargoItems[i] = null;
return true;
}
}
return false;
}
private boolean findNextTarget(TileEntityMinerBase minerBase)
{
//If mining has finished, or path has been blocked two or more times, try mining elsewhere
if (!this.minePoints.isEmpty() && this.pathBlockedCount < 2)
{
this.posTarget = this.minePoints.getFirst().clone();
GCLog.debug("Still mining at: " + posTarget.toString() + " Remaining shafts: " + this.minePoints.size());
return true;
}
// Target is completely mined: change target
this.posTarget = minerBase.findNextTarget();
this.pathBlockedCount = 0;
//No more mining targets, the whole area is mined
if (this.posTarget == null)
{
return false;
}
GCLog.debug("Miner target: " + posTarget.toString());
return true;
}
/**
* @return True if reached a turning point
*/
private boolean moveToTarget()
{
if (this.energyLevel < this.RETURNENERGY || this.inventoryDrops > this.RETURNDROPS)
{
AIstate = AISTATE_RETURNING;
this.pathBlockedCount = 0;
return true;
}
if (this.posTarget == null)
{
GCLog.severe("AstroMiner missing target: this is a bug.");
AIstate = AISTATE_STUCK;
return true;
}
if (this.moveToPos(this.posTarget, false))
{
AIstate = AISTATE_MINING;
wayPoints.add(this.posTarget.clone());
this.setMinePoints();
return true;
}
return false;
}
private void moveToBase()
{
if (this.wayPoints.size() == 0)
{
//When it gets there: stop and reverse in!
AIstate = AISTATE_DOCKING;
if (this.waypointBase != null)
{
//Teleport back to base in case of any serious problem
this.setPosition(this.waypointBase.x, this.waypointBase.y, this.waypointBase.z);
this.facingAI = this.baseFacing;
}
return;
}
if (this.moveToPos(this.wayPoints.getLast(), true))
{
this.wayPoints.removeLast();
}
}
private void setMinePoints()
{
//Still some areas left to mine from last visit (maybe it was full or out of power?)
if (this.minePoints.size() > 0)
{
return;
}
BlockVec3 inFront = new BlockVec3(MathHelper.floor_double(this.posX + 0.5D), MathHelper.floor_double(this.posY + 1.5D), MathHelper.floor_double(this.posZ + 0.5D));
int otherEnd = (this.worldObj.provider instanceof WorldProviderAsteroids) ? this.MINE_LENGTH_AST : this.MINE_LENGTH;
if (this.baseFacing == EnumFacing.NORTH || this.baseFacing == EnumFacing.WEST)
{
otherEnd = -otherEnd;
}
switch (this.baseFacing)
{
case NORTH:
case SOUTH:
this.minePoints.add(inFront.clone().translate(0, 0, otherEnd));
this.minePoints.add(inFront.clone().translate(4, 0, otherEnd));
this.minePoints.add(inFront.clone().translate(4, 0, 0));
this.minePoints.add(inFront.clone().translate(2, 3, 0));
this.minePoints.add(inFront.clone().translate(2, 3, otherEnd));
this.minePoints.add(inFront.clone().translate(-2, 3, otherEnd));
this.minePoints.add(inFront.clone().translate(-2, 3, 0));
this.minePoints.add(inFront.clone().translate(-4, 0, 0));
this.minePoints.add(inFront.clone().translate(-4, 0, otherEnd));
this.minePoints.add(inFront.clone().translate(-2, -3, otherEnd));
this.minePoints.add(inFront.clone().translate(-2, -3, 0));
this.minePoints.add(inFront.clone().translate(2, -3, 0));
this.minePoints.add(inFront.clone().translate(2, -3, otherEnd));
this.minePoints.add(inFront.clone().translate(0, 0, otherEnd));
break;
case WEST:
case EAST:
this.minePoints.add(inFront.clone().translate(otherEnd, 0, 0));
this.minePoints.add(inFront.clone().translate(otherEnd, 0, 4));
this.minePoints.add(inFront.clone().translate(0, 0, 4));
this.minePoints.add(inFront.clone().translate(0, 3, 2));
this.minePoints.add(inFront.clone().translate(otherEnd, 3, 2));
this.minePoints.add(inFront.clone().translate(otherEnd, 3, -2));
this.minePoints.add(inFront.clone().translate(0, 3, -2));
this.minePoints.add(inFront.clone().translate(0, 0, -4));
this.minePoints.add(inFront.clone().translate(otherEnd, 0, -4));
this.minePoints.add(inFront.clone().translate(otherEnd, -3, -2));
this.minePoints.add(inFront.clone().translate(0, -3, -2));
this.minePoints.add(inFront.clone().translate(0, -3, 2));
this.minePoints.add(inFront.clone().translate(otherEnd, -3, 2));
this.minePoints.add(inFront.clone().translate(otherEnd, 0, 0));
break;
}
}
/**
* @return True if reached a turning point
*/
private boolean doMining()
{
if (this.energyLevel < this.RETURNENERGY || this.inventoryDrops > this.RETURNDROPS || this.minePoints.size() == 0)
{
if (this.minePoints.size() > 0 && this.minePointCurrent != null)
{
this.minePoints.addFirst(this.minePointCurrent);
}
AIstate = AISTATE_RETURNING;
this.pathBlockedCount = 0;
GCLog.debug("Miner going home: " + this.posBase.toString() + " " + this.minePoints.size() + " shafts still to be mined");
return true;
}
if (this.moveToPos(this.minePoints.getFirst(), false))
{
this.minePointCurrent = this.minePoints.removeFirst();
GCLog.debug("Miner mid mining: " + this.minePointCurrent.toString() + " " + this.minePoints.size() + " shafts still to be mined");
return true;
}
return false;
}
private void tryBackIn()
{
if (this.waypointBase.distanceSquared(new BlockVec3(this)) <= 9.1D)
{
this.AIstate = AISTATE_DOCKING;
switch (this.baseFacing)
{
case NORTH:
this.targetYaw = 180;
break;
case SOUTH:
this.targetYaw = 0;
break;
case WEST:
this.targetYaw = 270;
break;
case EAST:
this.targetYaw = 90;
break;
}
}
else
{
this.freeze(FAIL_RETURNPATHBLOCKED);
}
}
/**
* Mine out the area in front of the miner (dist blocks from miner centre)
*
* @param limit Maximum block count to be mined this tick
* @param dist
* @return True if the mining failed (meaning the miner's path is blocked)
*/
private boolean prepareMove(int limit, int dist)
{
if (this.mineCountDown > 0)
{
this.mineCountDown--;
return false;
}
BlockVec3 inFront = new BlockVec3(MathHelper.floor_double(this.posX + 0.5D), MathHelper.floor_double(this.posY + 1.5D), MathHelper.floor_double(this.posZ + 0.5D));
if (dist == 2)
{
inFront.translate(headings2[this.facingAI.getIndex()]);
}
else
{
if ((this.facingAI.getIndex() & 1) == EnumFacing.DOWN.getIndex())
{
dist++;
}
if (dist > 0)
{
inFront.translate(headings[this.facingAI.getIndex()].clone().scale(dist));
}
}
if (!inFront.equals(this.mineLast) && this.AIstate != AISTATE_ATBASE)
{
this.mineCountDown = 3;
this.mineLast = inFront;
return false;
}
int x = inFront.x;
int y = inFront.y;
int z = inFront.z;
//Test not trying to mine own dock!
if (y == this.waypointBase.y && x == this.waypointBase.x - ((this.baseFacing == EnumFacing.EAST) ? 1 : 0) && z == this.waypointBase.z - ((this.baseFacing == EnumFacing.SOUTH) ? 1 : 0))
{
this.tryBackIn();
return false;
}
boolean wayBarred = false;
this.tryBlockLimit = limit;
//Check not obstructed by something immovable e.g. bedrock
//Mine out the 12 blocks in front of it in direction of travel when getting close
//There are 12 blocks around ... and 12 in front. One block per tick?
//(That means can move at 5/6 block per second when mining, and 1.67 bps when traveling)
BlockPos pos = new BlockPos(x, y, z);
switch (EnumFacing.getFront(this.facingAI.getIndex() & 6))
{
case DOWN:
if (tryMineBlock(pos))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(1, 0, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(1, 0, -1)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, 0, -1)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, 0, -2)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-1, 0, -2)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-1, 0, -1)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-2, 0, -1)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-2, 0, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-1, 0, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-1, 0, 1)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, 0, 1)))
{
wayBarred = true;
}
break;
case NORTH:
if (tryMineBlock(pos.add(0, -2, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-1, -2, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, -1, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-1, -1, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(1, -1, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-2, -1, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(1, 0, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-2, 0, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-1, 0, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, 1, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(-1, 1, 0)))
{
wayBarred = true;
}
break;
case WEST:
if (tryMineBlock(pos.add(0, -2, -1)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, -1, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, -1, -1)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, -1, +1)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, -1, -2)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, 0, 1)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, 0, -2)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, 0, -1)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, -2, 0)))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, 1, -1)))
{
wayBarred = true;
}
if (tryMineBlock(pos))
{
wayBarred = true;
}
if (tryMineBlock(pos.add(0, 1, 0)))
{
wayBarred = true;
}
break;
}
//If it is obstructed, return to base, or stand still if that is impossible
if (wayBarred)
{
if (this.playerMP != null)
{
this.playerMP.addChatMessage(new ChatComponentText(GCCoreUtil.translate("gui.message.astro_miner1_a.fail") + " " + GCCoreUtil.translate(EntityAstroMiner.blockingBlock.toString())));
}
this.motionX = 0;
this.motionY = 0;
this.motionZ = 0;
this.tryBlockLimit = 0;
if (this.AIstate == AISTATE_TRAVELLING)
{
this.AIstate = AISTATE_RETURNING;
}
else if (AIstate == AISTATE_MINING)
{
this.pathBlockedCount++;
this.AIstate = AISTATE_RETURNING;
}
else if (this.AIstate == AISTATE_RETURNING)
{
this.tryBackIn();
}
else
{
this.freeze(FAIL_RETURNPATHBLOCKED);
}
}
if (this.tryBlockLimit == limit && !this.noSpeedup)
{
this.motionX *= this.speedup;
this.motionY *= this.speedup;
this.motionZ *= this.speedup;
}
return wayBarred;
}
private boolean prepareMoveClient(int limit, int dist)
{
BlockVec3 inFront = new BlockVec3(MathHelper.floor_double(this.posX + 0.5D), MathHelper.floor_double(this.posY + 1.5D), MathHelper.floor_double(this.posZ + 0.5D));
if (dist == 2)
{
inFront.translate(headings2[this.facing.getIndex()]);
}
else
{
if ((this.facing.getIndex() & 1) == EnumFacing.DOWN.getIndex())
{
dist++;
}
if (dist > 0)
{
inFront.translate(headings[this.facing.getIndex()].clone().scale(dist));
}
}
if (inFront.equals(this.mineLast))
{
return false;
}
int x = inFront.x;
int y = inFront.y;
int z = inFront.z;
boolean wayBarred = false;
this.tryBlockLimit = limit;
//Check not obstructed by something immovable e.g. bedrock
//Mine out the 12 blocks in front of it in direction of travel when getting close
//There are 12 blocks around ... and 12 in front. One block per tick?
//(That means can move at 5/6 block per second when mining, and 1.67 bps when traveling)
BlockPos pos = new BlockPos(x, y, z);
switch (EnumFacing.getFront(this.facing.getIndex() & 6))
{
case DOWN:
if (tryBlockClient(pos))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(1, 0, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(1, 0, -1)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, 0, -1)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, 0, -2)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-1, 0, -2)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-1, 0, -1)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-2, 0, -1)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-2, 0, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-1, 0, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-1, 0, 1)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, 0, 1)))
{
wayBarred = true;
}
break;
case NORTH:
if (tryBlockClient(pos.add(0, -2, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-1, -2, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, -1, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-1, -1, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(1, -1, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-2, -1, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(1, 0, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-2, 0, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-1, 0, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, 1, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(-1, 1, 0)))
{
wayBarred = true;
}
break;
case WEST:
if (tryBlockClient(pos.add(0, -2, -1)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, -1, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, -1, -1)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, -1, +1)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, -1, -2)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, 0, 1)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, 0, -2)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, 0, -1)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, -2, 0)))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, 1, -1)))
{
wayBarred = true;
}
if (tryBlockClient(pos))
{
wayBarred = true;
}
if (tryBlockClient(pos.add(0, 1, 0)))
{
wayBarred = true;
}
break;
}
//If it is obstructed, return to base, or stand still if that is impossible
if (wayBarred)
{
this.tryBlockLimit = 0;
}
if (this.tryBlockLimit == limit)
{
this.mineLast = inFront;
}
return wayBarred;
}
private boolean tryMineBlock(BlockPos pos)
{
//Check things to avoid in front of it (see static list for list) including base type things
//Can move through liquids including flowing lava
IBlockState state = this.worldObj.getBlockState(pos);
Block b = state.getBlock();
if (b.getMaterial() == Material.air)
{
return false;
}
if (noMineList.contains(b))
{
blockingBlock.block = b;
blockingBlock.meta = b.getMetaFromState(state);
return !(this.AIstate == AISTATE_RETURNING && b == Blocks.lava);
}
if (b instanceof BlockLiquid)
{
return false;
}
if (b instanceof IFluidBlock)
{
return false;
}
boolean gtFlag = false;
if (b != GCBlocks.fallenMeteor)
{
if (b instanceof IPlantable && b != Blocks.tallgrass && b != Blocks.deadbush && b != Blocks.double_plant && b != Blocks.waterlily && !(b instanceof BlockFlower))
{
blockingBlock.block = b;
blockingBlock.meta = b.getMetaFromState(state);
return true;
}
int meta = b.getMetaFromState(state);
if (b.getBlockHardness(this.worldObj, pos) < 0)
{
blockingBlock.block = b;
blockingBlock.meta = meta;
return true;
}
if (b.hasTileEntity(state))
{
if (CompatibilityManager.isGTLoaded() && gregTechCheck(b))
{
gtFlag = true;
}
else
{
blockingBlock.block = b;
blockingBlock.meta = meta;
return true;
}
}
}
if (this.tryBlockLimit == 0)
{
return false;
}
int result = ForgeHooks.onBlockBreakEvent(this.worldObj, this.playerMP.theItemInWorldManager.getGameType(), this.playerMP, pos);
if (result < 0)
{
return true;
}
this.tryBlockLimit--;
ItemStack drops = gtFlag ? getGTDrops(this.worldObj, pos, b) : getPickBlock(this.worldObj, pos, b);
if (drops != null && !this.addToInventory(drops))
{
//drop itemstack if AstroMiner can't hold it
dropStack(pos, drops);
}
this.worldObj.setBlockState(pos, Blocks.air.getDefaultState(), 3);
return false;
}
private void dropStack(BlockPos pos, ItemStack drops)
{
float f = 0.7F;
double d0 = this.worldObj.rand.nextFloat() * f + (1.0F - f) * 0.5D;
double d1 = this.worldObj.rand.nextFloat() * f + (1.0F - f) * 0.5D;
double d2 = this.worldObj.rand.nextFloat() * f + (1.0F - f) * 0.5D;
EntityItem entityitem = new EntityItem(this.worldObj, pos.getX() + d0, pos.getY() + d1, pos.getZ() + d2, drops);
entityitem.setDefaultPickupDelay();
this.worldObj.spawnEntityInWorld(entityitem);
this.inventoryDrops++;
}
private boolean gregTechCheck(Block b)
{
Class clazz = CompatibilityManager.classGTOre;
return clazz != null && clazz.isInstance(b);
}
private ItemStack getGTDrops(World w, BlockPos pos, Block b)
{
List<ItemStack> array = b.getDrops(w, pos, b.getDefaultState(), 1);
if (array != null && array.size() > 0)
{
return array.get(0);
}
return null;
}
private boolean tryBlockClient(BlockPos pos)
{
BlockVec3 bv = new BlockVec3(pos.getX(), pos.getY(), pos.getZ());
if (this.laserBlocks.contains(bv))
{
return false;
}
//Add minable blocks to the laser fx list
IBlockState state = this.worldObj.getBlockState(pos);
Block b = state.getBlock();
if (b.getMaterial() == Material.air)
{
return false;
}
if (noMineList.contains(b))
{
return true;
}
if (b instanceof BlockLiquid)
{
return false;
}
if (b instanceof IFluidBlock)
{
return false;
}
if (b instanceof IPlantable)
{
return true;
}
int meta = b.getMetaFromState(state);
if (b.hasTileEntity(state) || b.getBlockHardness(this.worldObj, pos) < 0)
{
return true;
}
if (this.tryBlockLimit == 0)
{
return false;
}
this.tryBlockLimit--;
this.laserBlocks.add(bv);
this.laserTimes.add(this.ticksExisted);
return false;
}
public void removeLaserBlocks(int removeCount)
{
for (int i = 0; i < removeCount; i++)
{
this.laserBlocks.removeFirst();
this.laserTimes.removeFirst();
}
}
private ItemStack getPickBlock(World world, BlockPos pos, Block b)
{
if (b == GCBlocks.fallenMeteor)
{
return new ItemStack(GCItems.meteoricIronRaw);
}
int i = 0;
Item item = Item.getItemFromBlock(b);
if (item != null && item.getHasSubtypes())
{
i = b.getMetaFromState(world.getBlockState(pos));
}
return new ItemStack(item, 1, i);
}
private boolean addToInventory(ItemStack itemstack)
{
boolean flag1 = false;
int k = 0;
int invSize = this.getSizeInventory();
ItemStack itemstack1;
if (itemstack.isStackable())
{
while (itemstack.stackSize > 0 && k < invSize)
{
itemstack1 = this.cargoItems[k];
if (itemstack1 != null && itemstack1.getItem() == itemstack.getItem() && (!itemstack.getHasSubtypes() || itemstack.getItemDamage() == itemstack1.getItemDamage()) && ItemStack.areItemStackTagsEqual(itemstack, itemstack1))
{
int l = itemstack1.stackSize + itemstack.stackSize;
if (l <= itemstack.getMaxStackSize())
{
itemstack.stackSize = 0;
itemstack1.stackSize = l;
flag1 = true;
}
else if (itemstack1.stackSize < itemstack.getMaxStackSize())
{
itemstack.stackSize -= itemstack.getMaxStackSize() - itemstack1.stackSize;
itemstack1.stackSize = itemstack.getMaxStackSize();
flag1 = true;
}
}
++k;
}
}
if (itemstack.stackSize > 0)
{
k = 0;
while (k < invSize)
{
itemstack1 = this.cargoItems[k];
if (itemstack1 == null)
{
this.cargoItems[k] = itemstack.copy();
itemstack.stackSize = 0;
flag1 = true;
break;
}
++k;
}
}
if (flag1)
{
this.markDirty();
this.mineCount++;
}
return flag1;
}
/**
* Logic to move the miner to a given position
*
* @param pos
* @param reverse True if returning home (re-use same tunnels)
* @return False while the miner is en route, True when the position is reached
*/
private boolean moveToPos(BlockVec3 pos, boolean reverse)
{
this.noSpeedup = false;
if (reverse != (this.baseFacing.getIndex() < 4))
{
if (this.posZ > pos.z + 0.0001D || this.posZ < pos.z - 0.0001D)
{
this.moveToPosZ(pos.z, stopForTurn);
if (TEMPDEBUG)
{
GCLog.debug("At " + posX + "," + posY + "," + posZ + "Moving Z to " + pos.toString() + (stopForTurn ? " : Stop for turn " + this.rotationPitch + "," + this.rotationYaw + " | " + this.targetPitch + "," + this.targetYaw : ""));
}
}
else if (this.posY > pos.y - 0.9999D || this.posY < pos.y - 1.0001D)
{
this.moveToPosY(pos.y - 1, stopForTurn);
if (TEMPDEBUG)
{
GCLog.debug("At " + posX + "," + posY + "," + posZ + "Moving Y to " + pos.toString() + (stopForTurn ? " : Stop for turn " + this.rotationPitch + "," + this.rotationYaw + " | " + this.targetPitch + "," + this.targetYaw : ""));
}
}
else if (this.posX > pos.x + 0.0001D || this.posX < pos.x - 0.0001D)
{
this.moveToPosX(pos.x, stopForTurn);
if (TEMPDEBUG)
{
GCLog.debug("At " + posX + "," + posY + "," + posZ + "Moving X to " + pos.toString() + (stopForTurn ? " : Stop for turn " + this.rotationPitch + "," + this.rotationYaw + " | " + this.targetPitch + "," + this.targetYaw : ""));
}
}
else
{
return true;
}
//got there
}
else
{
if (this.posX > pos.x + 0.0001D || this.posX < pos.x - 0.0001D)
{
this.moveToPosX(pos.x, stopForTurn);
if (TEMPDEBUG)
{
GCLog.debug("At " + posX + "," + posY + "," + posZ + "Moving X to " + pos.toString() + (stopForTurn ? " : Stop for turn " + this.rotationPitch + "," + this.rotationYaw + " | " + this.targetPitch + "," + this.targetYaw : ""));
}
}
else if (this.posY > pos.y - 0.9999D || this.posY < pos.y - 1.0001D)
{
this.moveToPosY(pos.y - 1, stopForTurn);
if (TEMPDEBUG)
{
GCLog.debug("At " + posX + "," + posY + "," + posZ + "Moving Y to " + pos.toString() + (stopForTurn ? " : Stop for turn " + this.rotationPitch + "," + this.rotationYaw + " | " + this.targetPitch + "," + this.targetYaw : ""));
}
}
else if (this.posZ > pos.z + 0.0001D || this.posZ < pos.z - 0.0001D)
{
this.moveToPosZ(pos.z, stopForTurn);
if (TEMPDEBUG)
{
GCLog.debug("At " + posX + "," + posY + "," + posZ + "Moving Z to " + pos.toString() + (stopForTurn ? " : Stop for turn " + this.rotationPitch + "," + this.rotationYaw + " | " + this.targetPitch + "," + this.targetYaw : ""));
}
}
else
{
return true;
}
//got there
}
return false;
}
private void moveToPosX(int x, boolean stopForTurn)
{
this.targetPitch = 0;
if (this.posX > x)
{
if (this.AIstate != AISTATE_DOCKING)
{
this.targetYaw = 270;
}
this.motionX = -this.speed;
//TODO some acceleration and deceleration
if (this.motionX * speedup <= x - this.posX)
{
this.motionX = x - this.posX;
this.noSpeedup = true;
}
this.facingAI = EnumFacing.WEST;
}
else
{
if (this.AIstate != AISTATE_DOCKING)
{
this.targetYaw = 90;
}
this.motionX = this.speed;
if (this.motionX * speedup >= x - this.posX)
{
this.motionX = x - this.posX;
this.noSpeedup = true;
}
this.facingAI = EnumFacing.EAST;
}
if (stopForTurn)
{
this.motionX = 0;
}
this.motionY = 0;
this.motionZ = 0;
}
private void moveToPosY(int y, boolean stopForTurn)
{
if (this.posY > y)
{
this.targetPitch = -90;
this.motionY = -this.speed;
if (this.motionY * speedup <= y - this.posY)
{
this.motionY = y - this.posY;
this.noSpeedup = true;
}
this.facingAI = EnumFacing.DOWN;
}
else
{
this.targetPitch = 90;
this.motionY = this.speed;
if (this.motionY * speedup >= y - this.posY)
{
this.motionY = y - this.posY;
this.noSpeedup = true;
}
this.facingAI = EnumFacing.UP;
}
if (stopForTurn)
{
this.motionY = 0;
}
this.motionX = 0;
this.motionZ = 0;
}
private void moveToPosZ(int z, boolean stopForTurn)
{
this.targetPitch = 0;
if (this.posZ > z)
{
if (this.AIstate != AISTATE_DOCKING)
{
this.targetYaw = 180;
}
this.motionZ = -this.speed;
//TODO some acceleration and deceleration
if (this.motionZ * speedup <= z - this.posZ)
{
this.motionZ = z - this.posZ;
this.noSpeedup = true;
}
this.facingAI = EnumFacing.NORTH;
}
else
{
if (this.AIstate != AISTATE_DOCKING)
{
this.targetYaw = 0;
}
this.motionZ = this.speed;
if (this.motionZ * speedup >= z - this.posZ)
{
this.motionZ = z - this.posZ;
this.noSpeedup = true;
}
this.facingAI = EnumFacing.SOUTH;
}
if (stopForTurn)
{
this.motionZ = 0;
}
this.motionY = 0;
this.motionX = 0;
}
private boolean checkRotation()
{
boolean flag = true;
//Handle the turns when it changes direction
if (this.rotationPitch > this.targetPitch + 0.001F || this.rotationPitch < this.targetPitch - 0.001F)
{
if (this.rotationPitch > this.targetPitch + 180)
{
this.rotationPitch -= 360;
}
else if (this.rotationPitch < this.targetPitch - 180)
{
this.rotationPitch += 360;
}
if (this.rotationPitch > this.targetPitch)
{
this.rotationPitch -= this.rotSpeed;
if (this.rotationPitch < this.targetPitch)
{
this.rotationPitch = this.targetPitch;
}
}
else
{
this.rotationPitch += this.rotSpeed;
if (this.rotationPitch > this.targetPitch)
{
this.rotationPitch = this.targetPitch;
}
}
}
if (this.rotationYaw > this.targetYaw + 0.001F || this.rotationYaw < this.targetYaw - 0.001F)
{
if (this.rotationYaw > this.targetYaw + 180)
{
this.rotationYaw -= 360;
}
else if (this.rotationYaw < this.targetYaw - 180)
{
this.rotationYaw += 360;
}
if (this.rotationYaw > this.targetYaw)
{
this.rotationYaw -= this.rotSpeed;
if (this.rotationYaw < this.targetYaw)
{
this.rotationYaw = this.targetYaw;
}
}
else
{
this.rotationYaw += this.rotSpeed;
if (this.rotationYaw > this.targetYaw)
{
this.rotationYaw = this.targetYaw;
}
}
flag = false;
}
return flag;
}
/**
* x y z should be the mid-point of the 4 base blocks
*
* @param world
* @param x
* @param y
* @param z
* @param facing
* @param base
* @return
*/
public static boolean spawnMinerAtBase(World world, int x, int y, int z, EnumFacing facing, BlockVec3 base, EntityPlayerMP player)
{
if (world.isRemote)
{
return true;
}
final EntityAstroMiner miner = new EntityAstroMiner(world, new ItemStack[EntityAstroMiner.INV_SIZE], 0);
miner.setPlayer(player);
if (player.capabilities.isCreativeMode)
{
miner.spawnedInCreative = true;
}
miner.waypointBase = new BlockVec3(x, y, z).modifyPositionFromSide(facing, 1);
miner.setPosition(miner.waypointBase.x, miner.waypointBase.y - 1, miner.waypointBase.z);
miner.baseFacing = facing;
miner.facingAI = facing;
miner.lastFacing = facing;
miner.motionX = 0;
miner.motionY = 0;
miner.motionZ = 0;
miner.targetPitch = 0;
switch (facing)
{
case NORTH:
miner.targetYaw = 180;
break;
case SOUTH:
miner.targetYaw = 0;
break;
case WEST:
miner.targetYaw = 270;
break;
case EAST:
miner.targetYaw = 90;
break;
}
miner.rotationPitch = miner.targetPitch;
miner.rotationYaw = miner.targetYaw;
miner.setBoundingBoxForFacing();
miner.AIstate = AISTATE_ATBASE;
miner.posBase = base;
//Increase motion speed when moving in empty space between asteroids
miner.speedup = (world.provider instanceof WorldProviderAsteroids) ? SPEEDUP * 2.2D : SPEEDUP;
//Clear blocks, and test to see if its movement area in front of the base is blocked
if (miner.prepareMove(12, 0))
{
miner.isDead = true;
return false;
}
if (miner.prepareMove(12, 1))
{
miner.isDead = true;
return false;
}
if (miner.prepareMove(12, 2))
{
miner.isDead = true;
return false;
}
world.spawnEntityInWorld(miner);
miner.flagLink = true;
return true;
}
public void setPlayer(EntityPlayerMP player)
{
this.playerMP = player;
this.playerUUID = player.getUniqueID();
}
private void setBoundingBoxForFacing()
{
float xsize = cWIDTH;
float ysize = cWIDTH;
float zsize = cWIDTH;
switch (this.facing)
{
case DOWN:
case UP:
ysize = cLENGTH;
break;
case NORTH:
case SOUTH:
ysize = cHEIGHT;
zsize = cLENGTH;
break;
case WEST:
case EAST:
ysize = cHEIGHT;
xsize = cLENGTH;
break;
}
this.width = Math.max(xsize, zsize);
this.height = ysize;
this.setEntityBoundingBox(new AxisAlignedBB(this.posX - xsize / 2D, this.posY + 1D - ysize / 2D, this.posZ - zsize / 2D,
this.posX + xsize / 2D, this.posY + 1D + ysize / 2D, this.posZ + zsize / 2D));
}
@Override
public boolean attackEntityFrom(DamageSource par1DamageSource, float par2)
{
if (this.isDead || par1DamageSource.equals(DamageSource.cactus))
{
return true;
}
if (!this.worldObj.isRemote)
{
Entity e = par1DamageSource.getEntity();
//If creative mode player, kill the entity (even if player owner is offline) and drop nothing
if (e instanceof EntityPlayer && ((EntityPlayer) e).capabilities.isCreativeMode)
{
if (this.playerMP == null && !this.spawnedInCreative)
{
((EntityPlayer) e).addChatMessage(new ChatComponentText("WARNING: that Astro Miner belonged to an offline player, cannot reset player's Astro Miner count."));
}
this.kill();
return true;
}
//Invulnerable to mobs
if (this.isEntityInvulnerable() || (e instanceof EntityLivingBase && !(e instanceof EntityPlayer)))
{
return false;
}
else
{
this.setBeenAttacked();
// this.dataWatcher.updateObject(this.timeSinceHit, Integer.valueOf(10));
// this.dataWatcher.updateObject(this.currentDamage, Integer.valueOf((int) (this.dataWatcher.getWatchableObjectInt(this.currentDamage) + par2 * 10)));
this.shipDamage += par2 * 10;
if (e instanceof EntityPlayer)
{
this.shipDamage += par2 * 21;
// this.dataWatcher.updateObject(this.currentDamage, 100);
}
if (this.shipDamage > 90)
{
this.kill();
this.dropShipAsItem();
return true;
}
return true;
}
}
else
{
return true;
}
}
@Override
public AxisAlignedBB getCollisionBox(Entity par1Entity)
{
return par1Entity.getCollisionBoundingBox();
}
@Override
public boolean canBePushed()
{
return false;
}
@Override
public boolean canBeCollidedWith()
{
return !this.isDead;
}
@Override
public void performHurtAnimation()
{
// this.dataWatcher.updateObject(this.timeSinceHit, Integer.valueOf(10));
// this.dataWatcher.updateObject(this.currentDamage, Integer.valueOf(this.dataWatcher.getWatchableObjectInt(this.currentDamage) * 5));
}
public float getDamage()
{
return this.dataWatcher.getWatchableObjectFloat(19);
}
public void setDamage(float p_70492_1_)
{
this.dataWatcher.updateObject(19, Float.valueOf(p_70492_1_));
}
@Override
public void setLocationAndAngles(double x, double y, double z, float rotYaw, float rotPitch)
{
this.minecartX = x;
this.minecartY = y;
this.minecartZ = z;
super.setLocationAndAngles(x, y, z, rotYaw, rotPitch);
}
@SideOnly(Side.CLIENT)
@Override
public void setPositionAndRotation2(double x, double y, double z, float yaw, float pitch, int posRotationIncrements, boolean b)
{
this.minecartX = x;
this.minecartY = y;
this.minecartZ = z;
this.minecartYaw = y;
this.minecartPitch = pitch;
this.turnProgress = 0;
this.motionX = this.velocityX;
this.motionY = this.velocityY;
this.motionZ = this.velocityZ;
}
@Override
@SideOnly(Side.CLIENT)
public void setVelocity(double p_70016_1_, double p_70016_3_, double p_70016_5_)
{
this.velocityX = this.motionX = p_70016_1_;
this.velocityY = this.motionY = p_70016_3_;
this.velocityZ = this.motionZ = p_70016_5_;
this.turnProgress = 0;
}
@Override
protected void setSize(float p_70105_1_, float p_70105_2_)
{
this.setBoundingBoxForFacing();
}
@Override
public void setPosition(double p_70107_1_, double p_70107_3_, double p_70107_5_)
{
this.setEntityBoundingBox(this.getEntityBoundingBox().offset(p_70107_1_ - this.posX, p_70107_3_ - this.posY, p_70107_5_ - this.posZ));
this.posX = p_70107_1_;
this.posY = p_70107_3_;
this.posZ = p_70107_5_;
}
@Override
public void setDead()
{
if (!this.worldObj.isRemote && this.playerMP != null)
{
GCPlayerStats stats = GCPlayerStats.get(this.playerMP);
if (!this.spawnedInCreative)
{
int astroCount = stats.getAstroMinerCount();
if (astroCount > 0)
{
stats.setAstroMinerCount(stats.getAstroMinerCount() - 1);
}
}
AsteroidsTickHandlerServer.removeChunkData(stats, this);
}
super.setDead();
if (posBase != null)
{
TileEntity tileEntity = posBase.getTileEntity(this.worldObj);
if (tileEntity instanceof TileEntityMinerBase)
{
((TileEntityMinerBase) tileEntity).unlinkMiner();
}
}
if (this.soundUpdater != null)
{
this.soundUpdater.update();
}
}
public boolean isEntityInvulnerable()
{
//Can't be damaged if its player is offline - it's in a fully dormant state
return this.playerMP == null;
}
public List<ItemStack> getItemsDropped(List<ItemStack> droppedItems)
{
ItemStack rocket = new ItemStack(AsteroidsItems.astroMiner, 1, 0);
droppedItems.add(rocket);
for (int i = 0; i < this.cargoItems.length; i++)
{
if (this.cargoItems[i] != null)
{
droppedItems.add(this.cargoItems[i]);
}
this.cargoItems[i] = null;
}
return droppedItems;
}
public void dropShipAsItem()
{
if (this.worldObj.isRemote)
{
return;
}
for (final ItemStack item : this.getItemsDropped(new ArrayList<ItemStack>()))
{
EntityItem entityItem = this.entityDropItem(item, 0);
if (item.hasTagCompound())
{
entityItem.getEntityItem().setTagCompound((NBTTagCompound) item.getTagCompound().copy());
}
}
}
@Override
@SideOnly(Side.CLIENT)
public ITickable getSoundUpdater()
{
return this.soundUpdater;
}
@Override
@SideOnly(Side.CLIENT)
public ISound setSoundUpdater(EntityPlayerSP player)
{
this.soundUpdater = new SoundUpdaterMiner(player, this);
return (ISound) this.soundUpdater;
}
public void stopRocketSound()
{
if (this.soundUpdater != null)
{
((SoundUpdaterMiner) this.soundUpdater).stopRocketSound();
}
this.soundToStop = false;
}
@Override
public void transmitData(int[] data)
{
data[0] = (int) (this.posX);
data[1] = (int) (this.posY);
data[2] = (int) (this.posZ);
data[3] = this.energyLevel;
data[4] = this.AIstate;
}
@Override
public void receiveData(int[] data, String[] str)
{
str[0] = "";
str[1] = "x: " + data[0];
str[2] = "y: " + data[1];
str[3] = "z: " + data[2];
int energyPerCent = data[3] / 120;
str[4] = GCCoreUtil.translate("gui.energy_storage.desc.1") + ": " + energyPerCent + "%";
switch (data[4])
{
case EntityAstroMiner.AISTATE_STUCK:
str[0] = GCCoreUtil.translate("gui.message.no_energy.name");
break;
case EntityAstroMiner.AISTATE_ATBASE:
str[0] = GCCoreUtil.translate("gui.miner.docked");
break;
case EntityAstroMiner.AISTATE_TRAVELLING:
str[0] = GCCoreUtil.translate("gui.miner.travelling");
break;
case EntityAstroMiner.AISTATE_MINING:
str[0] = GCCoreUtil.translate("gui.miner.mining");
break;
case EntityAstroMiner.AISTATE_RETURNING:
str[0] = GCCoreUtil.translate("gui.miner.returning");
break;
case EntityAstroMiner.AISTATE_DOCKING:
str[0] = GCCoreUtil.translate("gui.miner.docking");
break;
case EntityAstroMiner.AISTATE_OFFLINE:
str[0] = GCCoreUtil.translate("gui.miner.offline");
break;
}
}
@Override
public void adjustDisplay(int[] data)
{
GL11.glScalef(0.9F, 0.9F, 0.9F);
}
@Override
protected void readEntityFromNBT(NBTTagCompound nbt)
{
final NBTTagList var2 = nbt.getTagList("Items", 10);
this.cargoItems = new ItemStack[this.INV_SIZE];
int itemCount = 0;
if (var2 != null)
{
for (int var3 = 0; var3 < var2.tagCount(); ++var3)
{
final NBTTagCompound var4 = var2.getCompoundTagAt(var3);
final int var5 = var4.getByte("Slot") & 255;
if (var5 < this.cargoItems.length)
{
ItemStack read = ItemStack.loadItemStackFromNBT(var4);
if (read != null)
{
this.cargoItems[var5] = read;
itemCount += read.stackSize;
}
}
}
}
this.mineCount = itemCount;
if (nbt.hasKey("sindex"))
{
this.serverIndex = nbt.getInteger("sindex");
}
else
{
this.serverIndex = -1;
}
if (nbt.hasKey("Energy"))
{
this.energyLevel = nbt.getInteger("Energy");
}
if (nbt.hasKey("BaseX"))
{
this.posBase = new BlockVec3(nbt.getInteger("BaseX"), nbt.getInteger("BaseY"), nbt.getInteger("BaseZ"));
this.flagLink = true;
}
if (nbt.hasKey("TargetX"))
{
this.posTarget = new BlockVec3(nbt.getInteger("TargetX"), nbt.getInteger("TargetY"), nbt.getInteger("TargetZ"));
}
if (nbt.hasKey("WBaseX"))
{
this.waypointBase = new BlockVec3(nbt.getInteger("WBaseX"), nbt.getInteger("WBaseY"), nbt.getInteger("WBaseZ"));
}
if (nbt.hasKey("BaseFacing"))
{
this.baseFacing = EnumFacing.getFront(nbt.getInteger("BaseFacing"));
}
if (nbt.hasKey("AIState"))
{
this.AIstate = nbt.getInteger("AIState");
}
if (nbt.hasKey("Facing"))
{
this.facingAI = EnumFacing.getFront(nbt.getInteger("Facing"));
switch (this.facingAI)
{
case NORTH:
this.targetYaw = 180;
break;
case SOUTH:
this.targetYaw = 0;
break;
case WEST:
this.targetYaw = 270;
break;
case EAST:
this.targetYaw = 90;
break;
}
}
this.lastFacing = null;
if (nbt.hasKey("WayPoints"))
{
this.wayPoints.clear();
final NBTTagList wpList = nbt.getTagList("WayPoints", 10);
for (int j = 0; j < wpList.tagCount(); j++)
{
NBTTagCompound bvTag = wpList.getCompoundTagAt(j);
this.wayPoints.add(BlockVec3.readFromNBT(bvTag));
}
}
if (nbt.hasKey("MinePoints"))
{
this.minePoints.clear();
final NBTTagList mpList = nbt.getTagList("MinePoints", 10);
for (int j = 0; j < mpList.tagCount(); j++)
{
NBTTagCompound bvTag = mpList.getCompoundTagAt(j);
this.minePoints.add(BlockVec3.readFromNBT(bvTag));
}
}
if (nbt.hasKey("MinePointCurrent"))
{
this.minePointCurrent = BlockVec3.readFromNBT(nbt.getCompoundTag("MinePointCurrent"));
}
else
{
this.minePointCurrent = null;
}
if (nbt.hasKey("playerUUIDMost", 4) && nbt.hasKey("playerUUIDLeast", 4))
{
this.playerUUID = new UUID(nbt.getLong("playerUUIDMost"), nbt.getLong("playerUUIDLeast"));
}
else
{
this.playerUUID = null;
}
if (nbt.hasKey("speedup"))
{
this.speedup = nbt.getDouble("speedup");
}
else
{
this.speedup = (WorldUtil.getProviderForDimensionServer(this.dimension) instanceof WorldProviderAsteroids) ? SPEEDUP * 1.6D : SPEEDUP;
}
this.pathBlockedCount = nbt.getInteger("pathBlockedCount");
this.spawnedInCreative = nbt.getBoolean("spawnedInCreative");
this.flagCheckPlayer = true;
}
@Override
protected void writeEntityToNBT(NBTTagCompound nbt)
{
final NBTTagList var2 = new NBTTagList();
if (this.cargoItems != null)
{
for (int var3 = 0; var3 < this.cargoItems.length; ++var3)
{
if (this.cargoItems[var3] != null)
{
final NBTTagCompound var4 = new NBTTagCompound();
var4.setByte("Slot", (byte) var3);
this.cargoItems[var3].writeToNBT(var4);
var2.appendTag(var4);
}
}
}
nbt.setTag("Items", var2);
nbt.setInteger("sindex", this.serverIndex);
nbt.setInteger("Energy", this.energyLevel);
if (this.posBase != null)
{
nbt.setInteger("BaseX", this.posBase.x);
nbt.setInteger("BaseY", this.posBase.y);
nbt.setInteger("BaseZ", this.posBase.z);
}
if (this.posTarget != null)
{
nbt.setInteger("TargetX", this.posTarget.x);
nbt.setInteger("TargetY", this.posTarget.y);
nbt.setInteger("TargetZ", this.posTarget.z);
}
if (this.waypointBase != null)
{
nbt.setInteger("WBaseX", this.waypointBase.x);
nbt.setInteger("WBaseY", this.waypointBase.y);
nbt.setInteger("WBaseZ", this.waypointBase.z);
}
nbt.setInteger("BaseFacing", this.baseFacing.getIndex());
nbt.setInteger("AIState", this.AIstate);
nbt.setInteger("Facing", this.facingAI.getIndex());
if (this.wayPoints.size() > 0)
{
NBTTagList wpList = new NBTTagList();
for (int j = 0; j < this.wayPoints.size(); j++)
{
wpList.appendTag(this.wayPoints.get(j).writeToNBT(new NBTTagCompound()));
}
nbt.setTag("WayPoints", wpList);
}
if (this.minePoints.size() > 0)
{
NBTTagList mpList = new NBTTagList();
for (int j = 0; j < this.minePoints.size(); j++)
{
mpList.appendTag(this.minePoints.get(j).writeToNBT(new NBTTagCompound()));
}
nbt.setTag("MinePoints", mpList);
}
if (this.minePointCurrent != null)
{
nbt.setTag("MinePointCurrent", this.minePointCurrent.writeToNBT(new NBTTagCompound()));
}
if (this.playerUUID != null)
{
nbt.setLong("playerUUIDMost", this.playerUUID.getMostSignificantBits());
nbt.setLong("playerUUIDLeast", this.playerUUID.getLeastSignificantBits());
}
nbt.setDouble("speedup", this.speedup);
nbt.setInteger("pathBlockedCount", this.pathBlockedCount);
nbt.setBoolean("spawnedInCreative", this.spawnedInCreative);
}
}