base mod created
This commit is contained in:
3761
build/tmp/recompileMc/sources/net/minecraft/entity/Entity.java
Normal file
3761
build/tmp/recompileMc/sources/net/minecraft/entity/Entity.java
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,291 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemMonsterPlacer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.network.datasync.DataParameter;
|
||||
import net.minecraft.network.datasync.DataSerializers;
|
||||
import net.minecraft.network.datasync.EntityDataManager;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class EntityAgeable extends EntityCreature
|
||||
{
|
||||
private static final DataParameter<Boolean> BABY = EntityDataManager.<Boolean>createKey(EntityAgeable.class, DataSerializers.BOOLEAN);
|
||||
protected int growingAge;
|
||||
protected int forcedAge;
|
||||
protected int forcedAgeTimer;
|
||||
private float ageWidth = -1.0F;
|
||||
private float ageHeight;
|
||||
|
||||
public EntityAgeable(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract EntityAgeable createChild(EntityAgeable ageable);
|
||||
|
||||
public boolean processInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
ItemStack itemstack = player.getHeldItem(hand);
|
||||
|
||||
if (itemstack.getItem() == Items.SPAWN_EGG)
|
||||
{
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
Class <? extends Entity > oclass = EntityList.getClass(ItemMonsterPlacer.getNamedIdFrom(itemstack));
|
||||
|
||||
if (oclass != null && this.getClass() == oclass)
|
||||
{
|
||||
EntityAgeable entityageable = this.createChild(this);
|
||||
|
||||
if (entityageable != null)
|
||||
{
|
||||
entityageable.setGrowingAge(-24000);
|
||||
entityageable.setLocationAndAngles(this.posX, this.posY, this.posZ, 0.0F, 0.0F);
|
||||
this.world.spawnEntity(entityageable);
|
||||
|
||||
if (itemstack.hasDisplayName())
|
||||
{
|
||||
entityageable.setCustomNameTag(itemstack.getDisplayName());
|
||||
}
|
||||
|
||||
if (!player.capabilities.isCreativeMode)
|
||||
{
|
||||
itemstack.shrink(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given item is a spawn egg that spawns the given class of entity.
|
||||
*/
|
||||
protected boolean holdingSpawnEggOfClass(ItemStack stack, Class <? extends Entity > entityClass)
|
||||
{
|
||||
if (stack.getItem() != Items.SPAWN_EGG)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
Class <? extends Entity > oclass = EntityList.getClass(ItemMonsterPlacer.getNamedIdFrom(stack));
|
||||
return oclass != null && entityClass == oclass;
|
||||
}
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
super.entityInit();
|
||||
this.dataManager.register(BABY, Boolean.valueOf(false));
|
||||
}
|
||||
|
||||
/**
|
||||
* The age value may be negative or positive or zero. If it's negative, it get's incremented on each tick, if it's
|
||||
* positive, it get's decremented each tick. Don't confuse this with EntityLiving.getAge. With a negative value the
|
||||
* Entity is considered a child.
|
||||
*/
|
||||
public int getGrowingAge()
|
||||
{
|
||||
if (this.world.isRemote)
|
||||
{
|
||||
return ((Boolean)this.dataManager.get(BABY)).booleanValue() ? -1 : 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.growingAge;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases this entity's age, optionally updating {@link #forcedAge}. If the entity is an adult (if the entity's
|
||||
* age is greater than or equal to 0) then the entity's age will be set to {@link #forcedAge}.
|
||||
*
|
||||
* @param growthSeconds Number of seconds to grow this entity by. The entity's age will be increased by 20 times
|
||||
* this number (i.e. this number converted to ticks).
|
||||
* @param updateForcedAge If true, updates {@link #forcedAge} and {@link #forcedAgeTimer}
|
||||
*/
|
||||
public void ageUp(int growthSeconds, boolean updateForcedAge)
|
||||
{
|
||||
int i = this.getGrowingAge();
|
||||
int j = i;
|
||||
i = i + growthSeconds * 20;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
i = 0;
|
||||
|
||||
if (j < 0)
|
||||
{
|
||||
this.onGrowingAdult();
|
||||
}
|
||||
}
|
||||
|
||||
int k = i - j;
|
||||
this.setGrowingAge(i);
|
||||
|
||||
if (updateForcedAge)
|
||||
{
|
||||
this.forcedAge += k;
|
||||
|
||||
if (this.forcedAgeTimer == 0)
|
||||
{
|
||||
this.forcedAgeTimer = 40;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.getGrowingAge() == 0)
|
||||
{
|
||||
this.setGrowingAge(this.forcedAge);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases this entity's age. If the entity is an adult (if the entity's age is greater than or equal to 0) then
|
||||
* the entity's age will be set to {@link #forcedAge}. This method does not update {@link #forcedAge}.
|
||||
*/
|
||||
public void addGrowth(int growth)
|
||||
{
|
||||
this.ageUp(growth, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The age value may be negative or positive or zero. If it's negative, it get's incremented on each tick, if it's
|
||||
* positive, it get's decremented each tick. With a negative value the Entity is considered a child.
|
||||
*/
|
||||
public void setGrowingAge(int age)
|
||||
{
|
||||
this.dataManager.set(BABY, Boolean.valueOf(age < 0));
|
||||
this.growingAge = age;
|
||||
this.setScaleForAge(this.isChild());
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.writeEntityToNBT(compound);
|
||||
compound.setInteger("Age", this.getGrowingAge());
|
||||
compound.setInteger("ForcedAge", this.forcedAge);
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
super.readEntityFromNBT(compound);
|
||||
this.setGrowingAge(compound.getInteger("Age"));
|
||||
this.forcedAge = compound.getInteger("ForcedAge");
|
||||
}
|
||||
|
||||
public void notifyDataManagerChange(DataParameter<?> key)
|
||||
{
|
||||
if (BABY.equals(key))
|
||||
{
|
||||
this.setScaleForAge(this.isChild());
|
||||
}
|
||||
|
||||
super.notifyDataManagerChange(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called frequently so the entity can update its state every tick as required. For example, zombies and skeletons
|
||||
* use this to react to sunlight and start to burn.
|
||||
*/
|
||||
public void onLivingUpdate()
|
||||
{
|
||||
super.onLivingUpdate();
|
||||
|
||||
if (this.world.isRemote)
|
||||
{
|
||||
if (this.forcedAgeTimer > 0)
|
||||
{
|
||||
if (this.forcedAgeTimer % 4 == 0)
|
||||
{
|
||||
this.world.spawnParticle(EnumParticleTypes.VILLAGER_HAPPY, this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + 0.5D + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, 0.0D, 0.0D, 0.0D);
|
||||
}
|
||||
|
||||
--this.forcedAgeTimer;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = this.getGrowingAge();
|
||||
|
||||
if (i < 0)
|
||||
{
|
||||
++i;
|
||||
this.setGrowingAge(i);
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
this.onGrowingAdult();
|
||||
}
|
||||
}
|
||||
else if (i > 0)
|
||||
{
|
||||
--i;
|
||||
this.setGrowingAge(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is called when Entity's growing age timer reaches 0 (negative values are considered as a child, positive as
|
||||
* an adult)
|
||||
*/
|
||||
protected void onGrowingAdult()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* If Animal, checks if the age timer is negative
|
||||
*/
|
||||
public boolean isChild()
|
||||
{
|
||||
return this.getGrowingAge() < 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* "Sets the scale for an ageable entity according to the boolean parameter, which says if it's a child."
|
||||
*/
|
||||
public void setScaleForAge(boolean child)
|
||||
{
|
||||
this.setScale(child ? 0.5F : 1.0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the width and height of the entity.
|
||||
*/
|
||||
protected final void setSize(float width, float height)
|
||||
{
|
||||
boolean flag = this.ageWidth > 0.0F;
|
||||
this.ageWidth = width;
|
||||
this.ageHeight = height;
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
this.setScale(1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void setScale(float scale)
|
||||
{
|
||||
super.setSize(this.ageWidth * scale, this.ageHeight * scale);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,544 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.Map.Entry;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.material.EnumPushReaction;
|
||||
import net.minecraft.init.PotionTypes;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import net.minecraft.network.datasync.DataParameter;
|
||||
import net.minecraft.network.datasync.DataSerializers;
|
||||
import net.minecraft.network.datasync.EntityDataManager;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.potion.PotionType;
|
||||
import net.minecraft.potion.PotionUtils;
|
||||
import net.minecraft.util.EnumParticleTypes;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.WorldServer;
|
||||
|
||||
public class EntityAreaEffectCloud extends Entity
|
||||
{
|
||||
private static final DataParameter<Float> RADIUS = EntityDataManager.<Float>createKey(EntityAreaEffectCloud.class, DataSerializers.FLOAT);
|
||||
private static final DataParameter<Integer> COLOR = EntityDataManager.<Integer>createKey(EntityAreaEffectCloud.class, DataSerializers.VARINT);
|
||||
private static final DataParameter<Boolean> IGNORE_RADIUS = EntityDataManager.<Boolean>createKey(EntityAreaEffectCloud.class, DataSerializers.BOOLEAN);
|
||||
private static final DataParameter<Integer> PARTICLE = EntityDataManager.<Integer>createKey(EntityAreaEffectCloud.class, DataSerializers.VARINT);
|
||||
private static final DataParameter<Integer> PARTICLE_PARAM_1 = EntityDataManager.<Integer>createKey(EntityAreaEffectCloud.class, DataSerializers.VARINT);
|
||||
private static final DataParameter<Integer> PARTICLE_PARAM_2 = EntityDataManager.<Integer>createKey(EntityAreaEffectCloud.class, DataSerializers.VARINT);
|
||||
private PotionType potion;
|
||||
private final List<PotionEffect> effects;
|
||||
private final Map<Entity, Integer> reapplicationDelayMap;
|
||||
private int duration;
|
||||
private int waitTime;
|
||||
private int reapplicationDelay;
|
||||
private boolean colorSet;
|
||||
private int durationOnUse;
|
||||
private float radiusOnUse;
|
||||
private float radiusPerTick;
|
||||
private EntityLivingBase owner;
|
||||
private UUID ownerUniqueId;
|
||||
|
||||
public EntityAreaEffectCloud(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.potion = PotionTypes.EMPTY;
|
||||
this.effects = Lists.<PotionEffect>newArrayList();
|
||||
this.reapplicationDelayMap = Maps.<Entity, Integer>newHashMap();
|
||||
this.duration = 600;
|
||||
this.waitTime = 20;
|
||||
this.reapplicationDelay = 20;
|
||||
this.noClip = true;
|
||||
this.isImmuneToFire = true;
|
||||
this.setRadius(3.0F);
|
||||
}
|
||||
|
||||
public EntityAreaEffectCloud(World worldIn, double x, double y, double z)
|
||||
{
|
||||
this(worldIn);
|
||||
this.setPosition(x, y, z);
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
this.getDataManager().register(COLOR, Integer.valueOf(0));
|
||||
this.getDataManager().register(RADIUS, Float.valueOf(0.5F));
|
||||
this.getDataManager().register(IGNORE_RADIUS, Boolean.valueOf(false));
|
||||
this.getDataManager().register(PARTICLE, Integer.valueOf(EnumParticleTypes.SPELL_MOB.getParticleID()));
|
||||
this.getDataManager().register(PARTICLE_PARAM_1, Integer.valueOf(0));
|
||||
this.getDataManager().register(PARTICLE_PARAM_2, Integer.valueOf(0));
|
||||
}
|
||||
|
||||
public void setRadius(float radiusIn)
|
||||
{
|
||||
double d0 = this.posX;
|
||||
double d1 = this.posY;
|
||||
double d2 = this.posZ;
|
||||
this.setSize(radiusIn * 2.0F, 0.5F);
|
||||
this.setPosition(d0, d1, d2);
|
||||
|
||||
if (!this.world.isRemote)
|
||||
{
|
||||
this.getDataManager().set(RADIUS, Float.valueOf(radiusIn));
|
||||
}
|
||||
}
|
||||
|
||||
public float getRadius()
|
||||
{
|
||||
return ((Float)this.getDataManager().get(RADIUS)).floatValue();
|
||||
}
|
||||
|
||||
public void setPotion(PotionType potionIn)
|
||||
{
|
||||
this.potion = potionIn;
|
||||
|
||||
if (!this.colorSet)
|
||||
{
|
||||
this.updateFixedColor();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFixedColor()
|
||||
{
|
||||
if (this.potion == PotionTypes.EMPTY && this.effects.isEmpty())
|
||||
{
|
||||
this.getDataManager().set(COLOR, Integer.valueOf(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.getDataManager().set(COLOR, Integer.valueOf(PotionUtils.getPotionColorFromEffectList(PotionUtils.mergeEffects(this.potion, this.effects))));
|
||||
}
|
||||
}
|
||||
|
||||
public void addEffect(PotionEffect effect)
|
||||
{
|
||||
this.effects.add(effect);
|
||||
|
||||
if (!this.colorSet)
|
||||
{
|
||||
this.updateFixedColor();
|
||||
}
|
||||
}
|
||||
|
||||
public int getColor()
|
||||
{
|
||||
return ((Integer)this.getDataManager().get(COLOR)).intValue();
|
||||
}
|
||||
|
||||
public void setColor(int colorIn)
|
||||
{
|
||||
this.colorSet = true;
|
||||
this.getDataManager().set(COLOR, Integer.valueOf(colorIn));
|
||||
}
|
||||
|
||||
public EnumParticleTypes getParticle()
|
||||
{
|
||||
return EnumParticleTypes.getParticleFromId(((Integer)this.getDataManager().get(PARTICLE)).intValue());
|
||||
}
|
||||
|
||||
public void setParticle(EnumParticleTypes particleIn)
|
||||
{
|
||||
this.getDataManager().set(PARTICLE, Integer.valueOf(particleIn.getParticleID()));
|
||||
}
|
||||
|
||||
public int getParticleParam1()
|
||||
{
|
||||
return ((Integer)this.getDataManager().get(PARTICLE_PARAM_1)).intValue();
|
||||
}
|
||||
|
||||
public void setParticleParam1(int particleParam)
|
||||
{
|
||||
this.getDataManager().set(PARTICLE_PARAM_1, Integer.valueOf(particleParam));
|
||||
}
|
||||
|
||||
public int getParticleParam2()
|
||||
{
|
||||
return ((Integer)this.getDataManager().get(PARTICLE_PARAM_2)).intValue();
|
||||
}
|
||||
|
||||
public void setParticleParam2(int particleParam)
|
||||
{
|
||||
this.getDataManager().set(PARTICLE_PARAM_2, Integer.valueOf(particleParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the radius should be ignored, and the effect should be shown in a single point instead of an area
|
||||
*/
|
||||
protected void setIgnoreRadius(boolean ignoreRadius)
|
||||
{
|
||||
this.getDataManager().set(IGNORE_RADIUS, Boolean.valueOf(ignoreRadius));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the radius should be ignored, and the effect should be shown in a single point instead of an area
|
||||
*/
|
||||
public boolean shouldIgnoreRadius()
|
||||
{
|
||||
return ((Boolean)this.getDataManager().get(IGNORE_RADIUS)).booleanValue();
|
||||
}
|
||||
|
||||
public int getDuration()
|
||||
{
|
||||
return this.duration;
|
||||
}
|
||||
|
||||
public void setDuration(int durationIn)
|
||||
{
|
||||
this.duration = durationIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update the entity's position/logic.
|
||||
*/
|
||||
public void onUpdate()
|
||||
{
|
||||
super.onUpdate();
|
||||
boolean flag = this.shouldIgnoreRadius();
|
||||
float f = this.getRadius();
|
||||
|
||||
if (this.world.isRemote)
|
||||
{
|
||||
EnumParticleTypes enumparticletypes = this.getParticle();
|
||||
int[] aint = new int[enumparticletypes.getArgumentCount()];
|
||||
|
||||
if (aint.length > 0)
|
||||
{
|
||||
aint[0] = this.getParticleParam1();
|
||||
}
|
||||
|
||||
if (aint.length > 1)
|
||||
{
|
||||
aint[1] = this.getParticleParam2();
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
if (this.rand.nextBoolean())
|
||||
{
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
float f1 = this.rand.nextFloat() * ((float)Math.PI * 2F);
|
||||
float f2 = MathHelper.sqrt(this.rand.nextFloat()) * 0.2F;
|
||||
float f3 = MathHelper.cos(f1) * f2;
|
||||
float f4 = MathHelper.sin(f1) * f2;
|
||||
|
||||
if (enumparticletypes == EnumParticleTypes.SPELL_MOB)
|
||||
{
|
||||
int j = this.rand.nextBoolean() ? 16777215 : this.getColor();
|
||||
int k = j >> 16 & 255;
|
||||
int l = j >> 8 & 255;
|
||||
int i1 = j & 255;
|
||||
this.world.spawnAlwaysVisibleParticle(EnumParticleTypes.SPELL_MOB.getParticleID(), this.posX + (double)f3, this.posY, this.posZ + (double)f4, (double)((float)k / 255.0F), (double)((float)l / 255.0F), (double)((float)i1 / 255.0F));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.world.spawnAlwaysVisibleParticle(enumparticletypes.getParticleID(), this.posX + (double)f3, this.posY, this.posZ + (double)f4, 0.0D, 0.0D, 0.0D, aint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float f5 = (float)Math.PI * f * f;
|
||||
|
||||
for (int k1 = 0; (float)k1 < f5; ++k1)
|
||||
{
|
||||
float f6 = this.rand.nextFloat() * ((float)Math.PI * 2F);
|
||||
float f7 = MathHelper.sqrt(this.rand.nextFloat()) * f;
|
||||
float f8 = MathHelper.cos(f6) * f7;
|
||||
float f9 = MathHelper.sin(f6) * f7;
|
||||
|
||||
if (enumparticletypes == EnumParticleTypes.SPELL_MOB)
|
||||
{
|
||||
int l1 = this.getColor();
|
||||
int i2 = l1 >> 16 & 255;
|
||||
int j2 = l1 >> 8 & 255;
|
||||
int j1 = l1 & 255;
|
||||
this.world.spawnAlwaysVisibleParticle(EnumParticleTypes.SPELL_MOB.getParticleID(), this.posX + (double)f8, this.posY, this.posZ + (double)f9, (double)((float)i2 / 255.0F), (double)((float)j2 / 255.0F), (double)((float)j1 / 255.0F));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.world.spawnAlwaysVisibleParticle(enumparticletypes.getParticleID(), this.posX + (double)f8, this.posY, this.posZ + (double)f9, (0.5D - this.rand.nextDouble()) * 0.15D, 0.009999999776482582D, (0.5D - this.rand.nextDouble()) * 0.15D, aint);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.ticksExisted >= this.waitTime + this.duration)
|
||||
{
|
||||
this.setDead();
|
||||
return;
|
||||
}
|
||||
|
||||
boolean flag1 = this.ticksExisted < this.waitTime;
|
||||
|
||||
if (flag != flag1)
|
||||
{
|
||||
this.setIgnoreRadius(flag1);
|
||||
}
|
||||
|
||||
if (flag1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.radiusPerTick != 0.0F)
|
||||
{
|
||||
f += this.radiusPerTick;
|
||||
|
||||
if (f < 0.5F)
|
||||
{
|
||||
this.setDead();
|
||||
return;
|
||||
}
|
||||
|
||||
this.setRadius(f);
|
||||
}
|
||||
|
||||
if (this.ticksExisted % 5 == 0)
|
||||
{
|
||||
Iterator<Entry<Entity, Integer>> iterator = this.reapplicationDelayMap.entrySet().iterator();
|
||||
|
||||
while (iterator.hasNext())
|
||||
{
|
||||
Entry<Entity, Integer> entry = (Entry)iterator.next();
|
||||
|
||||
if (this.ticksExisted >= ((Integer)entry.getValue()).intValue())
|
||||
{
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
|
||||
List<PotionEffect> potions = Lists.<PotionEffect>newArrayList();
|
||||
|
||||
for (PotionEffect potioneffect1 : this.potion.getEffects())
|
||||
{
|
||||
potions.add(new PotionEffect(potioneffect1.getPotion(), potioneffect1.getDuration() / 4, potioneffect1.getAmplifier(), potioneffect1.getIsAmbient(), potioneffect1.doesShowParticles()));
|
||||
}
|
||||
|
||||
potions.addAll(this.effects);
|
||||
|
||||
if (potions.isEmpty())
|
||||
{
|
||||
this.reapplicationDelayMap.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
List<EntityLivingBase> list = this.world.<EntityLivingBase>getEntitiesWithinAABB(EntityLivingBase.class, this.getEntityBoundingBox());
|
||||
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
for (EntityLivingBase entitylivingbase : list)
|
||||
{
|
||||
if (!this.reapplicationDelayMap.containsKey(entitylivingbase) && entitylivingbase.canBeHitWithPotion())
|
||||
{
|
||||
double d0 = entitylivingbase.posX - this.posX;
|
||||
double d1 = entitylivingbase.posZ - this.posZ;
|
||||
double d2 = d0 * d0 + d1 * d1;
|
||||
|
||||
if (d2 <= (double)(f * f))
|
||||
{
|
||||
this.reapplicationDelayMap.put(entitylivingbase, Integer.valueOf(this.ticksExisted + this.reapplicationDelay));
|
||||
|
||||
for (PotionEffect potioneffect : potions)
|
||||
{
|
||||
if (potioneffect.getPotion().isInstant())
|
||||
{
|
||||
potioneffect.getPotion().affectEntity(this, this.getOwner(), entitylivingbase, potioneffect.getAmplifier(), 0.5D);
|
||||
}
|
||||
else
|
||||
{
|
||||
entitylivingbase.addPotionEffect(new PotionEffect(potioneffect));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.radiusOnUse != 0.0F)
|
||||
{
|
||||
f += this.radiusOnUse;
|
||||
|
||||
if (f < 0.5F)
|
||||
{
|
||||
this.setDead();
|
||||
return;
|
||||
}
|
||||
|
||||
this.setRadius(f);
|
||||
}
|
||||
|
||||
if (this.durationOnUse != 0)
|
||||
{
|
||||
this.duration += this.durationOnUse;
|
||||
|
||||
if (this.duration <= 0)
|
||||
{
|
||||
this.setDead();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setRadiusOnUse(float radiusOnUseIn)
|
||||
{
|
||||
this.radiusOnUse = radiusOnUseIn;
|
||||
}
|
||||
|
||||
public void setRadiusPerTick(float radiusPerTickIn)
|
||||
{
|
||||
this.radiusPerTick = radiusPerTickIn;
|
||||
}
|
||||
|
||||
public void setWaitTime(int waitTimeIn)
|
||||
{
|
||||
this.waitTime = waitTimeIn;
|
||||
}
|
||||
|
||||
public void setOwner(@Nullable EntityLivingBase ownerIn)
|
||||
{
|
||||
this.owner = ownerIn;
|
||||
this.ownerUniqueId = ownerIn == null ? null : ownerIn.getUniqueID();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EntityLivingBase getOwner()
|
||||
{
|
||||
if (this.owner == null && this.ownerUniqueId != null && this.world instanceof WorldServer)
|
||||
{
|
||||
Entity entity = ((WorldServer)this.world).getEntityFromUuid(this.ownerUniqueId);
|
||||
|
||||
if (entity instanceof EntityLivingBase)
|
||||
{
|
||||
this.owner = (EntityLivingBase)entity;
|
||||
}
|
||||
}
|
||||
|
||||
return this.owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
protected void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
this.ticksExisted = compound.getInteger("Age");
|
||||
this.duration = compound.getInteger("Duration");
|
||||
this.waitTime = compound.getInteger("WaitTime");
|
||||
this.reapplicationDelay = compound.getInteger("ReapplicationDelay");
|
||||
this.durationOnUse = compound.getInteger("DurationOnUse");
|
||||
this.radiusOnUse = compound.getFloat("RadiusOnUse");
|
||||
this.radiusPerTick = compound.getFloat("RadiusPerTick");
|
||||
this.setRadius(compound.getFloat("Radius"));
|
||||
this.ownerUniqueId = compound.getUniqueId("OwnerUUID");
|
||||
|
||||
if (compound.hasKey("Particle", 8))
|
||||
{
|
||||
EnumParticleTypes enumparticletypes = EnumParticleTypes.getByName(compound.getString("Particle"));
|
||||
|
||||
if (enumparticletypes != null)
|
||||
{
|
||||
this.setParticle(enumparticletypes);
|
||||
this.setParticleParam1(compound.getInteger("ParticleParam1"));
|
||||
this.setParticleParam2(compound.getInteger("ParticleParam2"));
|
||||
}
|
||||
}
|
||||
|
||||
if (compound.hasKey("Color", 99))
|
||||
{
|
||||
this.setColor(compound.getInteger("Color"));
|
||||
}
|
||||
|
||||
if (compound.hasKey("Potion", 8))
|
||||
{
|
||||
this.setPotion(PotionUtils.getPotionTypeFromNBT(compound));
|
||||
}
|
||||
|
||||
if (compound.hasKey("Effects", 9))
|
||||
{
|
||||
NBTTagList nbttaglist = compound.getTagList("Effects", 10);
|
||||
this.effects.clear();
|
||||
|
||||
for (int i = 0; i < nbttaglist.tagCount(); ++i)
|
||||
{
|
||||
PotionEffect potioneffect = PotionEffect.readCustomPotionEffectFromNBT(nbttaglist.getCompoundTagAt(i));
|
||||
|
||||
if (potioneffect != null)
|
||||
{
|
||||
this.addEffect(potioneffect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
protected void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
compound.setInteger("Age", this.ticksExisted);
|
||||
compound.setInteger("Duration", this.duration);
|
||||
compound.setInteger("WaitTime", this.waitTime);
|
||||
compound.setInteger("ReapplicationDelay", this.reapplicationDelay);
|
||||
compound.setInteger("DurationOnUse", this.durationOnUse);
|
||||
compound.setFloat("RadiusOnUse", this.radiusOnUse);
|
||||
compound.setFloat("RadiusPerTick", this.radiusPerTick);
|
||||
compound.setFloat("Radius", this.getRadius());
|
||||
compound.setString("Particle", this.getParticle().getParticleName());
|
||||
compound.setInteger("ParticleParam1", this.getParticleParam1());
|
||||
compound.setInteger("ParticleParam2", this.getParticleParam2());
|
||||
|
||||
if (this.ownerUniqueId != null)
|
||||
{
|
||||
compound.setUniqueId("OwnerUUID", this.ownerUniqueId);
|
||||
}
|
||||
|
||||
if (this.colorSet)
|
||||
{
|
||||
compound.setInteger("Color", this.getColor());
|
||||
}
|
||||
|
||||
if (this.potion != PotionTypes.EMPTY && this.potion != null)
|
||||
{
|
||||
compound.setString("Potion", ((ResourceLocation)PotionType.REGISTRY.getNameForObject(this.potion)).toString());
|
||||
}
|
||||
|
||||
if (!this.effects.isEmpty())
|
||||
{
|
||||
NBTTagList nbttaglist = new NBTTagList();
|
||||
|
||||
for (PotionEffect potioneffect : this.effects)
|
||||
{
|
||||
nbttaglist.appendTag(potioneffect.writeCustomPotionEffectToNBT(new NBTTagCompound()));
|
||||
}
|
||||
|
||||
compound.setTag("Effects", nbttaglist);
|
||||
}
|
||||
}
|
||||
|
||||
public void notifyDataManagerChange(DataParameter<?> key)
|
||||
{
|
||||
if (RADIUS.equals(key))
|
||||
{
|
||||
this.setRadius(this.getRadius());
|
||||
}
|
||||
|
||||
super.notifyDataManagerChange(key);
|
||||
}
|
||||
|
||||
public EnumPushReaction getPushReaction()
|
||||
{
|
||||
return EnumPushReaction.IGNORE;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
|
||||
public class EntityBodyHelper
|
||||
{
|
||||
/** Instance of EntityLiving. */
|
||||
private final EntityLivingBase living;
|
||||
/** Used to progressively ajust the rotation of the body to the rotation of the head */
|
||||
private int rotationTickCounter;
|
||||
private float prevRenderYawHead;
|
||||
|
||||
public EntityBodyHelper(EntityLivingBase livingIn)
|
||||
{
|
||||
this.living = livingIn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the Head and Body rendenring angles
|
||||
*/
|
||||
public void updateRenderAngles()
|
||||
{
|
||||
double d0 = this.living.posX - this.living.prevPosX;
|
||||
double d1 = this.living.posZ - this.living.prevPosZ;
|
||||
|
||||
if (d0 * d0 + d1 * d1 > 2.500000277905201E-7D)
|
||||
{
|
||||
this.living.renderYawOffset = this.living.rotationYaw;
|
||||
this.living.rotationYawHead = this.computeAngleWithBound(this.living.renderYawOffset, this.living.rotationYawHead, 75.0F);
|
||||
this.prevRenderYawHead = this.living.rotationYawHead;
|
||||
this.rotationTickCounter = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.living.getPassengers().isEmpty() || !(this.living.getPassengers().get(0) instanceof EntityLiving))
|
||||
{
|
||||
float f = 75.0F;
|
||||
|
||||
if (Math.abs(this.living.rotationYawHead - this.prevRenderYawHead) > 15.0F)
|
||||
{
|
||||
this.rotationTickCounter = 0;
|
||||
this.prevRenderYawHead = this.living.rotationYawHead;
|
||||
}
|
||||
else
|
||||
{
|
||||
++this.rotationTickCounter;
|
||||
int i = 10;
|
||||
|
||||
if (this.rotationTickCounter > 10)
|
||||
{
|
||||
f = Math.max(1.0F - (float)(this.rotationTickCounter - 10) / 10.0F, 0.0F) * 75.0F;
|
||||
}
|
||||
}
|
||||
|
||||
this.living.renderYawOffset = this.computeAngleWithBound(this.living.rotationYawHead, this.living.renderYawOffset, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new angle2 such that the difference between angle1 and angle2 is lower than angleMax. Args : angle1,
|
||||
* angle2, angleMax
|
||||
*/
|
||||
private float computeAngleWithBound(float p_75665_1_, float p_75665_2_, float p_75665_3_)
|
||||
{
|
||||
float f = MathHelper.wrapDegrees(p_75665_1_ - p_75665_2_);
|
||||
|
||||
if (f < -p_75665_3_)
|
||||
{
|
||||
f = -p_75665_3_;
|
||||
}
|
||||
|
||||
if (f >= p_75665_3_)
|
||||
{
|
||||
f = p_75665_3_;
|
||||
}
|
||||
|
||||
return p_75665_1_ - f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import java.util.UUID;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.entity.passive.EntityTameable;
|
||||
import net.minecraft.pathfinding.PathNodeType;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class EntityCreature extends EntityLiving
|
||||
{
|
||||
public static final UUID FLEEING_SPEED_MODIFIER_UUID = UUID.fromString("E199AD21-BA8A-4C53-8D13-6182D5C69D3A");
|
||||
public static final AttributeModifier FLEEING_SPEED_MODIFIER = (new AttributeModifier(FLEEING_SPEED_MODIFIER_UUID, "Fleeing speed bonus", 2.0D, 2)).setSaved(false);
|
||||
private BlockPos homePosition = BlockPos.ORIGIN;
|
||||
/** If -1 there is no maximum distance */
|
||||
private float maximumHomeDistance = -1.0F;
|
||||
private final float restoreWaterCost = PathNodeType.WATER.getPriority();
|
||||
|
||||
public EntityCreature(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
public float getBlockPathWeight(BlockPos pos)
|
||||
{
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the entity's current position is a valid location to spawn this entity.
|
||||
*/
|
||||
public boolean getCanSpawnHere()
|
||||
{
|
||||
return super.getCanSpawnHere() && this.getBlockPathWeight(new BlockPos(this.posX, this.getEntityBoundingBox().minY, this.posZ)) >= 0.0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* if the entity got a PathEntity it returns true, else false
|
||||
*/
|
||||
public boolean hasPath()
|
||||
{
|
||||
return !this.navigator.noPath();
|
||||
}
|
||||
|
||||
public boolean isWithinHomeDistanceCurrentPosition()
|
||||
{
|
||||
return this.isWithinHomeDistanceFromPosition(new BlockPos(this));
|
||||
}
|
||||
|
||||
public boolean isWithinHomeDistanceFromPosition(BlockPos pos)
|
||||
{
|
||||
if (this.maximumHomeDistance == -1.0F)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.homePosition.distanceSq(pos) < (double)(this.maximumHomeDistance * this.maximumHomeDistance);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets home position and max distance for it
|
||||
*/
|
||||
public void setHomePosAndDistance(BlockPos pos, int distance)
|
||||
{
|
||||
this.homePosition = pos;
|
||||
this.maximumHomeDistance = (float)distance;
|
||||
}
|
||||
|
||||
public BlockPos getHomePosition()
|
||||
{
|
||||
return this.homePosition;
|
||||
}
|
||||
|
||||
public float getMaximumHomeDistance()
|
||||
{
|
||||
return this.maximumHomeDistance;
|
||||
}
|
||||
|
||||
public void detachHome()
|
||||
{
|
||||
this.maximumHomeDistance = -1.0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a home area is defined for this entity.
|
||||
*/
|
||||
public boolean hasHome()
|
||||
{
|
||||
return this.maximumHomeDistance != -1.0F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies logic related to leashes, for example dragging the entity or breaking the leash.
|
||||
*/
|
||||
protected void updateLeashedState()
|
||||
{
|
||||
super.updateLeashedState();
|
||||
|
||||
if (this.getLeashed() && this.getLeashHolder() != null && this.getLeashHolder().world == this.world)
|
||||
{
|
||||
Entity entity = this.getLeashHolder();
|
||||
this.setHomePosAndDistance(new BlockPos((int)entity.posX, (int)entity.posY, (int)entity.posZ), 5);
|
||||
float f = this.getDistance(entity);
|
||||
|
||||
if (this instanceof EntityTameable && ((EntityTameable)this).isSitting())
|
||||
{
|
||||
if (f > 10.0F)
|
||||
{
|
||||
this.clearLeashed(true, true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.onLeashDistance(f);
|
||||
|
||||
if (f > 10.0F)
|
||||
{
|
||||
this.clearLeashed(true, true);
|
||||
this.tasks.disableControlFlag(1);
|
||||
}
|
||||
else if (f > 6.0F)
|
||||
{
|
||||
double d0 = (entity.posX - this.posX) / (double)f;
|
||||
double d1 = (entity.posY - this.posY) / (double)f;
|
||||
double d2 = (entity.posZ - this.posZ) / (double)f;
|
||||
this.motionX += d0 * Math.abs(d0) * 0.4D;
|
||||
this.motionY += d1 * Math.abs(d1) * 0.4D;
|
||||
this.motionZ += d2 * Math.abs(d2) * 0.4D;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.tasks.enableControlFlag(1);
|
||||
float f1 = 2.0F;
|
||||
Vec3d vec3d = (new Vec3d(entity.posX - this.posX, entity.posY - this.posY, entity.posZ - this.posZ)).normalize().scale((double)Math.max(f - 2.0F, 0.0F));
|
||||
this.getNavigator().tryMoveToXYZ(this.posX + vec3d.x, this.posY + vec3d.y, this.posZ + vec3d.z, this.followLeashSpeed());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected double followLeashSpeed()
|
||||
{
|
||||
return 1.0D;
|
||||
}
|
||||
|
||||
protected void onLeashDistance(float p_142017_1_)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public abstract class EntityFlying extends EntityLiving
|
||||
{
|
||||
public EntityFlying(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
public void fall(float distance, float damageMultiplier)
|
||||
{
|
||||
}
|
||||
|
||||
protected void updateFallState(double y, boolean onGroundIn, IBlockState state, BlockPos pos)
|
||||
{
|
||||
}
|
||||
|
||||
public void travel(float strafe, float vertical, float forward)
|
||||
{
|
||||
if (this.isInWater())
|
||||
{
|
||||
this.moveRelative(strafe, vertical, forward, 0.02F);
|
||||
this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ);
|
||||
this.motionX *= 0.800000011920929D;
|
||||
this.motionY *= 0.800000011920929D;
|
||||
this.motionZ *= 0.800000011920929D;
|
||||
}
|
||||
else if (this.isInLava())
|
||||
{
|
||||
this.moveRelative(strafe, vertical, forward, 0.02F);
|
||||
this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ);
|
||||
this.motionX *= 0.5D;
|
||||
this.motionY *= 0.5D;
|
||||
this.motionZ *= 0.5D;
|
||||
}
|
||||
else
|
||||
{
|
||||
float f = 0.91F;
|
||||
|
||||
if (this.onGround)
|
||||
{
|
||||
BlockPos underPos = new BlockPos(MathHelper.floor(this.posX), MathHelper.floor(this.getEntityBoundingBox().minY) - 1, MathHelper.floor(this.posZ));
|
||||
IBlockState underState = this.world.getBlockState(underPos);
|
||||
f = underState.getBlock().getSlipperiness(underState, this.world, underPos, this) * 0.91F;
|
||||
}
|
||||
|
||||
float f1 = 0.16277136F / (f * f * f);
|
||||
this.moveRelative(strafe, vertical, forward, this.onGround ? 0.1F * f1 : 0.02F);
|
||||
f = 0.91F;
|
||||
|
||||
if (this.onGround)
|
||||
{
|
||||
BlockPos underPos = new BlockPos(MathHelper.floor(this.posX), MathHelper.floor(this.getEntityBoundingBox().minY) - 1, MathHelper.floor(this.posZ));
|
||||
IBlockState underState = this.world.getBlockState(underPos);
|
||||
f = underState.getBlock().getSlipperiness(underState, this.world, underPos, this) * 0.91F;
|
||||
}
|
||||
|
||||
this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ);
|
||||
this.motionX *= (double)f;
|
||||
this.motionY *= (double)f;
|
||||
this.motionZ *= (double)f;
|
||||
}
|
||||
|
||||
this.prevLimbSwingAmount = this.limbSwingAmount;
|
||||
double d1 = this.posX - this.prevPosX;
|
||||
double d0 = this.posZ - this.prevPosZ;
|
||||
float f2 = MathHelper.sqrt(d1 * d1 + d0 * d0) * 4.0F;
|
||||
|
||||
if (f2 > 1.0F)
|
||||
{
|
||||
f2 = 1.0F;
|
||||
}
|
||||
|
||||
this.limbSwingAmount += (f2 - this.limbSwingAmount) * 0.4F;
|
||||
this.limbSwing += this.limbSwingAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this entity should move as if it were on a ladder (either because it's actually on a ladder, or
|
||||
* for AI reasons)
|
||||
*/
|
||||
public boolean isOnLadder()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.BlockRedstoneDiode;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.effect.EntityLightningBolt;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.Mirror;
|
||||
import net.minecraft.util.Rotation;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
public abstract class EntityHanging extends Entity
|
||||
{
|
||||
private static final Predicate<Entity> IS_HANGING_ENTITY = new Predicate<Entity>()
|
||||
{
|
||||
public boolean apply(@Nullable Entity p_apply_1_)
|
||||
{
|
||||
return p_apply_1_ instanceof EntityHanging;
|
||||
}
|
||||
};
|
||||
private int tickCounter1;
|
||||
protected BlockPos hangingPosition;
|
||||
/** The direction the entity is facing */
|
||||
@Nullable
|
||||
public EnumFacing facingDirection;
|
||||
|
||||
public EntityHanging(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
this.setSize(0.5F, 0.5F);
|
||||
}
|
||||
|
||||
public EntityHanging(World worldIn, BlockPos hangingPositionIn)
|
||||
{
|
||||
this(worldIn);
|
||||
this.hangingPosition = hangingPositionIn;
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates facing and bounding box based on it
|
||||
*/
|
||||
protected void updateFacingWithBoundingBox(EnumFacing facingDirectionIn)
|
||||
{
|
||||
Validate.notNull(facingDirectionIn);
|
||||
Validate.isTrue(facingDirectionIn.getAxis().isHorizontal());
|
||||
this.facingDirection = facingDirectionIn;
|
||||
this.rotationYaw = (float)(this.facingDirection.getHorizontalIndex() * 90);
|
||||
this.prevRotationYaw = this.rotationYaw;
|
||||
this.updateBoundingBox();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the entity bounding box based on current facing
|
||||
*/
|
||||
protected void updateBoundingBox()
|
||||
{
|
||||
if (this.facingDirection != null)
|
||||
{
|
||||
double d0 = (double)this.hangingPosition.getX() + 0.5D;
|
||||
double d1 = (double)this.hangingPosition.getY() + 0.5D;
|
||||
double d2 = (double)this.hangingPosition.getZ() + 0.5D;
|
||||
double d3 = 0.46875D;
|
||||
double d4 = this.offs(this.getWidthPixels());
|
||||
double d5 = this.offs(this.getHeightPixels());
|
||||
d0 = d0 - (double)this.facingDirection.getFrontOffsetX() * 0.46875D;
|
||||
d2 = d2 - (double)this.facingDirection.getFrontOffsetZ() * 0.46875D;
|
||||
d1 = d1 + d5;
|
||||
EnumFacing enumfacing = this.facingDirection.rotateYCCW();
|
||||
d0 = d0 + d4 * (double)enumfacing.getFrontOffsetX();
|
||||
d2 = d2 + d4 * (double)enumfacing.getFrontOffsetZ();
|
||||
this.posX = d0;
|
||||
this.posY = d1;
|
||||
this.posZ = d2;
|
||||
double d6 = (double)this.getWidthPixels();
|
||||
double d7 = (double)this.getHeightPixels();
|
||||
double d8 = (double)this.getWidthPixels();
|
||||
|
||||
if (this.facingDirection.getAxis() == EnumFacing.Axis.Z)
|
||||
{
|
||||
d8 = 1.0D;
|
||||
}
|
||||
else
|
||||
{
|
||||
d6 = 1.0D;
|
||||
}
|
||||
|
||||
d6 = d6 / 32.0D;
|
||||
d7 = d7 / 32.0D;
|
||||
d8 = d8 / 32.0D;
|
||||
this.setEntityBoundingBox(new AxisAlignedBB(d0 - d6, d1 - d7, d2 - d8, d0 + d6, d1 + d7, d2 + d8));
|
||||
}
|
||||
}
|
||||
|
||||
private double offs(int p_190202_1_)
|
||||
{
|
||||
return p_190202_1_ % 32 == 0 ? 0.5D : 0.0D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to update the entity's position/logic.
|
||||
*/
|
||||
public void onUpdate()
|
||||
{
|
||||
this.prevPosX = this.posX;
|
||||
this.prevPosY = this.posY;
|
||||
this.prevPosZ = this.posZ;
|
||||
|
||||
if (this.tickCounter1++ == 100 && !this.world.isRemote)
|
||||
{
|
||||
this.tickCounter1 = 0;
|
||||
|
||||
if (!this.isDead && !this.onValidSurface())
|
||||
{
|
||||
this.setDead();
|
||||
this.onBroken((Entity)null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks to make sure painting can be placed there
|
||||
*/
|
||||
public boolean onValidSurface()
|
||||
{
|
||||
if (!this.world.getCollisionBoxes(this, this.getEntityBoundingBox()).isEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = Math.max(1, this.getWidthPixels() / 16);
|
||||
int j = Math.max(1, this.getHeightPixels() / 16);
|
||||
BlockPos blockpos = this.hangingPosition.offset(this.facingDirection.getOpposite());
|
||||
EnumFacing enumfacing = this.facingDirection.rotateYCCW();
|
||||
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
|
||||
|
||||
for (int k = 0; k < i; ++k)
|
||||
{
|
||||
for (int l = 0; l < j; ++l)
|
||||
{
|
||||
int i1 = (i - 1) / -2;
|
||||
int j1 = (j - 1) / -2;
|
||||
blockpos$mutableblockpos.setPos(blockpos).move(enumfacing, k + i1).move(EnumFacing.UP, l + j1);
|
||||
IBlockState iblockstate = this.world.getBlockState(blockpos$mutableblockpos);
|
||||
|
||||
if (iblockstate.isSideSolid(this.world, blockpos$mutableblockpos, this.facingDirection))
|
||||
continue;
|
||||
|
||||
if (!iblockstate.getMaterial().isSolid() && !BlockRedstoneDiode.isDiode(iblockstate))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this.world.getEntitiesInAABBexcluding(this, this.getEntityBoundingBox(), IS_HANGING_ENTITY).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if other Entities should be prevented from moving through this Entity.
|
||||
*/
|
||||
public boolean canBeCollidedWith()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a player attacks an entity. If this returns true the attack will not happen.
|
||||
*/
|
||||
public boolean hitByEntity(Entity entityIn)
|
||||
{
|
||||
return entityIn instanceof EntityPlayer ? this.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer)entityIn), 0.0F) : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the horizontal facing direction of this Entity.
|
||||
*/
|
||||
public EnumFacing getHorizontalFacing()
|
||||
{
|
||||
return this.facingDirection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the entity is attacked.
|
||||
*/
|
||||
public boolean attackEntityFrom(DamageSource source, float amount)
|
||||
{
|
||||
if (this.isEntityInvulnerable(source))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!this.isDead && !this.world.isRemote)
|
||||
{
|
||||
this.setDead();
|
||||
this.markVelocityChanged();
|
||||
this.onBroken(source.getTrueSource());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to move the entity towards the specified location.
|
||||
*/
|
||||
public void move(MoverType type, double x, double y, double z)
|
||||
{
|
||||
if (!this.world.isRemote && !this.isDead && x * x + y * y + z * z > 0.0D)
|
||||
{
|
||||
this.setDead();
|
||||
this.onBroken((Entity)null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds to the current velocity of the entity, and sets {@link #isAirBorne} to true.
|
||||
*/
|
||||
public void addVelocity(double x, double y, double z)
|
||||
{
|
||||
if (!this.world.isRemote && !this.isDead && x * x + y * y + z * z > 0.0D)
|
||||
{
|
||||
this.setDead();
|
||||
this.onBroken((Entity)null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
compound.setByte("Facing", (byte)this.facingDirection.getHorizontalIndex());
|
||||
BlockPos blockpos = this.getHangingPosition();
|
||||
compound.setInteger("TileX", blockpos.getX());
|
||||
compound.setInteger("TileY", blockpos.getY());
|
||||
compound.setInteger("TileZ", blockpos.getZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
this.hangingPosition = new BlockPos(compound.getInteger("TileX"), compound.getInteger("TileY"), compound.getInteger("TileZ"));
|
||||
this.updateFacingWithBoundingBox(EnumFacing.getHorizontal(compound.getByte("Facing")));
|
||||
}
|
||||
|
||||
public abstract int getWidthPixels();
|
||||
|
||||
public abstract int getHeightPixels();
|
||||
|
||||
/**
|
||||
* Called when this entity is broken. Entity parameter may be null.
|
||||
*/
|
||||
public abstract void onBroken(@Nullable Entity brokenEntity);
|
||||
|
||||
public abstract void playPlaceSound();
|
||||
|
||||
/**
|
||||
* Drops an item at the position of the entity.
|
||||
*/
|
||||
public EntityItem entityDropItem(ItemStack stack, float offsetY)
|
||||
{
|
||||
EntityItem entityitem = new EntityItem(this.world, this.posX + (double)((float)this.facingDirection.getFrontOffsetX() * 0.15F), this.posY + (double)offsetY, this.posZ + (double)((float)this.facingDirection.getFrontOffsetZ() * 0.15F), stack);
|
||||
entityitem.setDefaultPickupDelay();
|
||||
this.world.spawnEntity(entityitem);
|
||||
return entityitem;
|
||||
}
|
||||
|
||||
protected boolean shouldSetPosAfterLoading()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the x,y,z of the entity from the given parameters. Also seems to set up a bounding box.
|
||||
*/
|
||||
public void setPosition(double x, double y, double z)
|
||||
{
|
||||
this.hangingPosition = new BlockPos(x, y, z);
|
||||
this.updateBoundingBox();
|
||||
this.isAirBorne = true;
|
||||
}
|
||||
|
||||
public BlockPos getHangingPosition()
|
||||
{
|
||||
return this.hangingPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the entity's current yaw with the given Rotation and returns it. This does not have a side-effect.
|
||||
*/
|
||||
@SuppressWarnings("incomplete-switch")
|
||||
public float getRotatedYaw(Rotation transformRotation)
|
||||
{
|
||||
if (this.facingDirection != null && this.facingDirection.getAxis() != EnumFacing.Axis.Y)
|
||||
{
|
||||
switch (transformRotation)
|
||||
{
|
||||
case CLOCKWISE_180:
|
||||
this.facingDirection = this.facingDirection.getOpposite();
|
||||
break;
|
||||
case COUNTERCLOCKWISE_90:
|
||||
this.facingDirection = this.facingDirection.rotateYCCW();
|
||||
break;
|
||||
case CLOCKWISE_90:
|
||||
this.facingDirection = this.facingDirection.rotateY();
|
||||
}
|
||||
}
|
||||
|
||||
float f = MathHelper.wrapDegrees(this.rotationYaw);
|
||||
|
||||
switch (transformRotation)
|
||||
{
|
||||
case CLOCKWISE_180:
|
||||
return f + 180.0F;
|
||||
case COUNTERCLOCKWISE_90:
|
||||
return f + 90.0F;
|
||||
case CLOCKWISE_90:
|
||||
return f + 270.0F;
|
||||
default:
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the entity's current yaw with the given Mirror and returns it. This does not have a side-effect.
|
||||
*/
|
||||
public float getMirroredYaw(Mirror transformMirror)
|
||||
{
|
||||
return this.getRotatedYaw(transformMirror.toRotation(this.facingDirection));
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a lightning bolt hits the entity.
|
||||
*/
|
||||
public void onStruckByLightning(EntityLightningBolt lightningBolt)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import java.util.List;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.block.BlockFence;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.init.SoundEvents;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public class EntityLeashKnot extends EntityHanging
|
||||
{
|
||||
public EntityLeashKnot(World worldIn)
|
||||
{
|
||||
super(worldIn);
|
||||
}
|
||||
|
||||
public EntityLeashKnot(World worldIn, BlockPos hangingPositionIn)
|
||||
{
|
||||
super(worldIn, hangingPositionIn);
|
||||
this.setPosition((double)hangingPositionIn.getX() + 0.5D, (double)hangingPositionIn.getY() + 0.5D, (double)hangingPositionIn.getZ() + 0.5D);
|
||||
float f = 0.125F;
|
||||
float f1 = 0.1875F;
|
||||
float f2 = 0.25F;
|
||||
this.setEntityBoundingBox(new AxisAlignedBB(this.posX - 0.1875D, this.posY - 0.25D + 0.125D, this.posZ - 0.1875D, this.posX + 0.1875D, this.posY + 0.25D + 0.125D, this.posZ + 0.1875D));
|
||||
this.forceSpawn = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the x,y,z of the entity from the given parameters. Also seems to set up a bounding box.
|
||||
*/
|
||||
public void setPosition(double x, double y, double z)
|
||||
{
|
||||
super.setPosition((double)MathHelper.floor(x) + 0.5D, (double)MathHelper.floor(y) + 0.5D, (double)MathHelper.floor(z) + 0.5D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the entity bounding box based on current facing
|
||||
*/
|
||||
protected void updateBoundingBox()
|
||||
{
|
||||
this.posX = (double)this.hangingPosition.getX() + 0.5D;
|
||||
this.posY = (double)this.hangingPosition.getY() + 0.5D;
|
||||
this.posZ = (double)this.hangingPosition.getZ() + 0.5D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates facing and bounding box based on it
|
||||
*/
|
||||
public void updateFacingWithBoundingBox(EnumFacing facingDirectionIn)
|
||||
{
|
||||
}
|
||||
|
||||
public int getWidthPixels()
|
||||
{
|
||||
return 9;
|
||||
}
|
||||
|
||||
public int getHeightPixels()
|
||||
{
|
||||
return 9;
|
||||
}
|
||||
|
||||
public float getEyeHeight()
|
||||
{
|
||||
return -0.0625F;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the entity is in range to render.
|
||||
*/
|
||||
@SideOnly(Side.CLIENT)
|
||||
public boolean isInRangeToRenderDist(double distance)
|
||||
{
|
||||
return distance < 1024.0D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when this entity is broken. Entity parameter may be null.
|
||||
*/
|
||||
public void onBroken(@Nullable Entity brokenEntity)
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_LEASHKNOT_BREAK, 1.0F, 1.0F);
|
||||
}
|
||||
|
||||
/**
|
||||
* Either write this entity to the NBT tag given and return true, or return false without doing anything. If this
|
||||
* returns false the entity is not saved on disk. Riding entities return false here as they are saved with their
|
||||
* mount.
|
||||
*/
|
||||
public boolean writeToNBTOptional(NBTTagCompound compound)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
public void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
public void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
}
|
||||
|
||||
public boolean processInitialInteract(EntityPlayer player, EnumHand hand)
|
||||
{
|
||||
if (this.world.isRemote)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean flag = false;
|
||||
double d0 = 7.0D;
|
||||
List<EntityLiving> list = this.world.<EntityLiving>getEntitiesWithinAABB(EntityLiving.class, new AxisAlignedBB(this.posX - 7.0D, this.posY - 7.0D, this.posZ - 7.0D, this.posX + 7.0D, this.posY + 7.0D, this.posZ + 7.0D));
|
||||
|
||||
for (EntityLiving entityliving : list)
|
||||
{
|
||||
if (entityliving.getLeashed() && entityliving.getLeashHolder() == player)
|
||||
{
|
||||
entityliving.setLeashHolder(this, true);
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!flag)
|
||||
{
|
||||
this.setDead();
|
||||
|
||||
if (player.capabilities.isCreativeMode)
|
||||
{
|
||||
for (EntityLiving entityliving1 : list)
|
||||
{
|
||||
if (entityliving1.getLeashed() && entityliving1.getLeashHolder() == this)
|
||||
{
|
||||
entityliving1.clearLeashed(true, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* checks to make sure painting can be placed there
|
||||
*/
|
||||
public boolean onValidSurface()
|
||||
{
|
||||
return this.world.getBlockState(this.hangingPosition).getBlock() instanceof BlockFence;
|
||||
}
|
||||
|
||||
public static EntityLeashKnot createKnot(World worldIn, BlockPos fence)
|
||||
{
|
||||
EntityLeashKnot entityleashknot = new EntityLeashKnot(worldIn, fence);
|
||||
worldIn.spawnEntity(entityleashknot);
|
||||
entityleashknot.playPlaceSound();
|
||||
return entityleashknot;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static EntityLeashKnot getKnotForPosition(World worldIn, BlockPos pos)
|
||||
{
|
||||
int i = pos.getX();
|
||||
int j = pos.getY();
|
||||
int k = pos.getZ();
|
||||
|
||||
for (EntityLeashKnot entityleashknot : worldIn.getEntitiesWithinAABB(EntityLeashKnot.class, new AxisAlignedBB((double)i - 1.0D, (double)j - 1.0D, (double)k - 1.0D, (double)i + 1.0D, (double)j + 1.0D, (double)k + 1.0D)))
|
||||
{
|
||||
if (entityleashknot.getHangingPosition().equals(pos))
|
||||
{
|
||||
return entityleashknot;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void playPlaceSound()
|
||||
{
|
||||
this.playSound(SoundEvents.ENTITY_LEASHKNOT_PLACE, 1.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,532 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.boss.EntityDragon;
|
||||
import net.minecraft.entity.boss.EntityWither;
|
||||
import net.minecraft.entity.effect.EntityLightningBolt;
|
||||
import net.minecraft.entity.item.EntityArmorStand;
|
||||
import net.minecraft.entity.item.EntityBoat;
|
||||
import net.minecraft.entity.item.EntityEnderCrystal;
|
||||
import net.minecraft.entity.item.EntityEnderEye;
|
||||
import net.minecraft.entity.item.EntityEnderPearl;
|
||||
import net.minecraft.entity.item.EntityExpBottle;
|
||||
import net.minecraft.entity.item.EntityFallingBlock;
|
||||
import net.minecraft.entity.item.EntityFireworkRocket;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.item.EntityItemFrame;
|
||||
import net.minecraft.entity.item.EntityMinecart;
|
||||
import net.minecraft.entity.item.EntityMinecartChest;
|
||||
import net.minecraft.entity.item.EntityMinecartCommandBlock;
|
||||
import net.minecraft.entity.item.EntityMinecartEmpty;
|
||||
import net.minecraft.entity.item.EntityMinecartFurnace;
|
||||
import net.minecraft.entity.item.EntityMinecartHopper;
|
||||
import net.minecraft.entity.item.EntityMinecartMobSpawner;
|
||||
import net.minecraft.entity.item.EntityMinecartTNT;
|
||||
import net.minecraft.entity.item.EntityPainting;
|
||||
import net.minecraft.entity.item.EntityTNTPrimed;
|
||||
import net.minecraft.entity.item.EntityXPOrb;
|
||||
import net.minecraft.entity.monster.EntityBlaze;
|
||||
import net.minecraft.entity.monster.EntityCaveSpider;
|
||||
import net.minecraft.entity.monster.EntityCreeper;
|
||||
import net.minecraft.entity.monster.EntityElderGuardian;
|
||||
import net.minecraft.entity.monster.EntityEnderman;
|
||||
import net.minecraft.entity.monster.EntityEndermite;
|
||||
import net.minecraft.entity.monster.EntityEvoker;
|
||||
import net.minecraft.entity.monster.EntityGhast;
|
||||
import net.minecraft.entity.monster.EntityGiantZombie;
|
||||
import net.minecraft.entity.monster.EntityGuardian;
|
||||
import net.minecraft.entity.monster.EntityHusk;
|
||||
import net.minecraft.entity.monster.EntityIllusionIllager;
|
||||
import net.minecraft.entity.monster.EntityIronGolem;
|
||||
import net.minecraft.entity.monster.EntityMagmaCube;
|
||||
import net.minecraft.entity.monster.EntityPigZombie;
|
||||
import net.minecraft.entity.monster.EntityPolarBear;
|
||||
import net.minecraft.entity.monster.EntityShulker;
|
||||
import net.minecraft.entity.monster.EntitySilverfish;
|
||||
import net.minecraft.entity.monster.EntitySkeleton;
|
||||
import net.minecraft.entity.monster.EntitySlime;
|
||||
import net.minecraft.entity.monster.EntitySnowman;
|
||||
import net.minecraft.entity.monster.EntitySpider;
|
||||
import net.minecraft.entity.monster.EntityStray;
|
||||
import net.minecraft.entity.monster.EntityVex;
|
||||
import net.minecraft.entity.monster.EntityVindicator;
|
||||
import net.minecraft.entity.monster.EntityWitch;
|
||||
import net.minecraft.entity.monster.EntityWitherSkeleton;
|
||||
import net.minecraft.entity.monster.EntityZombie;
|
||||
import net.minecraft.entity.monster.EntityZombieVillager;
|
||||
import net.minecraft.entity.passive.EntityBat;
|
||||
import net.minecraft.entity.passive.EntityChicken;
|
||||
import net.minecraft.entity.passive.EntityCow;
|
||||
import net.minecraft.entity.passive.EntityDonkey;
|
||||
import net.minecraft.entity.passive.EntityHorse;
|
||||
import net.minecraft.entity.passive.EntityLlama;
|
||||
import net.minecraft.entity.passive.EntityMooshroom;
|
||||
import net.minecraft.entity.passive.EntityMule;
|
||||
import net.minecraft.entity.passive.EntityOcelot;
|
||||
import net.minecraft.entity.passive.EntityParrot;
|
||||
import net.minecraft.entity.passive.EntityPig;
|
||||
import net.minecraft.entity.passive.EntityRabbit;
|
||||
import net.minecraft.entity.passive.EntitySheep;
|
||||
import net.minecraft.entity.passive.EntitySkeletonHorse;
|
||||
import net.minecraft.entity.passive.EntitySquid;
|
||||
import net.minecraft.entity.passive.EntityVillager;
|
||||
import net.minecraft.entity.passive.EntityWolf;
|
||||
import net.minecraft.entity.passive.EntityZombieHorse;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.projectile.EntityDragonFireball;
|
||||
import net.minecraft.entity.projectile.EntityEgg;
|
||||
import net.minecraft.entity.projectile.EntityEvokerFangs;
|
||||
import net.minecraft.entity.projectile.EntityLargeFireball;
|
||||
import net.minecraft.entity.projectile.EntityLlamaSpit;
|
||||
import net.minecraft.entity.projectile.EntityPotion;
|
||||
import net.minecraft.entity.projectile.EntityShulkerBullet;
|
||||
import net.minecraft.entity.projectile.EntitySmallFireball;
|
||||
import net.minecraft.entity.projectile.EntitySnowball;
|
||||
import net.minecraft.entity.projectile.EntitySpectralArrow;
|
||||
import net.minecraft.entity.projectile.EntityTippedArrow;
|
||||
import net.minecraft.entity.projectile.EntityWitherSkull;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.stats.StatBase;
|
||||
import net.minecraft.stats.StatList;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
import net.minecraft.util.registry.RegistryNamespaced;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class EntityList
|
||||
{
|
||||
public static final ResourceLocation LIGHTNING_BOLT = new ResourceLocation("lightning_bolt");
|
||||
private static final ResourceLocation PLAYER = new ResourceLocation("player");
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
/** This is a HashMap of the Creative Entity Eggs/Spawners. */
|
||||
public static final Map<ResourceLocation, EntityList.EntityEggInfo> ENTITY_EGGS = Maps.<ResourceLocation, EntityList.EntityEggInfo>newLinkedHashMap();
|
||||
private static final Set<ResourceLocation> EXTRA_NAMES = Sets.newHashSet();
|
||||
|
||||
/**
|
||||
* Gets the {@link ResourceLocation} that identifies the given entity's type.
|
||||
*/
|
||||
@Nullable
|
||||
public static ResourceLocation getKey(Entity entityIn)
|
||||
{
|
||||
return getKey(entityIn.getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the {@link ResourceLocation} that identifies the given entity's type.
|
||||
*
|
||||
* @return The resource location, or null if the {@link #REGISTRY} does not contain a mapping for that class.
|
||||
*/
|
||||
@Nullable
|
||||
public static ResourceLocation getKey(Class <? extends Entity > entityIn)
|
||||
{
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.fml.common.registry.EntityRegistry.getEntry(entityIn);
|
||||
return entry == null ? null : entry.getRegistryName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original name for the entity, used in versions prior to 1.11. This name is also used for translation
|
||||
* strings.
|
||||
*
|
||||
* @return The entity's original name, or null if the given entity's type is not known.
|
||||
*/
|
||||
@Nullable
|
||||
public static String getEntityString(Entity entityIn)
|
||||
{
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.fml.common.registry.EntityRegistry.getEntry(entityIn.getClass());
|
||||
return entry == null ? null : entry.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the original name for the given entity type, used in versions prior to 1.11. Note that even entities added
|
||||
* after 1.11 have old names as returned by this method.
|
||||
* <p>
|
||||
* This name is also used for translation strings; translate <code>"entity.$oldid.name"</code> (with
|
||||
* <var>$oldid</var> being the result of this method) to get those names. Note that the name is upper-case in most
|
||||
* situations.
|
||||
*
|
||||
* @return The original entity name, or null if there is no known entity for that type.
|
||||
*/
|
||||
@Nullable
|
||||
public static String getTranslationName(@Nullable ResourceLocation entityType)
|
||||
{
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.fml.common.registry.ForgeRegistries.ENTITIES.getValue(entityType);
|
||||
return entry == null ? null : entry.getName();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static Class <? extends Entity > getClassFromID(int entityID)
|
||||
{
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.registries.GameData.getEntityRegistry().getValue(entityID);
|
||||
return entry == null ? null : entry.getEntityClass();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static Class <? extends Entity > getClassFromName(String p_192839_0_)
|
||||
{
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.fml.common.registry.ForgeRegistries.ENTITIES.getValue(new ResourceLocation(p_192839_0_));
|
||||
return entry == null ? null : entry.getEntityClass();
|
||||
}
|
||||
|
||||
public static int getID(Class<? extends Entity> cls)
|
||||
{
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.fml.common.registry.EntityRegistry.getEntry(cls);
|
||||
return entry == null ? -1 : net.minecraftforge.registries.GameData.getEntityRegistry().getID(entry);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Class<? extends Entity> getClass(ResourceLocation key)
|
||||
{
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.fml.common.registry.ForgeRegistries.ENTITIES.getValue(key);
|
||||
return entry == null ? null : entry.getEntityClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new entity of the given type in the given world.
|
||||
*
|
||||
* @return The newly created entity, or null if creation failed
|
||||
*/
|
||||
@Nullable
|
||||
public static Entity newEntity(@Nullable Class <? extends Entity > clazz, World worldIn)
|
||||
{
|
||||
if (clazz == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.fml.common.registry.EntityRegistry.getEntry(clazz);
|
||||
if (entry != null) return entry.newInstance(worldIn);
|
||||
return clazz.getConstructor(World.class).newInstance(worldIn);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
exception.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new entity with the given numeric networked entity type ID in the given world.
|
||||
*
|
||||
* @return The newly created entity, or null if creation failed
|
||||
*/
|
||||
@Nullable
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static Entity createEntityByID(int entityID, World worldIn)
|
||||
{
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.registries.GameData.getEntityRegistry().getValue(entityID);
|
||||
return entry == null ? null : entry.newInstance(worldIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new entity of the given type in the given world.
|
||||
*
|
||||
* @return The newly created entity, or null if creation failed
|
||||
*/
|
||||
@Nullable
|
||||
public static Entity createEntityByIDFromName(ResourceLocation name, World worldIn)
|
||||
{
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.fml.common.registry.ForgeRegistries.ENTITIES.getValue(name);
|
||||
return entry == null ? null : entry.newInstance(worldIn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new entity from the given NBT data in the given world.
|
||||
* <p>
|
||||
* If the entity fails to create, null will be returned and a warning will be logged.
|
||||
*
|
||||
* @return The newly created entity, or null
|
||||
*/
|
||||
@Nullable
|
||||
public static Entity createEntityFromNBT(NBTTagCompound nbt, World worldIn)
|
||||
{
|
||||
ResourceLocation resourcelocation = new ResourceLocation(nbt.getString("id"));
|
||||
Entity entity = createEntityByIDFromName(resourcelocation, worldIn);
|
||||
|
||||
if (entity == null)
|
||||
{
|
||||
LOGGER.warn("Skipping Entity with id {}", (Object)resourcelocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
entity.readFromNBT(nbt);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
net.minecraftforge.fml.common.FMLLog.log.error("An Entity {}({}) has thrown an exception during loading, its state cannot be restored. Report this to the mod author",
|
||||
nbt.getString("id"), entity.getName(), e);
|
||||
entity = null;
|
||||
}
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a collection of all known entity types.
|
||||
*
|
||||
* @return A collection of all known entity types. Do not modify this collection.
|
||||
*/
|
||||
public static Set<ResourceLocation> getEntityNameList()
|
||||
{
|
||||
return Sets.union(net.minecraftforge.fml.common.registry.ForgeRegistries.ENTITIES.getKeys(), EXTRA_NAMES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given entity type matches the type of that entity, correctly handling behavior of players and
|
||||
* lightning bolts.
|
||||
*
|
||||
* @return true if the type matches
|
||||
*/
|
||||
public static boolean isMatchingName(Entity entityIn, ResourceLocation entityName)
|
||||
{
|
||||
ResourceLocation resourcelocation = getKey(entityIn.getClass());
|
||||
|
||||
if (resourcelocation != null)
|
||||
{
|
||||
return resourcelocation.equals(entityName);
|
||||
}
|
||||
else if (entityIn instanceof EntityPlayer)
|
||||
{
|
||||
return PLAYER.equals(entityName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return entityIn instanceof EntityLightningBolt ? LIGHTNING_BOLT.equals(entityName) : false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the given resource location matches a registered entity type, correctly handling behavior of players
|
||||
* and lightning bols.
|
||||
*
|
||||
* @return true if the type is an entity.
|
||||
*/
|
||||
public static boolean isRegistered(ResourceLocation entityName)
|
||||
{
|
||||
return PLAYER.equals(entityName) || getEntityNameList().contains(entityName);
|
||||
}
|
||||
|
||||
public static String getValidTypeNames()
|
||||
{
|
||||
StringBuilder stringbuilder = new StringBuilder();
|
||||
|
||||
for (ResourceLocation resourcelocation : getEntityNameList())
|
||||
{
|
||||
stringbuilder.append((Object)resourcelocation).append(", ");
|
||||
}
|
||||
|
||||
stringbuilder.append((Object)PLAYER);
|
||||
return stringbuilder.toString();
|
||||
}
|
||||
|
||||
public static void init()
|
||||
{
|
||||
register(1, "item", EntityItem.class, "Item");
|
||||
register(2, "xp_orb", EntityXPOrb.class, "XPOrb");
|
||||
register(3, "area_effect_cloud", EntityAreaEffectCloud.class, "AreaEffectCloud");
|
||||
register(4, "elder_guardian", EntityElderGuardian.class, "ElderGuardian");
|
||||
register(5, "wither_skeleton", EntityWitherSkeleton.class, "WitherSkeleton");
|
||||
register(6, "stray", EntityStray.class, "Stray");
|
||||
register(7, "egg", EntityEgg.class, "ThrownEgg");
|
||||
register(8, "leash_knot", EntityLeashKnot.class, "LeashKnot");
|
||||
register(9, "painting", EntityPainting.class, "Painting");
|
||||
register(10, "arrow", EntityTippedArrow.class, "Arrow");
|
||||
register(11, "snowball", EntitySnowball.class, "Snowball");
|
||||
register(12, "fireball", EntityLargeFireball.class, "Fireball");
|
||||
register(13, "small_fireball", EntitySmallFireball.class, "SmallFireball");
|
||||
register(14, "ender_pearl", EntityEnderPearl.class, "ThrownEnderpearl");
|
||||
register(15, "eye_of_ender_signal", EntityEnderEye.class, "EyeOfEnderSignal");
|
||||
register(16, "potion", EntityPotion.class, "ThrownPotion");
|
||||
register(17, "xp_bottle", EntityExpBottle.class, "ThrownExpBottle");
|
||||
register(18, "item_frame", EntityItemFrame.class, "ItemFrame");
|
||||
register(19, "wither_skull", EntityWitherSkull.class, "WitherSkull");
|
||||
register(20, "tnt", EntityTNTPrimed.class, "PrimedTnt");
|
||||
register(21, "falling_block", EntityFallingBlock.class, "FallingSand");
|
||||
register(22, "fireworks_rocket", EntityFireworkRocket.class, "FireworksRocketEntity");
|
||||
register(23, "husk", EntityHusk.class, "Husk");
|
||||
register(24, "spectral_arrow", EntitySpectralArrow.class, "SpectralArrow");
|
||||
register(25, "shulker_bullet", EntityShulkerBullet.class, "ShulkerBullet");
|
||||
register(26, "dragon_fireball", EntityDragonFireball.class, "DragonFireball");
|
||||
register(27, "zombie_villager", EntityZombieVillager.class, "ZombieVillager");
|
||||
register(28, "skeleton_horse", EntitySkeletonHorse.class, "SkeletonHorse");
|
||||
register(29, "zombie_horse", EntityZombieHorse.class, "ZombieHorse");
|
||||
register(30, "armor_stand", EntityArmorStand.class, "ArmorStand");
|
||||
register(31, "donkey", EntityDonkey.class, "Donkey");
|
||||
register(32, "mule", EntityMule.class, "Mule");
|
||||
register(33, "evocation_fangs", EntityEvokerFangs.class, "EvocationFangs");
|
||||
register(34, "evocation_illager", EntityEvoker.class, "EvocationIllager");
|
||||
register(35, "vex", EntityVex.class, "Vex");
|
||||
register(36, "vindication_illager", EntityVindicator.class, "VindicationIllager");
|
||||
register(37, "illusion_illager", EntityIllusionIllager.class, "IllusionIllager");
|
||||
register(40, "commandblock_minecart", EntityMinecartCommandBlock.class, EntityMinecart.Type.COMMAND_BLOCK.getName());
|
||||
register(41, "boat", EntityBoat.class, "Boat");
|
||||
register(42, "minecart", EntityMinecartEmpty.class, EntityMinecart.Type.RIDEABLE.getName());
|
||||
register(43, "chest_minecart", EntityMinecartChest.class, EntityMinecart.Type.CHEST.getName());
|
||||
register(44, "furnace_minecart", EntityMinecartFurnace.class, EntityMinecart.Type.FURNACE.getName());
|
||||
register(45, "tnt_minecart", EntityMinecartTNT.class, EntityMinecart.Type.TNT.getName());
|
||||
register(46, "hopper_minecart", EntityMinecartHopper.class, EntityMinecart.Type.HOPPER.getName());
|
||||
register(47, "spawner_minecart", EntityMinecartMobSpawner.class, EntityMinecart.Type.SPAWNER.getName());
|
||||
register(50, "creeper", EntityCreeper.class, "Creeper");
|
||||
register(51, "skeleton", EntitySkeleton.class, "Skeleton");
|
||||
register(52, "spider", EntitySpider.class, "Spider");
|
||||
register(53, "giant", EntityGiantZombie.class, "Giant");
|
||||
register(54, "zombie", EntityZombie.class, "Zombie");
|
||||
register(55, "slime", EntitySlime.class, "Slime");
|
||||
register(56, "ghast", EntityGhast.class, "Ghast");
|
||||
register(57, "zombie_pigman", EntityPigZombie.class, "PigZombie");
|
||||
register(58, "enderman", EntityEnderman.class, "Enderman");
|
||||
register(59, "cave_spider", EntityCaveSpider.class, "CaveSpider");
|
||||
register(60, "silverfish", EntitySilverfish.class, "Silverfish");
|
||||
register(61, "blaze", EntityBlaze.class, "Blaze");
|
||||
register(62, "magma_cube", EntityMagmaCube.class, "LavaSlime");
|
||||
register(63, "ender_dragon", EntityDragon.class, "EnderDragon");
|
||||
register(64, "wither", EntityWither.class, "WitherBoss");
|
||||
register(65, "bat", EntityBat.class, "Bat");
|
||||
register(66, "witch", EntityWitch.class, "Witch");
|
||||
register(67, "endermite", EntityEndermite.class, "Endermite");
|
||||
register(68, "guardian", EntityGuardian.class, "Guardian");
|
||||
register(69, "shulker", EntityShulker.class, "Shulker");
|
||||
register(90, "pig", EntityPig.class, "Pig");
|
||||
register(91, "sheep", EntitySheep.class, "Sheep");
|
||||
register(92, "cow", EntityCow.class, "Cow");
|
||||
register(93, "chicken", EntityChicken.class, "Chicken");
|
||||
register(94, "squid", EntitySquid.class, "Squid");
|
||||
register(95, "wolf", EntityWolf.class, "Wolf");
|
||||
register(96, "mooshroom", EntityMooshroom.class, "MushroomCow");
|
||||
register(97, "snowman", EntitySnowman.class, "SnowMan");
|
||||
register(98, "ocelot", EntityOcelot.class, "Ozelot");
|
||||
register(99, "villager_golem", EntityIronGolem.class, "VillagerGolem");
|
||||
register(100, "horse", EntityHorse.class, "Horse");
|
||||
register(101, "rabbit", EntityRabbit.class, "Rabbit");
|
||||
register(102, "polar_bear", EntityPolarBear.class, "PolarBear");
|
||||
register(103, "llama", EntityLlama.class, "Llama");
|
||||
register(104, "llama_spit", EntityLlamaSpit.class, "LlamaSpit");
|
||||
register(105, "parrot", EntityParrot.class, "Parrot");
|
||||
register(120, "villager", EntityVillager.class, "Villager");
|
||||
register(200, "ender_crystal", EntityEnderCrystal.class, "EnderCrystal");
|
||||
addSpawnInfo("bat", 4996656, 986895);
|
||||
addSpawnInfo("blaze", 16167425, 16775294);
|
||||
addSpawnInfo("cave_spider", 803406, 11013646);
|
||||
addSpawnInfo("chicken", 10592673, 16711680);
|
||||
addSpawnInfo("cow", 4470310, 10592673);
|
||||
addSpawnInfo("creeper", 894731, 0);
|
||||
addSpawnInfo("donkey", 5457209, 8811878);
|
||||
addSpawnInfo("elder_guardian", 13552826, 7632531);
|
||||
addSpawnInfo("enderman", 1447446, 0);
|
||||
addSpawnInfo("endermite", 1447446, 7237230);
|
||||
addSpawnInfo("evocation_illager", 9804699, 1973274);
|
||||
addSpawnInfo("ghast", 16382457, 12369084);
|
||||
addSpawnInfo("guardian", 5931634, 15826224);
|
||||
addSpawnInfo("horse", 12623485, 15656192);
|
||||
addSpawnInfo("husk", 7958625, 15125652);
|
||||
addSpawnInfo("llama", 12623485, 10051392);
|
||||
addSpawnInfo("magma_cube", 3407872, 16579584);
|
||||
addSpawnInfo("mooshroom", 10489616, 12040119);
|
||||
addSpawnInfo("mule", 1769984, 5321501);
|
||||
addSpawnInfo("ocelot", 15720061, 5653556);
|
||||
addSpawnInfo("parrot", 894731, 16711680);
|
||||
addSpawnInfo("pig", 15771042, 14377823);
|
||||
addSpawnInfo("polar_bear", 15921906, 9803152);
|
||||
addSpawnInfo("rabbit", 10051392, 7555121);
|
||||
addSpawnInfo("sheep", 15198183, 16758197);
|
||||
addSpawnInfo("shulker", 9725844, 5060690);
|
||||
addSpawnInfo("silverfish", 7237230, 3158064);
|
||||
addSpawnInfo("skeleton", 12698049, 4802889);
|
||||
addSpawnInfo("skeleton_horse", 6842447, 15066584);
|
||||
addSpawnInfo("slime", 5349438, 8306542);
|
||||
addSpawnInfo("spider", 3419431, 11013646);
|
||||
addSpawnInfo("squid", 2243405, 7375001);
|
||||
addSpawnInfo("stray", 6387319, 14543594);
|
||||
addSpawnInfo("vex", 8032420, 15265265);
|
||||
addSpawnInfo("villager", 5651507, 12422002);
|
||||
addSpawnInfo("vindication_illager", 9804699, 2580065);
|
||||
addSpawnInfo("witch", 3407872, 5349438);
|
||||
addSpawnInfo("wither_skeleton", 1315860, 4672845);
|
||||
addSpawnInfo("wolf", 14144467, 13545366);
|
||||
addSpawnInfo("zombie", 44975, 7969893);
|
||||
addSpawnInfo("zombie_horse", 3232308, 9945732);
|
||||
addSpawnInfo("zombie_pigman", 15373203, 5009705);
|
||||
addSpawnInfo("zombie_villager", 5651507, 7969893);
|
||||
EXTRA_NAMES.add(LIGHTNING_BOLT);
|
||||
}
|
||||
|
||||
private static void register(int id, String name, Class <? extends Entity > clazz, String oldName)
|
||||
{
|
||||
try
|
||||
{
|
||||
clazz.getConstructor(World.class);
|
||||
}
|
||||
catch (NoSuchMethodException var5)
|
||||
{
|
||||
throw new RuntimeException("Invalid class " + clazz + " no constructor taking " + World.class.getName());
|
||||
}
|
||||
|
||||
if ((clazz.getModifiers() & 1024) == 1024)
|
||||
{
|
||||
throw new RuntimeException("Invalid abstract class " + clazz);
|
||||
}
|
||||
else
|
||||
{
|
||||
ResourceLocation resourcelocation = new ResourceLocation(name);
|
||||
net.minecraftforge.registries.GameData.registerEntity(id, resourcelocation, clazz, oldName);
|
||||
}
|
||||
}
|
||||
|
||||
protected static EntityList.EntityEggInfo addSpawnInfo(String id, int primaryColor, int secondaryColor)
|
||||
{
|
||||
ResourceLocation resourcelocation = new ResourceLocation(id);
|
||||
EntityList.EntityEggInfo egg = new EntityList.EntityEggInfo(resourcelocation, primaryColor, secondaryColor);
|
||||
net.minecraftforge.fml.common.registry.EntityEntry entry = net.minecraftforge.fml.common.registry.ForgeRegistries.ENTITIES.getValue(resourcelocation);
|
||||
if (entry != null) entry.setEgg(egg);
|
||||
return (EntityList.EntityEggInfo)ENTITY_EGGS.put(resourcelocation, egg);
|
||||
}
|
||||
|
||||
public static class EntityEggInfo
|
||||
{
|
||||
/** The entityID of the spawned mob */
|
||||
public final ResourceLocation spawnedID;
|
||||
/** Base color of the egg */
|
||||
public final int primaryColor;
|
||||
/** Color of the egg spots */
|
||||
public final int secondaryColor;
|
||||
public final StatBase killEntityStat;
|
||||
public final StatBase entityKilledByStat;
|
||||
|
||||
public EntityEggInfo(ResourceLocation idIn, int primaryColorIn, int secondaryColorIn)
|
||||
{
|
||||
this.spawnedID = idIn;
|
||||
this.primaryColor = primaryColorIn;
|
||||
this.secondaryColor = secondaryColorIn;
|
||||
this.killEntityStat = StatList.getStatKillEntity(this);
|
||||
this.entityKilledByStat = StatList.getStatEntityKilledBy(this);
|
||||
}
|
||||
|
||||
// Forge start
|
||||
public EntityEggInfo(ResourceLocation id, int primaryColor, int secondaryColor, StatBase killEntityStatistic, StatBase entityKilledByStatistic)
|
||||
{
|
||||
this.spawnedID = id;
|
||||
this.primaryColor = primaryColor;
|
||||
this.secondaryColor = secondaryColor;
|
||||
this.killEntityStat = killEntityStatistic;
|
||||
this.entityKilledByStat = entityKilledByStatistic;
|
||||
}
|
||||
// Forge end
|
||||
}
|
||||
}
|
||||
1612
build/tmp/recompileMc/sources/net/minecraft/entity/EntityLiving.java
Normal file
1612
build/tmp/recompileMc/sources/net/minecraft/entity/EntityLiving.java
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,105 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import java.util.Map;
|
||||
import net.minecraft.entity.boss.EntityDragon;
|
||||
import net.minecraft.entity.boss.EntityWither;
|
||||
import net.minecraft.entity.monster.EntityBlaze;
|
||||
import net.minecraft.entity.monster.EntityCaveSpider;
|
||||
import net.minecraft.entity.monster.EntityCreeper;
|
||||
import net.minecraft.entity.monster.EntityEnderman;
|
||||
import net.minecraft.entity.monster.EntityEndermite;
|
||||
import net.minecraft.entity.monster.EntityGhast;
|
||||
import net.minecraft.entity.monster.EntityGiantZombie;
|
||||
import net.minecraft.entity.monster.EntityGuardian;
|
||||
import net.minecraft.entity.monster.EntityHusk;
|
||||
import net.minecraft.entity.monster.EntityIronGolem;
|
||||
import net.minecraft.entity.monster.EntityMagmaCube;
|
||||
import net.minecraft.entity.monster.EntityPigZombie;
|
||||
import net.minecraft.entity.monster.EntitySilverfish;
|
||||
import net.minecraft.entity.monster.EntitySkeleton;
|
||||
import net.minecraft.entity.monster.EntitySlime;
|
||||
import net.minecraft.entity.monster.EntitySnowman;
|
||||
import net.minecraft.entity.monster.EntitySpider;
|
||||
import net.minecraft.entity.monster.EntityStray;
|
||||
import net.minecraft.entity.monster.EntityWitch;
|
||||
import net.minecraft.entity.monster.EntityWitherSkeleton;
|
||||
import net.minecraft.entity.monster.EntityZombie;
|
||||
import net.minecraft.entity.monster.EntityZombieVillager;
|
||||
import net.minecraft.entity.passive.EntityBat;
|
||||
import net.minecraft.entity.passive.EntityChicken;
|
||||
import net.minecraft.entity.passive.EntityCow;
|
||||
import net.minecraft.entity.passive.EntityDonkey;
|
||||
import net.minecraft.entity.passive.EntityHorse;
|
||||
import net.minecraft.entity.passive.EntityMooshroom;
|
||||
import net.minecraft.entity.passive.EntityMule;
|
||||
import net.minecraft.entity.passive.EntityOcelot;
|
||||
import net.minecraft.entity.passive.EntityParrot;
|
||||
import net.minecraft.entity.passive.EntityPig;
|
||||
import net.minecraft.entity.passive.EntityRabbit;
|
||||
import net.minecraft.entity.passive.EntitySheep;
|
||||
import net.minecraft.entity.passive.EntitySkeletonHorse;
|
||||
import net.minecraft.entity.passive.EntitySquid;
|
||||
import net.minecraft.entity.passive.EntityVillager;
|
||||
import net.minecraft.entity.passive.EntityWolf;
|
||||
import net.minecraft.entity.passive.EntityZombieHorse;
|
||||
|
||||
public class EntitySpawnPlacementRegistry
|
||||
{
|
||||
private static final Map < Class<?>, EntityLiving.SpawnPlacementType > ENTITY_PLACEMENTS = Maps. < Class<?>, EntityLiving.SpawnPlacementType > newHashMap();
|
||||
|
||||
public static EntityLiving.SpawnPlacementType getPlacementForEntity(Class<?> entityClass)
|
||||
{
|
||||
return ENTITY_PLACEMENTS.getOrDefault(entityClass, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
}
|
||||
|
||||
public static void setPlacementType(Class<? extends Entity> entityClass, EntityLiving.SpawnPlacementType placementType)
|
||||
{
|
||||
ENTITY_PLACEMENTS.putIfAbsent(entityClass, placementType);
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
ENTITY_PLACEMENTS.put(EntityBat.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityChicken.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityCow.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityHorse.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntitySkeletonHorse.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityZombieHorse.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityDonkey.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityMule.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityMooshroom.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityOcelot.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityPig.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityRabbit.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityParrot.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntitySheep.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntitySnowman.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntitySquid.class, EntityLiving.SpawnPlacementType.IN_WATER);
|
||||
ENTITY_PLACEMENTS.put(EntityIronGolem.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityWolf.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityVillager.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityDragon.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityWither.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityBlaze.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityCaveSpider.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityCreeper.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityEnderman.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityEndermite.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityGhast.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityGiantZombie.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityGuardian.class, EntityLiving.SpawnPlacementType.IN_WATER);
|
||||
ENTITY_PLACEMENTS.put(EntityMagmaCube.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityPigZombie.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntitySilverfish.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntitySkeleton.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityWitherSkeleton.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityStray.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntitySlime.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntitySpider.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityWitch.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityZombie.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityZombieVillager.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
ENTITY_PLACEMENTS.put(EntityHusk.class, EntityLiving.SpawnPlacementType.ON_GROUND);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,441 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import net.minecraft.crash.CrashReport;
|
||||
import net.minecraft.crash.CrashReportCategory;
|
||||
import net.minecraft.crash.ICrashReportDetail;
|
||||
import net.minecraft.entity.boss.EntityDragon;
|
||||
import net.minecraft.entity.boss.EntityWither;
|
||||
import net.minecraft.entity.item.EntityArmorStand;
|
||||
import net.minecraft.entity.item.EntityBoat;
|
||||
import net.minecraft.entity.item.EntityEnderCrystal;
|
||||
import net.minecraft.entity.item.EntityEnderEye;
|
||||
import net.minecraft.entity.item.EntityEnderPearl;
|
||||
import net.minecraft.entity.item.EntityExpBottle;
|
||||
import net.minecraft.entity.item.EntityFallingBlock;
|
||||
import net.minecraft.entity.item.EntityFireworkRocket;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.item.EntityMinecart;
|
||||
import net.minecraft.entity.item.EntityTNTPrimed;
|
||||
import net.minecraft.entity.item.EntityXPOrb;
|
||||
import net.minecraft.entity.passive.EntityBat;
|
||||
import net.minecraft.entity.passive.EntitySquid;
|
||||
import net.minecraft.entity.passive.IAnimals;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.entity.projectile.EntityArrow;
|
||||
import net.minecraft.entity.projectile.EntityEgg;
|
||||
import net.minecraft.entity.projectile.EntityEvokerFangs;
|
||||
import net.minecraft.entity.projectile.EntityFireball;
|
||||
import net.minecraft.entity.projectile.EntityFishHook;
|
||||
import net.minecraft.entity.projectile.EntityLlamaSpit;
|
||||
import net.minecraft.entity.projectile.EntityPotion;
|
||||
import net.minecraft.entity.projectile.EntityShulkerBullet;
|
||||
import net.minecraft.entity.projectile.EntitySmallFireball;
|
||||
import net.minecraft.entity.projectile.EntitySnowball;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.play.server.SPacketEntityAttach;
|
||||
import net.minecraft.network.play.server.SPacketSetPassengers;
|
||||
import net.minecraft.util.IntHashMap;
|
||||
import net.minecraft.util.ReportedException;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.WorldServer;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class EntityTracker
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
private final WorldServer world;
|
||||
/** List of tracked entities, used for iteration operations on tracked entities. */
|
||||
private final Set<EntityTrackerEntry> entries = Sets.<EntityTrackerEntry>newHashSet();
|
||||
/** Used for identity lookup of tracked entities. */
|
||||
private final IntHashMap<EntityTrackerEntry> trackedEntityHashTable = new IntHashMap<EntityTrackerEntry>();
|
||||
private int maxTrackingDistanceThreshold;
|
||||
|
||||
public EntityTracker(WorldServer theWorldIn)
|
||||
{
|
||||
this.world = theWorldIn;
|
||||
this.maxTrackingDistanceThreshold = theWorldIn.getMinecraftServer().getPlayerList().getEntityViewDistance();
|
||||
}
|
||||
|
||||
public static long getPositionLong(double value)
|
||||
{
|
||||
return MathHelper.lfloor(value * 4096.0D);
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public static void updateServerPosition(Entity entityIn, double x, double y, double z)
|
||||
{
|
||||
entityIn.serverPosX = getPositionLong(x);
|
||||
entityIn.serverPosY = getPositionLong(y);
|
||||
entityIn.serverPosZ = getPositionLong(z);
|
||||
}
|
||||
|
||||
public void track(Entity entityIn)
|
||||
{
|
||||
if (net.minecraftforge.fml.common.registry.EntityRegistry.instance().tryTrackingEntity(this, entityIn)) return;
|
||||
|
||||
if (entityIn instanceof EntityPlayerMP)
|
||||
{
|
||||
this.track(entityIn, 512, 2);
|
||||
EntityPlayerMP entityplayermp = (EntityPlayerMP)entityIn;
|
||||
|
||||
for (EntityTrackerEntry entitytrackerentry : this.entries)
|
||||
{
|
||||
if (entitytrackerentry.getTrackedEntity() != entityplayermp)
|
||||
{
|
||||
entitytrackerentry.updatePlayerEntity(entityplayermp);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (entityIn instanceof EntityFishHook)
|
||||
{
|
||||
this.track(entityIn, 64, 5, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityArrow)
|
||||
{
|
||||
this.track(entityIn, 64, 20, false);
|
||||
}
|
||||
else if (entityIn instanceof EntitySmallFireball)
|
||||
{
|
||||
this.track(entityIn, 64, 10, false);
|
||||
}
|
||||
else if (entityIn instanceof EntityFireball)
|
||||
{
|
||||
this.track(entityIn, 64, 10, true);
|
||||
}
|
||||
else if (entityIn instanceof EntitySnowball)
|
||||
{
|
||||
this.track(entityIn, 64, 10, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityLlamaSpit)
|
||||
{
|
||||
this.track(entityIn, 64, 10, false);
|
||||
}
|
||||
else if (entityIn instanceof EntityEnderPearl)
|
||||
{
|
||||
this.track(entityIn, 64, 10, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityEnderEye)
|
||||
{
|
||||
this.track(entityIn, 64, 4, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityEgg)
|
||||
{
|
||||
this.track(entityIn, 64, 10, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityPotion)
|
||||
{
|
||||
this.track(entityIn, 64, 10, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityExpBottle)
|
||||
{
|
||||
this.track(entityIn, 64, 10, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityFireworkRocket)
|
||||
{
|
||||
this.track(entityIn, 64, 10, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityItem)
|
||||
{
|
||||
this.track(entityIn, 64, 20, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityMinecart)
|
||||
{
|
||||
this.track(entityIn, 80, 3, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityBoat)
|
||||
{
|
||||
this.track(entityIn, 80, 3, true);
|
||||
}
|
||||
else if (entityIn instanceof EntitySquid)
|
||||
{
|
||||
this.track(entityIn, 64, 3, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityWither)
|
||||
{
|
||||
this.track(entityIn, 80, 3, false);
|
||||
}
|
||||
else if (entityIn instanceof EntityShulkerBullet)
|
||||
{
|
||||
this.track(entityIn, 80, 3, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityBat)
|
||||
{
|
||||
this.track(entityIn, 80, 3, false);
|
||||
}
|
||||
else if (entityIn instanceof EntityDragon)
|
||||
{
|
||||
this.track(entityIn, 160, 3, true);
|
||||
}
|
||||
else if (entityIn instanceof IAnimals)
|
||||
{
|
||||
this.track(entityIn, 80, 3, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityTNTPrimed)
|
||||
{
|
||||
this.track(entityIn, 160, 10, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityFallingBlock)
|
||||
{
|
||||
this.track(entityIn, 160, 20, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityHanging)
|
||||
{
|
||||
this.track(entityIn, 160, Integer.MAX_VALUE, false);
|
||||
}
|
||||
else if (entityIn instanceof EntityArmorStand)
|
||||
{
|
||||
this.track(entityIn, 160, 3, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityXPOrb)
|
||||
{
|
||||
this.track(entityIn, 160, 20, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityAreaEffectCloud)
|
||||
{
|
||||
this.track(entityIn, 160, Integer.MAX_VALUE, true);
|
||||
}
|
||||
else if (entityIn instanceof EntityEnderCrystal)
|
||||
{
|
||||
this.track(entityIn, 256, Integer.MAX_VALUE, false);
|
||||
}
|
||||
else if (entityIn instanceof EntityEvokerFangs)
|
||||
{
|
||||
this.track(entityIn, 160, 2, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void track(Entity entityIn, int trackingRange, int updateFrequency)
|
||||
{
|
||||
this.track(entityIn, trackingRange, updateFrequency, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Args : Entity, trackingRange, updateFrequency, sendVelocityUpdates
|
||||
*/
|
||||
public void track(Entity entityIn, int trackingRange, final int updateFrequency, boolean sendVelocityUpdates)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (this.trackedEntityHashTable.containsItem(entityIn.getEntityId()))
|
||||
{
|
||||
throw new IllegalStateException("Entity is already tracked!");
|
||||
}
|
||||
|
||||
EntityTrackerEntry entitytrackerentry = new EntityTrackerEntry(entityIn, trackingRange, this.maxTrackingDistanceThreshold, updateFrequency, sendVelocityUpdates);
|
||||
this.entries.add(entitytrackerentry);
|
||||
this.trackedEntityHashTable.addKey(entityIn.getEntityId(), entitytrackerentry);
|
||||
entitytrackerentry.updatePlayerEntities(this.world.playerEntities);
|
||||
}
|
||||
catch (Throwable throwable)
|
||||
{
|
||||
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Adding entity to track");
|
||||
CrashReportCategory crashreportcategory = crashreport.makeCategory("Entity To Track");
|
||||
crashreportcategory.addCrashSection("Tracking range", trackingRange + " blocks");
|
||||
crashreportcategory.addDetail("Update interval", new ICrashReportDetail<String>()
|
||||
{
|
||||
public String call() throws Exception
|
||||
{
|
||||
String s = "Once per " + updateFrequency + " ticks";
|
||||
|
||||
if (updateFrequency == Integer.MAX_VALUE)
|
||||
{
|
||||
s = "Maximum (" + s + ")";
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
});
|
||||
entityIn.addEntityCrashInfo(crashreportcategory);
|
||||
((EntityTrackerEntry)this.trackedEntityHashTable.lookup(entityIn.getEntityId())).getTrackedEntity().addEntityCrashInfo(crashreport.makeCategory("Entity That Is Already Tracked"));
|
||||
|
||||
try
|
||||
{
|
||||
throw new ReportedException(crashreport);
|
||||
}
|
||||
catch (ReportedException reportedexception)
|
||||
{
|
||||
LOGGER.error("\"Silently\" catching entity tracking error.", (Throwable)reportedexception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void untrack(Entity entityIn)
|
||||
{
|
||||
if (entityIn instanceof EntityPlayerMP)
|
||||
{
|
||||
EntityPlayerMP entityplayermp = (EntityPlayerMP)entityIn;
|
||||
|
||||
for (EntityTrackerEntry entitytrackerentry : this.entries)
|
||||
{
|
||||
entitytrackerentry.removeFromTrackedPlayers(entityplayermp);
|
||||
}
|
||||
}
|
||||
|
||||
EntityTrackerEntry entitytrackerentry1 = this.trackedEntityHashTable.removeObject(entityIn.getEntityId());
|
||||
|
||||
if (entitytrackerentry1 != null)
|
||||
{
|
||||
this.entries.remove(entitytrackerentry1);
|
||||
entitytrackerentry1.sendDestroyEntityPacketToTrackedPlayers();
|
||||
}
|
||||
}
|
||||
|
||||
public void tick()
|
||||
{
|
||||
List<EntityPlayerMP> list = Lists.<EntityPlayerMP>newArrayList();
|
||||
|
||||
for (EntityTrackerEntry entitytrackerentry : this.entries)
|
||||
{
|
||||
entitytrackerentry.updatePlayerList(this.world.playerEntities);
|
||||
|
||||
if (entitytrackerentry.playerEntitiesUpdated)
|
||||
{
|
||||
Entity entity = entitytrackerentry.getTrackedEntity();
|
||||
|
||||
if (entity instanceof EntityPlayerMP)
|
||||
{
|
||||
list.add((EntityPlayerMP)entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < list.size(); ++i)
|
||||
{
|
||||
EntityPlayerMP entityplayermp = list.get(i);
|
||||
|
||||
for (EntityTrackerEntry entitytrackerentry1 : this.entries)
|
||||
{
|
||||
if (entitytrackerentry1.getTrackedEntity() != entityplayermp)
|
||||
{
|
||||
entitytrackerentry1.updatePlayerEntity(entityplayermp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateVisibility(EntityPlayerMP player)
|
||||
{
|
||||
for (EntityTrackerEntry entitytrackerentry : this.entries)
|
||||
{
|
||||
if (entitytrackerentry.getTrackedEntity() == player)
|
||||
{
|
||||
entitytrackerentry.updatePlayerEntities(this.world.playerEntities);
|
||||
}
|
||||
else
|
||||
{
|
||||
entitytrackerentry.updatePlayerEntity(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sendToTracking(Entity entityIn, Packet<?> packetIn)
|
||||
{
|
||||
EntityTrackerEntry entitytrackerentry = this.trackedEntityHashTable.lookup(entityIn.getEntityId());
|
||||
|
||||
if (entitytrackerentry != null)
|
||||
{
|
||||
entitytrackerentry.sendPacketToTrackedPlayers(packetIn);
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================== FORGE START =====================================*/
|
||||
|
||||
// don't expose the EntityTrackerEntry directly so mods can't mess with the data in there as easily
|
||||
/**
|
||||
* Get all players tracking the given Entity. The Entity must be part of the World that this Tracker belongs to.
|
||||
* @param entity the Entity
|
||||
* @return all players tracking the Entity
|
||||
*/
|
||||
public Set<? extends net.minecraft.entity.player.EntityPlayer> getTrackingPlayers(Entity entity)
|
||||
{
|
||||
EntityTrackerEntry entry = (EntityTrackerEntry) trackedEntityHashTable.lookup(entity.getEntityId());
|
||||
if (entry == null)
|
||||
return java.util.Collections.emptySet();
|
||||
else
|
||||
return java.util.Collections.unmodifiableSet(entry.trackingPlayers);
|
||||
}
|
||||
|
||||
/* ======================================== FORGE END =====================================*/
|
||||
|
||||
public void sendToTrackingAndSelf(Entity entityIn, Packet<?> packetIn)
|
||||
{
|
||||
EntityTrackerEntry entitytrackerentry = this.trackedEntityHashTable.lookup(entityIn.getEntityId());
|
||||
|
||||
if (entitytrackerentry != null)
|
||||
{
|
||||
entitytrackerentry.sendToTrackingAndSelf(packetIn);
|
||||
}
|
||||
}
|
||||
|
||||
public void removePlayerFromTrackers(EntityPlayerMP player)
|
||||
{
|
||||
for (EntityTrackerEntry entitytrackerentry : this.entries)
|
||||
{
|
||||
entitytrackerentry.removeTrackedPlayerSymmetric(player);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send packets to player for every tracked entity in this chunk that is either leashed to something or someone, or
|
||||
* has passengers
|
||||
*/
|
||||
public void sendLeashedEntitiesInChunk(EntityPlayerMP player, Chunk chunkIn)
|
||||
{
|
||||
List<Entity> list = Lists.<Entity>newArrayList();
|
||||
List<Entity> list1 = Lists.<Entity>newArrayList();
|
||||
|
||||
for (EntityTrackerEntry entitytrackerentry : this.entries)
|
||||
{
|
||||
Entity entity = entitytrackerentry.getTrackedEntity();
|
||||
|
||||
if (entity != player && entity.chunkCoordX == chunkIn.x && entity.chunkCoordZ == chunkIn.z)
|
||||
{
|
||||
entitytrackerentry.updatePlayerEntity(player);
|
||||
|
||||
if (entity instanceof EntityLiving && ((EntityLiving)entity).getLeashHolder() != null)
|
||||
{
|
||||
list.add(entity);
|
||||
}
|
||||
|
||||
if (!entity.getPassengers().isEmpty())
|
||||
{
|
||||
list1.add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!list.isEmpty())
|
||||
{
|
||||
for (Entity entity1 : list)
|
||||
{
|
||||
player.connection.sendPacket(new SPacketEntityAttach(entity1, ((EntityLiving)entity1).getLeashHolder()));
|
||||
}
|
||||
}
|
||||
|
||||
if (!list1.isEmpty())
|
||||
{
|
||||
for (Entity entity2 : list1)
|
||||
{
|
||||
player.connection.sendPacket(new SPacketSetPassengers(entity2));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setViewDistance(int p_187252_1_)
|
||||
{
|
||||
this.maxTrackingDistanceThreshold = (p_187252_1_ - 1) * 16;
|
||||
|
||||
for (EntityTrackerEntry entitytrackerentry : this.entries)
|
||||
{
|
||||
entitytrackerentry.setMaxRange(this.maxTrackingDistanceThreshold);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,712 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.ai.attributes.AttributeMap;
|
||||
import net.minecraft.entity.ai.attributes.IAttributeInstance;
|
||||
import net.minecraft.entity.item.EntityArmorStand;
|
||||
import net.minecraft.entity.item.EntityBoat;
|
||||
import net.minecraft.entity.item.EntityEnderCrystal;
|
||||
import net.minecraft.entity.item.EntityEnderEye;
|
||||
import net.minecraft.entity.item.EntityEnderPearl;
|
||||
import net.minecraft.entity.item.EntityExpBottle;
|
||||
import net.minecraft.entity.item.EntityFallingBlock;
|
||||
import net.minecraft.entity.item.EntityFireworkRocket;
|
||||
import net.minecraft.entity.item.EntityItem;
|
||||
import net.minecraft.entity.item.EntityItemFrame;
|
||||
import net.minecraft.entity.item.EntityMinecart;
|
||||
import net.minecraft.entity.item.EntityPainting;
|
||||
import net.minecraft.entity.item.EntityTNTPrimed;
|
||||
import net.minecraft.entity.item.EntityXPOrb;
|
||||
import net.minecraft.entity.passive.IAnimals;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.entity.player.EntityPlayerMP;
|
||||
import net.minecraft.entity.projectile.EntityArrow;
|
||||
import net.minecraft.entity.projectile.EntityDragonFireball;
|
||||
import net.minecraft.entity.projectile.EntityEgg;
|
||||
import net.minecraft.entity.projectile.EntityEvokerFangs;
|
||||
import net.minecraft.entity.projectile.EntityFireball;
|
||||
import net.minecraft.entity.projectile.EntityFishHook;
|
||||
import net.minecraft.entity.projectile.EntityLlamaSpit;
|
||||
import net.minecraft.entity.projectile.EntityPotion;
|
||||
import net.minecraft.entity.projectile.EntityShulkerBullet;
|
||||
import net.minecraft.entity.projectile.EntitySmallFireball;
|
||||
import net.minecraft.entity.projectile.EntitySnowball;
|
||||
import net.minecraft.entity.projectile.EntitySpectralArrow;
|
||||
import net.minecraft.entity.projectile.EntityTippedArrow;
|
||||
import net.minecraft.entity.projectile.EntityWitherSkull;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.inventory.EntityEquipmentSlot;
|
||||
import net.minecraft.item.ItemMap;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.datasync.EntityDataManager;
|
||||
import net.minecraft.network.play.server.SPacketEntity;
|
||||
import net.minecraft.network.play.server.SPacketEntityEffect;
|
||||
import net.minecraft.network.play.server.SPacketEntityEquipment;
|
||||
import net.minecraft.network.play.server.SPacketEntityHeadLook;
|
||||
import net.minecraft.network.play.server.SPacketEntityMetadata;
|
||||
import net.minecraft.network.play.server.SPacketEntityProperties;
|
||||
import net.minecraft.network.play.server.SPacketEntityTeleport;
|
||||
import net.minecraft.network.play.server.SPacketEntityVelocity;
|
||||
import net.minecraft.network.play.server.SPacketSetPassengers;
|
||||
import net.minecraft.network.play.server.SPacketSpawnExperienceOrb;
|
||||
import net.minecraft.network.play.server.SPacketSpawnMob;
|
||||
import net.minecraft.network.play.server.SPacketSpawnObject;
|
||||
import net.minecraft.network.play.server.SPacketSpawnPainting;
|
||||
import net.minecraft.network.play.server.SPacketSpawnPlayer;
|
||||
import net.minecraft.network.play.server.SPacketUseBed;
|
||||
import net.minecraft.potion.PotionEffect;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.world.storage.MapData;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class EntityTrackerEntry
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
/** The entity that this EntityTrackerEntry tracks. */
|
||||
private final Entity trackedEntity;
|
||||
private final int range;
|
||||
private int maxRange;
|
||||
/** check for sync when ticks % updateFrequency==0 */
|
||||
private final int updateFrequency;
|
||||
/** The encoded entity X position. */
|
||||
private long encodedPosX;
|
||||
/** The encoded entity Y position. */
|
||||
private long encodedPosY;
|
||||
/** The encoded entity Z position. */
|
||||
private long encodedPosZ;
|
||||
/** The encoded entity yaw rotation. */
|
||||
private int encodedRotationYaw;
|
||||
/** The encoded entity pitch rotation. */
|
||||
private int encodedRotationPitch;
|
||||
private int lastHeadMotion;
|
||||
private double lastTrackedEntityMotionX;
|
||||
private double lastTrackedEntityMotionY;
|
||||
private double motionZ;
|
||||
public int updateCounter;
|
||||
private double lastTrackedEntityPosX;
|
||||
private double lastTrackedEntityPosY;
|
||||
private double lastTrackedEntityPosZ;
|
||||
private boolean updatedPlayerVisibility;
|
||||
private final boolean sendVelocityUpdates;
|
||||
/**
|
||||
* every 400 ticks a full teleport packet is sent, rather than just a "move me +x" command, so that position
|
||||
* remains fully synced.
|
||||
*/
|
||||
private int ticksSinceLastForcedTeleport;
|
||||
private List<Entity> passengers = Collections.<Entity>emptyList();
|
||||
private boolean ridingEntity;
|
||||
private boolean onGround;
|
||||
public boolean playerEntitiesUpdated;
|
||||
/** Holds references to all the players that are currently receiving position updates for this entity. */
|
||||
public final Set<EntityPlayerMP> trackingPlayers = Sets.<EntityPlayerMP>newHashSet();
|
||||
|
||||
public EntityTrackerEntry(Entity entityIn, int rangeIn, int maxRangeIn, int updateFrequencyIn, boolean sendVelocityUpdatesIn)
|
||||
{
|
||||
this.trackedEntity = entityIn;
|
||||
this.range = rangeIn;
|
||||
this.maxRange = maxRangeIn;
|
||||
this.updateFrequency = updateFrequencyIn;
|
||||
this.sendVelocityUpdates = sendVelocityUpdatesIn;
|
||||
this.encodedPosX = EntityTracker.getPositionLong(entityIn.posX);
|
||||
this.encodedPosY = EntityTracker.getPositionLong(entityIn.posY);
|
||||
this.encodedPosZ = EntityTracker.getPositionLong(entityIn.posZ);
|
||||
this.encodedRotationYaw = MathHelper.floor(entityIn.rotationYaw * 256.0F / 360.0F);
|
||||
this.encodedRotationPitch = MathHelper.floor(entityIn.rotationPitch * 256.0F / 360.0F);
|
||||
this.lastHeadMotion = MathHelper.floor(entityIn.getRotationYawHead() * 256.0F / 360.0F);
|
||||
this.onGround = entityIn.onGround;
|
||||
}
|
||||
|
||||
public boolean equals(Object p_equals_1_)
|
||||
{
|
||||
if (p_equals_1_ instanceof EntityTrackerEntry)
|
||||
{
|
||||
return ((EntityTrackerEntry)p_equals_1_).trackedEntity.getEntityId() == this.trackedEntity.getEntityId();
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return this.trackedEntity.getEntityId();
|
||||
}
|
||||
|
||||
public void updatePlayerList(List<EntityPlayer> players)
|
||||
{
|
||||
this.playerEntitiesUpdated = false;
|
||||
|
||||
if (!this.updatedPlayerVisibility || this.trackedEntity.getDistanceSq(this.lastTrackedEntityPosX, this.lastTrackedEntityPosY, this.lastTrackedEntityPosZ) > 16.0D)
|
||||
{
|
||||
this.lastTrackedEntityPosX = this.trackedEntity.posX;
|
||||
this.lastTrackedEntityPosY = this.trackedEntity.posY;
|
||||
this.lastTrackedEntityPosZ = this.trackedEntity.posZ;
|
||||
this.updatedPlayerVisibility = true;
|
||||
this.playerEntitiesUpdated = true;
|
||||
this.updatePlayerEntities(players);
|
||||
}
|
||||
|
||||
List<Entity> list = this.trackedEntity.getPassengers();
|
||||
|
||||
if (!list.equals(this.passengers))
|
||||
{
|
||||
this.passengers = list;
|
||||
this.sendPacketToTrackedPlayers(new SPacketSetPassengers(this.trackedEntity));
|
||||
}
|
||||
|
||||
if (this.trackedEntity instanceof EntityItemFrame && this.updateCounter % 10 == 0)
|
||||
{
|
||||
EntityItemFrame entityitemframe = (EntityItemFrame)this.trackedEntity;
|
||||
ItemStack itemstack = entityitemframe.getDisplayedItem();
|
||||
|
||||
if (itemstack.getItem() instanceof ItemMap)
|
||||
{
|
||||
MapData mapdata = ((ItemMap) itemstack.getItem()).getMapData(itemstack, this.trackedEntity.world);
|
||||
|
||||
for (EntityPlayer entityplayer : players)
|
||||
{
|
||||
EntityPlayerMP entityplayermp = (EntityPlayerMP)entityplayer;
|
||||
mapdata.updateVisiblePlayers(entityplayermp, itemstack);
|
||||
Packet<?> packet = ((ItemMap) itemstack.getItem()).createMapDataPacket(itemstack, this.trackedEntity.world, entityplayermp);
|
||||
|
||||
if (packet != null)
|
||||
{
|
||||
entityplayermp.connection.sendPacket(packet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.sendMetadata();
|
||||
}
|
||||
|
||||
if (this.updateCounter % this.updateFrequency == 0 || this.trackedEntity.isAirBorne || this.trackedEntity.getDataManager().isDirty())
|
||||
{
|
||||
if (this.trackedEntity.isRiding())
|
||||
{
|
||||
int j1 = MathHelper.floor(this.trackedEntity.rotationYaw * 256.0F / 360.0F);
|
||||
int l1 = MathHelper.floor(this.trackedEntity.rotationPitch * 256.0F / 360.0F);
|
||||
boolean flag3 = Math.abs(j1 - this.encodedRotationYaw) >= 1 || Math.abs(l1 - this.encodedRotationPitch) >= 1;
|
||||
|
||||
if (flag3)
|
||||
{
|
||||
this.sendPacketToTrackedPlayers(new SPacketEntity.S16PacketEntityLook(this.trackedEntity.getEntityId(), (byte)j1, (byte)l1, this.trackedEntity.onGround));
|
||||
this.encodedRotationYaw = j1;
|
||||
this.encodedRotationPitch = l1;
|
||||
}
|
||||
|
||||
this.encodedPosX = EntityTracker.getPositionLong(this.trackedEntity.posX);
|
||||
this.encodedPosY = EntityTracker.getPositionLong(this.trackedEntity.posY);
|
||||
this.encodedPosZ = EntityTracker.getPositionLong(this.trackedEntity.posZ);
|
||||
this.sendMetadata();
|
||||
this.ridingEntity = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
++this.ticksSinceLastForcedTeleport;
|
||||
long i1 = EntityTracker.getPositionLong(this.trackedEntity.posX);
|
||||
long i2 = EntityTracker.getPositionLong(this.trackedEntity.posY);
|
||||
long j2 = EntityTracker.getPositionLong(this.trackedEntity.posZ);
|
||||
int k2 = MathHelper.floor(this.trackedEntity.rotationYaw * 256.0F / 360.0F);
|
||||
int i = MathHelper.floor(this.trackedEntity.rotationPitch * 256.0F / 360.0F);
|
||||
long j = i1 - this.encodedPosX;
|
||||
long k = i2 - this.encodedPosY;
|
||||
long l = j2 - this.encodedPosZ;
|
||||
Packet<?> packet1 = null;
|
||||
boolean flag = j * j + k * k + l * l >= 128L || this.updateCounter % 60 == 0;
|
||||
boolean flag1 = Math.abs(k2 - this.encodedRotationYaw) >= 1 || Math.abs(i - this.encodedRotationPitch) >= 1;
|
||||
|
||||
if (this.updateCounter > 0 || this.trackedEntity instanceof EntityArrow)
|
||||
{
|
||||
if (j >= -32768L && j < 32768L && k >= -32768L && k < 32768L && l >= -32768L && l < 32768L && this.ticksSinceLastForcedTeleport <= 400 && !this.ridingEntity && this.onGround == this.trackedEntity.onGround)
|
||||
{
|
||||
if ((!flag || !flag1) && !(this.trackedEntity instanceof EntityArrow))
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
packet1 = new SPacketEntity.S15PacketEntityRelMove(this.trackedEntity.getEntityId(), j, k, l, this.trackedEntity.onGround);
|
||||
}
|
||||
else if (flag1)
|
||||
{
|
||||
packet1 = new SPacketEntity.S16PacketEntityLook(this.trackedEntity.getEntityId(), (byte)k2, (byte)i, this.trackedEntity.onGround);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
packet1 = new SPacketEntity.S17PacketEntityLookMove(this.trackedEntity.getEntityId(), j, k, l, (byte)k2, (byte)i, this.trackedEntity.onGround);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.onGround = this.trackedEntity.onGround;
|
||||
this.ticksSinceLastForcedTeleport = 0;
|
||||
this.resetPlayerVisibility();
|
||||
packet1 = new SPacketEntityTeleport(this.trackedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
boolean flag2 = this.sendVelocityUpdates;
|
||||
|
||||
if (this.trackedEntity instanceof EntityLivingBase && ((EntityLivingBase)this.trackedEntity).isElytraFlying())
|
||||
{
|
||||
flag2 = true;
|
||||
}
|
||||
|
||||
if (flag2 && this.updateCounter > 0)
|
||||
{
|
||||
double d0 = this.trackedEntity.motionX - this.lastTrackedEntityMotionX;
|
||||
double d1 = this.trackedEntity.motionY - this.lastTrackedEntityMotionY;
|
||||
double d2 = this.trackedEntity.motionZ - this.motionZ;
|
||||
double d3 = 0.02D;
|
||||
double d4 = d0 * d0 + d1 * d1 + d2 * d2;
|
||||
|
||||
if (d4 > 4.0E-4D || d4 > 0.0D && this.trackedEntity.motionX == 0.0D && this.trackedEntity.motionY == 0.0D && this.trackedEntity.motionZ == 0.0D)
|
||||
{
|
||||
this.lastTrackedEntityMotionX = this.trackedEntity.motionX;
|
||||
this.lastTrackedEntityMotionY = this.trackedEntity.motionY;
|
||||
this.motionZ = this.trackedEntity.motionZ;
|
||||
this.sendPacketToTrackedPlayers(new SPacketEntityVelocity(this.trackedEntity.getEntityId(), this.lastTrackedEntityMotionX, this.lastTrackedEntityMotionY, this.motionZ));
|
||||
}
|
||||
}
|
||||
|
||||
if (packet1 != null)
|
||||
{
|
||||
this.sendPacketToTrackedPlayers(packet1);
|
||||
}
|
||||
|
||||
this.sendMetadata();
|
||||
|
||||
if (flag)
|
||||
{
|
||||
this.encodedPosX = i1;
|
||||
this.encodedPosY = i2;
|
||||
this.encodedPosZ = j2;
|
||||
}
|
||||
|
||||
if (flag1)
|
||||
{
|
||||
this.encodedRotationYaw = k2;
|
||||
this.encodedRotationPitch = i;
|
||||
}
|
||||
|
||||
this.ridingEntity = false;
|
||||
}
|
||||
|
||||
int k1 = MathHelper.floor(this.trackedEntity.getRotationYawHead() * 256.0F / 360.0F);
|
||||
|
||||
if (Math.abs(k1 - this.lastHeadMotion) >= 1)
|
||||
{
|
||||
this.sendPacketToTrackedPlayers(new SPacketEntityHeadLook(this.trackedEntity, (byte)k1));
|
||||
this.lastHeadMotion = k1;
|
||||
}
|
||||
|
||||
this.trackedEntity.isAirBorne = false;
|
||||
}
|
||||
|
||||
++this.updateCounter;
|
||||
|
||||
if (this.trackedEntity.velocityChanged)
|
||||
{
|
||||
this.sendToTrackingAndSelf(new SPacketEntityVelocity(this.trackedEntity));
|
||||
this.trackedEntity.velocityChanged = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the entity metadata (DataWatcher) and attributes to all players tracking this entity, including the entity
|
||||
* itself if a player.
|
||||
*/
|
||||
private void sendMetadata()
|
||||
{
|
||||
EntityDataManager entitydatamanager = this.trackedEntity.getDataManager();
|
||||
|
||||
if (entitydatamanager.isDirty())
|
||||
{
|
||||
this.sendToTrackingAndSelf(new SPacketEntityMetadata(this.trackedEntity.getEntityId(), entitydatamanager, false));
|
||||
}
|
||||
|
||||
if (this.trackedEntity instanceof EntityLivingBase)
|
||||
{
|
||||
AttributeMap attributemap = (AttributeMap)((EntityLivingBase)this.trackedEntity).getAttributeMap();
|
||||
Set<IAttributeInstance> set = attributemap.getDirtyInstances();
|
||||
|
||||
if (!set.isEmpty())
|
||||
{
|
||||
this.sendToTrackingAndSelf(new SPacketEntityProperties(this.trackedEntity.getEntityId(), set));
|
||||
}
|
||||
|
||||
set.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the given packet to all players tracking this entity.
|
||||
*/
|
||||
public void sendPacketToTrackedPlayers(Packet<?> packetIn)
|
||||
{
|
||||
for (EntityPlayerMP entityplayermp : this.trackingPlayers)
|
||||
{
|
||||
entityplayermp.connection.sendPacket(packetIn);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendToTrackingAndSelf(Packet<?> packetIn)
|
||||
{
|
||||
this.sendPacketToTrackedPlayers(packetIn);
|
||||
|
||||
if (this.trackedEntity instanceof EntityPlayerMP)
|
||||
{
|
||||
((EntityPlayerMP)this.trackedEntity).connection.sendPacket(packetIn);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendDestroyEntityPacketToTrackedPlayers()
|
||||
{
|
||||
for (EntityPlayerMP entityplayermp : this.trackingPlayers)
|
||||
{
|
||||
this.trackedEntity.removeTrackingPlayer(entityplayermp);
|
||||
entityplayermp.removeEntity(this.trackedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFromTrackedPlayers(EntityPlayerMP playerMP)
|
||||
{
|
||||
if (this.trackingPlayers.contains(playerMP))
|
||||
{
|
||||
this.trackedEntity.removeTrackingPlayer(playerMP);
|
||||
playerMP.removeEntity(this.trackedEntity);
|
||||
this.trackingPlayers.remove(playerMP);
|
||||
}
|
||||
}
|
||||
|
||||
public void updatePlayerEntity(EntityPlayerMP playerMP)
|
||||
{
|
||||
if (playerMP != this.trackedEntity)
|
||||
{
|
||||
if (this.isVisibleTo(playerMP))
|
||||
{
|
||||
if (!this.trackingPlayers.contains(playerMP) && (this.isPlayerWatchingThisChunk(playerMP) || this.trackedEntity.forceSpawn))
|
||||
{
|
||||
this.trackingPlayers.add(playerMP);
|
||||
Packet<?> packet = this.createSpawnPacket();
|
||||
playerMP.connection.sendPacket(packet);
|
||||
|
||||
if (!this.trackedEntity.getDataManager().isEmpty())
|
||||
{
|
||||
playerMP.connection.sendPacket(new SPacketEntityMetadata(this.trackedEntity.getEntityId(), this.trackedEntity.getDataManager(), true));
|
||||
}
|
||||
|
||||
boolean flag = this.sendVelocityUpdates;
|
||||
|
||||
if (this.trackedEntity instanceof EntityLivingBase)
|
||||
{
|
||||
AttributeMap attributemap = (AttributeMap)((EntityLivingBase)this.trackedEntity).getAttributeMap();
|
||||
Collection<IAttributeInstance> collection = attributemap.getWatchedAttributes();
|
||||
|
||||
if (!collection.isEmpty())
|
||||
{
|
||||
playerMP.connection.sendPacket(new SPacketEntityProperties(this.trackedEntity.getEntityId(), collection));
|
||||
}
|
||||
|
||||
if (((EntityLivingBase)this.trackedEntity).isElytraFlying())
|
||||
{
|
||||
flag = true;
|
||||
}
|
||||
}
|
||||
|
||||
this.lastTrackedEntityMotionX = this.trackedEntity.motionX;
|
||||
this.lastTrackedEntityMotionY = this.trackedEntity.motionY;
|
||||
this.motionZ = this.trackedEntity.motionZ;
|
||||
|
||||
if (flag && !(packet instanceof SPacketSpawnMob))
|
||||
{
|
||||
playerMP.connection.sendPacket(new SPacketEntityVelocity(this.trackedEntity.getEntityId(), this.trackedEntity.motionX, this.trackedEntity.motionY, this.trackedEntity.motionZ));
|
||||
}
|
||||
|
||||
if (this.trackedEntity instanceof EntityLivingBase)
|
||||
{
|
||||
for (EntityEquipmentSlot entityequipmentslot : EntityEquipmentSlot.values())
|
||||
{
|
||||
ItemStack itemstack = ((EntityLivingBase)this.trackedEntity).getItemStackFromSlot(entityequipmentslot);
|
||||
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
playerMP.connection.sendPacket(new SPacketEntityEquipment(this.trackedEntity.getEntityId(), entityequipmentslot, itemstack));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.trackedEntity instanceof EntityPlayer)
|
||||
{
|
||||
EntityPlayer entityplayer = (EntityPlayer)this.trackedEntity;
|
||||
|
||||
if (entityplayer.isPlayerSleeping())
|
||||
{
|
||||
playerMP.connection.sendPacket(new SPacketUseBed(entityplayer, new BlockPos(this.trackedEntity)));
|
||||
}
|
||||
}
|
||||
|
||||
if (this.trackedEntity instanceof EntityLivingBase)
|
||||
{
|
||||
EntityLivingBase entitylivingbase = (EntityLivingBase)this.trackedEntity;
|
||||
|
||||
for (PotionEffect potioneffect : entitylivingbase.getActivePotionEffects())
|
||||
{
|
||||
playerMP.connection.sendPacket(new SPacketEntityEffect(this.trackedEntity.getEntityId(), potioneffect));
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.trackedEntity.getPassengers().isEmpty())
|
||||
{
|
||||
playerMP.connection.sendPacket(new SPacketSetPassengers(this.trackedEntity));
|
||||
}
|
||||
|
||||
if (this.trackedEntity.isRiding())
|
||||
{
|
||||
playerMP.connection.sendPacket(new SPacketSetPassengers(this.trackedEntity.getRidingEntity()));
|
||||
}
|
||||
|
||||
this.trackedEntity.addTrackingPlayer(playerMP);
|
||||
playerMP.addEntity(this.trackedEntity);
|
||||
net.minecraftforge.event.ForgeEventFactory.onStartEntityTracking(trackedEntity, playerMP);
|
||||
}
|
||||
}
|
||||
else if (this.trackingPlayers.contains(playerMP))
|
||||
{
|
||||
this.trackingPlayers.remove(playerMP);
|
||||
this.trackedEntity.removeTrackingPlayer(playerMP);
|
||||
playerMP.removeEntity(this.trackedEntity);
|
||||
net.minecraftforge.event.ForgeEventFactory.onStopEntityTracking(trackedEntity, playerMP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isVisibleTo(EntityPlayerMP playerMP)
|
||||
{
|
||||
double d0 = playerMP.posX - (double)this.encodedPosX / 4096.0D;
|
||||
double d1 = playerMP.posZ - (double)this.encodedPosZ / 4096.0D;
|
||||
int i = Math.min(this.range, this.maxRange);
|
||||
return d0 >= (double)(-i) && d0 <= (double)i && d1 >= (double)(-i) && d1 <= (double)i && this.trackedEntity.isSpectatedByPlayer(playerMP);
|
||||
}
|
||||
|
||||
private boolean isPlayerWatchingThisChunk(EntityPlayerMP playerMP)
|
||||
{
|
||||
return playerMP.getServerWorld().getPlayerChunkMap().isPlayerWatchingChunk(playerMP, this.trackedEntity.chunkCoordX, this.trackedEntity.chunkCoordZ);
|
||||
}
|
||||
|
||||
public void updatePlayerEntities(List<EntityPlayer> players)
|
||||
{
|
||||
for (int i = 0; i < players.size(); ++i)
|
||||
{
|
||||
this.updatePlayerEntity((EntityPlayerMP)players.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a spawn packet for the entity managed by this entry.
|
||||
*/
|
||||
private Packet<?> createSpawnPacket()
|
||||
{
|
||||
if (this.trackedEntity.isDead)
|
||||
{
|
||||
LOGGER.warn("Fetching addPacket for removed entity");
|
||||
}
|
||||
|
||||
Packet pkt = net.minecraftforge.fml.common.network.internal.FMLNetworkHandler.getEntitySpawningPacket(this.trackedEntity);
|
||||
if (pkt != null) return pkt;
|
||||
|
||||
if (this.trackedEntity instanceof EntityPlayerMP)
|
||||
{
|
||||
return new SPacketSpawnPlayer((EntityPlayer)this.trackedEntity);
|
||||
}
|
||||
else if (this.trackedEntity instanceof IAnimals)
|
||||
{
|
||||
this.lastHeadMotion = MathHelper.floor(this.trackedEntity.getRotationYawHead() * 256.0F / 360.0F);
|
||||
return new SPacketSpawnMob((EntityLivingBase)this.trackedEntity);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityPainting)
|
||||
{
|
||||
return new SPacketSpawnPainting((EntityPainting)this.trackedEntity);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityItem)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 2, 1);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityMinecart)
|
||||
{
|
||||
EntityMinecart entityminecart = (EntityMinecart)this.trackedEntity;
|
||||
return new SPacketSpawnObject(this.trackedEntity, 10, entityminecart.getType().getId());
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityBoat)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 1);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityXPOrb)
|
||||
{
|
||||
return new SPacketSpawnExperienceOrb((EntityXPOrb)this.trackedEntity);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityFishHook)
|
||||
{
|
||||
Entity entity2 = ((EntityFishHook)this.trackedEntity).getAngler();
|
||||
return new SPacketSpawnObject(this.trackedEntity, 90, entity2 == null ? this.trackedEntity.getEntityId() : entity2.getEntityId());
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntitySpectralArrow)
|
||||
{
|
||||
Entity entity1 = ((EntitySpectralArrow)this.trackedEntity).shootingEntity;
|
||||
return new SPacketSpawnObject(this.trackedEntity, 91, 1 + (entity1 == null ? this.trackedEntity.getEntityId() : entity1.getEntityId()));
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityTippedArrow)
|
||||
{
|
||||
Entity entity = ((EntityArrow)this.trackedEntity).shootingEntity;
|
||||
return new SPacketSpawnObject(this.trackedEntity, 60, 1 + (entity == null ? this.trackedEntity.getEntityId() : entity.getEntityId()));
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntitySnowball)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 61);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityLlamaSpit)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 68);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityPotion)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 73);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityExpBottle)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 75);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityEnderPearl)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 65);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityEnderEye)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 72);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityFireworkRocket)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 76);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityFireball)
|
||||
{
|
||||
EntityFireball entityfireball = (EntityFireball)this.trackedEntity;
|
||||
SPacketSpawnObject spacketspawnobject = null;
|
||||
int i = 63;
|
||||
|
||||
if (this.trackedEntity instanceof EntitySmallFireball)
|
||||
{
|
||||
i = 64;
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityDragonFireball)
|
||||
{
|
||||
i = 93;
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityWitherSkull)
|
||||
{
|
||||
i = 66;
|
||||
}
|
||||
|
||||
if (entityfireball.shootingEntity != null)
|
||||
{
|
||||
spacketspawnobject = new SPacketSpawnObject(this.trackedEntity, i, ((EntityFireball)this.trackedEntity).shootingEntity.getEntityId());
|
||||
}
|
||||
else
|
||||
{
|
||||
spacketspawnobject = new SPacketSpawnObject(this.trackedEntity, i, 0);
|
||||
}
|
||||
|
||||
spacketspawnobject.setSpeedX((int)(entityfireball.accelerationX * 8000.0D));
|
||||
spacketspawnobject.setSpeedY((int)(entityfireball.accelerationY * 8000.0D));
|
||||
spacketspawnobject.setSpeedZ((int)(entityfireball.accelerationZ * 8000.0D));
|
||||
return spacketspawnobject;
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityShulkerBullet)
|
||||
{
|
||||
SPacketSpawnObject spacketspawnobject1 = new SPacketSpawnObject(this.trackedEntity, 67, 0);
|
||||
spacketspawnobject1.setSpeedX((int)(this.trackedEntity.motionX * 8000.0D));
|
||||
spacketspawnobject1.setSpeedY((int)(this.trackedEntity.motionY * 8000.0D));
|
||||
spacketspawnobject1.setSpeedZ((int)(this.trackedEntity.motionZ * 8000.0D));
|
||||
return spacketspawnobject1;
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityEgg)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 62);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityEvokerFangs)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 79);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityTNTPrimed)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 50);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityEnderCrystal)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 51);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityFallingBlock)
|
||||
{
|
||||
EntityFallingBlock entityfallingblock = (EntityFallingBlock)this.trackedEntity;
|
||||
return new SPacketSpawnObject(this.trackedEntity, 70, Block.getStateId(entityfallingblock.getBlock()));
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityArmorStand)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 78);
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityItemFrame)
|
||||
{
|
||||
EntityItemFrame entityitemframe = (EntityItemFrame)this.trackedEntity;
|
||||
return new SPacketSpawnObject(this.trackedEntity, 71, entityitemframe.facingDirection.getHorizontalIndex(), entityitemframe.getHangingPosition());
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityLeashKnot)
|
||||
{
|
||||
EntityLeashKnot entityleashknot = (EntityLeashKnot)this.trackedEntity;
|
||||
return new SPacketSpawnObject(this.trackedEntity, 77, 0, entityleashknot.getHangingPosition());
|
||||
}
|
||||
else if (this.trackedEntity instanceof EntityAreaEffectCloud)
|
||||
{
|
||||
return new SPacketSpawnObject(this.trackedEntity, 3);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Don't know how to add " + this.trackedEntity.getClass() + "!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a tracked player from our list and tell the tracked player to destroy us from their world.
|
||||
*/
|
||||
public void removeTrackedPlayerSymmetric(EntityPlayerMP playerMP)
|
||||
{
|
||||
if (this.trackingPlayers.contains(playerMP))
|
||||
{
|
||||
this.trackingPlayers.remove(playerMP);
|
||||
this.trackedEntity.removeTrackingPlayer(playerMP);
|
||||
playerMP.removeEntity(this.trackedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public Entity getTrackedEntity()
|
||||
{
|
||||
return this.trackedEntity;
|
||||
}
|
||||
|
||||
public void setMaxRange(int maxRangeIn)
|
||||
{
|
||||
this.maxRange = maxRangeIn;
|
||||
}
|
||||
|
||||
public void resetPlayerVisibility()
|
||||
{
|
||||
this.updatedPlayerVisibility = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
public enum EnumCreatureAttribute
|
||||
{
|
||||
UNDEFINED,
|
||||
UNDEAD,
|
||||
ARTHROPOD,
|
||||
ILLAGER;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.entity.monster.IMob;
|
||||
import net.minecraft.entity.passive.EntityAmbientCreature;
|
||||
import net.minecraft.entity.passive.EntityAnimal;
|
||||
import net.minecraft.entity.passive.EntityWaterMob;
|
||||
import net.minecraft.entity.passive.IAnimals;
|
||||
|
||||
public enum EnumCreatureType
|
||||
{
|
||||
MONSTER(IMob.class, 70, Material.AIR, false, false),
|
||||
CREATURE(EntityAnimal.class, 10, Material.AIR, true, true),
|
||||
AMBIENT(EntityAmbientCreature.class, 15, Material.AIR, true, false),
|
||||
WATER_CREATURE(EntityWaterMob.class, 5, Material.WATER, true, false);
|
||||
|
||||
private final Class <? extends IAnimals > creatureClass;
|
||||
private final int maxNumberOfCreature;
|
||||
private final Material creatureMaterial;
|
||||
/** A flag indicating whether this creature type is peaceful. */
|
||||
private final boolean isPeacefulCreature;
|
||||
/** Whether this creature type is an animal. */
|
||||
private final boolean isAnimal;
|
||||
|
||||
private EnumCreatureType(Class <? extends IAnimals > creatureClassIn, int maxNumberOfCreatureIn, Material creatureMaterialIn, boolean isPeacefulCreatureIn, boolean isAnimalIn)
|
||||
{
|
||||
this.creatureClass = creatureClassIn;
|
||||
this.maxNumberOfCreature = maxNumberOfCreatureIn;
|
||||
this.creatureMaterial = creatureMaterialIn;
|
||||
this.isPeacefulCreature = isPeacefulCreatureIn;
|
||||
this.isAnimal = isAnimalIn;
|
||||
}
|
||||
|
||||
public Class <? extends IAnimals > getCreatureClass()
|
||||
{
|
||||
return this.creatureClass;
|
||||
}
|
||||
|
||||
public int getMaxNumberOfCreature()
|
||||
{
|
||||
return this.maxNumberOfCreature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets whether or not this creature type is peaceful.
|
||||
*/
|
||||
public boolean getPeacefulCreature()
|
||||
{
|
||||
return this.isPeacefulCreature;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether this creature type is an animal.
|
||||
*/
|
||||
public boolean getAnimal()
|
||||
{
|
||||
return this.isAnimal;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
public interface IEntityLivingData
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import net.minecraft.util.DamageSource;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
public interface IEntityMultiPart
|
||||
{
|
||||
World getWorld();
|
||||
|
||||
boolean attackEntityFromPart(MultiPartEntityPart dragonPart, DamageSource source, float damage);
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public interface IEntityOwnable
|
||||
{
|
||||
@Nullable
|
||||
UUID getOwnerId();
|
||||
|
||||
@Nullable
|
||||
Entity getOwner();
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public interface IJumpingMount
|
||||
{
|
||||
@SideOnly(Side.CLIENT)
|
||||
void setJumpPower(int jumpPowerIn);
|
||||
|
||||
boolean canJump();
|
||||
|
||||
void handleStartJump(int p_184775_1_);
|
||||
|
||||
void handleStopJump();
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.village.MerchantRecipe;
|
||||
import net.minecraft.village.MerchantRecipeList;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
public interface IMerchant
|
||||
{
|
||||
void setCustomer(@Nullable EntityPlayer player);
|
||||
|
||||
@Nullable
|
||||
EntityPlayer getCustomer();
|
||||
|
||||
@Nullable
|
||||
MerchantRecipeList getRecipes(EntityPlayer player);
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
void setRecipes(@Nullable MerchantRecipeList recipeList);
|
||||
|
||||
void useRecipe(MerchantRecipe recipe);
|
||||
|
||||
/**
|
||||
* Notifies the merchant of a possible merchantrecipe being fulfilled or not. Usually, this is just a sound byte
|
||||
* being played depending if the suggested itemstack is not null.
|
||||
*/
|
||||
void verifySellingItem(ItemStack stack);
|
||||
|
||||
/**
|
||||
* Get the formatted ChatComponent that will be used for the sender's username in chat
|
||||
*/
|
||||
ITextComponent getDisplayName();
|
||||
|
||||
World getWorld();
|
||||
|
||||
BlockPos getPos();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import net.minecraft.entity.passive.IAnimals;
|
||||
|
||||
public interface INpc extends IAnimals
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
public interface IProjectile
|
||||
{
|
||||
/**
|
||||
* Similar to setArrowHeading, it's point the throwable entity to a x, y, z direction.
|
||||
*/
|
||||
void shoot(double x, double y, double z, float velocity, float inaccuracy);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
public interface IRangedAttackMob
|
||||
{
|
||||
/**
|
||||
* Attack the specified entity using a ranged attack.
|
||||
*/
|
||||
void attackEntityWithRangedAttack(EntityLivingBase target, float distanceFactor);
|
||||
|
||||
void setSwingingArms(boolean swingingArms);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
public enum MoverType
|
||||
{
|
||||
SELF,
|
||||
PLAYER,
|
||||
PISTON,
|
||||
SHULKER_BOX,
|
||||
SHULKER;
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.util.DamageSource;
|
||||
|
||||
public class MultiPartEntityPart extends Entity
|
||||
{
|
||||
/** The dragon entity this dragon part belongs to */
|
||||
public final IEntityMultiPart parent;
|
||||
public final String partName;
|
||||
|
||||
public MultiPartEntityPart(IEntityMultiPart parent, String partName, float width, float height)
|
||||
{
|
||||
super(parent.getWorld());
|
||||
this.setSize(width, height);
|
||||
this.parent = parent;
|
||||
this.partName = partName;
|
||||
}
|
||||
|
||||
protected void entityInit()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
protected void readEntityFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to write subclass entity data to NBT.
|
||||
*/
|
||||
protected void writeEntityToNBT(NBTTagCompound compound)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if other Entities should be prevented from moving through this Entity.
|
||||
*/
|
||||
public boolean canBeCollidedWith()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the entity is attacked.
|
||||
*/
|
||||
public boolean attackEntityFrom(DamageSource source, float amount)
|
||||
{
|
||||
return this.isEntityInvulnerable(source) ? false : this.parent.attackEntityFromPart(this, source, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if Entity argument is equal to this Entity
|
||||
*/
|
||||
public boolean isEntityEqual(Entity entityIn)
|
||||
{
|
||||
return this == entityIn || this.parent == entityIn;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.InventoryMerchant;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
import net.minecraft.village.MerchantRecipe;
|
||||
import net.minecraft.village.MerchantRecipeList;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraftforge.fml.relauncher.Side;
|
||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
public class NpcMerchant implements IMerchant
|
||||
{
|
||||
/** Instance of Merchants Inventory. */
|
||||
private final InventoryMerchant merchantInventory;
|
||||
/** This merchant's current player customer. */
|
||||
private final EntityPlayer customer;
|
||||
/** The MerchantRecipeList instance. */
|
||||
private MerchantRecipeList recipeList;
|
||||
private final ITextComponent name;
|
||||
|
||||
public NpcMerchant(EntityPlayer customerIn, ITextComponent nameIn)
|
||||
{
|
||||
this.customer = customerIn;
|
||||
this.name = nameIn;
|
||||
this.merchantInventory = new InventoryMerchant(customerIn, this);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public EntityPlayer getCustomer()
|
||||
{
|
||||
return this.customer;
|
||||
}
|
||||
|
||||
public void setCustomer(@Nullable EntityPlayer player)
|
||||
{
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public MerchantRecipeList getRecipes(EntityPlayer player)
|
||||
{
|
||||
return this.recipeList;
|
||||
}
|
||||
|
||||
public void setRecipes(@Nullable MerchantRecipeList recipeList)
|
||||
{
|
||||
this.recipeList = recipeList;
|
||||
}
|
||||
|
||||
public void useRecipe(MerchantRecipe recipe)
|
||||
{
|
||||
recipe.incrementToolUses();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the merchant of a possible merchantrecipe being fulfilled or not. Usually, this is just a sound byte
|
||||
* being played depending if the suggested itemstack is not null.
|
||||
*/
|
||||
public void verifySellingItem(ItemStack stack)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the formatted ChatComponent that will be used for the sender's username in chat
|
||||
*/
|
||||
public ITextComponent getDisplayName()
|
||||
{
|
||||
return (ITextComponent)(this.name != null ? this.name : new TextComponentTranslation("entity.Villager.name", new Object[0]));
|
||||
}
|
||||
|
||||
public World getWorld()
|
||||
{
|
||||
return this.customer.world;
|
||||
}
|
||||
|
||||
public BlockPos getPos()
|
||||
{
|
||||
return new BlockPos(this.customer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
package net.minecraft.entity;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.entity.ai.attributes.AbstractAttributeMap;
|
||||
import net.minecraft.entity.ai.attributes.AttributeModifier;
|
||||
import net.minecraft.entity.ai.attributes.IAttribute;
|
||||
import net.minecraft.entity.ai.attributes.IAttributeInstance;
|
||||
import net.minecraft.entity.ai.attributes.RangedAttribute;
|
||||
import net.minecraft.nbt.NBTTagCompound;
|
||||
import net.minecraft.nbt.NBTTagList;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class SharedMonsterAttributes
|
||||
{
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
public static final IAttribute MAX_HEALTH = (new RangedAttribute((IAttribute)null, "generic.maxHealth", 20.0D, Float.MIN_VALUE, 1024.0D)).setDescription("Max Health").setShouldWatch(true); // Forge: set smallest max-health value to fix MC-119183. This gets rounded to float so we use the smallest positive float value.
|
||||
public static final IAttribute FOLLOW_RANGE = (new RangedAttribute((IAttribute)null, "generic.followRange", 32.0D, 0.0D, 2048.0D)).setDescription("Follow Range");
|
||||
public static final IAttribute KNOCKBACK_RESISTANCE = (new RangedAttribute((IAttribute)null, "generic.knockbackResistance", 0.0D, 0.0D, 1.0D)).setDescription("Knockback Resistance");
|
||||
public static final IAttribute MOVEMENT_SPEED = (new RangedAttribute((IAttribute)null, "generic.movementSpeed", 0.699999988079071D, 0.0D, 1024.0D)).setDescription("Movement Speed").setShouldWatch(true);
|
||||
public static final IAttribute FLYING_SPEED = (new RangedAttribute((IAttribute)null, "generic.flyingSpeed", 0.4000000059604645D, 0.0D, 1024.0D)).setDescription("Flying Speed").setShouldWatch(true);
|
||||
public static final IAttribute ATTACK_DAMAGE = new RangedAttribute((IAttribute)null, "generic.attackDamage", 2.0D, 0.0D, 2048.0D);
|
||||
public static final IAttribute ATTACK_SPEED = (new RangedAttribute((IAttribute)null, "generic.attackSpeed", 4.0D, 0.0D, 1024.0D)).setShouldWatch(true);
|
||||
public static final IAttribute ARMOR = (new RangedAttribute((IAttribute)null, "generic.armor", 0.0D, 0.0D, 30.0D)).setShouldWatch(true);
|
||||
public static final IAttribute ARMOR_TOUGHNESS = (new RangedAttribute((IAttribute)null, "generic.armorToughness", 0.0D, 0.0D, 20.0D)).setShouldWatch(true);
|
||||
public static final IAttribute LUCK = (new RangedAttribute((IAttribute)null, "generic.luck", 0.0D, -1024.0D, 1024.0D)).setShouldWatch(true);
|
||||
|
||||
/**
|
||||
* Creates an NBTTagList from a BaseAttributeMap, including all its AttributeInstances
|
||||
*/
|
||||
public static NBTTagList writeBaseAttributeMapToNBT(AbstractAttributeMap map)
|
||||
{
|
||||
NBTTagList nbttaglist = new NBTTagList();
|
||||
|
||||
for (IAttributeInstance iattributeinstance : map.getAllAttributes())
|
||||
{
|
||||
nbttaglist.appendTag(writeAttributeInstanceToNBT(iattributeinstance));
|
||||
}
|
||||
|
||||
return nbttaglist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NBTTagCompound from an AttributeInstance, including its AttributeModifiers
|
||||
*/
|
||||
private static NBTTagCompound writeAttributeInstanceToNBT(IAttributeInstance instance)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = new NBTTagCompound();
|
||||
IAttribute iattribute = instance.getAttribute();
|
||||
nbttagcompound.setString("Name", iattribute.getName());
|
||||
nbttagcompound.setDouble("Base", instance.getBaseValue());
|
||||
Collection<AttributeModifier> collection = instance.getModifiers();
|
||||
|
||||
if (collection != null && !collection.isEmpty())
|
||||
{
|
||||
NBTTagList nbttaglist = new NBTTagList();
|
||||
|
||||
for (AttributeModifier attributemodifier : collection)
|
||||
{
|
||||
if (attributemodifier.isSaved())
|
||||
{
|
||||
nbttaglist.appendTag(writeAttributeModifierToNBT(attributemodifier));
|
||||
}
|
||||
}
|
||||
|
||||
nbttagcompound.setTag("Modifiers", nbttaglist);
|
||||
}
|
||||
|
||||
return nbttagcompound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NBTTagCompound from an AttributeModifier
|
||||
*/
|
||||
public static NBTTagCompound writeAttributeModifierToNBT(AttributeModifier modifier)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = new NBTTagCompound();
|
||||
nbttagcompound.setString("Name", modifier.getName());
|
||||
nbttagcompound.setDouble("Amount", modifier.getAmount());
|
||||
nbttagcompound.setInteger("Operation", modifier.getOperation());
|
||||
nbttagcompound.setUniqueId("UUID", modifier.getID());
|
||||
return nbttagcompound;
|
||||
}
|
||||
|
||||
public static void setAttributeModifiers(AbstractAttributeMap map, NBTTagList list)
|
||||
{
|
||||
for (int i = 0; i < list.tagCount(); ++i)
|
||||
{
|
||||
NBTTagCompound nbttagcompound = list.getCompoundTagAt(i);
|
||||
IAttributeInstance iattributeinstance = map.getAttributeInstanceByName(nbttagcompound.getString("Name"));
|
||||
|
||||
if (iattributeinstance == null)
|
||||
{
|
||||
LOGGER.warn("Ignoring unknown attribute '{}'", (Object)nbttagcompound.getString("Name"));
|
||||
}
|
||||
else
|
||||
{
|
||||
applyModifiersToAttributeInstance(iattributeinstance, nbttagcompound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void applyModifiersToAttributeInstance(IAttributeInstance instance, NBTTagCompound compound)
|
||||
{
|
||||
instance.setBaseValue(compound.getDouble("Base"));
|
||||
|
||||
if (compound.hasKey("Modifiers", 9))
|
||||
{
|
||||
NBTTagList nbttaglist = compound.getTagList("Modifiers", 10);
|
||||
|
||||
for (int i = 0; i < nbttaglist.tagCount(); ++i)
|
||||
{
|
||||
AttributeModifier attributemodifier = readAttributeModifierFromNBT(nbttaglist.getCompoundTagAt(i));
|
||||
|
||||
if (attributemodifier != null)
|
||||
{
|
||||
AttributeModifier attributemodifier1 = instance.getModifier(attributemodifier.getID());
|
||||
|
||||
if (attributemodifier1 != null)
|
||||
{
|
||||
instance.removeModifier(attributemodifier1);
|
||||
}
|
||||
|
||||
instance.applyModifier(attributemodifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AttributeModifier from an NBTTagCompound
|
||||
*/
|
||||
@Nullable
|
||||
public static AttributeModifier readAttributeModifierFromNBT(NBTTagCompound compound)
|
||||
{
|
||||
UUID uuid = compound.getUniqueId("UUID");
|
||||
|
||||
try
|
||||
{
|
||||
return new AttributeModifier(uuid, compound.getString("Name"), compound.getDouble("Amount"), compound.getInteger("Operation"));
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
LOGGER.warn("Unable to create attribute: {}", (Object)exception.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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_));
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 + '}';
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user