base mod created

This commit is contained in:
Mohammad-Ali Minaie
2018-10-08 09:07:47 -04:00
parent 0a7700c356
commit b86dedad2f
7848 changed files with 584664 additions and 1 deletions

View File

@@ -0,0 +1,205 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.pathfinding.Path;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class EntityAIAttackMelee extends EntityAIBase
{
World world;
protected EntityCreature attacker;
/** An amount of decrementing ticks that allows the entity to attack once the tick reaches 0. */
protected int attackTick;
/** The speed with which the mob will approach the target */
double speedTowardsTarget;
/** When true, the mob will continue chasing its target, even if it can't find a path to them right now. */
boolean longMemory;
/** The PathEntity of our entity. */
Path path;
private int delayCounter;
private double targetX;
private double targetY;
private double targetZ;
protected final int attackInterval = 20;
private int failedPathFindingPenalty = 0;
private boolean canPenalize = false;
public EntityAIAttackMelee(EntityCreature creature, double speedIn, boolean useLongMemory)
{
this.attacker = creature;
this.world = creature.world;
this.speedTowardsTarget = speedIn;
this.longMemory = useLongMemory;
this.setMutexBits(3);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
EntityLivingBase entitylivingbase = this.attacker.getAttackTarget();
if (entitylivingbase == null)
{
return false;
}
else if (!entitylivingbase.isEntityAlive())
{
return false;
}
else
{
if (canPenalize)
{
if (--this.delayCounter <= 0)
{
this.path = this.attacker.getNavigator().getPathToEntityLiving(entitylivingbase);
this.delayCounter = 4 + this.attacker.getRNG().nextInt(7);
return this.path != null;
}
else
{
return true;
}
}
this.path = this.attacker.getNavigator().getPathToEntityLiving(entitylivingbase);
if (this.path != null)
{
return true;
}
else
{
return this.getAttackReachSqr(entitylivingbase) >= this.attacker.getDistanceSq(entitylivingbase.posX, entitylivingbase.getEntityBoundingBox().minY, entitylivingbase.posZ);
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
EntityLivingBase entitylivingbase = this.attacker.getAttackTarget();
if (entitylivingbase == null)
{
return false;
}
else if (!entitylivingbase.isEntityAlive())
{
return false;
}
else if (!this.longMemory)
{
return !this.attacker.getNavigator().noPath();
}
else if (!this.attacker.isWithinHomeDistanceFromPosition(new BlockPos(entitylivingbase)))
{
return false;
}
else
{
return !(entitylivingbase instanceof EntityPlayer) || !((EntityPlayer)entitylivingbase).isSpectator() && !((EntityPlayer)entitylivingbase).isCreative();
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.attacker.getNavigator().setPath(this.path, this.speedTowardsTarget);
this.delayCounter = 0;
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
EntityLivingBase entitylivingbase = this.attacker.getAttackTarget();
if (entitylivingbase instanceof EntityPlayer && (((EntityPlayer)entitylivingbase).isSpectator() || ((EntityPlayer)entitylivingbase).isCreative()))
{
this.attacker.setAttackTarget((EntityLivingBase)null);
}
this.attacker.getNavigator().clearPath();
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
EntityLivingBase entitylivingbase = this.attacker.getAttackTarget();
this.attacker.getLookHelper().setLookPositionWithEntity(entitylivingbase, 30.0F, 30.0F);
double d0 = this.attacker.getDistanceSq(entitylivingbase.posX, entitylivingbase.getEntityBoundingBox().minY, entitylivingbase.posZ);
--this.delayCounter;
if ((this.longMemory || this.attacker.getEntitySenses().canSee(entitylivingbase)) && this.delayCounter <= 0 && (this.targetX == 0.0D && this.targetY == 0.0D && this.targetZ == 0.0D || entitylivingbase.getDistanceSq(this.targetX, this.targetY, this.targetZ) >= 1.0D || this.attacker.getRNG().nextFloat() < 0.05F))
{
this.targetX = entitylivingbase.posX;
this.targetY = entitylivingbase.getEntityBoundingBox().minY;
this.targetZ = entitylivingbase.posZ;
this.delayCounter = 4 + this.attacker.getRNG().nextInt(7);
if (this.canPenalize)
{
this.delayCounter += failedPathFindingPenalty;
if (this.attacker.getNavigator().getPath() != null)
{
net.minecraft.pathfinding.PathPoint finalPathPoint = this.attacker.getNavigator().getPath().getFinalPathPoint();
if (finalPathPoint != null && entitylivingbase.getDistanceSq(finalPathPoint.x, finalPathPoint.y, finalPathPoint.z) < 1)
failedPathFindingPenalty = 0;
else
failedPathFindingPenalty += 10;
}
else
{
failedPathFindingPenalty += 10;
}
}
if (d0 > 1024.0D)
{
this.delayCounter += 10;
}
else if (d0 > 256.0D)
{
this.delayCounter += 5;
}
if (!this.attacker.getNavigator().tryMoveToEntityLiving(entitylivingbase, this.speedTowardsTarget))
{
this.delayCounter += 15;
}
}
this.attackTick = Math.max(this.attackTick - 1, 0);
this.checkAndPerformAttack(entitylivingbase, d0);
}
protected void checkAndPerformAttack(EntityLivingBase p_190102_1_, double p_190102_2_)
{
double d0 = this.getAttackReachSqr(p_190102_1_);
if (p_190102_2_ <= d0 && this.attackTick <= 0)
{
this.attackTick = 20;
this.attacker.swingArm(EnumHand.MAIN_HAND);
this.attacker.attackEntityAsMob(p_190102_1_);
}
}
protected double getAttackReachSqr(EntityLivingBase attackTarget)
{
return (double)(this.attacker.width * 2.0F * this.attacker.width * 2.0F + attackTarget.width);
}
}

View File

@@ -0,0 +1,136 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IRangedAttackMob;
import net.minecraft.util.math.MathHelper;
public class EntityAIAttackRanged extends EntityAIBase
{
/** The entity the AI instance has been applied to */
private final EntityLiving entityHost;
/** The entity (as a RangedAttackMob) the AI instance has been applied to. */
private final IRangedAttackMob rangedAttackEntityHost;
private EntityLivingBase attackTarget;
/**
* A decrementing tick that spawns a ranged attack once this value reaches 0. It is then set back to the
* maxRangedAttackTime.
*/
private int rangedAttackTime;
private final double entityMoveSpeed;
private int seeTime;
private final int attackIntervalMin;
/** The maximum time the AI has to wait before peforming another ranged attack. */
private final int maxRangedAttackTime;
private final float attackRadius;
private final float maxAttackDistance;
public EntityAIAttackRanged(IRangedAttackMob attacker, double movespeed, int maxAttackTime, float maxAttackDistanceIn)
{
this(attacker, movespeed, maxAttackTime, maxAttackTime, maxAttackDistanceIn);
}
public EntityAIAttackRanged(IRangedAttackMob attacker, double movespeed, int p_i1650_4_, int maxAttackTime, float maxAttackDistanceIn)
{
this.rangedAttackTime = -1;
if (!(attacker instanceof EntityLivingBase))
{
throw new IllegalArgumentException("ArrowAttackGoal requires Mob implements RangedAttackMob");
}
else
{
this.rangedAttackEntityHost = attacker;
this.entityHost = (EntityLiving)attacker;
this.entityMoveSpeed = movespeed;
this.attackIntervalMin = p_i1650_4_;
this.maxRangedAttackTime = maxAttackTime;
this.attackRadius = maxAttackDistanceIn;
this.maxAttackDistance = maxAttackDistanceIn * maxAttackDistanceIn;
this.setMutexBits(3);
}
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
EntityLivingBase entitylivingbase = this.entityHost.getAttackTarget();
if (entitylivingbase == null)
{
return false;
}
else
{
this.attackTarget = entitylivingbase;
return true;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.shouldExecute() || !this.entityHost.getNavigator().noPath();
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.attackTarget = null;
this.seeTime = 0;
this.rangedAttackTime = -1;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
double d0 = this.entityHost.getDistanceSq(this.attackTarget.posX, this.attackTarget.getEntityBoundingBox().minY, this.attackTarget.posZ);
boolean flag = this.entityHost.getEntitySenses().canSee(this.attackTarget);
if (flag)
{
++this.seeTime;
}
else
{
this.seeTime = 0;
}
if (d0 <= (double)this.maxAttackDistance && this.seeTime >= 20)
{
this.entityHost.getNavigator().clearPath();
}
else
{
this.entityHost.getNavigator().tryMoveToEntityLiving(this.attackTarget, this.entityMoveSpeed);
}
this.entityHost.getLookHelper().setLookPositionWithEntity(this.attackTarget, 30.0F, 30.0F);
if (--this.rangedAttackTime == 0)
{
if (!flag)
{
return;
}
float f = MathHelper.sqrt(d0) / this.attackRadius;
float lvt_5_1_ = MathHelper.clamp(f, 0.1F, 1.0F);
this.rangedAttackEntityHost.attackEntityWithRangedAttack(this.attackTarget, lvt_5_1_);
this.rangedAttackTime = MathHelper.floor(f * (float)(this.maxRangedAttackTime - this.attackIntervalMin) + (float)this.attackIntervalMin);
}
else if (this.rangedAttackTime < 0)
{
float f2 = MathHelper.sqrt(d0) / this.attackRadius;
this.rangedAttackTime = MathHelper.floor(f2 * (float)(this.maxRangedAttackTime - this.attackIntervalMin) + (float)this.attackIntervalMin);
}
}
}

View File

@@ -0,0 +1,174 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IRangedAttackMob;
import net.minecraft.entity.monster.EntityMob;
import net.minecraft.init.Items;
import net.minecraft.item.ItemBow;
import net.minecraft.util.EnumHand;
public class EntityAIAttackRangedBow<T extends EntityMob & IRangedAttackMob> extends EntityAIBase
{
private final T entity;
private final double moveSpeedAmp;
private int attackCooldown;
private final float maxAttackDistance;
private int attackTime = -1;
private int seeTime;
private boolean strafingClockwise;
private boolean strafingBackwards;
private int strafingTime = -1;
public EntityAIAttackRangedBow(T p_i47515_1_, double p_i47515_2_, int p_i47515_4_, float p_i47515_5_)
{
this.entity = p_i47515_1_;
this.moveSpeedAmp = p_i47515_2_;
this.attackCooldown = p_i47515_4_;
this.maxAttackDistance = p_i47515_5_ * p_i47515_5_;
this.setMutexBits(3);
}
public void setAttackCooldown(int p_189428_1_)
{
this.attackCooldown = p_189428_1_;
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
return this.entity.getAttackTarget() == null ? false : this.isBowInMainhand();
}
protected boolean isBowInMainhand()
{
return !this.entity.getHeldItemMainhand().isEmpty() && this.entity.getHeldItemMainhand().getItem() == Items.BOW;
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return (this.shouldExecute() || !this.entity.getNavigator().noPath()) && this.isBowInMainhand();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
super.startExecuting();
((IRangedAttackMob)this.entity).setSwingingArms(true);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
super.resetTask();
((IRangedAttackMob)this.entity).setSwingingArms(false);
this.seeTime = 0;
this.attackTime = -1;
this.entity.resetActiveHand();
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
EntityLivingBase entitylivingbase = this.entity.getAttackTarget();
if (entitylivingbase != null)
{
double d0 = this.entity.getDistanceSq(entitylivingbase.posX, entitylivingbase.getEntityBoundingBox().minY, entitylivingbase.posZ);
boolean flag = this.entity.getEntitySenses().canSee(entitylivingbase);
boolean flag1 = this.seeTime > 0;
if (flag != flag1)
{
this.seeTime = 0;
}
if (flag)
{
++this.seeTime;
}
else
{
--this.seeTime;
}
if (d0 <= (double)this.maxAttackDistance && this.seeTime >= 20)
{
this.entity.getNavigator().clearPath();
++this.strafingTime;
}
else
{
this.entity.getNavigator().tryMoveToEntityLiving(entitylivingbase, this.moveSpeedAmp);
this.strafingTime = -1;
}
if (this.strafingTime >= 20)
{
if ((double)this.entity.getRNG().nextFloat() < 0.3D)
{
this.strafingClockwise = !this.strafingClockwise;
}
if ((double)this.entity.getRNG().nextFloat() < 0.3D)
{
this.strafingBackwards = !this.strafingBackwards;
}
this.strafingTime = 0;
}
if (this.strafingTime > -1)
{
if (d0 > (double)(this.maxAttackDistance * 0.75F))
{
this.strafingBackwards = false;
}
else if (d0 < (double)(this.maxAttackDistance * 0.25F))
{
this.strafingBackwards = true;
}
this.entity.getMoveHelper().strafe(this.strafingBackwards ? -0.5F : 0.5F, this.strafingClockwise ? 0.5F : -0.5F);
this.entity.faceEntity(entitylivingbase, 30.0F, 30.0F);
}
else
{
this.entity.getLookHelper().setLookPositionWithEntity(entitylivingbase, 30.0F, 30.0F);
}
if (this.entity.isHandActive())
{
if (!flag && this.seeTime < -60)
{
this.entity.resetActiveHand();
}
else if (flag)
{
int i = this.entity.getItemInUseMaxCount();
if (i >= 20)
{
this.entity.resetActiveHand();
((IRangedAttackMob)this.entity).attackEntityWithRangedAttack(entitylivingbase, ItemBow.getArrowVelocity(i));
this.attackTime = this.attackCooldown;
}
}
}
else if (--this.attackTime <= 0 && this.seeTime >= -60)
{
this.entity.setActiveHand(EnumHand.MAIN_HAND);
}
}
}
}

View File

@@ -0,0 +1,125 @@
package net.minecraft.entity.ai;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature;
import net.minecraft.pathfinding.Path;
import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.util.EntitySelectors;
import net.minecraft.util.math.Vec3d;
public class EntityAIAvoidEntity<T extends Entity> extends EntityAIBase
{
private final Predicate<Entity> canBeSeenSelector;
/** The entity we are attached to */
protected EntityCreature entity;
private final double farSpeed;
private final double nearSpeed;
protected T closestLivingEntity;
private final float avoidDistance;
/** The PathEntity of our entity */
private Path path;
/** The PathNavigate of our entity */
private final PathNavigate navigation;
/** Class of entity this behavior seeks to avoid */
private final Class<T> classToAvoid;
private final Predicate <? super T > avoidTargetSelector;
public EntityAIAvoidEntity(EntityCreature entityIn, Class<T> classToAvoidIn, float avoidDistanceIn, double farSpeedIn, double nearSpeedIn)
{
this(entityIn, classToAvoidIn, Predicates.alwaysTrue(), avoidDistanceIn, farSpeedIn, nearSpeedIn);
}
public EntityAIAvoidEntity(EntityCreature entityIn, Class<T> classToAvoidIn, Predicate <? super T > avoidTargetSelectorIn, float avoidDistanceIn, double farSpeedIn, double nearSpeedIn)
{
this.canBeSeenSelector = new Predicate<Entity>()
{
public boolean apply(@Nullable Entity p_apply_1_)
{
return p_apply_1_.isEntityAlive() && EntityAIAvoidEntity.this.entity.getEntitySenses().canSee(p_apply_1_) && !EntityAIAvoidEntity.this.entity.isOnSameTeam(p_apply_1_);
}
};
this.entity = entityIn;
this.classToAvoid = classToAvoidIn;
this.avoidTargetSelector = avoidTargetSelectorIn;
this.avoidDistance = avoidDistanceIn;
this.farSpeed = farSpeedIn;
this.nearSpeed = nearSpeedIn;
this.navigation = entityIn.getNavigator();
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
List<T> list = this.entity.world.<T>getEntitiesWithinAABB(this.classToAvoid, this.entity.getEntityBoundingBox().grow((double)this.avoidDistance, 3.0D, (double)this.avoidDistance), Predicates.and(EntitySelectors.CAN_AI_TARGET, this.canBeSeenSelector, this.avoidTargetSelector));
if (list.isEmpty())
{
return false;
}
else
{
this.closestLivingEntity = list.get(0);
Vec3d vec3d = RandomPositionGenerator.findRandomTargetBlockAwayFrom(this.entity, 16, 7, new Vec3d(this.closestLivingEntity.posX, this.closestLivingEntity.posY, this.closestLivingEntity.posZ));
if (vec3d == null)
{
return false;
}
else if (this.closestLivingEntity.getDistanceSq(vec3d.x, vec3d.y, vec3d.z) < this.closestLivingEntity.getDistanceSq(this.entity))
{
return false;
}
else
{
this.path = this.navigation.getPathToXYZ(vec3d.x, vec3d.y, vec3d.z);
return this.path != null;
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.navigation.noPath();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.navigation.setPath(this.path, this.farSpeed);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.closestLivingEntity = null;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
if (this.entity.getDistanceSq(this.closestLivingEntity) < 49.0D)
{
this.entity.getNavigator().setSpeed(this.nearSpeed);
}
else
{
this.entity.getNavigator().setSpeed(this.farSpeed);
}
}
}

View File

@@ -0,0 +1,72 @@
package net.minecraft.entity.ai;
public abstract class EntityAIBase
{
/**
* A bitmask telling which other tasks may not run concurrently. The test is a simple bitwise AND - if it yields
* zero, the two tasks may run concurrently, if not - they must run exclusively from each other.
*/
private int mutexBits;
/**
* Returns whether the EntityAIBase should begin execution.
*/
public abstract boolean shouldExecute();
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.shouldExecute();
}
/**
* Determine if this AI Task is interruptible by a higher (= lower value) priority task. All vanilla AITask have
* this value set to true.
*/
public boolean isInterruptible()
{
return true;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
}
/**
* Sets the mutex bitflags, see getMutexBits. Flag 1 for motion, flag 2 for look/head movement, flag 4 for
* swimming/misc. Flags can be OR'ed.
*/
public void setMutexBits(int mutexBitsIn)
{
this.mutexBits = mutexBitsIn;
}
/**
* Get what actions this task will take that may potentially conflict with other tasks. The test is a simple bitwise
* AND - if it yields zero, the two tasks may run concurrently, if not - they must run exclusively from each other.
* See setMutextBits.
*/
public int getMutexBits()
{
return this.mutexBits;
}
}

View File

@@ -0,0 +1,103 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.passive.EntityWolf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumHand;
import net.minecraft.world.World;
public class EntityAIBeg extends EntityAIBase
{
private final EntityWolf wolf;
private EntityPlayer player;
private final World world;
private final float minPlayerDistance;
private int timeoutCounter;
public EntityAIBeg(EntityWolf wolf, float minDistance)
{
this.wolf = wolf;
this.world = wolf.world;
this.minPlayerDistance = minDistance;
this.setMutexBits(2);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
this.player = this.world.getClosestPlayerToEntity(this.wolf, (double)this.minPlayerDistance);
return this.player == null ? false : this.hasTemptationItemInHand(this.player);
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
if (!this.player.isEntityAlive())
{
return false;
}
else if (this.wolf.getDistanceSq(this.player) > (double)(this.minPlayerDistance * this.minPlayerDistance))
{
return false;
}
else
{
return this.timeoutCounter > 0 && this.hasTemptationItemInHand(this.player);
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.wolf.setBegging(true);
this.timeoutCounter = 40 + this.wolf.getRNG().nextInt(40);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.wolf.setBegging(false);
this.player = null;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
this.wolf.getLookHelper().setLookPosition(this.player.posX, this.player.posY + (double)this.player.getEyeHeight(), this.player.posZ, 10.0F, (float)this.wolf.getVerticalFaceSpeed());
--this.timeoutCounter;
}
/**
* Gets if the Player has the Bone in the hand.
*/
private boolean hasTemptationItemInHand(EntityPlayer player)
{
for (EnumHand enumhand : EnumHand.values())
{
ItemStack itemstack = player.getHeldItem(enumhand);
if (this.wolf.isTamed() && itemstack.getItem() == Items.BONE)
{
return true;
}
if (this.wolf.isBreedingItem(itemstack))
{
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,107 @@
package net.minecraft.entity.ai;
import net.minecraft.block.Block;
import net.minecraft.block.BlockDoor;
import net.minecraft.entity.EntityLiving;
import net.minecraft.world.EnumDifficulty;
public class EntityAIBreakDoor extends EntityAIDoorInteract
{
private int breakingTime;
private int previousBreakProgress = -1;
public EntityAIBreakDoor(EntityLiving entityIn)
{
super(entityIn);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!super.shouldExecute())
{
return false;
}
else if (!net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.entity.world, this.entity) || !this.entity.world.getBlockState(this.doorPosition).getBlock().canEntityDestroy(this.entity.world.getBlockState(this.doorPosition), this.entity.world, this.doorPosition, this.entity) || !net.minecraftforge.event.ForgeEventFactory.onEntityDestroyBlock(this.entity, this.doorPosition, this.entity.world.getBlockState(this.doorPosition)))
{
return false;
}
else
{
BlockDoor blockdoor = this.doorBlock;
return !BlockDoor.isOpen(this.entity.world, this.doorPosition);
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
super.startExecuting();
this.breakingTime = 0;
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
double d0 = this.entity.getDistanceSq(this.doorPosition);
boolean flag;
if (this.breakingTime <= 240)
{
BlockDoor blockdoor = this.doorBlock;
if (!BlockDoor.isOpen(this.entity.world, this.doorPosition) && d0 < 4.0D)
{
flag = true;
return flag;
}
}
flag = false;
return flag;
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
super.resetTask();
this.entity.world.sendBlockBreakProgress(this.entity.getEntityId(), this.doorPosition, -1);
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
super.updateTask();
if (this.entity.getRNG().nextInt(20) == 0)
{
this.entity.world.playEvent(1019, this.doorPosition, 0);
}
++this.breakingTime;
int i = (int)((float)this.breakingTime / 240.0F * 10.0F);
if (i != this.previousBreakProgress)
{
this.entity.world.sendBlockBreakProgress(this.entity.getEntityId(), this.doorPosition, i);
this.previousBreakProgress = i;
}
if (this.breakingTime == 240 && this.entity.world.getDifficulty() == EnumDifficulty.HARD)
{
this.entity.world.setBlockToAir(this.doorPosition);
this.entity.world.playEvent(1021, this.doorPosition, 0);
this.entity.world.playEvent(2001, this.doorPosition, Block.getIdFromBlock(this.doorBlock));
}
}
}

View File

@@ -0,0 +1,67 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityCreeper;
public class EntityAICreeperSwell extends EntityAIBase
{
/** The creeper that is swelling. */
EntityCreeper swellingCreeper;
/** The creeper's attack target. This is used for the changing of the creeper's state. */
EntityLivingBase creeperAttackTarget;
public EntityAICreeperSwell(EntityCreeper entitycreeperIn)
{
this.swellingCreeper = entitycreeperIn;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
EntityLivingBase entitylivingbase = this.swellingCreeper.getAttackTarget();
return this.swellingCreeper.getCreeperState() > 0 || entitylivingbase != null && this.swellingCreeper.getDistanceSq(entitylivingbase) < 9.0D;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.swellingCreeper.getNavigator().clearPath();
this.creeperAttackTarget = this.swellingCreeper.getAttackTarget();
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.creeperAttackTarget = null;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
if (this.creeperAttackTarget == null)
{
this.swellingCreeper.setCreeperState(-1);
}
else if (this.swellingCreeper.getDistanceSq(this.creeperAttackTarget) > 49.0D)
{
this.swellingCreeper.setCreeperState(-1);
}
else if (!this.swellingCreeper.getEntitySenses().canSee(this.creeperAttackTarget))
{
this.swellingCreeper.setCreeperState(-1);
}
else
{
this.swellingCreeper.setCreeperState(1);
}
}
}

View File

@@ -0,0 +1,64 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.village.Village;
public class EntityAIDefendVillage extends EntityAITarget
{
EntityIronGolem irongolem;
/** The aggressor of the iron golem's village which is now the golem's attack target. */
EntityLivingBase villageAgressorTarget;
public EntityAIDefendVillage(EntityIronGolem ironGolemIn)
{
super(ironGolemIn, false, true);
this.irongolem = ironGolemIn;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
Village village = this.irongolem.getVillage();
if (village == null)
{
return false;
}
else
{
this.villageAgressorTarget = village.findNearestVillageAggressor(this.irongolem);
if (this.villageAgressorTarget instanceof EntityCreeper)
{
return false;
}
else if (this.isSuitableTarget(this.villageAgressorTarget, false))
{
return true;
}
else if (this.taskOwner.getRNG().nextInt(20) == 0)
{
this.villageAgressorTarget = village.getNearestTargetPlayer(this.irongolem);
return this.isSuitableTarget(this.villageAgressorTarget, false);
}
else
{
return false;
}
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.irongolem.setAttackTarget(this.villageAgressorTarget);
super.startExecuting();
}
}

View File

@@ -0,0 +1,116 @@
package net.minecraft.entity.ai;
import net.minecraft.block.Block;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLiving;
import net.minecraft.pathfinding.Path;
import net.minecraft.pathfinding.PathNavigateGround;
import net.minecraft.pathfinding.PathPoint;
import net.minecraft.util.math.BlockPos;
public abstract class EntityAIDoorInteract extends EntityAIBase
{
protected EntityLiving entity;
protected BlockPos doorPosition = BlockPos.ORIGIN;
/** The wooden door block */
protected BlockDoor doorBlock;
/** If is true then the Entity has stopped Door Interaction and compoleted the task. */
boolean hasStoppedDoorInteraction;
float entityPositionX;
float entityPositionZ;
public EntityAIDoorInteract(EntityLiving entityIn)
{
this.entity = entityIn;
if (!(entityIn.getNavigator() instanceof PathNavigateGround))
{
throw new IllegalArgumentException("Unsupported mob type for DoorInteractGoal");
}
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.entity.collidedHorizontally)
{
return false;
}
else
{
PathNavigateGround pathnavigateground = (PathNavigateGround)this.entity.getNavigator();
Path path = pathnavigateground.getPath();
if (path != null && !path.isFinished() && pathnavigateground.getEnterDoors())
{
for (int i = 0; i < Math.min(path.getCurrentPathIndex() + 2, path.getCurrentPathLength()); ++i)
{
PathPoint pathpoint = path.getPathPointFromIndex(i);
this.doorPosition = new BlockPos(pathpoint.x, pathpoint.y + 1, pathpoint.z);
if (this.entity.getDistanceSq((double)this.doorPosition.getX(), this.entity.posY, (double)this.doorPosition.getZ()) <= 2.25D)
{
this.doorBlock = this.getBlockDoor(this.doorPosition);
if (this.doorBlock != null)
{
return true;
}
}
}
this.doorPosition = (new BlockPos(this.entity)).up();
this.doorBlock = this.getBlockDoor(this.doorPosition);
return this.doorBlock != null;
}
else
{
return false;
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.hasStoppedDoorInteraction;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.hasStoppedDoorInteraction = false;
this.entityPositionX = (float)((double)((float)this.doorPosition.getX() + 0.5F) - this.entity.posX);
this.entityPositionZ = (float)((double)((float)this.doorPosition.getZ() + 0.5F) - this.entity.posZ);
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
float f = (float)((double)((float)this.doorPosition.getX() + 0.5F) - this.entity.posX);
float f1 = (float)((double)((float)this.doorPosition.getZ() + 0.5F) - this.entity.posZ);
float f2 = this.entityPositionX * f + this.entityPositionZ * f1;
if (f2 < 0.0F)
{
this.hasStoppedDoorInteraction = true;
}
}
private BlockDoor getBlockDoor(BlockPos pos)
{
IBlockState iblockstate = this.entity.world.getBlockState(pos);
Block block = iblockstate.getBlock();
return block instanceof BlockDoor && iblockstate.getMaterial() == Material.WOOD ? (BlockDoor)block : null;
}
}

View File

@@ -0,0 +1,126 @@
package net.minecraft.entity.ai;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import net.minecraft.block.Block;
import net.minecraft.block.BlockTallGrass;
import net.minecraft.block.state.IBlockState;
import net.minecraft.block.state.pattern.BlockStateMatcher;
import net.minecraft.entity.EntityLiving;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class EntityAIEatGrass extends EntityAIBase
{
private static final Predicate<IBlockState> IS_TALL_GRASS = BlockStateMatcher.forBlock(Blocks.TALLGRASS).where(BlockTallGrass.TYPE, Predicates.equalTo(BlockTallGrass.EnumType.GRASS));
/** The entity owner of this AITask */
private final EntityLiving grassEaterEntity;
/** The world the grass eater entity is eating from */
private final World entityWorld;
/** Number of ticks since the entity started to eat grass */
int eatingGrassTimer;
public EntityAIEatGrass(EntityLiving grassEaterEntityIn)
{
this.grassEaterEntity = grassEaterEntityIn;
this.entityWorld = grassEaterEntityIn.world;
this.setMutexBits(7);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.grassEaterEntity.getRNG().nextInt(this.grassEaterEntity.isChild() ? 50 : 1000) != 0)
{
return false;
}
else
{
BlockPos blockpos = new BlockPos(this.grassEaterEntity.posX, this.grassEaterEntity.posY, this.grassEaterEntity.posZ);
if (IS_TALL_GRASS.apply(this.entityWorld.getBlockState(blockpos)))
{
return true;
}
else
{
return this.entityWorld.getBlockState(blockpos.down()).getBlock() == Blocks.GRASS;
}
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.eatingGrassTimer = 40;
this.entityWorld.setEntityState(this.grassEaterEntity, (byte)10);
this.grassEaterEntity.getNavigator().clearPath();
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.eatingGrassTimer = 0;
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.eatingGrassTimer > 0;
}
/**
* Number of ticks since the entity started to eat grass
*/
public int getEatingGrassTimer()
{
return this.eatingGrassTimer;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
this.eatingGrassTimer = Math.max(0, this.eatingGrassTimer - 1);
if (this.eatingGrassTimer == 4)
{
BlockPos blockpos = new BlockPos(this.grassEaterEntity.posX, this.grassEaterEntity.posY, this.grassEaterEntity.posZ);
if (IS_TALL_GRASS.apply(this.entityWorld.getBlockState(blockpos)))
{
if (net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.entityWorld, this.grassEaterEntity))
{
this.entityWorld.destroyBlock(blockpos, false);
}
this.grassEaterEntity.eatGrassBonus();
}
else
{
BlockPos blockpos1 = blockpos.down();
if (this.entityWorld.getBlockState(blockpos1).getBlock() == Blocks.GRASS)
{
if (net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.entityWorld, this.grassEaterEntity))
{
this.entityWorld.playEvent(2001, blockpos1, Block.getIdFromBlock(Blocks.GRASS));
this.entityWorld.setBlockState(blockpos1, Blocks.DIRT.getDefaultState(), 2);
}
this.grassEaterEntity.eatGrassBonus();
}
}
}
}
}

View File

@@ -0,0 +1,132 @@
package net.minecraft.entity.ai;
import com.google.common.base.Predicate;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.IAttributeInstance;
import net.minecraft.entity.player.EntityPlayerMP;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class EntityAIFindEntityNearest extends EntityAIBase
{
private static final Logger LOGGER = LogManager.getLogger();
private final EntityLiving mob;
private final Predicate<EntityLivingBase> predicate;
private final EntityAINearestAttackableTarget.Sorter sorter;
private EntityLivingBase target;
private final Class <? extends EntityLivingBase > classToCheck;
public EntityAIFindEntityNearest(EntityLiving mobIn, Class <? extends EntityLivingBase > p_i45884_2_)
{
this.mob = mobIn;
this.classToCheck = p_i45884_2_;
if (mobIn instanceof EntityCreature)
{
LOGGER.warn("Use NearestAttackableTargetGoal.class for PathfinerMob mobs!");
}
this.predicate = new Predicate<EntityLivingBase>()
{
public boolean apply(@Nullable EntityLivingBase p_apply_1_)
{
double d0 = EntityAIFindEntityNearest.this.getFollowRange();
if (p_apply_1_.isSneaking())
{
d0 *= 0.800000011920929D;
}
if (p_apply_1_.isInvisible())
{
return false;
}
else
{
return (double)p_apply_1_.getDistance(EntityAIFindEntityNearest.this.mob) > d0 ? false : EntityAITarget.isSuitableTarget(EntityAIFindEntityNearest.this.mob, p_apply_1_, false, true);
}
}
};
this.sorter = new EntityAINearestAttackableTarget.Sorter(mobIn);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
double d0 = this.getFollowRange();
List<EntityLivingBase> list = this.mob.world.<EntityLivingBase>getEntitiesWithinAABB(this.classToCheck, this.mob.getEntityBoundingBox().grow(d0, 4.0D, d0), this.predicate);
Collections.sort(list, this.sorter);
if (list.isEmpty())
{
return false;
}
else
{
this.target = list.get(0);
return true;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
EntityLivingBase entitylivingbase = this.mob.getAttackTarget();
if (entitylivingbase == null)
{
return false;
}
else if (!entitylivingbase.isEntityAlive())
{
return false;
}
else
{
double d0 = this.getFollowRange();
if (this.mob.getDistanceSq(entitylivingbase) > d0 * d0)
{
return false;
}
else
{
return !(entitylivingbase instanceof EntityPlayerMP) || !((EntityPlayerMP)entitylivingbase).interactionManager.isCreative();
}
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.mob.setAttackTarget(this.target);
super.startExecuting();
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.mob.setAttackTarget((EntityLivingBase)null);
super.startExecuting();
}
protected double getFollowRange()
{
IAttributeInstance iattributeinstance = this.mob.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE);
return iattributeinstance == null ? 16.0D : iattributeinstance.getAttributeValue();
}
}

View File

@@ -0,0 +1,170 @@
package net.minecraft.entity.ai;
import com.google.common.base.Predicate;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.IAttributeInstance;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.scoreboard.Team;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class EntityAIFindEntityNearestPlayer extends EntityAIBase
{
private static final Logger LOGGER = LogManager.getLogger();
/** The entity that use this AI */
private final EntityLiving entityLiving;
/** Use to determine if an entity correspond to specification */
private final Predicate<Entity> predicate;
/** Used to compare two entities */
private final EntityAINearestAttackableTarget.Sorter sorter;
/** The current target */
private EntityLivingBase entityTarget;
public EntityAIFindEntityNearestPlayer(EntityLiving entityLivingIn)
{
this.entityLiving = entityLivingIn;
if (entityLivingIn instanceof EntityCreature)
{
LOGGER.warn("Use NearestAttackableTargetGoal.class for PathfinerMob mobs!");
}
this.predicate = new Predicate<Entity>()
{
public boolean apply(@Nullable Entity p_apply_1_)
{
if (!(p_apply_1_ instanceof EntityPlayer))
{
return false;
}
else if (((EntityPlayer)p_apply_1_).capabilities.disableDamage)
{
return false;
}
else
{
double d0 = EntityAIFindEntityNearestPlayer.this.maxTargetRange();
if (p_apply_1_.isSneaking())
{
d0 *= 0.800000011920929D;
}
if (p_apply_1_.isInvisible())
{
float f = ((EntityPlayer)p_apply_1_).getArmorVisibility();
if (f < 0.1F)
{
f = 0.1F;
}
d0 *= (double)(0.7F * f);
}
return (double)p_apply_1_.getDistance(EntityAIFindEntityNearestPlayer.this.entityLiving) > d0 ? false : EntityAITarget.isSuitableTarget(EntityAIFindEntityNearestPlayer.this.entityLiving, (EntityLivingBase)p_apply_1_, false, true);
}
}
};
this.sorter = new EntityAINearestAttackableTarget.Sorter(entityLivingIn);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
double d0 = this.maxTargetRange();
List<EntityPlayer> list = this.entityLiving.world.<EntityPlayer>getEntitiesWithinAABB(EntityPlayer.class, this.entityLiving.getEntityBoundingBox().grow(d0, 4.0D, d0), this.predicate);
Collections.sort(list, this.sorter);
if (list.isEmpty())
{
return false;
}
else
{
this.entityTarget = list.get(0);
return true;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
EntityLivingBase entitylivingbase = this.entityLiving.getAttackTarget();
if (entitylivingbase == null)
{
return false;
}
else if (!entitylivingbase.isEntityAlive())
{
return false;
}
else if (entitylivingbase instanceof EntityPlayer && ((EntityPlayer)entitylivingbase).capabilities.disableDamage)
{
return false;
}
else
{
Team team = this.entityLiving.getTeam();
Team team1 = entitylivingbase.getTeam();
if (team != null && team1 == team)
{
return false;
}
else
{
double d0 = this.maxTargetRange();
if (this.entityLiving.getDistanceSq(entitylivingbase) > d0 * d0)
{
return false;
}
else
{
return !(entitylivingbase instanceof EntityPlayerMP) || !((EntityPlayerMP)entitylivingbase).interactionManager.isCreative();
}
}
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.entityLiving.setAttackTarget(this.entityTarget);
super.startExecuting();
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.entityLiving.setAttackTarget((EntityLivingBase)null);
super.startExecuting();
}
/**
* Return the max target range of the entiity (16 by default)
*/
protected double maxTargetRange()
{
IAttributeInstance iattributeinstance = this.entityLiving.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE);
return iattributeinstance == null ? 16.0D : iattributeinstance.getAttributeValue();
}
}

View File

@@ -0,0 +1,101 @@
package net.minecraft.entity.ai;
import java.util.Random;
import javax.annotation.Nullable;
import net.minecraft.entity.EntityCreature;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class EntityAIFleeSun extends EntityAIBase
{
private final EntityCreature creature;
private double shelterX;
private double shelterY;
private double shelterZ;
private final double movementSpeed;
private final World world;
public EntityAIFleeSun(EntityCreature theCreatureIn, double movementSpeedIn)
{
this.creature = theCreatureIn;
this.movementSpeed = movementSpeedIn;
this.world = theCreatureIn.world;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.world.isDaytime())
{
return false;
}
else if (!this.creature.isBurning())
{
return false;
}
else if (!this.world.canSeeSky(new BlockPos(this.creature.posX, this.creature.getEntityBoundingBox().minY, this.creature.posZ)))
{
return false;
}
else if (!this.creature.getItemStackFromSlot(EntityEquipmentSlot.HEAD).isEmpty())
{
return false;
}
else
{
Vec3d vec3d = this.findPossibleShelter();
if (vec3d == null)
{
return false;
}
else
{
this.shelterX = vec3d.x;
this.shelterY = vec3d.y;
this.shelterZ = vec3d.z;
return true;
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.creature.getNavigator().noPath();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.creature.getNavigator().tryMoveToXYZ(this.shelterX, this.shelterY, this.shelterZ, this.movementSpeed);
}
@Nullable
private Vec3d findPossibleShelter()
{
Random random = this.creature.getRNG();
BlockPos blockpos = new BlockPos(this.creature.posX, this.creature.getEntityBoundingBox().minY, this.creature.posZ);
for (int i = 0; i < 10; ++i)
{
BlockPos blockpos1 = blockpos.add(random.nextInt(20) - 10, random.nextInt(6) - 3, random.nextInt(20) - 10);
if (!this.world.canSeeSky(blockpos1) && this.creature.getBlockPathWeight(blockpos1) < 0.0F)
{
return new Vec3d((double)blockpos1.getX(), (double)blockpos1.getY(), (double)blockpos1.getZ());
}
}
return null;
}
}

View File

@@ -0,0 +1,132 @@
package net.minecraft.entity.ai;
import com.google.common.base.Predicate;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.entity.EntityLiving;
import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.pathfinding.PathNavigateFlying;
import net.minecraft.pathfinding.PathNavigateGround;
import net.minecraft.pathfinding.PathNodeType;
public class EntityAIFollow extends EntityAIBase
{
private final EntityLiving entity;
private final Predicate<EntityLiving> followPredicate;
private EntityLiving followingEntity;
private final double speedModifier;
private final PathNavigate navigation;
private int timeToRecalcPath;
private final float stopDistance;
private float oldWaterCost;
private final float areaSize;
public EntityAIFollow(final EntityLiving p_i47417_1_, double p_i47417_2_, float p_i47417_4_, float p_i47417_5_)
{
this.entity = p_i47417_1_;
this.followPredicate = new Predicate<EntityLiving>()
{
public boolean apply(@Nullable EntityLiving p_apply_1_)
{
return p_apply_1_ != null && p_i47417_1_.getClass() != p_apply_1_.getClass();
}
};
this.speedModifier = p_i47417_2_;
this.navigation = p_i47417_1_.getNavigator();
this.stopDistance = p_i47417_4_;
this.areaSize = p_i47417_5_;
this.setMutexBits(3);
if (!(p_i47417_1_.getNavigator() instanceof PathNavigateGround) && !(p_i47417_1_.getNavigator() instanceof PathNavigateFlying))
{
throw new IllegalArgumentException("Unsupported mob type for FollowMobGoal");
}
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
List<EntityLiving> list = this.entity.world.<EntityLiving>getEntitiesWithinAABB(EntityLiving.class, this.entity.getEntityBoundingBox().grow((double)this.areaSize), this.followPredicate);
if (!list.isEmpty())
{
for (EntityLiving entityliving : list)
{
if (!entityliving.isInvisible())
{
this.followingEntity = entityliving;
return true;
}
}
}
return false;
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.followingEntity != null && !this.navigation.noPath() && this.entity.getDistanceSq(this.followingEntity) > (double)(this.stopDistance * this.stopDistance);
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.timeToRecalcPath = 0;
this.oldWaterCost = this.entity.getPathPriority(PathNodeType.WATER);
this.entity.setPathPriority(PathNodeType.WATER, 0.0F);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.followingEntity = null;
this.navigation.clearPath();
this.entity.setPathPriority(PathNodeType.WATER, this.oldWaterCost);
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
if (this.followingEntity != null && !this.entity.getLeashed())
{
this.entity.getLookHelper().setLookPositionWithEntity(this.followingEntity, 10.0F, (float)this.entity.getVerticalFaceSpeed());
if (--this.timeToRecalcPath <= 0)
{
this.timeToRecalcPath = 10;
double d0 = this.entity.posX - this.followingEntity.posX;
double d1 = this.entity.posY - this.followingEntity.posY;
double d2 = this.entity.posZ - this.followingEntity.posZ;
double d3 = d0 * d0 + d1 * d1 + d2 * d2;
if (d3 > (double)(this.stopDistance * this.stopDistance))
{
this.navigation.tryMoveToEntityLiving(this.followingEntity, this.speedModifier);
}
else
{
this.navigation.clearPath();
EntityLookHelper entitylookhelper = this.followingEntity.getLookHelper();
if (d3 <= (double)this.stopDistance || entitylookhelper.getLookPosX() == this.entity.posX && entitylookhelper.getLookPosY() == this.entity.posY && entitylookhelper.getLookPosZ() == this.entity.posZ)
{
double d4 = this.followingEntity.posX - this.entity.posX;
double d5 = this.followingEntity.posZ - this.entity.posZ;
this.navigation.tryMoveToXYZ(this.entity.posX - d4, this.entity.posY, this.entity.posZ - d5, this.speedModifier);
}
}
}
}
}
}

View File

@@ -0,0 +1,103 @@
package net.minecraft.entity.ai;
import java.util.List;
import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.entity.passive.EntityVillager;
public class EntityAIFollowGolem extends EntityAIBase
{
private final EntityVillager villager;
private EntityIronGolem ironGolem;
private int takeGolemRoseTick;
private boolean tookGolemRose;
public EntityAIFollowGolem(EntityVillager villagerIn)
{
this.villager = villagerIn;
this.setMutexBits(3);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.villager.getGrowingAge() >= 0)
{
return false;
}
else if (!this.villager.world.isDaytime())
{
return false;
}
else
{
List<EntityIronGolem> list = this.villager.world.<EntityIronGolem>getEntitiesWithinAABB(EntityIronGolem.class, this.villager.getEntityBoundingBox().grow(6.0D, 2.0D, 6.0D));
if (list.isEmpty())
{
return false;
}
else
{
for (EntityIronGolem entityirongolem : list)
{
if (entityirongolem.getHoldRoseTick() > 0)
{
this.ironGolem = entityirongolem;
break;
}
}
return this.ironGolem != null;
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.ironGolem.getHoldRoseTick() > 0;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.takeGolemRoseTick = this.villager.getRNG().nextInt(320);
this.tookGolemRose = false;
this.ironGolem.getNavigator().clearPath();
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.ironGolem = null;
this.villager.getNavigator().clearPath();
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
this.villager.getLookHelper().setLookPositionWithEntity(this.ironGolem, 30.0F, 30.0F);
if (this.ironGolem.getHoldRoseTick() == this.takeGolemRoseTick)
{
this.villager.getNavigator().tryMoveToEntityLiving(this.ironGolem, 0.5D);
this.tookGolemRose = true;
}
if (this.tookGolemRose && this.villager.getDistanceSq(this.ironGolem) < 4.0D)
{
this.ironGolem.setHoldingRose(false);
this.villager.getNavigator().clearPath();
}
}
}

View File

@@ -0,0 +1,151 @@
package net.minecraft.entity.ai;
import net.minecraft.block.state.BlockFaceShape;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityTameable;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.pathfinding.PathNavigateFlying;
import net.minecraft.pathfinding.PathNavigateGround;
import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.world.World;
public class EntityAIFollowOwner extends EntityAIBase
{
private final EntityTameable tameable;
private EntityLivingBase owner;
World world;
private final double followSpeed;
private final PathNavigate petPathfinder;
private int timeToRecalcPath;
float maxDist;
float minDist;
private float oldWaterCost;
public EntityAIFollowOwner(EntityTameable tameableIn, double followSpeedIn, float minDistIn, float maxDistIn)
{
this.tameable = tameableIn;
this.world = tameableIn.world;
this.followSpeed = followSpeedIn;
this.petPathfinder = tameableIn.getNavigator();
this.minDist = minDistIn;
this.maxDist = maxDistIn;
this.setMutexBits(3);
if (!(tameableIn.getNavigator() instanceof PathNavigateGround) && !(tameableIn.getNavigator() instanceof PathNavigateFlying))
{
throw new IllegalArgumentException("Unsupported mob type for FollowOwnerGoal");
}
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
EntityLivingBase entitylivingbase = this.tameable.getOwner();
if (entitylivingbase == null)
{
return false;
}
else if (entitylivingbase instanceof EntityPlayer && ((EntityPlayer)entitylivingbase).isSpectator())
{
return false;
}
else if (this.tameable.isSitting())
{
return false;
}
else if (this.tameable.getDistanceSq(entitylivingbase) < (double)(this.minDist * this.minDist))
{
return false;
}
else
{
this.owner = entitylivingbase;
return true;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.petPathfinder.noPath() && this.tameable.getDistanceSq(this.owner) > (double)(this.maxDist * this.maxDist) && !this.tameable.isSitting();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.timeToRecalcPath = 0;
this.oldWaterCost = this.tameable.getPathPriority(PathNodeType.WATER);
this.tameable.setPathPriority(PathNodeType.WATER, 0.0F);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.owner = null;
this.petPathfinder.clearPath();
this.tameable.setPathPriority(PathNodeType.WATER, this.oldWaterCost);
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
this.tameable.getLookHelper().setLookPositionWithEntity(this.owner, 10.0F, (float)this.tameable.getVerticalFaceSpeed());
if (!this.tameable.isSitting())
{
if (--this.timeToRecalcPath <= 0)
{
this.timeToRecalcPath = 10;
if (!this.petPathfinder.tryMoveToEntityLiving(this.owner, this.followSpeed))
{
if (!this.tameable.getLeashed() && !this.tameable.isRiding())
{
if (this.tameable.getDistanceSq(this.owner) >= 144.0D)
{
int i = MathHelper.floor(this.owner.posX) - 2;
int j = MathHelper.floor(this.owner.posZ) - 2;
int k = MathHelper.floor(this.owner.getEntityBoundingBox().minY);
for (int l = 0; l <= 4; ++l)
{
for (int i1 = 0; i1 <= 4; ++i1)
{
if ((l < 1 || i1 < 1 || l > 3 || i1 > 3) && this.isTeleportFriendlyBlock(i, j, k, l, i1))
{
this.tameable.setLocationAndAngles((double)((float)(i + l) + 0.5F), (double)k, (double)((float)(j + i1) + 0.5F), this.tameable.rotationYaw, this.tameable.rotationPitch);
this.petPathfinder.clearPath();
return;
}
}
}
}
}
}
}
}
}
protected boolean isTeleportFriendlyBlock(int x, int p_192381_2_, int y, int p_192381_4_, int p_192381_5_)
{
BlockPos blockpos = new BlockPos(x + p_192381_4_, y - 1, p_192381_2_ + p_192381_5_);
IBlockState iblockstate = this.world.getBlockState(blockpos);
return iblockstate.getBlockFaceShape(this.world, blockpos, EnumFacing.DOWN) == BlockFaceShape.SOLID && iblockstate.canEntitySpawn(this.tameable) && this.world.isAirBlock(blockpos.up()) && this.world.isAirBlock(blockpos.up(2));
}
}

View File

@@ -0,0 +1,20 @@
package net.minecraft.entity.ai;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.passive.EntityTameable;
import net.minecraft.util.math.BlockPos;
public class EntityAIFollowOwnerFlying extends EntityAIFollowOwner
{
public EntityAIFollowOwnerFlying(EntityTameable p_i47416_1_, double p_i47416_2_, float p_i47416_4_, float p_i47416_5_)
{
super(p_i47416_1_, p_i47416_2_, p_i47416_4_, p_i47416_5_);
}
protected boolean isTeleportFriendlyBlock(int x, int p_192381_2_, int y, int p_192381_4_, int p_192381_5_)
{
IBlockState iblockstate = this.world.getBlockState(new BlockPos(x + p_192381_4_, y - 1, p_192381_2_ + p_192381_5_));
return (iblockstate.isTopSolid() || iblockstate.getMaterial() == Material.LEAVES) && this.world.isAirBlock(new BlockPos(x + p_192381_4_, y, p_192381_2_ + p_192381_5_)) && this.world.isAirBlock(new BlockPos(x + p_192381_4_, y + 1, p_192381_2_ + p_192381_5_));
}
}

View File

@@ -0,0 +1,112 @@
package net.minecraft.entity.ai;
import java.util.List;
import net.minecraft.entity.passive.EntityAnimal;
public class EntityAIFollowParent extends EntityAIBase
{
/** The child that is following its parent. */
EntityAnimal childAnimal;
EntityAnimal parentAnimal;
double moveSpeed;
private int delayCounter;
public EntityAIFollowParent(EntityAnimal animal, double speed)
{
this.childAnimal = animal;
this.moveSpeed = speed;
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.childAnimal.getGrowingAge() >= 0)
{
return false;
}
else
{
List<EntityAnimal> list = this.childAnimal.world.<EntityAnimal>getEntitiesWithinAABB(this.childAnimal.getClass(), this.childAnimal.getEntityBoundingBox().grow(8.0D, 4.0D, 8.0D));
EntityAnimal entityanimal = null;
double d0 = Double.MAX_VALUE;
for (EntityAnimal entityanimal1 : list)
{
if (entityanimal1.getGrowingAge() >= 0)
{
double d1 = this.childAnimal.getDistanceSq(entityanimal1);
if (d1 <= d0)
{
d0 = d1;
entityanimal = entityanimal1;
}
}
}
if (entityanimal == null)
{
return false;
}
else if (d0 < 9.0D)
{
return false;
}
else
{
this.parentAnimal = entityanimal;
return true;
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
if (this.childAnimal.getGrowingAge() >= 0)
{
return false;
}
else if (!this.parentAnimal.isEntityAlive())
{
return false;
}
else
{
double d0 = this.childAnimal.getDistanceSq(this.parentAnimal);
return d0 >= 9.0D && d0 <= 256.0D;
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.delayCounter = 0;
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.parentAnimal = null;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
if (--this.delayCounter <= 0)
{
this.delayCounter = 10;
this.childAnimal.getNavigator().tryMoveToEntityLiving(this.parentAnimal, this.moveSpeed);
}
}
}

View File

@@ -0,0 +1,163 @@
package net.minecraft.entity.ai;
import net.minecraft.block.Block;
import net.minecraft.block.BlockCrops;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.init.Blocks;
import net.minecraft.init.Items;
import net.minecraft.inventory.InventoryBasic;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class EntityAIHarvestFarmland extends EntityAIMoveToBlock
{
/** Villager that is harvesting */
private final EntityVillager villager;
private boolean hasFarmItem;
private boolean wantsToReapStuff;
/** 0 => harvest, 1 => replant, -1 => none */
private int currentTask;
public EntityAIHarvestFarmland(EntityVillager villagerIn, double speedIn)
{
super(villagerIn, speedIn, 16);
this.villager = villagerIn;
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.runDelay <= 0)
{
if (!net.minecraftforge.event.ForgeEventFactory.getMobGriefingEvent(this.villager.world, this.villager))
{
return false;
}
this.currentTask = -1;
this.hasFarmItem = this.villager.isFarmItemInInventory();
this.wantsToReapStuff = this.villager.wantsMoreFood();
}
return super.shouldExecute();
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.currentTask >= 0 && super.shouldContinueExecuting();
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
super.updateTask();
this.villager.getLookHelper().setLookPosition((double)this.destinationBlock.getX() + 0.5D, (double)(this.destinationBlock.getY() + 1), (double)this.destinationBlock.getZ() + 0.5D, 10.0F, (float)this.villager.getVerticalFaceSpeed());
if (this.getIsAboveDestination())
{
World world = this.villager.world;
BlockPos blockpos = this.destinationBlock.up();
IBlockState iblockstate = world.getBlockState(blockpos);
Block block = iblockstate.getBlock();
if (this.currentTask == 0 && block instanceof BlockCrops && ((BlockCrops)block).isMaxAge(iblockstate))
{
world.destroyBlock(blockpos, true);
}
else if (this.currentTask == 1 && iblockstate.getMaterial() == Material.AIR)
{
InventoryBasic inventorybasic = this.villager.getVillagerInventory();
for (int i = 0; i < inventorybasic.getSizeInventory(); ++i)
{
ItemStack itemstack = inventorybasic.getStackInSlot(i);
boolean flag = false;
if (!itemstack.isEmpty())
{
if (itemstack.getItem() == Items.WHEAT_SEEDS)
{
world.setBlockState(blockpos, Blocks.WHEAT.getDefaultState(), 3);
flag = true;
}
else if (itemstack.getItem() == Items.POTATO)
{
world.setBlockState(blockpos, Blocks.POTATOES.getDefaultState(), 3);
flag = true;
}
else if (itemstack.getItem() == Items.CARROT)
{
world.setBlockState(blockpos, Blocks.CARROTS.getDefaultState(), 3);
flag = true;
}
else if (itemstack.getItem() == Items.BEETROOT_SEEDS)
{
world.setBlockState(blockpos, Blocks.BEETROOTS.getDefaultState(), 3);
flag = true;
}
else if (itemstack.getItem() instanceof net.minecraftforge.common.IPlantable) {
if(((net.minecraftforge.common.IPlantable)itemstack.getItem()).getPlantType(world,blockpos) == net.minecraftforge.common.EnumPlantType.Crop) {
world.setBlockState(blockpos, ((net.minecraftforge.common.IPlantable)itemstack.getItem()).getPlant(world,blockpos),3);
flag = true;
}
}
}
if (flag)
{
itemstack.shrink(1);
if (itemstack.isEmpty())
{
inventorybasic.setInventorySlotContents(i, ItemStack.EMPTY);
}
break;
}
}
}
this.currentTask = -1;
this.runDelay = 10;
}
}
/**
* Return true to set given position as destination
*/
protected boolean shouldMoveTo(World worldIn, BlockPos pos)
{
Block block = worldIn.getBlockState(pos).getBlock();
if (block == Blocks.FARMLAND)
{
pos = pos.up();
IBlockState iblockstate = worldIn.getBlockState(pos);
block = iblockstate.getBlock();
if (block instanceof BlockCrops && ((BlockCrops)block).isMaxAge(iblockstate) && this.wantsToReapStuff && (this.currentTask == 0 || this.currentTask < 0))
{
this.currentTask = 0;
return true;
}
if (iblockstate.getMaterial() == Material.AIR && this.hasFarmItem && (this.currentTask == 1 || this.currentTask < 0))
{
this.currentTask = 1;
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,82 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityTameable;
import net.minecraft.util.math.AxisAlignedBB;
public class EntityAIHurtByTarget extends EntityAITarget
{
private final boolean entityCallsForHelp;
/** Store the previous revengeTimer value */
private int revengeTimerOld;
private final Class<?>[] excludedReinforcementTypes;
public EntityAIHurtByTarget(EntityCreature creatureIn, boolean entityCallsForHelpIn, Class<?>... excludedReinforcementTypes)
{
super(creatureIn, true);
this.entityCallsForHelp = entityCallsForHelpIn;
this.excludedReinforcementTypes = excludedReinforcementTypes;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
int i = this.taskOwner.getRevengeTimer();
EntityLivingBase entitylivingbase = this.taskOwner.getRevengeTarget();
return i != this.revengeTimerOld && entitylivingbase != null && this.isSuitableTarget(entitylivingbase, false);
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.taskOwner.setAttackTarget(this.taskOwner.getRevengeTarget());
this.target = this.taskOwner.getAttackTarget();
this.revengeTimerOld = this.taskOwner.getRevengeTimer();
this.unseenMemoryTicks = 300;
if (this.entityCallsForHelp)
{
this.alertOthers();
}
super.startExecuting();
}
protected void alertOthers()
{
double d0 = this.getTargetDistance();
for (EntityCreature entitycreature : this.taskOwner.world.getEntitiesWithinAABB(this.taskOwner.getClass(), (new AxisAlignedBB(this.taskOwner.posX, this.taskOwner.posY, this.taskOwner.posZ, this.taskOwner.posX + 1.0D, this.taskOwner.posY + 1.0D, this.taskOwner.posZ + 1.0D)).grow(d0, 10.0D, d0)))
{
if (this.taskOwner != entitycreature && entitycreature.getAttackTarget() == null && (!(this.taskOwner instanceof EntityTameable) || ((EntityTameable)this.taskOwner).getOwner() == ((EntityTameable)entitycreature).getOwner()) && !entitycreature.isOnSameTeam(this.taskOwner.getRevengeTarget()))
{
boolean flag = false;
for (Class<?> oclass : this.excludedReinforcementTypes)
{
if (entitycreature.getClass() == oclass)
{
flag = true;
break;
}
}
if (!flag)
{
this.setEntityAttackTarget(entitycreature, this.taskOwner.getRevengeTarget());
}
}
}
}
protected void setEntityAttackTarget(EntityCreature creatureIn, EntityLivingBase entityLivingBaseIn)
{
creatureIn.setAttackTarget(entityLivingBaseIn);
}
}

View File

@@ -0,0 +1,59 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityShoulderRiding;
import net.minecraft.entity.player.EntityPlayer;
public class EntityAILandOnOwnersShoulder extends EntityAIBase
{
private final EntityShoulderRiding entity;
private EntityPlayer owner;
private boolean isSittingOnShoulder;
public EntityAILandOnOwnersShoulder(EntityShoulderRiding p_i47415_1_)
{
this.entity = p_i47415_1_;
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
EntityLivingBase entitylivingbase = this.entity.getOwner();
boolean flag = entitylivingbase != null && !((EntityPlayer)entitylivingbase).isSpectator() && !((EntityPlayer)entitylivingbase).capabilities.isFlying && !entitylivingbase.isInWater();
return !this.entity.isSitting() && flag && this.entity.canSitOnShoulder();
}
/**
* Determine if this AI Task is interruptible by a higher (= lower value) priority task. All vanilla AITask have
* this value set to true.
*/
public boolean isInterruptible()
{
return !this.isSittingOnShoulder;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.owner = (EntityPlayer)this.entity.getOwner();
this.isSittingOnShoulder = false;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
if (!this.isSittingOnShoulder && !this.entity.isSitting() && !this.entity.getLeashed())
{
if (this.entity.getEntityBoundingBox().intersects(this.owner.getEntityBoundingBox()))
{
this.isSittingOnShoulder = this.entity.setEntityOnShoulder(this.owner);
}
}
}
}

View File

@@ -0,0 +1,81 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.math.MathHelper;
public class EntityAILeapAtTarget extends EntityAIBase
{
/** The entity that is leaping. */
EntityLiving leaper;
/** The entity that the leaper is leaping towards. */
EntityLivingBase leapTarget;
/** The entity's motionY after leaping. */
float leapMotionY;
public EntityAILeapAtTarget(EntityLiving leapingEntity, float leapMotionYIn)
{
this.leaper = leapingEntity;
this.leapMotionY = leapMotionYIn;
this.setMutexBits(5);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
this.leapTarget = this.leaper.getAttackTarget();
if (this.leapTarget == null)
{
return false;
}
else
{
double d0 = this.leaper.getDistanceSq(this.leapTarget);
if (d0 >= 4.0D && d0 <= 16.0D)
{
if (!this.leaper.onGround)
{
return false;
}
else
{
return this.leaper.getRNG().nextInt(5) == 0;
}
}
else
{
return false;
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.leaper.onGround;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
double d0 = this.leapTarget.posX - this.leaper.posX;
double d1 = this.leapTarget.posZ - this.leaper.posZ;
float f = MathHelper.sqrt(d0 * d0 + d1 * d1);
if ((double)f >= 1.0E-4D)
{
this.leaper.motionX += d0 / (double)f * 0.5D * 0.800000011920929D + this.leaper.motionX * 0.20000000298023224D;
this.leaper.motionZ += d1 / (double)f * 0.5D * 0.800000011920929D + this.leaper.motionZ * 0.20000000298023224D;
}
this.leaper.motionY = (double)this.leapMotionY;
}
}

View File

@@ -0,0 +1,171 @@
package net.minecraft.entity.ai;
import java.util.List;
import net.minecraft.entity.passive.EntityLlama;
import net.minecraft.util.math.Vec3d;
public class EntityAILlamaFollowCaravan extends EntityAIBase
{
public EntityLlama llama;
private double speedModifier;
private int distCheckCounter;
public EntityAILlamaFollowCaravan(EntityLlama llamaIn, double speedModifierIn)
{
this.llama = llamaIn;
this.speedModifier = speedModifierIn;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.llama.getLeashed() && !this.llama.inCaravan())
{
List<EntityLlama> list = this.llama.world.<EntityLlama>getEntitiesWithinAABB(this.llama.getClass(), this.llama.getEntityBoundingBox().grow(9.0D, 4.0D, 9.0D));
EntityLlama entityllama = null;
double d0 = Double.MAX_VALUE;
for (EntityLlama entityllama1 : list)
{
if (entityllama1.inCaravan() && !entityllama1.hasCaravanTrail())
{
double d1 = this.llama.getDistanceSq(entityllama1);
if (d1 <= d0)
{
d0 = d1;
entityllama = entityllama1;
}
}
}
if (entityllama == null)
{
for (EntityLlama entityllama2 : list)
{
if (entityllama2.getLeashed() && !entityllama2.hasCaravanTrail())
{
double d2 = this.llama.getDistanceSq(entityllama2);
if (d2 <= d0)
{
d0 = d2;
entityllama = entityllama2;
}
}
}
}
if (entityllama == null)
{
return false;
}
else if (d0 < 4.0D)
{
return false;
}
else if (!entityllama.getLeashed() && !this.firstIsLeashed(entityllama, 1))
{
return false;
}
else
{
this.llama.joinCaravan(entityllama);
return true;
}
}
else
{
return false;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
if (this.llama.inCaravan() && this.llama.getCaravanHead().isEntityAlive() && this.firstIsLeashed(this.llama, 0))
{
double d0 = this.llama.getDistanceSq(this.llama.getCaravanHead());
if (d0 > 676.0D)
{
if (this.speedModifier <= 3.0D)
{
this.speedModifier *= 1.2D;
this.distCheckCounter = 40;
return true;
}
if (this.distCheckCounter == 0)
{
return false;
}
}
if (this.distCheckCounter > 0)
{
--this.distCheckCounter;
}
return true;
}
else
{
return false;
}
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.llama.leaveCaravan();
this.speedModifier = 2.1D;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
if (this.llama.inCaravan())
{
EntityLlama entityllama = this.llama.getCaravanHead();
double d0 = (double)this.llama.getDistance(entityllama);
float f = 2.0F;
Vec3d vec3d = (new Vec3d(entityllama.posX - this.llama.posX, entityllama.posY - this.llama.posY, entityllama.posZ - this.llama.posZ)).normalize().scale(Math.max(d0 - 2.0D, 0.0D));
this.llama.getNavigator().tryMoveToXYZ(this.llama.posX + vec3d.x, this.llama.posY + vec3d.y, this.llama.posZ + vec3d.z, this.speedModifier);
}
}
private boolean firstIsLeashed(EntityLlama p_190858_1_, int p_190858_2_)
{
if (p_190858_2_ > 8)
{
return false;
}
else if (p_190858_1_.inCaravan())
{
if (p_190858_1_.getCaravanHead().getLeashed())
{
return true;
}
else
{
EntityLlama entityllama = p_190858_1_.getCaravanHead();
++p_190858_2_;
return this.firstIsLeashed(entityllama, p_190858_2_);
}
}
else
{
return false;
}
}
}

View File

@@ -0,0 +1,31 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
public class EntityAILookAtTradePlayer extends EntityAIWatchClosest
{
private final EntityVillager villager;
public EntityAILookAtTradePlayer(EntityVillager villagerIn)
{
super(villagerIn, EntityPlayer.class, 8.0F);
this.villager = villagerIn;
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.villager.isTrading())
{
this.closestEntity = this.villager.getCustomer();
return true;
}
else
{
return false;
}
}
}

View File

@@ -0,0 +1,72 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.monster.EntityIronGolem;
import net.minecraft.entity.passive.EntityVillager;
public class EntityAILookAtVillager extends EntityAIBase
{
private final EntityIronGolem ironGolem;
private EntityVillager villager;
private int lookTime;
public EntityAILookAtVillager(EntityIronGolem ironGolemIn)
{
this.ironGolem = ironGolemIn;
this.setMutexBits(3);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.ironGolem.world.isDaytime())
{
return false;
}
else if (this.ironGolem.getRNG().nextInt(8000) != 0)
{
return false;
}
else
{
this.villager = (EntityVillager)this.ironGolem.world.findNearestEntityWithinAABB(EntityVillager.class, this.ironGolem.getEntityBoundingBox().grow(6.0D, 2.0D, 6.0D), this.ironGolem);
return this.villager != null;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.lookTime > 0;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.lookTime = 400;
this.ironGolem.setHoldingRose(true);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.ironGolem.setHoldingRose(false);
this.villager = null;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
this.ironGolem.getLookHelper().setLookPositionWithEntity(this.villager, 30.0F, 30.0F);
--this.lookTime;
}
}

View File

@@ -0,0 +1,57 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLiving;
public class EntityAILookIdle extends EntityAIBase
{
/** The entity that is looking idle. */
private final EntityLiving idleEntity;
/** X offset to look at */
private double lookX;
/** Z offset to look at */
private double lookZ;
/** A decrementing tick that stops the entity from being idle once it reaches 0. */
private int idleTime;
public EntityAILookIdle(EntityLiving entitylivingIn)
{
this.idleEntity = entitylivingIn;
this.setMutexBits(3);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
return this.idleEntity.getRNG().nextFloat() < 0.02F;
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.idleTime >= 0;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
double d0 = (Math.PI * 2D) * this.idleEntity.getRNG().nextDouble();
this.lookX = Math.cos(d0);
this.lookZ = Math.sin(d0);
this.idleTime = 20 + this.idleEntity.getRNG().nextInt(20);
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
--this.idleTime;
this.idleEntity.getLookHelper().setLookPosition(this.idleEntity.posX + this.lookX, this.idleEntity.posY + (double)this.idleEntity.getEyeHeight(), this.idleEntity.posZ + this.lookZ, (float)this.idleEntity.getHorizontalFaceSpeed(), (float)this.idleEntity.getVerticalFaceSpeed());
}
}

View File

@@ -0,0 +1,169 @@
package net.minecraft.entity.ai;
import java.util.List;
import java.util.Random;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.entity.EntityAgeable;
import net.minecraft.entity.item.EntityXPOrb;
import net.minecraft.entity.passive.EntityAnimal;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.stats.StatList;
import net.minecraft.util.EnumParticleTypes;
import net.minecraft.world.World;
public class EntityAIMate extends EntityAIBase
{
private final EntityAnimal animal;
private final Class <? extends EntityAnimal > mateClass;
World world;
private EntityAnimal targetMate;
/** Delay preventing a baby from spawning immediately when two mate-able animals find each other. */
int spawnBabyDelay;
/** The speed the creature moves at during mating behavior. */
double moveSpeed;
public EntityAIMate(EntityAnimal animal, double speedIn)
{
this(animal, speedIn, animal.getClass());
}
public EntityAIMate(EntityAnimal p_i47306_1_, double p_i47306_2_, Class <? extends EntityAnimal > p_i47306_4_)
{
this.animal = p_i47306_1_;
this.world = p_i47306_1_.world;
this.mateClass = p_i47306_4_;
this.moveSpeed = p_i47306_2_;
this.setMutexBits(3);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.animal.isInLove())
{
return false;
}
else
{
this.targetMate = this.getNearbyMate();
return this.targetMate != null;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.targetMate.isEntityAlive() && this.targetMate.isInLove() && this.spawnBabyDelay < 60;
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.targetMate = null;
this.spawnBabyDelay = 0;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
this.animal.getLookHelper().setLookPositionWithEntity(this.targetMate, 10.0F, (float)this.animal.getVerticalFaceSpeed());
this.animal.getNavigator().tryMoveToEntityLiving(this.targetMate, this.moveSpeed);
++this.spawnBabyDelay;
if (this.spawnBabyDelay >= 60 && this.animal.getDistanceSq(this.targetMate) < 9.0D)
{
this.spawnBaby();
}
}
/**
* Loops through nearby animals and finds another animal of the same type that can be mated with. Returns the first
* valid mate found.
*/
private EntityAnimal getNearbyMate()
{
List<EntityAnimal> list = this.world.<EntityAnimal>getEntitiesWithinAABB(this.mateClass, this.animal.getEntityBoundingBox().grow(8.0D));
double d0 = Double.MAX_VALUE;
EntityAnimal entityanimal = null;
for (EntityAnimal entityanimal1 : list)
{
if (this.animal.canMateWith(entityanimal1) && this.animal.getDistanceSq(entityanimal1) < d0)
{
entityanimal = entityanimal1;
d0 = this.animal.getDistanceSq(entityanimal1);
}
}
return entityanimal;
}
/**
* Spawns a baby animal of the same type.
*/
private void spawnBaby()
{
EntityAgeable entityageable = this.animal.createChild(this.targetMate);
final net.minecraftforge.event.entity.living.BabyEntitySpawnEvent event = new net.minecraftforge.event.entity.living.BabyEntitySpawnEvent(animal, targetMate, entityageable);
final boolean cancelled = net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event);
entityageable = event.getChild();
if (cancelled) {
//Reset the "inLove" state for the animals
this.animal.setGrowingAge(6000);
this.targetMate.setGrowingAge(6000);
this.animal.resetInLove();
this.targetMate.resetInLove();
return;
}
if (entityageable != null)
{
EntityPlayerMP entityplayermp = this.animal.getLoveCause();
if (entityplayermp == null && this.targetMate.getLoveCause() != null)
{
entityplayermp = this.targetMate.getLoveCause();
}
if (entityplayermp != null)
{
entityplayermp.addStat(StatList.ANIMALS_BRED);
CriteriaTriggers.BRED_ANIMALS.trigger(entityplayermp, this.animal, this.targetMate, entityageable);
}
this.animal.setGrowingAge(6000);
this.targetMate.setGrowingAge(6000);
this.animal.resetInLove();
this.targetMate.resetInLove();
entityageable.setGrowingAge(-24000);
entityageable.setLocationAndAngles(this.animal.posX, this.animal.posY, this.animal.posZ, 0.0F, 0.0F);
this.world.spawnEntity(entityageable);
Random random = this.animal.getRNG();
for (int i = 0; i < 7; ++i)
{
double d0 = random.nextGaussian() * 0.02D;
double d1 = random.nextGaussian() * 0.02D;
double d2 = random.nextGaussian() * 0.02D;
double d3 = random.nextDouble() * (double)this.animal.width * 2.0D - (double)this.animal.width;
double d4 = 0.5D + random.nextDouble() * (double)this.animal.height;
double d5 = random.nextDouble() * (double)this.animal.width * 2.0D - (double)this.animal.width;
this.world.spawnParticle(EnumParticleTypes.HEART, this.animal.posX + d3, this.animal.posY + d4, this.animal.posZ + d5, d0, d1, d2);
}
if (this.world.getGameRules().getBoolean("doMobLoot"))
{
this.world.spawnEntity(new EntityXPOrb(this.world, this.animal.posX, this.animal.posY, this.animal.posZ, random.nextInt(7) + 1));
}
}
}
}

View File

@@ -0,0 +1,103 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityCreature;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.village.Village;
import net.minecraft.village.VillageDoorInfo;
public class EntityAIMoveIndoors extends EntityAIBase
{
private final EntityCreature entity;
private VillageDoorInfo doorInfo;
private int insidePosX = -1;
private int insidePosZ = -1;
public EntityAIMoveIndoors(EntityCreature entityIn)
{
this.entity = entityIn;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
BlockPos blockpos = new BlockPos(this.entity);
if ((!this.entity.world.isDaytime() || this.entity.world.isRaining() && !this.entity.world.getBiome(blockpos).canRain()) && this.entity.world.provider.hasSkyLight())
{
if (this.entity.getRNG().nextInt(50) != 0)
{
return false;
}
else if (this.insidePosX != -1 && this.entity.getDistanceSq((double)this.insidePosX, this.entity.posY, (double)this.insidePosZ) < 4.0D)
{
return false;
}
else
{
Village village = this.entity.world.getVillageCollection().getNearestVillage(blockpos, 14);
if (village == null)
{
return false;
}
else
{
this.doorInfo = village.getDoorInfo(blockpos);
return this.doorInfo != null;
}
}
}
else
{
return false;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.entity.getNavigator().noPath();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.insidePosX = -1;
BlockPos blockpos = this.doorInfo.getInsideBlockPos();
int i = blockpos.getX();
int j = blockpos.getY();
int k = blockpos.getZ();
if (this.entity.getDistanceSq(blockpos) > 256.0D)
{
Vec3d vec3d = RandomPositionGenerator.findRandomTargetBlockTowards(this.entity, 14, 3, new Vec3d((double)i + 0.5D, (double)j, (double)k + 0.5D));
if (vec3d != null)
{
this.entity.getNavigator().tryMoveToXYZ(vec3d.x, vec3d.y, vec3d.z, 1.0D);
}
}
else
{
this.entity.getNavigator().tryMoveToXYZ((double)i + 0.5D, (double)j, (double)k + 0.5D, 1.0D);
}
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.insidePosX = this.doorInfo.getInsideBlockPos().getX();
this.insidePosZ = this.doorInfo.getInsideBlockPos().getZ();
this.doorInfo = null;
}
}

View File

@@ -0,0 +1,171 @@
package net.minecraft.entity.ai;
import com.google.common.collect.Lists;
import java.util.List;
import net.minecraft.entity.EntityCreature;
import net.minecraft.pathfinding.Path;
import net.minecraft.pathfinding.PathNavigateGround;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.village.Village;
import net.minecraft.village.VillageDoorInfo;
public class EntityAIMoveThroughVillage extends EntityAIBase
{
private final EntityCreature entity;
private final double movementSpeed;
/** The PathNavigate of our entity. */
private Path path;
private VillageDoorInfo doorInfo;
private final boolean isNocturnal;
private final List<VillageDoorInfo> doorList = Lists.<VillageDoorInfo>newArrayList();
public EntityAIMoveThroughVillage(EntityCreature entityIn, double movementSpeedIn, boolean isNocturnalIn)
{
this.entity = entityIn;
this.movementSpeed = movementSpeedIn;
this.isNocturnal = isNocturnalIn;
this.setMutexBits(1);
if (!(entityIn.getNavigator() instanceof PathNavigateGround))
{
throw new IllegalArgumentException("Unsupported mob for MoveThroughVillageGoal");
}
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
this.resizeDoorList();
if (this.isNocturnal && this.entity.world.isDaytime())
{
return false;
}
else
{
Village village = this.entity.world.getVillageCollection().getNearestVillage(new BlockPos(this.entity), 0);
if (village == null)
{
return false;
}
else
{
this.doorInfo = this.findNearestDoor(village);
if (this.doorInfo == null)
{
return false;
}
else
{
PathNavigateGround pathnavigateground = (PathNavigateGround)this.entity.getNavigator();
boolean flag = pathnavigateground.getEnterDoors();
pathnavigateground.setBreakDoors(false);
this.path = pathnavigateground.getPathToPos(this.doorInfo.getDoorBlockPos());
pathnavigateground.setBreakDoors(flag);
if (this.path != null)
{
return true;
}
else
{
Vec3d vec3d = RandomPositionGenerator.findRandomTargetBlockTowards(this.entity, 10, 7, new Vec3d((double)this.doorInfo.getDoorBlockPos().getX(), (double)this.doorInfo.getDoorBlockPos().getY(), (double)this.doorInfo.getDoorBlockPos().getZ()));
if (vec3d == null)
{
return false;
}
else
{
pathnavigateground.setBreakDoors(false);
this.path = this.entity.getNavigator().getPathToXYZ(vec3d.x, vec3d.y, vec3d.z);
pathnavigateground.setBreakDoors(flag);
return this.path != null;
}
}
}
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
if (this.entity.getNavigator().noPath())
{
return false;
}
else
{
float f = this.entity.width + 4.0F;
return this.entity.getDistanceSq(this.doorInfo.getDoorBlockPos()) > (double)(f * f);
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.entity.getNavigator().setPath(this.path, this.movementSpeed);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
if (this.entity.getNavigator().noPath() || this.entity.getDistanceSq(this.doorInfo.getDoorBlockPos()) < 16.0D)
{
this.doorList.add(this.doorInfo);
}
}
private VillageDoorInfo findNearestDoor(Village villageIn)
{
VillageDoorInfo villagedoorinfo = null;
int i = Integer.MAX_VALUE;
for (VillageDoorInfo villagedoorinfo1 : villageIn.getVillageDoorInfoList())
{
int j = villagedoorinfo1.getDistanceSquared(MathHelper.floor(this.entity.posX), MathHelper.floor(this.entity.posY), MathHelper.floor(this.entity.posZ));
if (j < i && !this.doesDoorListContain(villagedoorinfo1))
{
villagedoorinfo = villagedoorinfo1;
i = j;
}
}
return villagedoorinfo;
}
private boolean doesDoorListContain(VillageDoorInfo doorInfoIn)
{
for (VillageDoorInfo villagedoorinfo : this.doorList)
{
if (doorInfoIn.getDoorBlockPos().equals(villagedoorinfo.getDoorBlockPos()))
{
return true;
}
}
return false;
}
private void resizeDoorList()
{
if (this.doorList.size() > 15)
{
this.doorList.remove(0);
}
}
}

View File

@@ -0,0 +1,128 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityCreature;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public abstract class EntityAIMoveToBlock extends EntityAIBase
{
private final EntityCreature creature;
private final double movementSpeed;
/** Controls task execution delay */
protected int runDelay;
private int timeoutCounter;
private int maxStayTicks;
/** Block to move to */
protected BlockPos destinationBlock = BlockPos.ORIGIN;
private boolean isAboveDestination;
private final int searchLength;
public EntityAIMoveToBlock(EntityCreature creature, double speedIn, int length)
{
this.creature = creature;
this.movementSpeed = speedIn;
this.searchLength = length;
this.setMutexBits(5);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.runDelay > 0)
{
--this.runDelay;
return false;
}
else
{
this.runDelay = 200 + this.creature.getRNG().nextInt(200);
return this.searchForDestination();
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.timeoutCounter >= -this.maxStayTicks && this.timeoutCounter <= 1200 && this.shouldMoveTo(this.creature.world, this.destinationBlock);
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.creature.getNavigator().tryMoveToXYZ((double)((float)this.destinationBlock.getX()) + 0.5D, (double)(this.destinationBlock.getY() + 1), (double)((float)this.destinationBlock.getZ()) + 0.5D, this.movementSpeed);
this.timeoutCounter = 0;
this.maxStayTicks = this.creature.getRNG().nextInt(this.creature.getRNG().nextInt(1200) + 1200) + 1200;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
if (this.creature.getDistanceSqToCenter(this.destinationBlock.up()) > 1.0D)
{
this.isAboveDestination = false;
++this.timeoutCounter;
if (this.timeoutCounter % 40 == 0)
{
this.creature.getNavigator().tryMoveToXYZ((double)((float)this.destinationBlock.getX()) + 0.5D, (double)(this.destinationBlock.getY() + 1), (double)((float)this.destinationBlock.getZ()) + 0.5D, this.movementSpeed);
}
}
else
{
this.isAboveDestination = true;
--this.timeoutCounter;
}
}
protected boolean getIsAboveDestination()
{
return this.isAboveDestination;
}
/**
* Searches and sets new destination block and returns true if a suitable block (specified in {@link
* net.minecraft.entity.ai.EntityAIMoveToBlock#shouldMoveTo(World, BlockPos) EntityAIMoveToBlock#shouldMoveTo(World,
* BlockPos)}) can be found.
*/
private boolean searchForDestination()
{
int i = this.searchLength;
int j = 1;
BlockPos blockpos = new BlockPos(this.creature);
for (int k = 0; k <= 1; k = k > 0 ? -k : 1 - k)
{
for (int l = 0; l < i; ++l)
{
for (int i1 = 0; i1 <= l; i1 = i1 > 0 ? -i1 : 1 - i1)
{
for (int j1 = i1 < l && i1 > -l ? l : 0; j1 <= l; j1 = j1 > 0 ? -j1 : 1 - j1)
{
BlockPos blockpos1 = blockpos.add(i1, k - 1, j1);
if (this.creature.isWithinHomeDistanceFromPosition(blockpos1) && this.shouldMoveTo(this.creature.world, blockpos1))
{
this.destinationBlock = blockpos1;
return true;
}
}
}
}
}
return false;
}
/**
* Return true to set given position as destination
*/
protected abstract boolean shouldMoveTo(World worldIn, BlockPos pos);
}

View File

@@ -0,0 +1,65 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityCreature;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
public class EntityAIMoveTowardsRestriction extends EntityAIBase
{
private final EntityCreature creature;
private double movePosX;
private double movePosY;
private double movePosZ;
private final double movementSpeed;
public EntityAIMoveTowardsRestriction(EntityCreature creatureIn, double speedIn)
{
this.creature = creatureIn;
this.movementSpeed = speedIn;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.creature.isWithinHomeDistanceCurrentPosition())
{
return false;
}
else
{
BlockPos blockpos = this.creature.getHomePosition();
Vec3d vec3d = RandomPositionGenerator.findRandomTargetBlockTowards(this.creature, 16, 7, new Vec3d((double)blockpos.getX(), (double)blockpos.getY(), (double)blockpos.getZ()));
if (vec3d == null)
{
return false;
}
else
{
this.movePosX = vec3d.x;
this.movePosY = vec3d.y;
this.movePosZ = vec3d.z;
return true;
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.creature.getNavigator().noPath();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.creature.getNavigator().tryMoveToXYZ(this.movePosX, this.movePosY, this.movePosZ, this.movementSpeed);
}
}

View File

@@ -0,0 +1,82 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.math.Vec3d;
public class EntityAIMoveTowardsTarget extends EntityAIBase
{
private final EntityCreature creature;
private EntityLivingBase targetEntity;
private double movePosX;
private double movePosY;
private double movePosZ;
private final double speed;
/** If the distance to the target entity is further than this, this AI task will not run. */
private final float maxTargetDistance;
public EntityAIMoveTowardsTarget(EntityCreature creature, double speedIn, float targetMaxDistance)
{
this.creature = creature;
this.speed = speedIn;
this.maxTargetDistance = targetMaxDistance;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
this.targetEntity = this.creature.getAttackTarget();
if (this.targetEntity == null)
{
return false;
}
else if (this.targetEntity.getDistanceSq(this.creature) > (double)(this.maxTargetDistance * this.maxTargetDistance))
{
return false;
}
else
{
Vec3d vec3d = RandomPositionGenerator.findRandomTargetBlockTowards(this.creature, 16, 7, new Vec3d(this.targetEntity.posX, this.targetEntity.posY, this.targetEntity.posZ));
if (vec3d == null)
{
return false;
}
else
{
this.movePosX = vec3d.x;
this.movePosY = vec3d.y;
this.movePosZ = vec3d.z;
return true;
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.creature.getNavigator().noPath() && this.targetEntity.isEntityAlive() && this.targetEntity.getDistanceSq(this.creature) < (double)(this.maxTargetDistance * this.maxTargetDistance);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.targetEntity = null;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.creature.getNavigator().tryMoveToXYZ(this.movePosX, this.movePosY, this.movePosZ, this.speed);
}
}

View File

@@ -0,0 +1,160 @@
package net.minecraft.entity.ai;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.annotation.Nullable;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.monster.EntityCreeper;
import net.minecraft.entity.monster.EntitySkeleton;
import net.minecraft.entity.monster.EntityZombie;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.init.Items;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EntitySelectors;
import net.minecraft.util.math.AxisAlignedBB;
public class EntityAINearestAttackableTarget<T extends EntityLivingBase> extends EntityAITarget
{
protected final Class<T> targetClass;
private final int targetChance;
/** Instance of EntityAINearestAttackableTargetSorter. */
protected final EntityAINearestAttackableTarget.Sorter sorter;
protected final Predicate <? super T > targetEntitySelector;
protected T targetEntity;
public EntityAINearestAttackableTarget(EntityCreature creature, Class<T> classTarget, boolean checkSight)
{
this(creature, classTarget, checkSight, false);
}
public EntityAINearestAttackableTarget(EntityCreature creature, Class<T> classTarget, boolean checkSight, boolean onlyNearby)
{
this(creature, classTarget, 10, checkSight, onlyNearby, (Predicate)null);
}
public EntityAINearestAttackableTarget(EntityCreature creature, Class<T> classTarget, int chance, boolean checkSight, boolean onlyNearby, @Nullable final Predicate <? super T > targetSelector)
{
super(creature, checkSight, onlyNearby);
this.targetClass = classTarget;
this.targetChance = chance;
this.sorter = new EntityAINearestAttackableTarget.Sorter(creature);
this.setMutexBits(1);
this.targetEntitySelector = new Predicate<T>()
{
public boolean apply(@Nullable T p_apply_1_)
{
if (p_apply_1_ == null)
{
return false;
}
else if (targetSelector != null && !targetSelector.apply(p_apply_1_))
{
return false;
}
else
{
return !EntitySelectors.NOT_SPECTATING.apply(p_apply_1_) ? false : EntityAINearestAttackableTarget.this.isSuitableTarget(p_apply_1_, false);
}
}
};
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.targetChance > 0 && this.taskOwner.getRNG().nextInt(this.targetChance) != 0)
{
return false;
}
else if (this.targetClass != EntityPlayer.class && this.targetClass != EntityPlayerMP.class)
{
List<T> list = this.taskOwner.world.<T>getEntitiesWithinAABB(this.targetClass, this.getTargetableArea(this.getTargetDistance()), this.targetEntitySelector);
if (list.isEmpty())
{
return false;
}
else
{
Collections.sort(list, this.sorter);
this.targetEntity = list.get(0);
return true;
}
}
else
{
this.targetEntity = (T)this.taskOwner.world.getNearestAttackablePlayer(this.taskOwner.posX, this.taskOwner.posY + (double)this.taskOwner.getEyeHeight(), this.taskOwner.posZ, this.getTargetDistance(), this.getTargetDistance(), new Function<EntityPlayer, Double>()
{
@Nullable
public Double apply(@Nullable EntityPlayer p_apply_1_)
{
ItemStack itemstack = p_apply_1_.getItemStackFromSlot(EntityEquipmentSlot.HEAD);
if (itemstack.getItem() == Items.SKULL)
{
int i = itemstack.getItemDamage();
boolean flag = EntityAINearestAttackableTarget.this.taskOwner instanceof EntitySkeleton && i == 0;
boolean flag1 = EntityAINearestAttackableTarget.this.taskOwner instanceof EntityZombie && i == 2;
boolean flag2 = EntityAINearestAttackableTarget.this.taskOwner instanceof EntityCreeper && i == 4;
if (flag || flag1 || flag2)
{
return 0.5D;
}
}
return 1.0D;
}
}, (Predicate<EntityPlayer>)this.targetEntitySelector);
return this.targetEntity != null;
}
}
protected AxisAlignedBB getTargetableArea(double targetDistance)
{
return this.taskOwner.getEntityBoundingBox().grow(targetDistance, 4.0D, targetDistance);
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.taskOwner.setAttackTarget(this.targetEntity);
super.startExecuting();
}
public static class Sorter implements Comparator<Entity>
{
private final Entity entity;
public Sorter(Entity entityIn)
{
this.entity = entityIn;
}
public int compare(Entity p_compare_1_, Entity p_compare_2_)
{
double d0 = this.entity.getDistanceSq(p_compare_1_);
double d1 = this.entity.getDistanceSq(p_compare_2_);
if (d0 < d1)
{
return -1;
}
else
{
return d0 > d1 ? 1 : 0;
}
}
}
}

View File

@@ -0,0 +1,98 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.world.World;
public class EntityAIOcelotAttack extends EntityAIBase
{
World world;
EntityLiving entity;
EntityLivingBase target;
int attackCountdown;
public EntityAIOcelotAttack(EntityLiving theEntityIn)
{
this.entity = theEntityIn;
this.world = theEntityIn.world;
this.setMutexBits(3);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
EntityLivingBase entitylivingbase = this.entity.getAttackTarget();
if (entitylivingbase == null)
{
return false;
}
else
{
this.target = entitylivingbase;
return true;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
if (!this.target.isEntityAlive())
{
return false;
}
else if (this.entity.getDistanceSq(this.target) > 225.0D)
{
return false;
}
else
{
return !this.entity.getNavigator().noPath() || this.shouldExecute();
}
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.target = null;
this.entity.getNavigator().clearPath();
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
this.entity.getLookHelper().setLookPositionWithEntity(this.target, 30.0F, 30.0F);
double d0 = (double)(this.entity.width * 2.0F * this.entity.width * 2.0F);
double d1 = this.entity.getDistanceSq(this.target.posX, this.target.getEntityBoundingBox().minY, this.target.posZ);
double d2 = 0.8D;
if (d1 > d0 && d1 < 16.0D)
{
d2 = 1.33D;
}
else if (d1 < 225.0D)
{
d2 = 0.6D;
}
this.entity.getNavigator().tryMoveToEntityLiving(this.target, d2);
this.attackCountdown = Math.max(this.attackCountdown - 1, 0);
if (d1 <= d0)
{
if (this.attackCountdown <= 0)
{
this.attackCountdown = 20;
this.entity.attackEntityAsMob(this.target);
}
}
}
}

View File

@@ -0,0 +1,106 @@
package net.minecraft.entity.ai;
import net.minecraft.block.Block;
import net.minecraft.block.BlockBed;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.passive.EntityOcelot;
import net.minecraft.init.Blocks;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityChest;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
public class EntityAIOcelotSit extends EntityAIMoveToBlock
{
private final EntityOcelot ocelot;
public EntityAIOcelotSit(EntityOcelot ocelotIn, double p_i45315_2_)
{
super(ocelotIn, p_i45315_2_, 8);
this.ocelot = ocelotIn;
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
return this.ocelot.isTamed() && !this.ocelot.isSitting() && super.shouldExecute();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
super.startExecuting();
this.ocelot.getAISit().setSitting(false);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
super.resetTask();
this.ocelot.setSitting(false);
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
super.updateTask();
this.ocelot.getAISit().setSitting(false);
if (!this.getIsAboveDestination())
{
this.ocelot.setSitting(false);
}
else if (!this.ocelot.isSitting())
{
this.ocelot.setSitting(true);
}
}
/**
* Return true to set given position as destination
*/
protected boolean shouldMoveTo(World worldIn, BlockPos pos)
{
if (!worldIn.isAirBlock(pos.up()))
{
return false;
}
else
{
IBlockState iblockstate = worldIn.getBlockState(pos);
Block block = iblockstate.getBlock();
if (block == Blocks.CHEST)
{
TileEntity tileentity = worldIn.getTileEntity(pos);
if (tileentity instanceof TileEntityChest && ((TileEntityChest)tileentity).numPlayersUsing < 1)
{
return true;
}
}
else
{
if (block == Blocks.LIT_FURNACE)
{
return true;
}
if (block == Blocks.BED && iblockstate.getValue(BlockBed.PART) != BlockBed.EnumPartType.HEAD)
{
return true;
}
}
return false;
}
}
}

View File

@@ -0,0 +1,55 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLiving;
public class EntityAIOpenDoor extends EntityAIDoorInteract
{
/** If the entity close the door */
boolean closeDoor;
/** The temporisation before the entity close the door (in ticks, always 20 = 1 second) */
int closeDoorTemporisation;
public EntityAIOpenDoor(EntityLiving entitylivingIn, boolean shouldClose)
{
super(entitylivingIn);
this.entity = entitylivingIn;
this.closeDoor = shouldClose;
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.closeDoor && this.closeDoorTemporisation > 0 && super.shouldContinueExecuting();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.closeDoorTemporisation = 20;
this.doorBlock.toggleDoor(this.entity.world, this.doorPosition, true);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
if (this.closeDoor)
{
this.doorBlock.toggleDoor(this.entity.world, this.doorPosition, false);
}
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
--this.closeDoorTemporisation;
super.updateTask();
}
}

View File

@@ -0,0 +1,60 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityTameable;
public class EntityAIOwnerHurtByTarget extends EntityAITarget
{
EntityTameable tameable;
EntityLivingBase attacker;
private int timestamp;
public EntityAIOwnerHurtByTarget(EntityTameable theDefendingTameableIn)
{
super(theDefendingTameableIn, false);
this.tameable = theDefendingTameableIn;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.tameable.isTamed())
{
return false;
}
else
{
EntityLivingBase entitylivingbase = this.tameable.getOwner();
if (entitylivingbase == null)
{
return false;
}
else
{
this.attacker = entitylivingbase.getRevengeTarget();
int i = entitylivingbase.getRevengeTimer();
return i != this.timestamp && this.isSuitableTarget(this.attacker, false) && this.tameable.shouldAttackEntity(this.attacker, entitylivingbase);
}
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.taskOwner.setAttackTarget(this.attacker);
EntityLivingBase entitylivingbase = this.tameable.getOwner();
if (entitylivingbase != null)
{
this.timestamp = entitylivingbase.getRevengeTimer();
}
super.startExecuting();
}
}

View File

@@ -0,0 +1,60 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityTameable;
public class EntityAIOwnerHurtTarget extends EntityAITarget
{
EntityTameable tameable;
EntityLivingBase attacker;
private int timestamp;
public EntityAIOwnerHurtTarget(EntityTameable theEntityTameableIn)
{
super(theEntityTameableIn, false);
this.tameable = theEntityTameableIn;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.tameable.isTamed())
{
return false;
}
else
{
EntityLivingBase entitylivingbase = this.tameable.getOwner();
if (entitylivingbase == null)
{
return false;
}
else
{
this.attacker = entitylivingbase.getLastAttackedEntity();
int i = entitylivingbase.getLastAttackedEntityTime();
return i != this.timestamp && this.isSuitableTarget(this.attacker, false) && this.tameable.shouldAttackEntity(this.attacker, entitylivingbase);
}
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.taskOwner.setAttackTarget(this.attacker);
EntityLivingBase entitylivingbase = this.tameable.getOwner();
if (entitylivingbase != null)
{
this.timestamp = entitylivingbase.getLastAttackedEntityTime();
}
super.startExecuting();
}
}

View File

@@ -0,0 +1,124 @@
package net.minecraft.entity.ai;
import javax.annotation.Nullable;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityCreature;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
public class EntityAIPanic extends EntityAIBase
{
protected final EntityCreature creature;
protected double speed;
protected double randPosX;
protected double randPosY;
protected double randPosZ;
public EntityAIPanic(EntityCreature creature, double speedIn)
{
this.creature = creature;
this.speed = speedIn;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.creature.getRevengeTarget() == null && !this.creature.isBurning())
{
return false;
}
else
{
if (this.creature.isBurning())
{
BlockPos blockpos = this.getRandPos(this.creature.world, this.creature, 5, 4);
if (blockpos != null)
{
this.randPosX = (double)blockpos.getX();
this.randPosY = (double)blockpos.getY();
this.randPosZ = (double)blockpos.getZ();
return true;
}
}
return this.findRandomPosition();
}
}
protected boolean findRandomPosition()
{
Vec3d vec3d = RandomPositionGenerator.findRandomTarget(this.creature, 5, 4);
if (vec3d == null)
{
return false;
}
else
{
this.randPosX = vec3d.x;
this.randPosY = vec3d.y;
this.randPosZ = vec3d.z;
return true;
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.creature.getNavigator().tryMoveToXYZ(this.randPosX, this.randPosY, this.randPosZ, this.speed);
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.creature.getNavigator().noPath();
}
@Nullable
private BlockPos getRandPos(World worldIn, Entity entityIn, int horizontalRange, int verticalRange)
{
BlockPos blockpos = new BlockPos(entityIn);
int i = blockpos.getX();
int j = blockpos.getY();
int k = blockpos.getZ();
float f = (float)(horizontalRange * horizontalRange * verticalRange * 2);
BlockPos blockpos1 = null;
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
for (int l = i - horizontalRange; l <= i + horizontalRange; ++l)
{
for (int i1 = j - verticalRange; i1 <= j + verticalRange; ++i1)
{
for (int j1 = k - horizontalRange; j1 <= k + horizontalRange; ++j1)
{
blockpos$mutableblockpos.setPos(l, i1, j1);
IBlockState iblockstate = worldIn.getBlockState(blockpos$mutableblockpos);
if (iblockstate.getMaterial() == Material.WATER)
{
float f1 = (float)((l - i) * (l - i) + (i1 - j) * (i1 - j) + (j1 - k) * (j1 - k));
if (f1 < f)
{
f = f1;
blockpos1 = new BlockPos(blockpos$mutableblockpos);
}
}
}
}
}
return blockpos1;
}
}

View File

@@ -0,0 +1,124 @@
package net.minecraft.entity.ai;
import java.util.List;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.util.math.Vec3d;
public class EntityAIPlay extends EntityAIBase
{
private final EntityVillager villager;
private EntityLivingBase targetVillager;
private final double speed;
private int playTime;
public EntityAIPlay(EntityVillager villagerIn, double speedIn)
{
this.villager = villagerIn;
this.speed = speedIn;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.villager.getGrowingAge() >= 0)
{
return false;
}
else if (this.villager.getRNG().nextInt(400) != 0)
{
return false;
}
else
{
List<EntityVillager> list = this.villager.world.<EntityVillager>getEntitiesWithinAABB(EntityVillager.class, this.villager.getEntityBoundingBox().grow(6.0D, 3.0D, 6.0D));
double d0 = Double.MAX_VALUE;
for (EntityVillager entityvillager : list)
{
if (entityvillager != this.villager && !entityvillager.isPlaying() && entityvillager.getGrowingAge() < 0)
{
double d1 = entityvillager.getDistanceSq(this.villager);
if (d1 <= d0)
{
d0 = d1;
this.targetVillager = entityvillager;
}
}
}
if (this.targetVillager == null)
{
Vec3d vec3d = RandomPositionGenerator.findRandomTarget(this.villager, 16, 3);
if (vec3d == null)
{
return false;
}
}
return true;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.playTime > 0;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
if (this.targetVillager != null)
{
this.villager.setPlaying(true);
}
this.playTime = 1000;
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.villager.setPlaying(false);
this.targetVillager = null;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
--this.playTime;
if (this.targetVillager != null)
{
if (this.villager.getDistanceSq(this.targetVillager) > 4.0D)
{
this.villager.getNavigator().tryMoveToEntityLiving(this.targetVillager, this.speed);
}
}
else if (this.villager.getNavigator().noPath())
{
Vec3d vec3d = RandomPositionGenerator.findRandomTarget(this.villager, 16, 3);
if (vec3d == null)
{
return;
}
this.villager.getNavigator().tryMoveToXYZ(vec3d.x, vec3d.y, vec3d.z, this.speed);
}
}
}

View File

@@ -0,0 +1,99 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityCreature;
import net.minecraft.pathfinding.PathNavigateGround;
import net.minecraft.util.math.BlockPos;
import net.minecraft.village.Village;
import net.minecraft.village.VillageDoorInfo;
public class EntityAIRestrictOpenDoor extends EntityAIBase
{
private final EntityCreature entity;
private VillageDoorInfo frontDoor;
public EntityAIRestrictOpenDoor(EntityCreature creatureIn)
{
this.entity = creatureIn;
if (!(creatureIn.getNavigator() instanceof PathNavigateGround))
{
throw new IllegalArgumentException("Unsupported mob type for RestrictOpenDoorGoal");
}
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.entity.world.isDaytime())
{
return false;
}
else
{
BlockPos blockpos = new BlockPos(this.entity);
Village village = this.entity.world.getVillageCollection().getNearestVillage(blockpos, 16);
if (village == null)
{
return false;
}
else
{
this.frontDoor = village.getNearestDoor(blockpos);
if (this.frontDoor == null)
{
return false;
}
else
{
return (double)this.frontDoor.getDistanceToInsideBlockSq(blockpos) < 2.25D;
}
}
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
if (this.entity.world.isDaytime())
{
return false;
}
else
{
return !this.frontDoor.getIsDetachedFromVillageFlag() && this.frontDoor.isInsideSide(new BlockPos(this.entity));
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
((PathNavigateGround)this.entity.getNavigator()).setBreakDoors(false);
((PathNavigateGround)this.entity.getNavigator()).setEnterDoors(false);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
((PathNavigateGround)this.entity.getNavigator()).setBreakDoors(true);
((PathNavigateGround)this.entity.getNavigator()).setEnterDoors(true);
this.frontDoor = null;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
this.frontDoor.incrementDoorOpeningRestrictionCounter();
}
}

View File

@@ -0,0 +1,39 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityCreature;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.pathfinding.PathNavigateGround;
public class EntityAIRestrictSun extends EntityAIBase
{
private final EntityCreature entity;
public EntityAIRestrictSun(EntityCreature creature)
{
this.entity = creature;
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
return this.entity.world.isDaytime() && this.entity.getItemStackFromSlot(EntityEquipmentSlot.HEAD).isEmpty();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
((PathNavigateGround)this.entity.getNavigator()).setAvoidSun(true);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
((PathNavigateGround)this.entity.getNavigator()).setAvoidSun(false);
}
}

View File

@@ -0,0 +1,99 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.Entity;
import net.minecraft.entity.passive.AbstractHorse;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.math.Vec3d;
public class EntityAIRunAroundLikeCrazy extends EntityAIBase
{
private final AbstractHorse horseHost;
private final double speed;
private double targetX;
private double targetY;
private double targetZ;
public EntityAIRunAroundLikeCrazy(AbstractHorse horse, double speedIn)
{
this.horseHost = horse;
this.speed = speedIn;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.horseHost.isTame() && this.horseHost.isBeingRidden())
{
Vec3d vec3d = RandomPositionGenerator.findRandomTarget(this.horseHost, 5, 4);
if (vec3d == null)
{
return false;
}
else
{
this.targetX = vec3d.x;
this.targetY = vec3d.y;
this.targetZ = vec3d.z;
return true;
}
}
else
{
return false;
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.horseHost.getNavigator().tryMoveToXYZ(this.targetX, this.targetY, this.targetZ, this.speed);
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.horseHost.isTame() && !this.horseHost.getNavigator().noPath() && this.horseHost.isBeingRidden();
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
if (!this.horseHost.isTame() && this.horseHost.getRNG().nextInt(50) == 0)
{
Entity entity = (Entity)this.horseHost.getPassengers().get(0);
if (entity == null)
{
return;
}
if (entity instanceof EntityPlayer)
{
int i = this.horseHost.getTemper();
int j = this.horseHost.getMaxTemper();
if (j > 0 && this.horseHost.getRNG().nextInt(j) < i && !net.minecraftforge.event.ForgeEventFactory.onAnimalTame(horseHost, (EntityPlayer)entity))
{
this.horseHost.setTamedBy((EntityPlayer)entity);
return;
}
this.horseHost.increaseTemper(5);
}
this.horseHost.removePassengers();
this.horseHost.makeMad();
this.horseHost.world.setEntityState(this.horseHost, (byte)6);
}
}
}

View File

@@ -0,0 +1,74 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityTameable;
public class EntityAISit extends EntityAIBase
{
private final EntityTameable tameable;
/** If the EntityTameable is sitting. */
private boolean isSitting;
public EntityAISit(EntityTameable entityIn)
{
this.tameable = entityIn;
this.setMutexBits(5);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.tameable.isTamed())
{
return false;
}
else if (this.tameable.isInWater())
{
return false;
}
else if (!this.tameable.onGround)
{
return false;
}
else
{
EntityLivingBase entitylivingbase = this.tameable.getOwner();
if (entitylivingbase == null)
{
return true;
}
else
{
return this.tameable.getDistanceSq(entitylivingbase) < 144.0D && entitylivingbase.getRevengeTarget() != null ? false : this.isSitting;
}
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.tameable.getNavigator().clearPath();
this.tameable.setSitting(true);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.tameable.setSitting(false);
}
/**
* Sets the sitting flag.
*/
public void setSitting(boolean sitting)
{
this.isSitting = sitting;
}
}

View File

@@ -0,0 +1,85 @@
package net.minecraft.entity.ai;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.IEntityLivingData;
import net.minecraft.entity.effect.EntityLightningBolt;
import net.minecraft.entity.monster.EntitySkeleton;
import net.minecraft.entity.passive.AbstractHorse;
import net.minecraft.entity.passive.EntitySkeletonHorse;
import net.minecraft.init.Items;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.DifficultyInstance;
public class EntityAISkeletonRiders extends EntityAIBase
{
private final EntitySkeletonHorse horse;
public EntityAISkeletonRiders(EntitySkeletonHorse horseIn)
{
this.horse = horseIn;
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
return this.horse.world.isAnyPlayerWithinRangeAt(this.horse.posX, this.horse.posY, this.horse.posZ, 10.0D);
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
DifficultyInstance difficultyinstance = this.horse.world.getDifficultyForLocation(new BlockPos(this.horse));
this.horse.setTrap(false);
this.horse.setHorseTamed(true);
this.horse.setGrowingAge(0);
this.horse.world.addWeatherEffect(new EntityLightningBolt(this.horse.world, this.horse.posX, this.horse.posY, this.horse.posZ, true));
EntitySkeleton entityskeleton = this.createSkeleton(difficultyinstance, this.horse);
entityskeleton.startRiding(this.horse);
for (int i = 0; i < 3; ++i)
{
AbstractHorse abstracthorse = this.createHorse(difficultyinstance);
EntitySkeleton entityskeleton1 = this.createSkeleton(difficultyinstance, abstracthorse);
entityskeleton1.startRiding(abstracthorse);
abstracthorse.addVelocity(this.horse.getRNG().nextGaussian() * 0.5D, 0.0D, this.horse.getRNG().nextGaussian() * 0.5D);
}
}
private AbstractHorse createHorse(DifficultyInstance p_188515_1_)
{
EntitySkeletonHorse entityskeletonhorse = new EntitySkeletonHorse(this.horse.world);
entityskeletonhorse.onInitialSpawn(p_188515_1_, (IEntityLivingData)null);
entityskeletonhorse.setPosition(this.horse.posX, this.horse.posY, this.horse.posZ);
entityskeletonhorse.hurtResistantTime = 60;
entityskeletonhorse.enablePersistence();
entityskeletonhorse.setHorseTamed(true);
entityskeletonhorse.setGrowingAge(0);
entityskeletonhorse.world.spawnEntity(entityskeletonhorse);
return entityskeletonhorse;
}
private EntitySkeleton createSkeleton(DifficultyInstance p_188514_1_, AbstractHorse p_188514_2_)
{
EntitySkeleton entityskeleton = new EntitySkeleton(p_188514_2_.world);
entityskeleton.onInitialSpawn(p_188514_1_, (IEntityLivingData)null);
entityskeleton.setPosition(p_188514_2_.posX, p_188514_2_.posY, p_188514_2_.posZ);
entityskeleton.hurtResistantTime = 60;
entityskeleton.enablePersistence();
if (entityskeleton.getItemStackFromSlot(EntityEquipmentSlot.HEAD).isEmpty())
{
entityskeleton.setItemStackToSlot(EntityEquipmentSlot.HEAD, new ItemStack(Items.IRON_HELMET));
}
entityskeleton.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, EnchantmentHelper.addRandomEnchantment(entityskeleton.getRNG(), entityskeleton.getHeldItemMainhand(), (int)(5.0F + p_188514_1_.getClampedAdditionalDifficulty() * (float)entityskeleton.getRNG().nextInt(18)), false));
entityskeleton.setItemStackToSlot(EntityEquipmentSlot.HEAD, EnchantmentHelper.addRandomEnchantment(entityskeleton.getRNG(), entityskeleton.getItemStackFromSlot(EntityEquipmentSlot.HEAD), (int)(5.0F + p_188514_1_.getClampedAdditionalDifficulty() * (float)entityskeleton.getRNG().nextInt(18)), false));
entityskeleton.world.spawnEntity(entityskeleton);
return entityskeleton;
}
}

View File

@@ -0,0 +1,44 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLiving;
import net.minecraft.pathfinding.PathNavigateFlying;
import net.minecraft.pathfinding.PathNavigateGround;
public class EntityAISwimming extends EntityAIBase
{
private final EntityLiving entity;
public EntityAISwimming(EntityLiving entityIn)
{
this.entity = entityIn;
this.setMutexBits(4);
if (entityIn.getNavigator() instanceof PathNavigateGround)
{
((PathNavigateGround)entityIn.getNavigator()).setCanSwim(true);
}
else if (entityIn.getNavigator() instanceof PathNavigateFlying)
{
((PathNavigateFlying)entityIn.getNavigator()).setCanFloat(true);
}
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
return this.entity.isInWater() || this.entity.isInLava();
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
if (this.entity.getRNG().nextFloat() < 0.8F)
{
this.entity.getJumpHelper().setJumping();
}
}
}

View File

@@ -0,0 +1,260 @@
package net.minecraft.entity.ai;
import javax.annotation.Nullable;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.IEntityOwnable;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.entity.ai.attributes.IAttributeInstance;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.pathfinding.Path;
import net.minecraft.pathfinding.PathPoint;
import net.minecraft.scoreboard.Team;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
public abstract class EntityAITarget extends EntityAIBase
{
/** The entity that this task belongs to */
protected final EntityCreature taskOwner;
/** If true, EntityAI targets must be able to be seen (cannot be blocked by walls) to be suitable targets. */
protected boolean shouldCheckSight;
/** When true, only entities that can be reached with minimal effort will be targetted. */
private final boolean nearbyOnly;
/** When nearbyOnly is true: 0 -> No target, but OK to search; 1 -> Nearby target found; 2 -> Target too far. */
private int targetSearchStatus;
/** When nearbyOnly is true, this throttles target searching to avoid excessive pathfinding. */
private int targetSearchDelay;
/**
* If @shouldCheckSight is true, the number of ticks before the interuption of this AITastk when the entity does't
* see the target
*/
private int targetUnseenTicks;
protected EntityLivingBase target;
protected int unseenMemoryTicks;
public EntityAITarget(EntityCreature creature, boolean checkSight)
{
this(creature, checkSight, false);
}
public EntityAITarget(EntityCreature creature, boolean checkSight, boolean onlyNearby)
{
this.unseenMemoryTicks = 60;
this.taskOwner = creature;
this.shouldCheckSight = checkSight;
this.nearbyOnly = onlyNearby;
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
EntityLivingBase entitylivingbase = this.taskOwner.getAttackTarget();
if (entitylivingbase == null)
{
entitylivingbase = this.target;
}
if (entitylivingbase == null)
{
return false;
}
else if (!entitylivingbase.isEntityAlive())
{
return false;
}
else
{
Team team = this.taskOwner.getTeam();
Team team1 = entitylivingbase.getTeam();
if (team != null && team1 == team)
{
return false;
}
else
{
double d0 = this.getTargetDistance();
if (this.taskOwner.getDistanceSq(entitylivingbase) > d0 * d0)
{
return false;
}
else
{
if (this.shouldCheckSight)
{
if (this.taskOwner.getEntitySenses().canSee(entitylivingbase))
{
this.targetUnseenTicks = 0;
}
else if (++this.targetUnseenTicks > this.unseenMemoryTicks)
{
return false;
}
}
if (entitylivingbase instanceof EntityPlayer && ((EntityPlayer)entitylivingbase).capabilities.disableDamage)
{
return false;
}
else
{
this.taskOwner.setAttackTarget(entitylivingbase);
return true;
}
}
}
}
}
protected double getTargetDistance()
{
IAttributeInstance iattributeinstance = this.taskOwner.getEntityAttribute(SharedMonsterAttributes.FOLLOW_RANGE);
return iattributeinstance == null ? 16.0D : iattributeinstance.getAttributeValue();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.targetSearchStatus = 0;
this.targetSearchDelay = 0;
this.targetUnseenTicks = 0;
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.taskOwner.setAttackTarget((EntityLivingBase)null);
this.target = null;
}
/**
* A static method used to see if an entity is a suitable target through a number of checks.
*/
public static boolean isSuitableTarget(EntityLiving attacker, @Nullable EntityLivingBase target, boolean includeInvincibles, boolean checkSight)
{
if (target == null)
{
return false;
}
else if (target == attacker)
{
return false;
}
else if (!target.isEntityAlive())
{
return false;
}
else if (!attacker.canAttackClass(target.getClass()))
{
return false;
}
else if (attacker.isOnSameTeam(target))
{
return false;
}
else
{
if (attacker instanceof IEntityOwnable && ((IEntityOwnable)attacker).getOwnerId() != null)
{
if (target instanceof IEntityOwnable && ((IEntityOwnable)attacker).getOwnerId().equals(((IEntityOwnable)target).getOwnerId()))
{
return false;
}
if (target == ((IEntityOwnable)attacker).getOwner())
{
return false;
}
}
else if (target instanceof EntityPlayer && !includeInvincibles && ((EntityPlayer)target).capabilities.disableDamage)
{
return false;
}
return !checkSight || attacker.getEntitySenses().canSee(target);
}
}
/**
* A method used to see if an entity is a suitable target through a number of checks. Args : entity,
* canTargetInvinciblePlayer
*/
protected boolean isSuitableTarget(@Nullable EntityLivingBase target, boolean includeInvincibles)
{
if (!isSuitableTarget(this.taskOwner, target, includeInvincibles, this.shouldCheckSight))
{
return false;
}
else if (!this.taskOwner.isWithinHomeDistanceFromPosition(new BlockPos(target)))
{
return false;
}
else
{
if (this.nearbyOnly)
{
if (--this.targetSearchDelay <= 0)
{
this.targetSearchStatus = 0;
}
if (this.targetSearchStatus == 0)
{
this.targetSearchStatus = this.canEasilyReach(target) ? 1 : 2;
}
if (this.targetSearchStatus == 2)
{
return false;
}
}
return true;
}
}
/**
* Checks to see if this entity can find a short path to the given target.
*/
private boolean canEasilyReach(EntityLivingBase target)
{
this.targetSearchDelay = 10 + this.taskOwner.getRNG().nextInt(5);
Path path = this.taskOwner.getNavigator().getPathToEntityLiving(target);
if (path == null)
{
return false;
}
else
{
PathPoint pathpoint = path.getFinalPathPoint();
if (pathpoint == null)
{
return false;
}
else
{
int i = pathpoint.x - MathHelper.floor(target.posX);
int j = pathpoint.z - MathHelper.floor(target.posZ);
return (double)(i * i + j * j) <= 2.25D;
}
}
}
public EntityAITarget setUnseenMemoryTicks(int p_190882_1_)
{
this.unseenMemoryTicks = p_190882_1_;
return this;
}
}

View File

@@ -0,0 +1,24 @@
package net.minecraft.entity.ai;
import com.google.common.base.Predicate;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.entity.passive.EntityTameable;
public class EntityAITargetNonTamed<T extends EntityLivingBase> extends EntityAINearestAttackableTarget<T>
{
private final EntityTameable tameable;
public EntityAITargetNonTamed(EntityTameable entityIn, Class<T> classTarget, boolean checkSight, Predicate <? super T > targetSelector)
{
super(entityIn, classTarget, 10, checkSight, false, targetSelector);
this.tameable = entityIn;
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
return !this.tameable.isTamed() && super.shouldExecute();
}
}

View File

@@ -0,0 +1,233 @@
package net.minecraft.entity.ai;
import com.google.common.collect.Sets;
import java.util.Iterator;
import java.util.Set;
import javax.annotation.Nullable;
import net.minecraft.profiler.Profiler;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class EntityAITasks
{
private static final Logger LOGGER = LogManager.getLogger();
/** A list of EntityAITaskEntrys in EntityAITasks. */
public final Set<EntityAITasks.EntityAITaskEntry> taskEntries = Sets.<EntityAITasks.EntityAITaskEntry>newLinkedHashSet();
/** A list of EntityAITaskEntrys that are currently being executed. */
private final Set<EntityAITasks.EntityAITaskEntry> executingTaskEntries = Sets.<EntityAITasks.EntityAITaskEntry>newLinkedHashSet();
/** Instance of Profiler. */
private final Profiler profiler;
private int tickCount;
private int tickRate = 3;
private int disabledControlFlags;
public EntityAITasks(Profiler profilerIn)
{
this.profiler = profilerIn;
}
/**
* Add a now AITask. Args : priority, task
*/
public void addTask(int priority, EntityAIBase task)
{
this.taskEntries.add(new EntityAITasks.EntityAITaskEntry(priority, task));
}
/**
* removes the indicated task from the entity's AI tasks.
*/
public void removeTask(EntityAIBase task)
{
Iterator<EntityAITasks.EntityAITaskEntry> iterator = this.taskEntries.iterator();
while (iterator.hasNext())
{
EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry = iterator.next();
EntityAIBase entityaibase = entityaitasks$entityaitaskentry.action;
if (entityaibase == task)
{
if (entityaitasks$entityaitaskentry.using)
{
entityaitasks$entityaitaskentry.using = false;
entityaitasks$entityaitaskentry.action.resetTask();
this.executingTaskEntries.remove(entityaitasks$entityaitaskentry);
}
iterator.remove();
return;
}
}
}
public void onUpdateTasks()
{
this.profiler.startSection("goalSetup");
if (this.tickCount++ % this.tickRate == 0)
{
for (EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry : this.taskEntries)
{
if (entityaitasks$entityaitaskentry.using)
{
if (!this.canUse(entityaitasks$entityaitaskentry) || !this.canContinue(entityaitasks$entityaitaskentry))
{
entityaitasks$entityaitaskentry.using = false;
entityaitasks$entityaitaskentry.action.resetTask();
this.executingTaskEntries.remove(entityaitasks$entityaitaskentry);
}
}
else if (this.canUse(entityaitasks$entityaitaskentry) && entityaitasks$entityaitaskentry.action.shouldExecute())
{
entityaitasks$entityaitaskentry.using = true;
entityaitasks$entityaitaskentry.action.startExecuting();
this.executingTaskEntries.add(entityaitasks$entityaitaskentry);
}
}
}
else
{
Iterator<EntityAITasks.EntityAITaskEntry> iterator = this.executingTaskEntries.iterator();
while (iterator.hasNext())
{
EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry1 = iterator.next();
if (!this.canContinue(entityaitasks$entityaitaskentry1))
{
entityaitasks$entityaitaskentry1.using = false;
entityaitasks$entityaitaskentry1.action.resetTask();
iterator.remove();
}
}
}
this.profiler.endSection();
if (!this.executingTaskEntries.isEmpty())
{
this.profiler.startSection("goalTick");
for (EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry2 : this.executingTaskEntries)
{
entityaitasks$entityaitaskentry2.action.updateTask();
}
this.profiler.endSection();
}
}
/**
* Determine if a specific AI Task should continue being executed.
*/
private boolean canContinue(EntityAITasks.EntityAITaskEntry taskEntry)
{
return taskEntry.action.shouldContinueExecuting();
}
/**
* Determine if a specific AI Task can be executed, which means that all running higher (= lower int value) priority
* tasks are compatible with it or all lower priority tasks can be interrupted.
*/
private boolean canUse(EntityAITasks.EntityAITaskEntry taskEntry)
{
if (this.executingTaskEntries.isEmpty())
{
return true;
}
else if (this.isControlFlagDisabled(taskEntry.action.getMutexBits()))
{
return false;
}
else
{
for (EntityAITasks.EntityAITaskEntry entityaitasks$entityaitaskentry : this.executingTaskEntries)
{
if (entityaitasks$entityaitaskentry != taskEntry)
{
if (taskEntry.priority >= entityaitasks$entityaitaskentry.priority)
{
if (!this.areTasksCompatible(taskEntry, entityaitasks$entityaitaskentry))
{
return false;
}
}
else if (!entityaitasks$entityaitaskentry.action.isInterruptible())
{
return false;
}
}
}
return true;
}
}
/**
* Returns whether two EntityAITaskEntries can be executed concurrently
*/
private boolean areTasksCompatible(EntityAITasks.EntityAITaskEntry taskEntry1, EntityAITasks.EntityAITaskEntry taskEntry2)
{
return (taskEntry1.action.getMutexBits() & taskEntry2.action.getMutexBits()) == 0;
}
public boolean isControlFlagDisabled(int p_188528_1_)
{
return (this.disabledControlFlags & p_188528_1_) > 0;
}
public void disableControlFlag(int p_188526_1_)
{
this.disabledControlFlags |= p_188526_1_;
}
public void enableControlFlag(int p_188525_1_)
{
this.disabledControlFlags &= ~p_188525_1_;
}
public void setControlFlag(int p_188527_1_, boolean p_188527_2_)
{
if (p_188527_2_)
{
this.enableControlFlag(p_188527_1_);
}
else
{
this.disableControlFlag(p_188527_1_);
}
}
public class EntityAITaskEntry
{
/** The EntityAIBase object. */
public final EntityAIBase action;
/** Priority of the EntityAIBase */
public final int priority;
public boolean using;
public EntityAITaskEntry(int priorityIn, EntityAIBase task)
{
this.priority = priorityIn;
this.action = task;
}
public boolean equals(@Nullable Object p_equals_1_)
{
if (this == p_equals_1_)
{
return true;
}
else
{
return p_equals_1_ != null && this.getClass() == p_equals_1_.getClass() ? this.action.equals(((EntityAITasks.EntityAITaskEntry)p_equals_1_).action) : false;
}
}
public int hashCode()
{
return this.action.hashCode();
}
}
}

View File

@@ -0,0 +1,167 @@
package net.minecraft.entity.ai;
import com.google.common.collect.Sets;
import java.util.Set;
import net.minecraft.entity.EntityCreature;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.pathfinding.PathNavigateGround;
public class EntityAITempt extends EntityAIBase
{
/** The entity using this AI that is tempted by the player. */
private final EntityCreature temptedEntity;
private final double speed;
/** X position of player tempting this mob */
private double targetX;
/** Y position of player tempting this mob */
private double targetY;
/** Z position of player tempting this mob */
private double targetZ;
/** Tempting player's pitch */
private double pitch;
/** Tempting player's yaw */
private double yaw;
/** The player that is tempting the entity that is using this AI. */
private EntityPlayer temptingPlayer;
/**
* A counter that is decremented each time the shouldExecute method is called. The shouldExecute method will always
* return false if delayTemptCounter is greater than 0.
*/
private int delayTemptCounter;
/** True if this EntityAITempt task is running */
private boolean isRunning;
private final Set<Item> temptItem;
/** Whether the entity using this AI will be scared by the tempter's sudden movement. */
private final boolean scaredByPlayerMovement;
public EntityAITempt(EntityCreature temptedEntityIn, double speedIn, Item temptItemIn, boolean scaredByPlayerMovementIn)
{
this(temptedEntityIn, speedIn, scaredByPlayerMovementIn, Sets.newHashSet(temptItemIn));
}
public EntityAITempt(EntityCreature temptedEntityIn, double speedIn, boolean scaredByPlayerMovementIn, Set<Item> temptItemIn)
{
this.temptedEntity = temptedEntityIn;
this.speed = speedIn;
this.temptItem = temptItemIn;
this.scaredByPlayerMovement = scaredByPlayerMovementIn;
this.setMutexBits(3);
if (!(temptedEntityIn.getNavigator() instanceof PathNavigateGround))
{
throw new IllegalArgumentException("Unsupported mob type for TemptGoal");
}
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.delayTemptCounter > 0)
{
--this.delayTemptCounter;
return false;
}
else
{
this.temptingPlayer = this.temptedEntity.world.getClosestPlayerToEntity(this.temptedEntity, 10.0D);
if (this.temptingPlayer == null)
{
return false;
}
else
{
return this.isTempting(this.temptingPlayer.getHeldItemMainhand()) || this.isTempting(this.temptingPlayer.getHeldItemOffhand());
}
}
}
protected boolean isTempting(ItemStack stack)
{
return this.temptItem.contains(stack.getItem());
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
if (this.scaredByPlayerMovement)
{
if (this.temptedEntity.getDistanceSq(this.temptingPlayer) < 36.0D)
{
if (this.temptingPlayer.getDistanceSq(this.targetX, this.targetY, this.targetZ) > 0.010000000000000002D)
{
return false;
}
if (Math.abs((double)this.temptingPlayer.rotationPitch - this.pitch) > 5.0D || Math.abs((double)this.temptingPlayer.rotationYaw - this.yaw) > 5.0D)
{
return false;
}
}
else
{
this.targetX = this.temptingPlayer.posX;
this.targetY = this.temptingPlayer.posY;
this.targetZ = this.temptingPlayer.posZ;
}
this.pitch = (double)this.temptingPlayer.rotationPitch;
this.yaw = (double)this.temptingPlayer.rotationYaw;
}
return this.shouldExecute();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.targetX = this.temptingPlayer.posX;
this.targetY = this.temptingPlayer.posY;
this.targetZ = this.temptingPlayer.posZ;
this.isRunning = true;
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.temptingPlayer = null;
this.temptedEntity.getNavigator().clearPath();
this.delayTemptCounter = 100;
this.isRunning = false;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
this.temptedEntity.getLookHelper().setLookPositionWithEntity(this.temptingPlayer, (float)(this.temptedEntity.getHorizontalFaceSpeed() + 20), (float)this.temptedEntity.getVerticalFaceSpeed());
if (this.temptedEntity.getDistanceSq(this.temptingPlayer) < 6.25D)
{
this.temptedEntity.getNavigator().clearPath();
}
else
{
this.temptedEntity.getNavigator().tryMoveToEntityLiving(this.temptingPlayer, this.speed);
}
}
/**
* @see #isRunning
*/
public boolean isRunning()
{
return this.isRunning;
}
}

View File

@@ -0,0 +1,71 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.entity.player.EntityPlayer;
public class EntityAITradePlayer extends EntityAIBase
{
private final EntityVillager villager;
public EntityAITradePlayer(EntityVillager villagerIn)
{
this.villager = villagerIn;
this.setMutexBits(5);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.villager.isEntityAlive())
{
return false;
}
else if (this.villager.isInWater())
{
return false;
}
else if (!this.villager.onGround)
{
return false;
}
else if (this.villager.velocityChanged)
{
return false;
}
else
{
EntityPlayer entityplayer = this.villager.getCustomer();
if (entityplayer == null)
{
return false;
}
else if (this.villager.getDistanceSq(entityplayer) > 16.0D)
{
return false;
}
else
{
return entityplayer.openContainer != null;
}
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.villager.getNavigator().clearPath();
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.villager.setCustomer((EntityPlayer)null);
}
}

View File

@@ -0,0 +1,102 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.init.Items;
import net.minecraft.inventory.InventoryBasic;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.MathHelper;
public class EntityAIVillagerInteract extends EntityAIWatchClosest2
{
/** The delay before the villager throws an itemstack (in ticks) */
private int interactionDelay;
private final EntityVillager villager;
public EntityAIVillagerInteract(EntityVillager villagerIn)
{
super(villagerIn, EntityVillager.class, 3.0F, 0.02F);
this.villager = villagerIn;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
super.startExecuting();
if (this.villager.canAbondonItems() && this.closestEntity instanceof EntityVillager && ((EntityVillager)this.closestEntity).wantsMoreFood())
{
this.interactionDelay = 10;
}
else
{
this.interactionDelay = 0;
}
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
super.updateTask();
if (this.interactionDelay > 0)
{
--this.interactionDelay;
if (this.interactionDelay == 0)
{
InventoryBasic inventorybasic = this.villager.getVillagerInventory();
for (int i = 0; i < inventorybasic.getSizeInventory(); ++i)
{
ItemStack itemstack = inventorybasic.getStackInSlot(i);
ItemStack itemstack1 = ItemStack.EMPTY;
if (!itemstack.isEmpty())
{
Item item = itemstack.getItem();
if ((item == Items.BREAD || item == Items.POTATO || item == Items.CARROT || item == Items.BEETROOT) && itemstack.getCount() > 3)
{
int l = itemstack.getCount() / 2;
itemstack.shrink(l);
itemstack1 = new ItemStack(item, l, itemstack.getMetadata());
}
else if (item == Items.WHEAT && itemstack.getCount() > 5)
{
int j = itemstack.getCount() / 2 / 3 * 3;
int k = j / 3;
itemstack.shrink(j);
itemstack1 = new ItemStack(Items.BREAD, k, 0);
}
if (itemstack.isEmpty())
{
inventorybasic.setInventorySlotContents(i, ItemStack.EMPTY);
}
}
if (!itemstack1.isEmpty())
{
double d0 = this.villager.posY - 0.30000001192092896D + (double)this.villager.getEyeHeight();
EntityItem entityitem = new EntityItem(this.villager.world, this.villager.posX, d0, this.villager.posZ, itemstack1);
float f = 0.3F;
float f1 = this.villager.rotationYawHead;
float f2 = this.villager.rotationPitch;
entityitem.motionX = (double)(-MathHelper.sin(f1 * 0.017453292F) * MathHelper.cos(f2 * 0.017453292F) * 0.3F);
entityitem.motionZ = (double)(MathHelper.cos(f1 * 0.017453292F) * MathHelper.cos(f2 * 0.017453292F) * 0.3F);
entityitem.motionY = (double)(-MathHelper.sin(f2 * 0.017453292F) * 0.3F + 0.1F);
entityitem.setDefaultPickupDelay();
this.villager.world.spawnEntity(entityitem);
break;
}
}
}
}
}
}

View File

@@ -0,0 +1,145 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.Entity;
import net.minecraft.entity.passive.EntityVillager;
import net.minecraft.util.math.BlockPos;
import net.minecraft.village.Village;
import net.minecraft.world.World;
public class EntityAIVillagerMate extends EntityAIBase
{
private final EntityVillager villager;
private EntityVillager mate;
private final World world;
private int matingTimeout;
Village village;
public EntityAIVillagerMate(EntityVillager villagerIn)
{
this.villager = villagerIn;
this.world = villagerIn.world;
this.setMutexBits(3);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.villager.getGrowingAge() != 0)
{
return false;
}
else if (this.villager.getRNG().nextInt(500) != 0)
{
return false;
}
else
{
this.village = this.world.getVillageCollection().getNearestVillage(new BlockPos(this.villager), 0);
if (this.village == null)
{
return false;
}
else if (this.checkSufficientDoorsPresentForNewVillager() && this.villager.getIsWillingToMate(true))
{
Entity entity = this.world.findNearestEntityWithinAABB(EntityVillager.class, this.villager.getEntityBoundingBox().grow(8.0D, 3.0D, 8.0D), this.villager);
if (entity == null)
{
return false;
}
else
{
this.mate = (EntityVillager)entity;
return this.mate.getGrowingAge() == 0 && this.mate.getIsWillingToMate(true);
}
}
else
{
return false;
}
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.matingTimeout = 300;
this.villager.setMating(true);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.village = null;
this.mate = null;
this.villager.setMating(false);
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return this.matingTimeout >= 0 && this.checkSufficientDoorsPresentForNewVillager() && this.villager.getGrowingAge() == 0 && this.villager.getIsWillingToMate(false);
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
--this.matingTimeout;
this.villager.getLookHelper().setLookPositionWithEntity(this.mate, 10.0F, 30.0F);
if (this.villager.getDistanceSq(this.mate) > 2.25D)
{
this.villager.getNavigator().tryMoveToEntityLiving(this.mate, 0.25D);
}
else if (this.matingTimeout == 0 && this.mate.isMating())
{
this.giveBirth();
}
if (this.villager.getRNG().nextInt(35) == 0)
{
this.world.setEntityState(this.villager, (byte)12);
}
}
private boolean checkSufficientDoorsPresentForNewVillager()
{
if (!this.village.isMatingSeason())
{
return false;
}
else
{
int i = (int)((double)((float)this.village.getNumVillageDoors()) * 0.35D);
return this.village.getNumVillagers() < i;
}
}
private void giveBirth()
{
net.minecraft.entity.EntityAgeable entityvillager = this.villager.createChild(this.mate);
this.mate.setGrowingAge(6000);
this.villager.setGrowingAge(6000);
this.mate.setIsWillingToMate(false);
this.villager.setIsWillingToMate(false);
final net.minecraftforge.event.entity.living.BabyEntitySpawnEvent event = new net.minecraftforge.event.entity.living.BabyEntitySpawnEvent(villager, mate, entityvillager);
if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event) || event.getChild() == null) { return; }
entityvillager = event.getChild();
entityvillager.setGrowingAge(-24000);
entityvillager.setLocationAndAngles(this.villager.posX, this.villager.posY, this.villager.posZ, 0.0F, 0.0F);
this.world.spawnEntity(entityvillager);
this.world.setEntityState(entityvillager, (byte)12);
}
}

View File

@@ -0,0 +1,101 @@
package net.minecraft.entity.ai;
import javax.annotation.Nullable;
import net.minecraft.entity.EntityCreature;
import net.minecraft.util.math.Vec3d;
public class EntityAIWander extends EntityAIBase
{
protected final EntityCreature entity;
protected double x;
protected double y;
protected double z;
protected final double speed;
protected int executionChance;
protected boolean mustUpdate;
public EntityAIWander(EntityCreature creatureIn, double speedIn)
{
this(creatureIn, speedIn, 120);
}
public EntityAIWander(EntityCreature creatureIn, double speedIn, int chance)
{
this.entity = creatureIn;
this.speed = speedIn;
this.executionChance = chance;
this.setMutexBits(1);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (!this.mustUpdate)
{
if (this.entity.getIdleTime() >= 100)
{
return false;
}
if (this.entity.getRNG().nextInt(this.executionChance) != 0)
{
return false;
}
}
Vec3d vec3d = this.getPosition();
if (vec3d == null)
{
return false;
}
else
{
this.x = vec3d.x;
this.y = vec3d.y;
this.z = vec3d.z;
this.mustUpdate = false;
return true;
}
}
@Nullable
protected Vec3d getPosition()
{
return RandomPositionGenerator.findRandomTarget(this.entity, 10, 7);
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
return !this.entity.getNavigator().noPath();
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.entity.getNavigator().tryMoveToXYZ(this.x, this.y, this.z, this.speed);
}
/**
* Makes task to bypass chance
*/
public void makeUpdate()
{
this.mustUpdate = true;
}
/**
* Changes task random possibility for execution
*/
public void setExecutionChance(int newchance)
{
this.executionChance = newchance;
}
}

View File

@@ -0,0 +1,35 @@
package net.minecraft.entity.ai;
import javax.annotation.Nullable;
import net.minecraft.entity.EntityCreature;
import net.minecraft.util.math.Vec3d;
public class EntityAIWanderAvoidWater extends EntityAIWander
{
protected final float probability;
public EntityAIWanderAvoidWater(EntityCreature p_i47301_1_, double p_i47301_2_)
{
this(p_i47301_1_, p_i47301_2_, 0.001F);
}
public EntityAIWanderAvoidWater(EntityCreature p_i47302_1_, double p_i47302_2_, float p_i47302_4_)
{
super(p_i47302_1_, p_i47302_2_);
this.probability = p_i47302_4_;
}
@Nullable
protected Vec3d getPosition()
{
if (this.entity.isInWater())
{
Vec3d vec3d = RandomPositionGenerator.getLandPos(this.entity, 15, 7);
return vec3d == null ? super.getPosition() : vec3d;
}
else
{
return this.entity.getRNG().nextFloat() >= this.probability ? RandomPositionGenerator.getLandPos(this.entity, 10, 7) : super.getPosition();
}
}
}

View File

@@ -0,0 +1,72 @@
package net.minecraft.entity.ai;
import java.util.Iterator;
import javax.annotation.Nullable;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLeaves;
import net.minecraft.entity.EntityCreature;
import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class EntityAIWanderAvoidWaterFlying extends EntityAIWanderAvoidWater
{
public EntityAIWanderAvoidWaterFlying(EntityCreature p_i47413_1_, double p_i47413_2_)
{
super(p_i47413_1_, p_i47413_2_);
}
@Nullable
protected Vec3d getPosition()
{
Vec3d vec3d = null;
if (this.entity.isInWater() || this.entity.isOverWater())
{
vec3d = RandomPositionGenerator.getLandPos(this.entity, 15, 15);
}
if (this.entity.getRNG().nextFloat() >= this.probability)
{
vec3d = this.getTreePos();
}
return vec3d == null ? super.getPosition() : vec3d;
}
@Nullable
private Vec3d getTreePos()
{
BlockPos blockpos = new BlockPos(this.entity);
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
BlockPos.MutableBlockPos blockpos$mutableblockpos1 = new BlockPos.MutableBlockPos();
Iterable<BlockPos.MutableBlockPos> iterable = BlockPos.MutableBlockPos.getAllInBoxMutable(MathHelper.floor(this.entity.posX - 3.0D), MathHelper.floor(this.entity.posY - 6.0D), MathHelper.floor(this.entity.posZ - 3.0D), MathHelper.floor(this.entity.posX + 3.0D), MathHelper.floor(this.entity.posY + 6.0D), MathHelper.floor(this.entity.posZ + 3.0D));
Iterator iterator = iterable.iterator();
BlockPos blockpos1;
while (true)
{
if (!iterator.hasNext())
{
return null;
}
blockpos1 = (BlockPos)iterator.next();
if (!blockpos.equals(blockpos1))
{
Block block = this.entity.world.getBlockState(blockpos$mutableblockpos1.setPos(blockpos1).move(EnumFacing.DOWN)).getBlock();
boolean flag = block instanceof BlockLeaves || block == Blocks.LOG || block == Blocks.LOG2;
if (flag && this.entity.world.isAirBlock(blockpos1) && this.entity.world.isAirBlock(blockpos$mutableblockpos.setPos(blockpos1).move(EnumFacing.UP)))
{
break;
}
}
}
return new Vec3d((double)blockpos1.getX(), (double)blockpos1.getY(), (double)blockpos1.getZ());
}
}

View File

@@ -0,0 +1,110 @@
package net.minecraft.entity.ai;
import com.google.common.base.Predicates;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EntitySelectors;
public class EntityAIWatchClosest extends EntityAIBase
{
protected EntityLiving entity;
/** The closest entity which is being watched by this one. */
protected Entity closestEntity;
/** This is the Maximum distance that the AI will look for the Entity */
protected float maxDistanceForPlayer;
private int lookTime;
private final float chance;
protected Class <? extends Entity > watchedClass;
public EntityAIWatchClosest(EntityLiving entityIn, Class <? extends Entity > watchTargetClass, float maxDistance)
{
this.entity = entityIn;
this.watchedClass = watchTargetClass;
this.maxDistanceForPlayer = maxDistance;
this.chance = 0.02F;
this.setMutexBits(2);
}
public EntityAIWatchClosest(EntityLiving entityIn, Class <? extends Entity > watchTargetClass, float maxDistance, float chanceIn)
{
this.entity = entityIn;
this.watchedClass = watchTargetClass;
this.maxDistanceForPlayer = maxDistance;
this.chance = chanceIn;
this.setMutexBits(2);
}
/**
* Returns whether the EntityAIBase should begin execution.
*/
public boolean shouldExecute()
{
if (this.entity.getRNG().nextFloat() >= this.chance)
{
return false;
}
else
{
if (this.entity.getAttackTarget() != null)
{
this.closestEntity = this.entity.getAttackTarget();
}
if (this.watchedClass == EntityPlayer.class)
{
this.closestEntity = this.entity.world.getClosestPlayer(this.entity.posX, this.entity.posY, this.entity.posZ, (double)this.maxDistanceForPlayer, Predicates.and(EntitySelectors.NOT_SPECTATING, EntitySelectors.notRiding(this.entity)));
}
else
{
this.closestEntity = this.entity.world.findNearestEntityWithinAABB(this.watchedClass, this.entity.getEntityBoundingBox().grow((double)this.maxDistanceForPlayer, 3.0D, (double)this.maxDistanceForPlayer), this.entity);
}
return this.closestEntity != null;
}
}
/**
* Returns whether an in-progress EntityAIBase should continue executing
*/
public boolean shouldContinueExecuting()
{
if (!this.closestEntity.isEntityAlive())
{
return false;
}
else if (this.entity.getDistanceSq(this.closestEntity) > (double)(this.maxDistanceForPlayer * this.maxDistanceForPlayer))
{
return false;
}
else
{
return this.lookTime > 0;
}
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
this.lookTime = 40 + this.entity.getRNG().nextInt(40);
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
this.closestEntity = null;
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
this.entity.getLookHelper().setLookPosition(this.closestEntity.posX, this.closestEntity.posY + (double)this.closestEntity.getEyeHeight(), this.closestEntity.posZ, (float)this.entity.getHorizontalFaceSpeed(), (float)this.entity.getVerticalFaceSpeed());
--this.lookTime;
}
}

View File

@@ -0,0 +1,13 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
public class EntityAIWatchClosest2 extends EntityAIWatchClosest
{
public EntityAIWatchClosest2(EntityLiving entitylivingIn, Class <? extends Entity > watchTargetClass, float maxDistance, float chanceIn)
{
super(entitylivingIn, watchTargetClass, maxDistance, chanceIn);
this.setMutexBits(3);
}
}

View File

@@ -0,0 +1,51 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.monster.EntityZombie;
public class EntityAIZombieAttack extends EntityAIAttackMelee
{
private final EntityZombie zombie;
private int raiseArmTicks;
public EntityAIZombieAttack(EntityZombie zombieIn, double speedIn, boolean longMemoryIn)
{
super(zombieIn, speedIn, longMemoryIn);
this.zombie = zombieIn;
}
/**
* Execute a one shot task or start executing a continuous task
*/
public void startExecuting()
{
super.startExecuting();
this.raiseArmTicks = 0;
}
/**
* Reset the task's internal state. Called when this task is interrupted by another one
*/
public void resetTask()
{
super.resetTask();
this.zombie.setArmsRaised(false);
}
/**
* Keep ticking a continuous task that has already been started
*/
public void updateTask()
{
super.updateTask();
++this.raiseArmTicks;
if (this.raiseArmTicks >= 5 && this.attackTick < 10)
{
this.zombie.setArmsRaised(true);
}
else
{
this.zombie.setArmsRaised(false);
}
}
}

View File

@@ -0,0 +1,58 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.util.math.MathHelper;
public class EntityFlyHelper extends EntityMoveHelper
{
public EntityFlyHelper(EntityLiving p_i47418_1_)
{
super(p_i47418_1_);
}
public void onUpdateMoveHelper()
{
if (this.action == EntityMoveHelper.Action.MOVE_TO)
{
this.action = EntityMoveHelper.Action.WAIT;
this.entity.setNoGravity(true);
double d0 = this.posX - this.entity.posX;
double d1 = this.posY - this.entity.posY;
double d2 = this.posZ - this.entity.posZ;
double d3 = d0 * d0 + d1 * d1 + d2 * d2;
if (d3 < 2.500000277905201E-7D)
{
this.entity.setMoveVertical(0.0F);
this.entity.setMoveForward(0.0F);
return;
}
float f = (float)(MathHelper.atan2(d2, d0) * (180D / Math.PI)) - 90.0F;
this.entity.rotationYaw = this.limitAngle(this.entity.rotationYaw, f, 10.0F);
float f1;
if (this.entity.onGround)
{
f1 = (float)(this.speed * this.entity.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getAttributeValue());
}
else
{
f1 = (float)(this.speed * this.entity.getEntityAttribute(SharedMonsterAttributes.FLYING_SPEED).getAttributeValue());
}
this.entity.setAIMoveSpeed(f1);
double d4 = (double)MathHelper.sqrt(d0 * d0 + d2 * d2);
float f2 = (float)(-(MathHelper.atan2(d1, d4) * (180D / Math.PI)));
this.entity.rotationPitch = this.limitAngle(this.entity.rotationPitch, f2, 10.0F);
this.entity.setMoveVertical(d1 > 0.0D ? f1 : -f1);
}
else
{
this.entity.setNoGravity(false);
this.entity.setMoveVertical(0.0F);
this.entity.setMoveForward(0.0F);
}
}
}

View File

@@ -0,0 +1,28 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLiving;
public class EntityJumpHelper
{
private final EntityLiving entity;
protected boolean isJumping;
public EntityJumpHelper(EntityLiving entityIn)
{
this.entity = entityIn;
}
public void setJumping()
{
this.isJumping = true;
}
/**
* Called to actually make the entity jump if isJumping is true.
*/
public void doJump()
{
this.entity.setJumping(this.isJumping);
this.isJumping = false;
}
}

View File

@@ -0,0 +1,137 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.EntityLivingBase;
import net.minecraft.util.math.MathHelper;
public class EntityLookHelper
{
private final EntityLiving entity;
/** The amount of change that is made each update for an entity facing a direction. */
private float deltaLookYaw;
/** The amount of change that is made each update for an entity facing a direction. */
private float deltaLookPitch;
/** Whether or not the entity is trying to look at something. */
private boolean isLooking;
private double posX;
private double posY;
private double posZ;
public EntityLookHelper(EntityLiving entitylivingIn)
{
this.entity = entitylivingIn;
}
/**
* Sets position to look at using entity
*/
public void setLookPositionWithEntity(Entity entityIn, float deltaYaw, float deltaPitch)
{
this.posX = entityIn.posX;
if (entityIn instanceof EntityLivingBase)
{
this.posY = entityIn.posY + (double)entityIn.getEyeHeight();
}
else
{
this.posY = (entityIn.getEntityBoundingBox().minY + entityIn.getEntityBoundingBox().maxY) / 2.0D;
}
this.posZ = entityIn.posZ;
this.deltaLookYaw = deltaYaw;
this.deltaLookPitch = deltaPitch;
this.isLooking = true;
}
/**
* Sets position to look at
*/
public void setLookPosition(double x, double y, double z, float deltaYaw, float deltaPitch)
{
this.posX = x;
this.posY = y;
this.posZ = z;
this.deltaLookYaw = deltaYaw;
this.deltaLookPitch = deltaPitch;
this.isLooking = true;
}
/**
* Updates look
*/
public void onUpdateLook()
{
this.entity.rotationPitch = 0.0F;
if (this.isLooking)
{
this.isLooking = false;
double d0 = this.posX - this.entity.posX;
double d1 = this.posY - (this.entity.posY + (double)this.entity.getEyeHeight());
double d2 = this.posZ - this.entity.posZ;
double d3 = (double)MathHelper.sqrt(d0 * d0 + d2 * d2);
float f = (float)(MathHelper.atan2(d2, d0) * (180D / Math.PI)) - 90.0F;
float f1 = (float)(-(MathHelper.atan2(d1, d3) * (180D / Math.PI)));
this.entity.rotationPitch = this.updateRotation(this.entity.rotationPitch, f1, this.deltaLookPitch);
this.entity.rotationYawHead = this.updateRotation(this.entity.rotationYawHead, f, this.deltaLookYaw);
}
else
{
this.entity.rotationYawHead = this.updateRotation(this.entity.rotationYawHead, this.entity.renderYawOffset, 10.0F);
}
float f2 = MathHelper.wrapDegrees(this.entity.rotationYawHead - this.entity.renderYawOffset);
if (!this.entity.getNavigator().noPath())
{
if (f2 < -75.0F)
{
this.entity.rotationYawHead = this.entity.renderYawOffset - 75.0F;
}
if (f2 > 75.0F)
{
this.entity.rotationYawHead = this.entity.renderYawOffset + 75.0F;
}
}
}
private float updateRotation(float p_75652_1_, float p_75652_2_, float p_75652_3_)
{
float f = MathHelper.wrapDegrees(p_75652_2_ - p_75652_1_);
if (f > p_75652_3_)
{
f = p_75652_3_;
}
if (f < -p_75652_3_)
{
f = -p_75652_3_;
}
return p_75652_1_ + f;
}
public boolean getIsLooking()
{
return this.isLooking;
}
public double getLookPosX()
{
return this.posX;
}
public double getLookPosY()
{
return this.posY;
}
public double getLookPosZ()
{
return this.posZ;
}
}

View File

@@ -0,0 +1,203 @@
package net.minecraft.entity.ai;
import net.minecraft.entity.EntityLiving;
import net.minecraft.entity.SharedMonsterAttributes;
import net.minecraft.pathfinding.NodeProcessor;
import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.pathfinding.PathNodeType;
import net.minecraft.util.math.MathHelper;
public class EntityMoveHelper
{
/** The EntityLiving that is being moved */
protected final EntityLiving entity;
protected double posX;
protected double posY;
protected double posZ;
/** Multiplier for the entity's speed attribute value */
protected double speed;
protected float moveForward;
protected float moveStrafe;
public EntityMoveHelper.Action action = EntityMoveHelper.Action.WAIT;
public EntityMoveHelper(EntityLiving entitylivingIn)
{
this.entity = entitylivingIn;
}
public boolean isUpdating()
{
return this.action == EntityMoveHelper.Action.MOVE_TO;
}
public double getSpeed()
{
return this.speed;
}
/**
* Sets the speed and location to move to
*/
public void setMoveTo(double x, double y, double z, double speedIn)
{
this.posX = x;
this.posY = y;
this.posZ = z;
this.speed = speedIn;
this.action = EntityMoveHelper.Action.MOVE_TO;
}
public void strafe(float forward, float strafe)
{
this.action = EntityMoveHelper.Action.STRAFE;
this.moveForward = forward;
this.moveStrafe = strafe;
this.speed = 0.25D;
}
public void read(EntityMoveHelper that)
{
this.action = that.action;
this.posX = that.posX;
this.posY = that.posY;
this.posZ = that.posZ;
this.speed = Math.max(that.speed, 1.0D);
this.moveForward = that.moveForward;
this.moveStrafe = that.moveStrafe;
}
public void onUpdateMoveHelper()
{
if (this.action == EntityMoveHelper.Action.STRAFE)
{
float f = (float)this.entity.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getAttributeValue();
float f1 = (float)this.speed * f;
float f2 = this.moveForward;
float f3 = this.moveStrafe;
float f4 = MathHelper.sqrt(f2 * f2 + f3 * f3);
if (f4 < 1.0F)
{
f4 = 1.0F;
}
f4 = f1 / f4;
f2 = f2 * f4;
f3 = f3 * f4;
float f5 = MathHelper.sin(this.entity.rotationYaw * 0.017453292F);
float f6 = MathHelper.cos(this.entity.rotationYaw * 0.017453292F);
float f7 = f2 * f6 - f3 * f5;
float f8 = f3 * f6 + f2 * f5;
PathNavigate pathnavigate = this.entity.getNavigator();
if (pathnavigate != null)
{
NodeProcessor nodeprocessor = pathnavigate.getNodeProcessor();
if (nodeprocessor != null && nodeprocessor.getPathNodeType(this.entity.world, MathHelper.floor(this.entity.posX + (double)f7), MathHelper.floor(this.entity.posY), MathHelper.floor(this.entity.posZ + (double)f8)) != PathNodeType.WALKABLE)
{
this.moveForward = 1.0F;
this.moveStrafe = 0.0F;
f1 = f;
}
}
this.entity.setAIMoveSpeed(f1);
this.entity.setMoveForward(this.moveForward);
this.entity.setMoveStrafing(this.moveStrafe);
this.action = EntityMoveHelper.Action.WAIT;
}
else if (this.action == EntityMoveHelper.Action.MOVE_TO)
{
this.action = EntityMoveHelper.Action.WAIT;
double d0 = this.posX - this.entity.posX;
double d1 = this.posZ - this.entity.posZ;
double d2 = this.posY - this.entity.posY;
double d3 = d0 * d0 + d2 * d2 + d1 * d1;
if (d3 < 2.500000277905201E-7D)
{
this.entity.setMoveForward(0.0F);
return;
}
float f9 = (float)(MathHelper.atan2(d1, d0) * (180D / Math.PI)) - 90.0F;
this.entity.rotationYaw = this.limitAngle(this.entity.rotationYaw, f9, 90.0F);
this.entity.setAIMoveSpeed((float)(this.speed * this.entity.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getAttributeValue()));
if (d2 > (double)this.entity.stepHeight && d0 * d0 + d1 * d1 < (double)Math.max(1.0F, this.entity.width))
{
this.entity.getJumpHelper().setJumping();
this.action = EntityMoveHelper.Action.JUMPING;
}
}
else if (this.action == EntityMoveHelper.Action.JUMPING)
{
this.entity.setAIMoveSpeed((float)(this.speed * this.entity.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).getAttributeValue()));
if (this.entity.onGround)
{
this.action = EntityMoveHelper.Action.WAIT;
}
}
else
{
this.entity.setMoveForward(0.0F);
}
}
/**
* Attempt to rotate the first angle to become the second angle, but only allow overall direction change to at max
* be third parameter
*/
protected float limitAngle(float sourceAngle, float targetAngle, float maximumChange)
{
float f = MathHelper.wrapDegrees(targetAngle - sourceAngle);
if (f > maximumChange)
{
f = maximumChange;
}
if (f < -maximumChange)
{
f = -maximumChange;
}
float f1 = sourceAngle + f;
if (f1 < 0.0F)
{
f1 += 360.0F;
}
else if (f1 > 360.0F)
{
f1 -= 360.0F;
}
return f1;
}
public double getX()
{
return this.posX;
}
public double getY()
{
return this.posY;
}
public double getZ()
{
return this.posZ;
}
public static enum Action
{
WAIT,
MOVE_TO,
STRAFE,
JUMPING;
}
}

View File

@@ -0,0 +1,61 @@
package net.minecraft.entity.ai;
import com.google.common.collect.Lists;
import java.util.List;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLiving;
public class EntitySenses
{
EntityLiving entity;
/** Cache of entities which we can see */
List<Entity> seenEntities = Lists.<Entity>newArrayList();
/** Cache of entities which we cannot see */
List<Entity> unseenEntities = Lists.<Entity>newArrayList();
public EntitySenses(EntityLiving entityIn)
{
this.entity = entityIn;
}
/**
* Clears canSeeCachePositive and canSeeCacheNegative.
*/
public void clearSensingCache()
{
this.seenEntities.clear();
this.unseenEntities.clear();
}
/**
* Checks, whether 'our' entity can see the entity given as argument (true) or not (false), caching the result.
*/
public boolean canSee(Entity entityIn)
{
if (this.seenEntities.contains(entityIn))
{
return true;
}
else if (this.unseenEntities.contains(entityIn))
{
return false;
}
else
{
this.entity.world.profiler.startSection("canSee");
boolean flag = this.entity.canEntityBeSeen(entityIn);
this.entity.world.profiler.endSection();
if (flag)
{
this.seenEntities.add(entityIn);
}
else
{
this.unseenEntities.add(entityIn);
}
return flag;
}
}
}

View File

@@ -0,0 +1,181 @@
package net.minecraft.entity.ai;
import java.util.Random;
import javax.annotation.Nullable;
import net.minecraft.block.material.Material;
import net.minecraft.entity.EntityCreature;
import net.minecraft.pathfinding.PathNavigate;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
public class RandomPositionGenerator
{
/**
* used to store a driection when the user passes a point to move towards or away from. WARNING: NEVER THREAD SAFE.
* MULTIPLE findTowards and findAway calls, will share this var
*/
private static Vec3d staticVector = Vec3d.ZERO;
/**
* finds a random target within par1(x,z) and par2 (y) blocks
*/
@Nullable
public static Vec3d findRandomTarget(EntityCreature entitycreatureIn, int xz, int y)
{
return findRandomTargetBlock(entitycreatureIn, xz, y, (Vec3d)null);
}
@Nullable
public static Vec3d getLandPos(EntityCreature p_191377_0_, int p_191377_1_, int p_191377_2_)
{
return generateRandomPos(p_191377_0_, p_191377_1_, p_191377_2_, (Vec3d)null, false);
}
/**
* finds a random target within par1(x,z) and par2 (y) blocks in the direction of the point par3
*/
@Nullable
public static Vec3d findRandomTargetBlockTowards(EntityCreature entitycreatureIn, int xz, int y, Vec3d targetVec3)
{
staticVector = targetVec3.subtract(entitycreatureIn.posX, entitycreatureIn.posY, entitycreatureIn.posZ);
return findRandomTargetBlock(entitycreatureIn, xz, y, staticVector);
}
/**
* finds a random target within par1(x,z) and par2 (y) blocks in the reverse direction of the point par3
*/
@Nullable
public static Vec3d findRandomTargetBlockAwayFrom(EntityCreature entitycreatureIn, int xz, int y, Vec3d targetVec3)
{
staticVector = (new Vec3d(entitycreatureIn.posX, entitycreatureIn.posY, entitycreatureIn.posZ)).subtract(targetVec3);
return findRandomTargetBlock(entitycreatureIn, xz, y, staticVector);
}
/**
* searches 10 blocks at random in a within par1(x,z) and par2 (y) distance, ignores those not in the direction of
* par3Vec3, then points to the tile for which creature.getBlockPathWeight returns the highest number
*/
@Nullable
private static Vec3d findRandomTargetBlock(EntityCreature entitycreatureIn, int xz, int y, @Nullable Vec3d targetVec3)
{
return generateRandomPos(entitycreatureIn, xz, y, targetVec3, true);
}
@Nullable
private static Vec3d generateRandomPos(EntityCreature p_191379_0_, int p_191379_1_, int p_191379_2_, @Nullable Vec3d p_191379_3_, boolean p_191379_4_)
{
PathNavigate pathnavigate = p_191379_0_.getNavigator();
Random random = p_191379_0_.getRNG();
boolean flag;
if (p_191379_0_.hasHome())
{
double d0 = p_191379_0_.getHomePosition().distanceSq((double)MathHelper.floor(p_191379_0_.posX), (double)MathHelper.floor(p_191379_0_.posY), (double)MathHelper.floor(p_191379_0_.posZ)) + 4.0D;
double d1 = (double)(p_191379_0_.getMaximumHomeDistance() + (float)p_191379_1_);
flag = d0 < d1 * d1;
}
else
{
flag = false;
}
boolean flag1 = false;
float f = -99999.0F;
int k1 = 0;
int i = 0;
int j = 0;
for (int k = 0; k < 10; ++k)
{
int l = random.nextInt(2 * p_191379_1_ + 1) - p_191379_1_;
int i1 = random.nextInt(2 * p_191379_2_ + 1) - p_191379_2_;
int j1 = random.nextInt(2 * p_191379_1_ + 1) - p_191379_1_;
if (p_191379_3_ == null || (double)l * p_191379_3_.x + (double)j1 * p_191379_3_.z >= 0.0D)
{
if (p_191379_0_.hasHome() && p_191379_1_ > 1)
{
BlockPos blockpos = p_191379_0_.getHomePosition();
if (p_191379_0_.posX > (double)blockpos.getX())
{
l -= random.nextInt(p_191379_1_ / 2);
}
else
{
l += random.nextInt(p_191379_1_ / 2);
}
if (p_191379_0_.posZ > (double)blockpos.getZ())
{
j1 -= random.nextInt(p_191379_1_ / 2);
}
else
{
j1 += random.nextInt(p_191379_1_ / 2);
}
}
BlockPos blockpos1 = new BlockPos((double)l + p_191379_0_.posX, (double)i1 + p_191379_0_.posY, (double)j1 + p_191379_0_.posZ);
if ((!flag || p_191379_0_.isWithinHomeDistanceFromPosition(blockpos1)) && pathnavigate.canEntityStandOnPos(blockpos1))
{
if (!p_191379_4_)
{
blockpos1 = moveAboveSolid(blockpos1, p_191379_0_);
if (isWaterDestination(blockpos1, p_191379_0_))
{
continue;
}
}
float f1 = p_191379_0_.getBlockPathWeight(blockpos1);
if (f1 > f)
{
f = f1;
k1 = l;
i = i1;
j = j1;
flag1 = true;
}
}
}
}
if (flag1)
{
return new Vec3d((double)k1 + p_191379_0_.posX, (double)i + p_191379_0_.posY, (double)j + p_191379_0_.posZ);
}
else
{
return null;
}
}
private static BlockPos moveAboveSolid(BlockPos p_191378_0_, EntityCreature p_191378_1_)
{
if (!p_191378_1_.world.getBlockState(p_191378_0_).getMaterial().isSolid())
{
return p_191378_0_;
}
else
{
BlockPos blockpos;
for (blockpos = p_191378_0_.up(); blockpos.getY() < p_191378_1_.world.getHeight() && p_191378_1_.world.getBlockState(blockpos).getMaterial().isSolid(); blockpos = blockpos.up())
{
;
}
return blockpos;
}
}
private static boolean isWaterDestination(BlockPos p_191380_0_, EntityCreature p_191380_1_)
{
return p_191380_1_.world.getBlockState(p_191380_0_).getMaterial() == Material.WATER;
}
}

View File

@@ -0,0 +1,90 @@
package net.minecraft.entity.ai.attributes;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import java.util.Collection;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.Nullable;
import net.minecraft.util.LowerStringMap;
public abstract class AbstractAttributeMap
{
protected final Map<IAttribute, IAttributeInstance> attributes = Maps.<IAttribute, IAttributeInstance>newHashMap();
protected final Map<String, IAttributeInstance> attributesByName = new LowerStringMap();
protected final Multimap<IAttribute, IAttribute> descendantsByParent = HashMultimap.<IAttribute, IAttribute>create();
public IAttributeInstance getAttributeInstance(IAttribute attribute)
{
return this.attributes.get(attribute);
}
@Nullable
public IAttributeInstance getAttributeInstanceByName(String attributeName)
{
return this.attributesByName.get(attributeName);
}
/**
* Registers an attribute with this AttributeMap, returns a modifiable AttributeInstance associated with this map
*/
public IAttributeInstance registerAttribute(IAttribute attribute)
{
if (this.attributesByName.containsKey(attribute.getName()))
{
throw new IllegalArgumentException("Attribute is already registered!");
}
else
{
IAttributeInstance iattributeinstance = this.createInstance(attribute);
this.attributesByName.put(attribute.getName(), iattributeinstance);
this.attributes.put(attribute, iattributeinstance);
for (IAttribute iattribute = attribute.getParent(); iattribute != null; iattribute = iattribute.getParent())
{
this.descendantsByParent.put(iattribute, attribute);
}
return iattributeinstance;
}
}
protected abstract IAttributeInstance createInstance(IAttribute attribute);
public Collection<IAttributeInstance> getAllAttributes()
{
return this.attributesByName.values();
}
public void onAttributeModified(IAttributeInstance instance)
{
}
public void removeAttributeModifiers(Multimap<String, AttributeModifier> modifiers)
{
for (Entry<String, AttributeModifier> entry : modifiers.entries())
{
IAttributeInstance iattributeinstance = this.getAttributeInstanceByName(entry.getKey());
if (iattributeinstance != null)
{
iattributeinstance.removeModifier(entry.getValue());
}
}
}
public void applyAttributeModifiers(Multimap<String, AttributeModifier> modifiers)
{
for (Entry<String, AttributeModifier> entry : modifiers.entries())
{
IAttributeInstance iattributeinstance = this.getAttributeInstanceByName(entry.getKey());
if (iattributeinstance != null)
{
iattributeinstance.removeModifier(entry.getValue());
iattributeinstance.applyModifier(entry.getValue());
}
}
}
}

View File

@@ -0,0 +1,88 @@
package net.minecraft.entity.ai.attributes;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import net.minecraft.util.LowerStringMap;
public class AttributeMap extends AbstractAttributeMap
{
private final Set<IAttributeInstance> dirtyInstances = Sets.<IAttributeInstance>newHashSet();
protected final Map<String, IAttributeInstance> instancesByName = new LowerStringMap();
public ModifiableAttributeInstance getAttributeInstance(IAttribute attribute)
{
return (ModifiableAttributeInstance)super.getAttributeInstance(attribute);
}
public ModifiableAttributeInstance getAttributeInstanceByName(String attributeName)
{
IAttributeInstance iattributeinstance = super.getAttributeInstanceByName(attributeName);
if (iattributeinstance == null)
{
iattributeinstance = this.instancesByName.get(attributeName);
}
return (ModifiableAttributeInstance)iattributeinstance;
}
/**
* Registers an attribute with this AttributeMap, returns a modifiable AttributeInstance associated with this map
*/
public IAttributeInstance registerAttribute(IAttribute attribute)
{
IAttributeInstance iattributeinstance = super.registerAttribute(attribute);
if (attribute instanceof RangedAttribute && ((RangedAttribute)attribute).getDescription() != null)
{
this.instancesByName.put(((RangedAttribute)attribute).getDescription(), iattributeinstance);
}
return iattributeinstance;
}
protected IAttributeInstance createInstance(IAttribute attribute)
{
return new ModifiableAttributeInstance(this, attribute);
}
public void onAttributeModified(IAttributeInstance instance)
{
if (instance.getAttribute().getShouldWatch())
{
this.dirtyInstances.add(instance);
}
for (IAttribute iattribute : this.descendantsByParent.get(instance.getAttribute()))
{
ModifiableAttributeInstance modifiableattributeinstance = this.getAttributeInstance(iattribute);
if (modifiableattributeinstance != null)
{
modifiableattributeinstance.flagForUpdate();
}
}
}
public Set<IAttributeInstance> getDirtyInstances()
{
return this.dirtyInstances;
}
public Collection<IAttributeInstance> getWatchedAttributes()
{
Set<IAttributeInstance> set = Sets.<IAttributeInstance>newHashSet();
for (IAttributeInstance iattributeinstance : this.getAllAttributes())
{
if (iattributeinstance.getAttribute().getShouldWatch())
{
set.add(iattributeinstance);
}
}
return set;
}
}

View File

@@ -0,0 +1,109 @@
package net.minecraft.entity.ai.attributes;
import io.netty.util.internal.ThreadLocalRandom;
import java.util.UUID;
import net.minecraft.util.math.MathHelper;
import org.apache.commons.lang3.Validate;
public class AttributeModifier
{
private final double amount;
private final int operation;
private final String name;
private final UUID id;
/** If false, this modifier is not saved in NBT. Used for "natural" modifiers like speed boost from sprinting */
private boolean isSaved;
public AttributeModifier(String nameIn, double amountIn, int operationIn)
{
this(MathHelper.getRandomUUID(ThreadLocalRandom.current()), nameIn, amountIn, operationIn);
}
public AttributeModifier(UUID idIn, String nameIn, double amountIn, int operationIn)
{
this.isSaved = true;
this.id = idIn;
this.name = nameIn;
this.amount = amountIn;
this.operation = operationIn;
Validate.notEmpty(nameIn, "Modifier name cannot be empty");
Validate.inclusiveBetween(0L, 2L, (long)operationIn, "Invalid operation");
}
public UUID getID()
{
return this.id;
}
public String getName()
{
return this.name;
}
public int getOperation()
{
return this.operation;
}
public double getAmount()
{
return this.amount;
}
/**
* @see #isSaved
*/
public boolean isSaved()
{
return this.isSaved;
}
/**
* @see #isSaved
*/
public AttributeModifier setSaved(boolean saved)
{
this.isSaved = saved;
return this;
}
public boolean equals(Object p_equals_1_)
{
if (this == p_equals_1_)
{
return true;
}
else if (p_equals_1_ != null && this.getClass() == p_equals_1_.getClass())
{
AttributeModifier attributemodifier = (AttributeModifier)p_equals_1_;
if (this.id != null)
{
if (!this.id.equals(attributemodifier.id))
{
return false;
}
}
else if (attributemodifier.id != null)
{
return false;
}
return true;
}
else
{
return false;
}
}
public int hashCode()
{
return this.id != null ? this.id.hashCode() : 0;
}
public String toString()
{
return "AttributeModifier{amount=" + this.amount + ", operation=" + this.operation + ", name='" + this.name + '\'' + ", id=" + this.id + ", serialize=" + this.isSaved + '}';
}
}

View File

@@ -0,0 +1,60 @@
package net.minecraft.entity.ai.attributes;
import javax.annotation.Nullable;
public abstract class BaseAttribute implements IAttribute
{
private final IAttribute parent;
private final String unlocalizedName;
private final double defaultValue;
private boolean shouldWatch;
protected BaseAttribute(@Nullable IAttribute parentIn, String unlocalizedNameIn, double defaultValueIn)
{
this.parent = parentIn;
this.unlocalizedName = unlocalizedNameIn;
this.defaultValue = defaultValueIn;
if (unlocalizedNameIn == null)
{
throw new IllegalArgumentException("Name cannot be null!");
}
}
public String getName()
{
return this.unlocalizedName;
}
public double getDefaultValue()
{
return this.defaultValue;
}
public boolean getShouldWatch()
{
return this.shouldWatch;
}
public BaseAttribute setShouldWatch(boolean shouldWatchIn)
{
this.shouldWatch = shouldWatchIn;
return this;
}
@Nullable
public IAttribute getParent()
{
return this.parent;
}
public int hashCode()
{
return this.unlocalizedName.hashCode();
}
public boolean equals(Object p_equals_1_)
{
return p_equals_1_ instanceof IAttribute && this.unlocalizedName.equals(((IAttribute)p_equals_1_).getName());
}
}

View File

@@ -0,0 +1,17 @@
package net.minecraft.entity.ai.attributes;
import javax.annotation.Nullable;
public interface IAttribute
{
String getName();
double clampValue(double value);
double getDefaultValue();
boolean getShouldWatch();
@Nullable
IAttribute getParent();
}

View File

@@ -0,0 +1,42 @@
package net.minecraft.entity.ai.attributes;
import java.util.Collection;
import java.util.UUID;
import javax.annotation.Nullable;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public interface IAttributeInstance
{
/**
* Get the Attribute this is an instance of
*/
IAttribute getAttribute();
double getBaseValue();
void setBaseValue(double baseValue);
Collection<AttributeModifier> getModifiersByOperation(int operation);
Collection<AttributeModifier> getModifiers();
boolean hasModifier(AttributeModifier modifier);
/**
* Returns attribute modifier, if any, by the given UUID
*/
@Nullable
AttributeModifier getModifier(UUID uuid);
void applyModifier(AttributeModifier modifier);
void removeModifier(AttributeModifier modifier);
void removeModifier(UUID p_188479_1_);
@SideOnly(Side.CLIENT)
void removeAllModifiers();
double getAttributeValue();
}

View File

@@ -0,0 +1,220 @@
package net.minecraft.entity.ai.attributes;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import javax.annotation.Nullable;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
public class ModifiableAttributeInstance implements IAttributeInstance
{
/** The BaseAttributeMap this attributeInstance can be found in */
private final AbstractAttributeMap attributeMap;
/** The Attribute this is an instance of */
private final IAttribute genericAttribute;
private final Map<Integer, Set<AttributeModifier>> mapByOperation = Maps.<Integer, Set<AttributeModifier>>newHashMap();
private final Map<String, Set<AttributeModifier>> mapByName = Maps.<String, Set<AttributeModifier>>newHashMap();
private final Map<UUID, AttributeModifier> mapByUUID = Maps.<UUID, AttributeModifier>newHashMap();
private double baseValue;
private boolean needsUpdate = true;
private double cachedValue;
public ModifiableAttributeInstance(AbstractAttributeMap attributeMapIn, IAttribute genericAttributeIn)
{
this.attributeMap = attributeMapIn;
this.genericAttribute = genericAttributeIn;
this.baseValue = genericAttributeIn.getDefaultValue();
for (int i = 0; i < 3; ++i)
{
this.mapByOperation.put(Integer.valueOf(i), Sets.newHashSet());
}
}
/**
* Get the Attribute this is an instance of
*/
public IAttribute getAttribute()
{
return this.genericAttribute;
}
public double getBaseValue()
{
return this.baseValue;
}
public void setBaseValue(double baseValue)
{
if (baseValue != this.getBaseValue())
{
this.baseValue = baseValue;
this.flagForUpdate();
}
}
public Collection<AttributeModifier> getModifiersByOperation(int operation)
{
return (Collection)this.mapByOperation.get(Integer.valueOf(operation));
}
public Collection<AttributeModifier> getModifiers()
{
Set<AttributeModifier> set = Sets.<AttributeModifier>newHashSet();
for (int i = 0; i < 3; ++i)
{
set.addAll(this.getModifiersByOperation(i));
}
return set;
}
/**
* Returns attribute modifier, if any, by the given UUID
*/
@Nullable
public AttributeModifier getModifier(UUID uuid)
{
return this.mapByUUID.get(uuid);
}
public boolean hasModifier(AttributeModifier modifier)
{
return this.mapByUUID.get(modifier.getID()) != null;
}
public void applyModifier(AttributeModifier modifier)
{
if (this.getModifier(modifier.getID()) != null)
{
throw new IllegalArgumentException("Modifier is already applied on this attribute!");
}
else
{
Set<AttributeModifier> set = (Set)this.mapByName.get(modifier.getName());
if (set == null)
{
set = Sets.<AttributeModifier>newHashSet();
this.mapByName.put(modifier.getName(), set);
}
(this.mapByOperation.get(Integer.valueOf(modifier.getOperation()))).add(modifier);
set.add(modifier);
this.mapByUUID.put(modifier.getID(), modifier);
this.flagForUpdate();
}
}
protected void flagForUpdate()
{
this.needsUpdate = true;
this.attributeMap.onAttributeModified(this);
}
public void removeModifier(AttributeModifier modifier)
{
for (int i = 0; i < 3; ++i)
{
Set<AttributeModifier> set = (Set)this.mapByOperation.get(Integer.valueOf(i));
set.remove(modifier);
}
Set<AttributeModifier> set1 = (Set)this.mapByName.get(modifier.getName());
if (set1 != null)
{
set1.remove(modifier);
if (set1.isEmpty())
{
this.mapByName.remove(modifier.getName());
}
}
this.mapByUUID.remove(modifier.getID());
this.flagForUpdate();
}
public void removeModifier(UUID p_188479_1_)
{
AttributeModifier attributemodifier = this.getModifier(p_188479_1_);
if (attributemodifier != null)
{
this.removeModifier(attributemodifier);
}
}
@SideOnly(Side.CLIENT)
public void removeAllModifiers()
{
Collection<AttributeModifier> collection = this.getModifiers();
if (collection != null)
{
for (AttributeModifier attributemodifier : Lists.newArrayList(collection))
{
this.removeModifier(attributemodifier);
}
}
}
public double getAttributeValue()
{
if (this.needsUpdate)
{
this.cachedValue = this.computeValue();
this.needsUpdate = false;
}
return this.cachedValue;
}
private double computeValue()
{
double d0 = this.getBaseValue();
for (AttributeModifier attributemodifier : this.getAppliedModifiers(0))
{
d0 += attributemodifier.getAmount();
}
double d1 = d0;
for (AttributeModifier attributemodifier1 : this.getAppliedModifiers(1))
{
d1 += d0 * attributemodifier1.getAmount();
}
for (AttributeModifier attributemodifier2 : this.getAppliedModifiers(2))
{
d1 *= 1.0D + attributemodifier2.getAmount();
}
return this.genericAttribute.clampValue(d1);
}
private Collection<AttributeModifier> getAppliedModifiers(int operation)
{
Set<AttributeModifier> set = Sets.newHashSet(this.getModifiersByOperation(operation));
for (IAttribute iattribute = this.genericAttribute.getParent(); iattribute != null; iattribute = iattribute.getParent())
{
IAttributeInstance iattributeinstance = this.attributeMap.getAttributeInstance(iattribute);
if (iattributeinstance != null)
{
set.addAll(iattributeinstance.getModifiersByOperation(operation));
}
}
return set;
}
}

View File

@@ -0,0 +1,48 @@
package net.minecraft.entity.ai.attributes;
import javax.annotation.Nullable;
import net.minecraft.util.math.MathHelper;
public class RangedAttribute extends BaseAttribute
{
private final double minimumValue;
private final double maximumValue;
private String description;
public RangedAttribute(@Nullable IAttribute parentIn, String unlocalizedNameIn, double defaultValue, double minimumValueIn, double maximumValueIn)
{
super(parentIn, unlocalizedNameIn, defaultValue);
this.minimumValue = minimumValueIn;
this.maximumValue = maximumValueIn;
if (minimumValueIn > maximumValueIn)
{
throw new IllegalArgumentException("Minimum value cannot be bigger than maximum value!");
}
else if (defaultValue < minimumValueIn)
{
throw new IllegalArgumentException("Default value cannot be lower than minimum value!");
}
else if (defaultValue > maximumValueIn)
{
throw new IllegalArgumentException("Default value cannot be bigger than maximum value!");
}
}
public RangedAttribute setDescription(String descriptionIn)
{
this.description = descriptionIn;
return this;
}
public String getDescription()
{
return this.description;
}
public double clampValue(double value)
{
value = MathHelper.clamp(value, this.minimumValue, this.maximumValue);
return value;
}
}

View File

@@ -0,0 +1,7 @@
// Auto generated package-info by MCP
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
package net.minecraft.entity.ai.attributes;
import mcp.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;

View File

@@ -0,0 +1,7 @@
// Auto generated package-info by MCP
@ParametersAreNonnullByDefault
@MethodsReturnNonnullByDefault
package net.minecraft.entity.ai;
import mcp.MethodsReturnNonnullByDefault;
import javax.annotation.ParametersAreNonnullByDefault;