BloodMagic/src/main/java/WayofTime/bloodmagic/alchemyArray/AlchemyArrayEffectAttractor.java

492 lines
14 KiB
Java

package WayofTime.bloodmagic.alchemyArray;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.ai.EntityAIBase;
import net.minecraft.entity.ai.EntityAITasks;
import net.minecraft.entity.ai.EntityAITasks.EntityAITaskEntry;
import net.minecraft.entity.monster.EntityBlaze;
import net.minecraft.entity.monster.EntityEnderman;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.entity.monster.EntityPigZombie;
import net.minecraft.entity.monster.EntitySilverfish;
import net.minecraft.entity.monster.EntitySlime;
import net.minecraft.entity.monster.EntitySpider;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.pathfinding.Path;
import net.minecraft.pathfinding.PathFinder;
import net.minecraft.pathfinding.WalkNodeProcessor;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
import net.minecraftforge.common.util.FakePlayer;
import WayofTime.bloodmagic.api.Constants;
import WayofTime.bloodmagic.api.alchemyCrafting.AlchemyArrayEffect;
import WayofTime.bloodmagic.fakePlayer.FakePlayerBM;
import WayofTime.bloodmagic.tile.TileAlchemyArray;
import com.mojang.authlib.GameProfile;
/**
* Credits for the initial code go to Crazy Pants of EIO.
*/
public class AlchemyArrayEffectAttractor extends AlchemyArrayEffect
{
private FakePlayer target;
private Set<EntityLiving> tracking = new HashSet<EntityLiving>();
private int counter = 0;
private int maxMobsAttracted = 10000;
private int cooldown = 50;
public AlchemyArrayEffectAttractor(String key)
{
super(key);
}
@Override
public boolean update(TileEntity tile, int ticksActive)
{
BlockPos pos = tile.getPos();
counter++;
if (counter < 10)
{
Iterator<EntityLiving> itr = tracking.iterator();
while (itr.hasNext())
{
EntityLiving ent = itr.next();
onEntityTick(pos, ent);
}
return false;
}
counter = 0;
World world = tile.getWorld();
Set<EntityLiving> trackingThisTick = new HashSet<EntityLiving>();
List<EntityLiving> entsInBounds = world.getEntitiesWithinAABB(EntityLiving.class, getBounds(pos));
for (EntityLiving ent : entsInBounds)
{
if (!ent.isDead)// && isMobInFilter(ent))
{
double x = (pos.getX() + 0.5D - ent.posX);
double y = (pos.getY() + 1D - ent.posY);
double z = (pos.getZ() + 0.5D - ent.posZ);
double distance = Math.sqrt(x * x + y * y + z * z);
if (distance < 2 && tracking.contains(ent))
{
setEntityCooldown(pos, ent, cooldown);
removeAssignedAITask(pos, ent);
continue;
}
if (!canEntityBeTracked(pos, ent))
{
// System.out.println("Cooldown: " + getEntityCooldown(pos, ent));
decrementEntityCooldown(pos, ent);
continue;
}
if (tracking.contains(ent))
{
trackingThisTick.add(ent);
onEntityTick(pos, ent);
} else if (tracking.size() < maxMobsAttracted && trackMob(pos, ent))
{
trackingThisTick.add(ent);
onTracked(ent);
}
}
}
for (EntityLiving e : tracking)
{
if (!trackingThisTick.contains(e))
{
onUntracked(e);
}
}
tracking.clear();
tracking = trackingThisTick;
return false;
}
public boolean canEntityBeTracked(BlockPos pos, EntityLiving entity)
{
return getEntityCooldown(pos, entity) <= 0;
}
private String getPosKey(BlockPos pos)
{
return "BMAttractor:" + pos;
}
public int getEntityCooldown(BlockPos pos, EntityLiving entity)
{
return entity.getEntityData().getInteger(getPosKey(pos));
}
public void setEntityCooldown(BlockPos pos, EntityLiving entity, int cooldown)
{
entity.getEntityData().setInteger(getPosKey(pos), cooldown);
}
public void decrementEntityCooldown(BlockPos pos, EntityLiving entity)
{
int cooldown = getEntityCooldown(pos, entity);
if (cooldown > 0)
{
setEntityCooldown(pos, entity, cooldown - 1);
}
}
public AxisAlignedBB getBounds(BlockPos pos)
{
return new AxisAlignedBB(pos).expand(getRange(), getRange(), getRange());
}
public float getRange()
{
return 10;
}
private void onUntracked(EntityLiving e)
{
if (e instanceof EntityEnderman)
{
e.getEntityData().setBoolean("BM:tracked", false);
}
}
private void onTracked(EntityLiving e)
{
if (e instanceof EntityEnderman)
{
e.getEntityData().setBoolean("BM:tracked", true);
}
}
private void onEntityTick(BlockPos pos, EntityLiving ent)
{
if (ent instanceof EntitySlime)
{
ent.faceEntity(getTarget(ent.worldObj, pos), 10.0F, 20.0F);
} else if (ent instanceof EntitySilverfish)
{
if (counter < 10)
{
return;
}
EntitySilverfish sf = (EntitySilverfish) ent;
Path pathentity = getPathEntityToEntity(ent, getTarget(ent.worldObj, pos), getRange());
sf.getNavigator().setPath(pathentity, sf.getAIMoveSpeed());
} else if (ent instanceof EntityBlaze)
{
double x = (pos.getX() + 0.5D - ent.posX);
double y = (pos.getY() + 1D - ent.posY);
double z = (pos.getZ() + 0.5D - ent.posZ);
double distance = Math.sqrt(x * x + y * y + z * z);
if (distance > 1.25)
{
double speed = 0.01;
ent.motionX += x / distance * speed;
if (y > 0)
{
ent.motionY += (0.3 - ent.motionY) * 0.3;
}
ent.motionZ += z / distance * speed;
}
} else if (ent instanceof EntityPigZombie || ent instanceof EntitySpider)
{
forceMove(pos, ent);
// ent.setAttackTarget(target);
} else if (ent instanceof EntityEnderman)
{
((EntityEnderman) ent).setAttackTarget(getTarget(ent.worldObj, pos));
}
}
private void forceMove(BlockPos pos, EntityLiving ent)
{
double x = (pos.getX() + 0.5D - ent.posX);
double y = (pos.getY() + 1D - ent.posY);
double z = (pos.getZ() + 0.5D - ent.posZ);
double distance = Math.sqrt(x * x + y * y + z * z);
if (distance > 2)
{
EntityMob mod = (EntityMob) ent;
mod.faceEntity(getTarget(ent.worldObj, pos), 180, 0);
mod.moveEntityWithHeading(0, 0.3f);
if (mod.posY < pos.getY())
{
mod.setJumping(true);
} else
{
mod.setJumping(false);
}
}
}
public Path getPathEntityToEntity(Entity entity, Entity targetEntity, float range)
{
int targX = MathHelper.floor_double(targetEntity.posX);
int targY = MathHelper.floor_double(targetEntity.posY + 1.0D);
int targZ = MathHelper.floor_double(targetEntity.posZ);
PathFinder pf = new PathFinder(new WalkNodeProcessor());
return pf.findPath(targetEntity.worldObj, (EntityLiving) entity, new BlockPos(targX, targY, targZ), range);
}
private boolean trackMob(BlockPos pos, EntityLiving ent)
{
//TODO: Figure out if this crud is needed
if (useSetTarget(ent))
{
((EntityMob) ent).setAttackTarget(getTarget(ent.worldObj, pos));
return true;
} else if (useSpecialCase(ent))
{
return applySpecialCase(pos, ent);
} else
{
return attractUsingAITask(pos, ent);
}
}
private boolean useSetTarget(EntityLiving ent)
{
return ent instanceof EntityPigZombie || ent instanceof EntitySpider || ent instanceof EntitySilverfish;
}
public void removeAssignedAITask(BlockPos pos, EntityLiving ent)
{
Set<EntityAITaskEntry> entries = ent.tasks.taskEntries;
EntityAIBase remove = null;
for (EntityAITaskEntry entry : entries)
{
if (entry.action instanceof AttractTask)
{
AttractTask at = (AttractTask) entry.action;
if (at.coord.equals(pos))
{
remove = entry.action;
} else
{
continue;
}
}
}
if (remove != null)
{
ent.tasks.removeTask(remove);
}
}
private boolean attractUsingAITask(BlockPos pos, EntityLiving ent)
{
tracking.add(ent);
Set<EntityAITaskEntry> entries = ent.tasks.taskEntries;
// boolean hasTask = false;
EntityAIBase remove = null;
// boolean isTracked;
for (EntityAITaskEntry entry : entries)
{
if (entry.action instanceof AttractTask)
{
AttractTask at = (AttractTask) entry.action;
if (at.coord.equals(pos) || !at.continueExecuting())
{
remove = entry.action;
} else
{
return false;
}
}
}
if (remove != null)
{
ent.tasks.removeTask(remove);
}
cancelCurrentTasks(ent);
ent.tasks.addTask(0, new AttractTask(ent, getTarget(ent.worldObj, pos), pos));
return true;
}
private void cancelCurrentTasks(EntityLiving ent)
{
Iterator<EntityAITaskEntry> iterator = ent.tasks.taskEntries.iterator();
List<EntityAITasks.EntityAITaskEntry> currentTasks = new ArrayList<EntityAITasks.EntityAITaskEntry>();
while (iterator.hasNext())
{
EntityAITaskEntry entityaitaskentry = iterator.next();
if (entityaitaskentry != null)
{
if (entityaitaskentry.action instanceof AttractTask)
{
continue;
}
currentTasks.add(entityaitaskentry);
}
}
// Only available way to stop current execution is to remove all current
// tasks, then re-add them
for (EntityAITaskEntry task : currentTasks)
{
ent.tasks.removeTask(task.action);
ent.tasks.addTask(task.priority, task.action);
}
}
private boolean applySpecialCase(BlockPos pos, EntityLiving ent)
{
if (ent instanceof EntitySlime)
{
ent.faceEntity(getTarget(ent.worldObj, pos), 10.0F, 20.0F);
// ent.setAttackTarget(getTarget(ent.worldObj, pos));
return true;
} else if (ent instanceof EntitySilverfish)
{
EntitySilverfish es = (EntitySilverfish) ent;
Path pathentity = getPathEntityToEntity(ent, getTarget(ent.worldObj, pos), getRange());
es.getNavigator().setPath(pathentity, es.getAIMoveSpeed());
return true;
} else if (ent instanceof EntityBlaze)
{
return true;
}
return false;
}
private boolean useSpecialCase(EntityLiving ent)
{
return ent instanceof EntitySlime || ent instanceof EntitySilverfish || ent instanceof EntityBlaze;
}
public FakePlayer getTarget(World world, BlockPos pos)
{
if (target == null)
{
// System.out.println("...Hi? " + pos);
target = new Target(world, pos);
}
return target;
}
private class Target extends FakePlayerBM
{
public Target(World world, BlockPos pos)
{
super(world, pos, new GameProfile(null, Constants.Mod.MODID + "ArrayAttractor" + ":" + pos));
posY += 1;
}
}
private static class AttractTask extends EntityAIBase
{
private EntityLiving mob;
private BlockPos coord;
private FakePlayer target;
private int updatesSincePathing;
private boolean started = false;
private AttractTask(EntityLiving mob, FakePlayer target, BlockPos coord)
{
this.mob = mob;
this.coord = coord;
this.target = target;
}
@Override
public boolean shouldExecute()
{
return continueExecuting();
}
@Override
public void resetTask()
{
started = false;
updatesSincePathing = 0;
}
@Override
public boolean continueExecuting()
{
boolean res = false;
//TODO:
TileEntity te = mob.worldObj.getTileEntity(coord);
if (te instanceof TileAlchemyArray)
{
res = true;
}
return res;
}
@Override
public boolean isInterruptible()
{
return true;
}
@Override
public void updateTask()
{
if (!started || updatesSincePathing > 20)
{
started = true;
int speed = 1;
// mob.getNavigator().setAvoidsWater(false);
boolean res = mob.getNavigator().tryMoveToEntityLiving(target, speed);
if (!res)
{
mob.getNavigator().tryMoveToXYZ(target.posX, target.posY + 1, target.posZ, speed);
}
updatesSincePathing = 0;
} else
{
updatesSincePathing++;
}
}
}
@Override
public void writeToNBT(NBTTagCompound tag)
{
}
@Override
public void readFromNBT(NBTTagCompound tag)
{
}
@Override
public AlchemyArrayEffect getNewCopy()
{
return new AlchemyArrayEffectAttractor(key);
}
}