package net.minecraft.entity; import com.google.common.base.Objects; import com.google.common.collect.Maps; import java.util.Collection; import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.UUID; import javax.annotation.Nullable; import net.minecraft.advancements.CriteriaTriggers; import net.minecraft.block.Block; import net.minecraft.block.BlockLadder; import net.minecraft.block.BlockTrapDoor; import net.minecraft.block.SoundType; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.enchantment.EnchantmentFrostWalker; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.ai.attributes.AbstractAttributeMap; import net.minecraft.entity.ai.attributes.AttributeMap; 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.item.EntityBoat; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.item.EntityXPOrb; import net.minecraft.entity.passive.AbstractHorse; import net.minecraft.entity.passive.EntityWolf; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.projectile.EntityArrow; import net.minecraft.init.Blocks; import net.minecraft.init.Enchantments; import net.minecraft.init.Items; import net.minecraft.init.MobEffects; import net.minecraft.init.SoundEvents; import net.minecraft.inventory.EntityEquipmentSlot; import net.minecraft.item.EnumAction; import net.minecraft.item.Item; import net.minecraft.item.ItemArmor; import net.minecraft.item.ItemElytra; import net.minecraft.item.ItemStack; 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.network.play.server.SPacketAnimation; import net.minecraft.network.play.server.SPacketCollectItem; import net.minecraft.network.play.server.SPacketEntityEquipment; import net.minecraft.potion.Potion; import net.minecraft.potion.PotionEffect; import net.minecraft.potion.PotionUtils; import net.minecraft.stats.StatList; import net.minecraft.util.CombatRules; import net.minecraft.util.CombatTracker; import net.minecraft.util.DamageSource; import net.minecraft.util.EntityDamageSource; import net.minecraft.util.EntitySelectors; import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumHand; import net.minecraft.util.EnumHandSide; import net.minecraft.util.EnumParticleTypes; import net.minecraft.util.NonNullList; import net.minecraft.util.SoundEvent; import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.math.Vec3d; import net.minecraft.world.World; import net.minecraft.world.WorldServer; 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 abstract class EntityLivingBase extends Entity { private static final Logger LOGGER = LogManager.getLogger(); private static final UUID SPRINTING_SPEED_BOOST_ID = UUID.fromString("662A6B8D-DA3E-4C1C-8813-96EA6097278D"); private static final AttributeModifier SPRINTING_SPEED_BOOST = (new AttributeModifier(SPRINTING_SPEED_BOOST_ID, "Sprinting speed boost", 0.30000001192092896D, 2)).setSaved(false); public static final net.minecraft.entity.ai.attributes.IAttribute SWIM_SPEED = new net.minecraft.entity.ai.attributes.RangedAttribute(null, "forge.swimSpeed", 1.0D, 0.0D, 1024.0D).setShouldWatch(true); /** * Hand states, used to trigger blocking/eating/drinking animation. * * Note that this is completely unrelated to {@link #isSwingInProgress}/{@link #swingingHand}, which is used for the * swinging animation. */ protected static final DataParameter HAND_STATES = EntityDataManager.createKey(EntityLivingBase.class, DataSerializers.BYTE); private static final DataParameter HEALTH = EntityDataManager.createKey(EntityLivingBase.class, DataSerializers.FLOAT); private static final DataParameter POTION_EFFECTS = EntityDataManager.createKey(EntityLivingBase.class, DataSerializers.VARINT); private static final DataParameter HIDE_PARTICLES = EntityDataManager.createKey(EntityLivingBase.class, DataSerializers.BOOLEAN); private static final DataParameter ARROW_COUNT_IN_ENTITY = EntityDataManager.createKey(EntityLivingBase.class, DataSerializers.VARINT); private AbstractAttributeMap attributeMap; private final CombatTracker _combatTracker = new CombatTracker(this); private final Map activePotionsMap = Maps.newHashMap(); private final NonNullList handInventory = NonNullList.withSize(2, ItemStack.EMPTY); /** The array of item stacks that are used for armor in a living inventory. */ private final NonNullList armorArray = NonNullList.withSize(4, ItemStack.EMPTY); /** Whether an arm swing is currently in progress. */ public boolean isSwingInProgress; /** The hand that is currently being swung, if {@link #isSwingInProgress} is true. */ public EnumHand swingingHand; public int swingProgressInt; public int arrowHitTimer; /** The amount of time remaining this entity should act 'hurt'. (Visual appearance of red tint) */ public int hurtTime; /** What the hurt time was max set to last. */ public int maxHurtTime; /** The yaw at which this entity was last attacked from. */ public float attackedAtYaw; /** The amount of time remaining this entity should act 'dead', i.e. have a corpse in the world. */ public int deathTime; public float prevSwingProgress; public float swingProgress; protected int ticksSinceLastSwing; public float prevLimbSwingAmount; public float limbSwingAmount; public float limbSwing; public int maxHurtResistantTime = 20; public float prevCameraPitch; public float cameraPitch; /** An unused random value set in the constructor to a random number between 0 and 12398 */ public float randomUnused2; /** An unused random value set in the constructor to a random number between .01 and .02 */ public float randomUnused1; public float renderYawOffset; public float prevRenderYawOffset; /** Entity head rotation yaw */ public float rotationYawHead; /** Entity head rotation yaw at previous tick */ public float prevRotationYawHead; /** A factor used to determine how far this entity will move each tick if it is jumping or falling. */ public float jumpMovementFactor = 0.02F; /** The most recent player that has attacked this entity */ protected EntityPlayer attackingPlayer; /** * Set to 60 when hit by the player or the player's wolf, then decrements. Used to determine whether the entity * should drop items on death. */ protected int recentlyHit; /** This gets set on entity death, but never used. Looks like a duplicate of isDead */ protected boolean dead; /** The age of this EntityLiving (used to determine when it dies) */ protected int idleTime; protected float prevOnGroundSpeedFactor; protected float onGroundSpeedFactor; protected float movedDistance; protected float prevMovedDistance; /** An unused field that is set to 180 in the constructor of EntityPlayer (and otherwise is 0) */ protected float unused180; /** The score value of the Mob, the amount of points the mob is worth. */ protected int scoreValue; /** Damage taken in the last hit. Mobs are resistant to damage less than this for a short time after taking damage. */ protected float lastDamage; /** used to check whether entity is jumping. */ protected boolean isJumping; public float moveStrafing; public float moveVertical; public float moveForward; public float randomYawVelocity; /** The number of updates over which the new position and rotation are to be applied to the entity. */ protected int newPosRotationIncrements; /** The X position the entity will be interpolated to. Used for teleporting. */ protected double interpTargetX; /** The Y position the entity will be interpolated to. Used for teleporting. */ protected double interpTargetY; /** The Z position the entity will be interpolated to. Used for teleporting. */ protected double interpTargetZ; /** The yaw rotation the entity will be interpolated to. Used for teleporting. */ protected double interpTargetYaw; /** The pitch rotation the entity will be interpolated to. Used for teleporting. */ protected double interpTargetPitch; /** Whether the DataWatcher needs to be updated with the active potions */ private boolean potionsNeedUpdate = true; /** * Set immediately after this entity is attacked by another EntityLivingBase, allowing AI tasks to see who the * attacker was and handle accordingly. Reset to null after 100 ticks have passed. */ private EntityLivingBase revengeTarget; private int revengeTimer; private EntityLivingBase lastAttackedEntity; /** Holds the value of ticksExisted when setLastAttacker was last called. */ private int lastAttackedEntityTime; /** * A factor used to determine how far this entity will move each tick if it is walking on land. Adjusted by speed, * and slipperiness of the current block. */ private float landMovementFactor; /** Number of ticks since last jump */ private int jumpTicks; private float absorptionAmount; protected ItemStack activeItemStack = ItemStack.EMPTY; protected int activeItemStackUseCount; protected int ticksElytraFlying; /** The BlockPos the entity had during the previous tick. */ private BlockPos prevBlockpos; private DamageSource lastDamageSource; private long lastDamageStamp; /** * Called by the /kill command. */ public void onKillCommand() { this.attackEntityFrom(DamageSource.OUT_OF_WORLD, Float.MAX_VALUE); } public EntityLivingBase(World worldIn) { super(worldIn); this.applyEntityAttributes(); this.setHealth(this.getMaxHealth()); this.preventEntitySpawning = true; this.randomUnused1 = (float)((Math.random() + 1.0D) * 0.009999999776482582D); this.setPosition(this.posX, this.posY, this.posZ); this.randomUnused2 = (float)Math.random() * 12398.0F; this.rotationYaw = (float)(Math.random() * (Math.PI * 2D)); this.rotationYawHead = this.rotationYaw; this.stepHeight = 0.6F; } protected void entityInit() { this.dataManager.register(HAND_STATES, Byte.valueOf((byte)0)); this.dataManager.register(POTION_EFFECTS, Integer.valueOf(0)); this.dataManager.register(HIDE_PARTICLES, Boolean.valueOf(false)); this.dataManager.register(ARROW_COUNT_IN_ENTITY, Integer.valueOf(0)); this.dataManager.register(HEALTH, Float.valueOf(1.0F)); } protected void applyEntityAttributes() { this.getAttributeMap().registerAttribute(SharedMonsterAttributes.MAX_HEALTH); this.getAttributeMap().registerAttribute(SharedMonsterAttributes.KNOCKBACK_RESISTANCE); this.getAttributeMap().registerAttribute(SharedMonsterAttributes.MOVEMENT_SPEED); this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ARMOR); this.getAttributeMap().registerAttribute(SharedMonsterAttributes.ARMOR_TOUGHNESS); this.getAttributeMap().registerAttribute(SWIM_SPEED); } protected void updateFallState(double y, boolean onGroundIn, IBlockState state, BlockPos pos) { if (!this.isInWater()) { this.handleWaterMovement(); } if (!this.world.isRemote && this.fallDistance > 3.0F && onGroundIn) { float f = (float)MathHelper.ceil(this.fallDistance - 3.0F); if (!state.getBlock().isAir(state, world, pos)) { double d0 = Math.min((double)(0.2F + f / 15.0F), 2.5D); int i = (int)(150.0D * d0); if (!state.getBlock().addLandingEffects(state, (WorldServer)this.world, pos, state, this, i)) ((WorldServer)this.world).spawnParticle(EnumParticleTypes.BLOCK_DUST, this.posX, this.posY, this.posZ, i, 0.0D, 0.0D, 0.0D, 0.15000000596046448D, Block.getStateId(state)); } } super.updateFallState(y, onGroundIn, state, pos); } public boolean canBreatheUnderwater() { return false; } /** * Gets called every tick from main Entity class */ public void onEntityUpdate() { this.prevSwingProgress = this.swingProgress; super.onEntityUpdate(); this.world.profiler.startSection("livingEntityBaseTick"); boolean flag = this instanceof EntityPlayer; if (this.isEntityAlive()) { if (this.isEntityInsideOpaqueBlock()) { this.attackEntityFrom(DamageSource.IN_WALL, 1.0F); } else if (flag && !this.world.getWorldBorder().contains(this.getEntityBoundingBox())) { double d0 = this.world.getWorldBorder().getClosestDistance(this) + this.world.getWorldBorder().getDamageBuffer(); if (d0 < 0.0D) { double d1 = this.world.getWorldBorder().getDamageAmount(); if (d1 > 0.0D) { this.attackEntityFrom(DamageSource.IN_WALL, (float)Math.max(1, MathHelper.floor(-d0 * d1))); } } } } if (this.isImmuneToFire() || this.world.isRemote) { this.extinguish(); } boolean flag1 = flag && ((EntityPlayer)this).capabilities.disableDamage; if (this.isEntityAlive()) { if (!this.isInsideOfMaterial(Material.WATER)) { this.setAir(300); } else { if (!this.canBreatheUnderwater() && !this.isPotionActive(MobEffects.WATER_BREATHING) && !flag1) { this.setAir(this.decreaseAirSupply(this.getAir())); if (this.getAir() == -20) { this.setAir(0); for (int i = 0; i < 8; ++i) { float f2 = this.rand.nextFloat() - this.rand.nextFloat(); float f = this.rand.nextFloat() - this.rand.nextFloat(); float f1 = this.rand.nextFloat() - this.rand.nextFloat(); this.world.spawnParticle(EnumParticleTypes.WATER_BUBBLE, this.posX + (double)f2, this.posY + (double)f, this.posZ + (double)f1, this.motionX, this.motionY, this.motionZ); } this.attackEntityFrom(DamageSource.DROWN, 2.0F); } } if (!this.world.isRemote && this.isRiding() && this.getRidingEntity() != null && this.getRidingEntity().shouldDismountInWater(this)) { this.dismountRidingEntity(); } } if (!this.world.isRemote) { BlockPos blockpos = new BlockPos(this); if (!Objects.equal(this.prevBlockpos, blockpos)) { this.prevBlockpos = blockpos; this.frostWalk(blockpos); } } } if (this.isEntityAlive() && this.isWet()) { this.extinguish(); } this.prevCameraPitch = this.cameraPitch; if (this.hurtTime > 0) { --this.hurtTime; } if (this.hurtResistantTime > 0 && !(this instanceof EntityPlayerMP)) { --this.hurtResistantTime; } if (this.getHealth() <= 0.0F) { this.onDeathUpdate(); } if (this.recentlyHit > 0) { --this.recentlyHit; } else { this.attackingPlayer = null; } if (this.lastAttackedEntity != null && !this.lastAttackedEntity.isEntityAlive()) { this.lastAttackedEntity = null; } if (this.revengeTarget != null) { if (!this.revengeTarget.isEntityAlive()) { this.setRevengeTarget((EntityLivingBase)null); } else if (this.ticksExisted - this.revengeTimer > 100) { this.setRevengeTarget((EntityLivingBase)null); } } this.updatePotionEffects(); this.prevMovedDistance = this.movedDistance; this.prevRenderYawOffset = this.renderYawOffset; this.prevRotationYawHead = this.rotationYawHead; this.prevRotationYaw = this.rotationYaw; this.prevRotationPitch = this.rotationPitch; this.world.profiler.endSection(); } protected void frostWalk(BlockPos pos) { int i = EnchantmentHelper.getMaxEnchantmentLevel(Enchantments.FROST_WALKER, this); if (i > 0) { EnchantmentFrostWalker.freezeNearby(this, this.world, pos, i); } } /** * If Animal, checks if the age timer is negative */ public boolean isChild() { return false; } /** * handles entity death timer, experience orb and particle creation */ protected void onDeathUpdate() { ++this.deathTime; if (this.deathTime == 20) { if (!this.world.isRemote && (this.isPlayer() || this.recentlyHit > 0 && this.canDropLoot() && this.world.getGameRules().getBoolean("doMobLoot"))) { int i = this.getExperiencePoints(this.attackingPlayer); i = net.minecraftforge.event.ForgeEventFactory.getExperienceDrop(this, this.attackingPlayer, i); while (i > 0) { int j = EntityXPOrb.getXPSplit(i); i -= j; this.world.spawnEntity(new EntityXPOrb(this.world, this.posX, this.posY, this.posZ, j)); } } this.setDead(); for (int k = 0; k < 20; ++k) { double d2 = this.rand.nextGaussian() * 0.02D; double d0 = this.rand.nextGaussian() * 0.02D; double d1 = this.rand.nextGaussian() * 0.02D; this.world.spawnParticle(EnumParticleTypes.EXPLOSION_NORMAL, this.posX + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, this.posY + (double)(this.rand.nextFloat() * this.height), this.posZ + (double)(this.rand.nextFloat() * this.width * 2.0F) - (double)this.width, d2, d0, d1); } } } /** * Entity won't drop items or experience points if this returns false */ protected boolean canDropLoot() { return !this.isChild(); } /** * Decrements the entity's air supply when underwater */ protected int decreaseAirSupply(int air) { int i = EnchantmentHelper.getRespirationModifier(this); return i > 0 && this.rand.nextInt(i + 1) > 0 ? air : air - 1; } /** * Get the experience points the entity currently has. */ protected int getExperiencePoints(EntityPlayer player) { return 0; } /** * Only use is to identify if class is an instance of player for experience dropping */ protected boolean isPlayer() { return false; } public Random getRNG() { return this.rand; } @Nullable public EntityLivingBase getRevengeTarget() { return this.revengeTarget; } public int getRevengeTimer() { return this.revengeTimer; } /** * Hint to AI tasks that we were attacked by the passed EntityLivingBase and should retaliate. Is not guaranteed to * change our actual active target (for example if we are currently busy attacking someone else) */ public void setRevengeTarget(@Nullable EntityLivingBase livingBase) { this.revengeTarget = livingBase; this.revengeTimer = this.ticksExisted; net.minecraftforge.common.ForgeHooks.onLivingSetAttackTarget(this, livingBase); } public EntityLivingBase getLastAttackedEntity() { return this.lastAttackedEntity; } public int getLastAttackedEntityTime() { return this.lastAttackedEntityTime; } public void setLastAttackedEntity(Entity entityIn) { if (entityIn instanceof EntityLivingBase) { this.lastAttackedEntity = (EntityLivingBase)entityIn; } else { this.lastAttackedEntity = null; } this.lastAttackedEntityTime = this.ticksExisted; } public int getIdleTime() { return this.idleTime; } protected void playEquipSound(ItemStack stack) { if (!stack.isEmpty()) { SoundEvent soundevent = SoundEvents.ITEM_ARMOR_EQUIP_GENERIC; Item item = stack.getItem(); if (item instanceof ItemArmor) { soundevent = ((ItemArmor)item).getArmorMaterial().getSoundEvent(); } else if (item == Items.ELYTRA) { soundevent = SoundEvents.ITEM_ARMOR_EQIIP_ELYTRA; } this.playSound(soundevent, 1.0F, 1.0F); } } /** * (abstract) Protected helper method to write subclass entity data to NBT. */ public void writeEntityToNBT(NBTTagCompound compound) { compound.setFloat("Health", this.getHealth()); compound.setShort("HurtTime", (short)this.hurtTime); compound.setInteger("HurtByTimestamp", this.revengeTimer); compound.setShort("DeathTime", (short)this.deathTime); compound.setFloat("AbsorptionAmount", this.getAbsorptionAmount()); for (EntityEquipmentSlot entityequipmentslot : EntityEquipmentSlot.values()) { ItemStack itemstack = this.getItemStackFromSlot(entityequipmentslot); if (!itemstack.isEmpty()) { this.getAttributeMap().removeAttributeModifiers(itemstack.getAttributeModifiers(entityequipmentslot)); } } compound.setTag("Attributes", SharedMonsterAttributes.writeBaseAttributeMapToNBT(this.getAttributeMap())); for (EntityEquipmentSlot entityequipmentslot1 : EntityEquipmentSlot.values()) { ItemStack itemstack1 = this.getItemStackFromSlot(entityequipmentslot1); if (!itemstack1.isEmpty()) { this.getAttributeMap().applyAttributeModifiers(itemstack1.getAttributeModifiers(entityequipmentslot1)); } } if (!this.activePotionsMap.isEmpty()) { NBTTagList nbttaglist = new NBTTagList(); for (PotionEffect potioneffect : this.activePotionsMap.values()) { nbttaglist.appendTag(potioneffect.writeCustomPotionEffectToNBT(new NBTTagCompound())); } compound.setTag("ActiveEffects", nbttaglist); } compound.setBoolean("FallFlying", this.isElytraFlying()); } /** * (abstract) Protected helper method to read subclass entity data from NBT. */ public void readEntityFromNBT(NBTTagCompound compound) { this.setAbsorptionAmount(compound.getFloat("AbsorptionAmount")); if (compound.hasKey("Attributes", 9) && this.world != null && !this.world.isRemote) { SharedMonsterAttributes.setAttributeModifiers(this.getAttributeMap(), compound.getTagList("Attributes", 10)); } if (compound.hasKey("ActiveEffects", 9)) { NBTTagList nbttaglist = compound.getTagList("ActiveEffects", 10); for (int i = 0; i < nbttaglist.tagCount(); ++i) { NBTTagCompound nbttagcompound = nbttaglist.getCompoundTagAt(i); PotionEffect potioneffect = PotionEffect.readCustomPotionEffectFromNBT(nbttagcompound); if (potioneffect != null) { this.activePotionsMap.put(potioneffect.getPotion(), potioneffect); } } } if (compound.hasKey("Health", 99)) { this.setHealth(compound.getFloat("Health")); } this.hurtTime = compound.getShort("HurtTime"); this.deathTime = compound.getShort("DeathTime"); this.revengeTimer = compound.getInteger("HurtByTimestamp"); if (compound.hasKey("Team", 8)) { String s = compound.getString("Team"); boolean flag = this.world.getScoreboard().addPlayerToTeam(this.getCachedUniqueIdString(), s); if (!flag) { LOGGER.warn("Unable to add mob to team \"" + s + "\" (that team probably doesn't exist)"); } } if (compound.getBoolean("FallFlying")) { this.setFlag(7, true); } } protected void updatePotionEffects() { Iterator iterator = this.activePotionsMap.keySet().iterator(); try { while (iterator.hasNext()) { Potion potion = iterator.next(); PotionEffect potioneffect = this.activePotionsMap.get(potion); if (!potioneffect.onUpdate(this)) { if (!this.world.isRemote) { iterator.remove(); this.onFinishedPotionEffect(potioneffect); } } else if (potioneffect.getDuration() % 600 == 0) { this.onChangedPotionEffect(potioneffect, false); } } } catch (ConcurrentModificationException var11) { ; } if (this.potionsNeedUpdate) { if (!this.world.isRemote) { this.updatePotionMetadata(); } this.potionsNeedUpdate = false; } int i = ((Integer)this.dataManager.get(POTION_EFFECTS)).intValue(); boolean flag1 = ((Boolean)this.dataManager.get(HIDE_PARTICLES)).booleanValue(); if (i > 0) { boolean flag; if (this.isInvisible()) { flag = this.rand.nextInt(15) == 0; } else { flag = this.rand.nextBoolean(); } if (flag1) { flag &= this.rand.nextInt(5) == 0; } if (flag && i > 0) { double d0 = (double)(i >> 16 & 255) / 255.0D; double d1 = (double)(i >> 8 & 255) / 255.0D; double d2 = (double)(i >> 0 & 255) / 255.0D; this.world.spawnParticle(flag1 ? EnumParticleTypes.SPELL_MOB_AMBIENT : EnumParticleTypes.SPELL_MOB, this.posX + (this.rand.nextDouble() - 0.5D) * (double)this.width, this.posY + this.rand.nextDouble() * (double)this.height, this.posZ + (this.rand.nextDouble() - 0.5D) * (double)this.width, d0, d1, d2); } } } /** * Clears potion metadata values if the entity has no potion effects. Otherwise, updates potion effect color, * ambience, and invisibility metadata values */ protected void updatePotionMetadata() { if (this.activePotionsMap.isEmpty()) { this.resetPotionEffectMetadata(); this.setInvisible(false); } else { Collection collection = this.activePotionsMap.values(); net.minecraftforge.event.entity.living.PotionColorCalculationEvent event = new net.minecraftforge.event.entity.living.PotionColorCalculationEvent(this, PotionUtils.getPotionColorFromEffectList(collection), areAllPotionsAmbient(collection), collection); net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(event); this.dataManager.set(HIDE_PARTICLES, event.areParticlesHidden()); this.dataManager.set(POTION_EFFECTS, event.getColor()); this.setInvisible(this.isPotionActive(MobEffects.INVISIBILITY)); } } /** * Returns true if all of the potion effects in the specified collection are ambient. */ public static boolean areAllPotionsAmbient(Collection potionEffects) { for (PotionEffect potioneffect : potionEffects) { if (!potioneffect.getIsAmbient()) { return false; } } return true; } /** * Resets the potion effect color and ambience metadata values */ protected void resetPotionEffectMetadata() { this.dataManager.set(HIDE_PARTICLES, Boolean.valueOf(false)); this.dataManager.set(POTION_EFFECTS, Integer.valueOf(0)); } public void clearActivePotions() { if (!this.world.isRemote) { Iterator iterator = this.activePotionsMap.values().iterator(); while (iterator.hasNext()) { this.onFinishedPotionEffect(iterator.next()); iterator.remove(); } } } public Collection getActivePotionEffects() { return this.activePotionsMap.values(); } public Map getActivePotionMap() { return this.activePotionsMap; } public boolean isPotionActive(Potion potionIn) { return this.activePotionsMap.containsKey(potionIn); } /** * returns the PotionEffect for the supplied Potion if it is active, null otherwise. */ @Nullable public PotionEffect getActivePotionEffect(Potion potionIn) { return this.activePotionsMap.get(potionIn); } /** * adds a PotionEffect to the entity */ public void addPotionEffect(PotionEffect potioneffectIn) { if (this.isPotionApplicable(potioneffectIn)) { PotionEffect potioneffect = this.activePotionsMap.get(potioneffectIn.getPotion()); if (potioneffect == null) { this.activePotionsMap.put(potioneffectIn.getPotion(), potioneffectIn); this.onNewPotionEffect(potioneffectIn); } else { potioneffect.combine(potioneffectIn); this.onChangedPotionEffect(potioneffect, true); } } } public boolean isPotionApplicable(PotionEffect potioneffectIn) { if (this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD) { Potion potion = potioneffectIn.getPotion(); if (potion == MobEffects.REGENERATION || potion == MobEffects.POISON) { return false; } } return true; } /** * Returns true if this entity is undead. */ public boolean isEntityUndead() { return this.getCreatureAttribute() == EnumCreatureAttribute.UNDEAD; } /** * Removes the given potion effect from the active potion map and returns it. Does not call cleanup callbacks for * the end of the potion effect. */ @Nullable public PotionEffect removeActivePotionEffect(@Nullable Potion potioneffectin) { return this.activePotionsMap.remove(potioneffectin); } /** * Removes the given potion effect. */ public void removePotionEffect(Potion potionIn) { PotionEffect potioneffect = this.removeActivePotionEffect(potionIn); if (potioneffect != null) { this.onFinishedPotionEffect(potioneffect); } } protected void onNewPotionEffect(PotionEffect id) { this.potionsNeedUpdate = true; if (!this.world.isRemote) { id.getPotion().applyAttributesModifiersToEntity(this, this.getAttributeMap(), id.getAmplifier()); } } protected void onChangedPotionEffect(PotionEffect id, boolean p_70695_2_) { this.potionsNeedUpdate = true; if (p_70695_2_ && !this.world.isRemote) { Potion potion = id.getPotion(); potion.removeAttributesModifiersFromEntity(this, this.getAttributeMap(), id.getAmplifier()); potion.applyAttributesModifiersToEntity(this, this.getAttributeMap(), id.getAmplifier()); } } protected void onFinishedPotionEffect(PotionEffect effect) { this.potionsNeedUpdate = true; if (!this.world.isRemote) { effect.getPotion().removeAttributesModifiersFromEntity(this, this.getAttributeMap(), effect.getAmplifier()); } } /** * Heal living entity (param: amount of half-hearts) */ public void heal(float healAmount) { healAmount = net.minecraftforge.event.ForgeEventFactory.onLivingHeal(this, healAmount); if (healAmount <= 0) return; float f = this.getHealth(); if (f > 0.0F) { this.setHealth(f + healAmount); } } public final float getHealth() { return ((Float)this.dataManager.get(HEALTH)).floatValue(); } public void setHealth(float health) { this.dataManager.set(HEALTH, Float.valueOf(MathHelper.clamp(health, 0.0F, this.getMaxHealth()))); } /** * Called when the entity is attacked. */ public boolean attackEntityFrom(DamageSource source, float amount) { if (!net.minecraftforge.common.ForgeHooks.onLivingAttack(this, source, amount)) return false; if (this.isEntityInvulnerable(source)) { return false; } else if (this.world.isRemote) { return false; } else { this.idleTime = 0; if (this.getHealth() <= 0.0F) { return false; } else if (source.isFireDamage() && this.isPotionActive(MobEffects.FIRE_RESISTANCE)) { return false; } else { float f = amount; if ((source == DamageSource.ANVIL || source == DamageSource.FALLING_BLOCK) && !this.getItemStackFromSlot(EntityEquipmentSlot.HEAD).isEmpty()) { this.getItemStackFromSlot(EntityEquipmentSlot.HEAD).damageItem((int)(amount * 4.0F + this.rand.nextFloat() * amount * 2.0F), this); amount *= 0.75F; } boolean flag = false; if (amount > 0.0F && this.canBlockDamageSource(source)) { this.damageShield(amount); amount = 0.0F; if (!source.isProjectile()) { Entity entity = source.getImmediateSource(); if (entity instanceof EntityLivingBase) { this.blockUsingShield((EntityLivingBase)entity); } } flag = true; } this.limbSwingAmount = 1.5F; boolean flag1 = true; if ((float)this.hurtResistantTime > (float)this.maxHurtResistantTime / 2.0F) { if (amount <= this.lastDamage) { return false; } this.damageEntity(source, amount - this.lastDamage); this.lastDamage = amount; flag1 = false; } else { this.lastDamage = amount; this.hurtResistantTime = this.maxHurtResistantTime; this.damageEntity(source, amount); this.maxHurtTime = 10; this.hurtTime = this.maxHurtTime; } this.attackedAtYaw = 0.0F; Entity entity1 = source.getTrueSource(); if (entity1 != null) { if (entity1 instanceof EntityLivingBase) { this.setRevengeTarget((EntityLivingBase)entity1); } if (entity1 instanceof EntityPlayer) { this.recentlyHit = 100; this.attackingPlayer = (EntityPlayer)entity1; } else if (entity1 instanceof net.minecraft.entity.passive.EntityTameable) { net.minecraft.entity.passive.EntityTameable entitywolf = (net.minecraft.entity.passive.EntityTameable)entity1; if (entitywolf.isTamed()) { this.recentlyHit = 100; this.attackingPlayer = null; } } } if (flag1) { if (flag) { this.world.setEntityState(this, (byte)29); } else if (source instanceof EntityDamageSource && ((EntityDamageSource)source).getIsThornsDamage()) { this.world.setEntityState(this, (byte)33); } else { byte b0; if (source == DamageSource.DROWN) { b0 = 36; } else if (source.isFireDamage()) { b0 = 37; } else { b0 = 2; } this.world.setEntityState(this, b0); } if (source != DamageSource.DROWN && (!flag || amount > 0.0F)) { this.markVelocityChanged(); } if (entity1 != null) { double d1 = entity1.posX - this.posX; double d0; for (d0 = entity1.posZ - this.posZ; d1 * d1 + d0 * d0 < 1.0E-4D; d0 = (Math.random() - Math.random()) * 0.01D) { d1 = (Math.random() - Math.random()) * 0.01D; } this.attackedAtYaw = (float)(MathHelper.atan2(d0, d1) * (180D / Math.PI) - (double)this.rotationYaw); this.knockBack(entity1, 0.4F, d1, d0); } else { this.attackedAtYaw = (float)((int)(Math.random() * 2.0D) * 180); } } if (this.getHealth() <= 0.0F) { if (!this.checkTotemDeathProtection(source)) { SoundEvent soundevent = this.getDeathSound(); if (flag1 && soundevent != null) { this.playSound(soundevent, this.getSoundVolume(), this.getSoundPitch()); } this.onDeath(source); } } else if (flag1) { this.playHurtSound(source); } boolean flag2 = !flag || amount > 0.0F; if (flag2) { this.lastDamageSource = source; this.lastDamageStamp = this.world.getTotalWorldTime(); } if (this instanceof EntityPlayerMP) { CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((EntityPlayerMP)this, source, f, amount, flag); } if (entity1 instanceof EntityPlayerMP) { CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((EntityPlayerMP)entity1, this, source, f, amount, flag); } return flag2; } } } protected void blockUsingShield(EntityLivingBase p_190629_1_) { p_190629_1_.knockBack(this, 0.5F, this.posX - p_190629_1_.posX, this.posZ - p_190629_1_.posZ); } private boolean checkTotemDeathProtection(DamageSource p_190628_1_) { if (p_190628_1_.canHarmInCreative()) { return false; } else { ItemStack itemstack = null; for (EnumHand enumhand : EnumHand.values()) { ItemStack itemstack1 = this.getHeldItem(enumhand); if (itemstack1.getItem() == Items.TOTEM_OF_UNDYING) { itemstack = itemstack1.copy(); itemstack1.shrink(1); break; } } if (itemstack != null) { if (this instanceof EntityPlayerMP) { EntityPlayerMP entityplayermp = (EntityPlayerMP)this; entityplayermp.addStat(StatList.getObjectUseStats(Items.TOTEM_OF_UNDYING)); CriteriaTriggers.USED_TOTEM.trigger(entityplayermp, itemstack); } this.setHealth(1.0F); this.clearActivePotions(); this.addPotionEffect(new PotionEffect(MobEffects.REGENERATION, 900, 1)); this.addPotionEffect(new PotionEffect(MobEffects.ABSORPTION, 100, 1)); this.world.setEntityState(this, (byte)35); } return itemstack != null; } } @Nullable public DamageSource getLastDamageSource() { if (this.world.getTotalWorldTime() - this.lastDamageStamp > 40L) { this.lastDamageSource = null; } return this.lastDamageSource; } protected void playHurtSound(DamageSource source) { SoundEvent soundevent = this.getHurtSound(source); if (soundevent != null) { this.playSound(soundevent, this.getSoundVolume(), this.getSoundPitch()); } } /** * Determines whether the entity can block the damage source based on the damage source's location, whether the * damage source is blockable, and whether the entity is blocking. */ private boolean canBlockDamageSource(DamageSource damageSourceIn) { if (!damageSourceIn.isUnblockable() && this.isActiveItemStackBlocking()) { Vec3d vec3d = damageSourceIn.getDamageLocation(); if (vec3d != null) { Vec3d vec3d1 = this.getLook(1.0F); Vec3d vec3d2 = vec3d.subtractReverse(new Vec3d(this.posX, this.posY, this.posZ)).normalize(); vec3d2 = new Vec3d(vec3d2.x, 0.0D, vec3d2.z); if (vec3d2.dotProduct(vec3d1) < 0.0D) { return true; } } } return false; } /** * Renders broken item particles using the given ItemStack */ public void renderBrokenItemStack(ItemStack stack) { this.world.playSound(null, this.posX, this.posY, this.posZ, SoundEvents.ENTITY_ITEM_BREAK, this.getSoundCategory(), 0.8F, 0.8F + this.world.rand.nextFloat() * 0.4F); //Forge: Fix MC-2518 Items are not damaged on the client so client needs packet as well. for (int i = 0; i < 5; ++i) { Vec3d vec3d = new Vec3d(((double)this.rand.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D); vec3d = vec3d.rotatePitch(-this.rotationPitch * 0.017453292F); vec3d = vec3d.rotateYaw(-this.rotationYaw * 0.017453292F); double d0 = (double)(-this.rand.nextFloat()) * 0.6D - 0.3D; Vec3d vec3d1 = new Vec3d(((double)this.rand.nextFloat() - 0.5D) * 0.3D, d0, 0.6D); vec3d1 = vec3d1.rotatePitch(-this.rotationPitch * 0.017453292F); vec3d1 = vec3d1.rotateYaw(-this.rotationYaw * 0.017453292F); vec3d1 = vec3d1.addVector(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ); if (this.world instanceof WorldServer) //Forge: Fix MC-2518 spawnParticle is nooped on server, need to use server specific variant ((WorldServer)this.world).spawnParticle(EnumParticleTypes.ITEM_CRACK, vec3d1.x, vec3d1.y, vec3d1.z, 0, vec3d.x, vec3d.y + 0.05D, vec3d.z, 0.0D, Item.getIdFromItem(stack.getItem()), stack.getMetadata()); else //Fix the fact that spawning ItemCrack uses TWO arguments. this.world.spawnParticle(EnumParticleTypes.ITEM_CRACK, vec3d1.x, vec3d1.y, vec3d1.z, vec3d.x, vec3d.y + 0.05D, vec3d.z, Item.getIdFromItem(stack.getItem()), stack.getMetadata()); } } /** * Called when the mob's health reaches 0. */ public void onDeath(DamageSource cause) { if (net.minecraftforge.common.ForgeHooks.onLivingDeath(this, cause)) return; if (!this.dead) { Entity entity = cause.getTrueSource(); EntityLivingBase entitylivingbase = this.getAttackingEntity(); if (this.scoreValue >= 0 && entitylivingbase != null) { entitylivingbase.awardKillScore(this, this.scoreValue, cause); } if (entity != null) { entity.onKillEntity(this); } this.dead = true; this.getCombatTracker().reset(); if (!this.world.isRemote) { int i = net.minecraftforge.common.ForgeHooks.getLootingLevel(this, entity, cause); captureDrops = true; capturedDrops.clear(); if (this.canDropLoot() && this.world.getGameRules().getBoolean("doMobLoot")) { boolean flag = this.recentlyHit > 0; this.dropLoot(flag, i, cause); } captureDrops = false; if (!net.minecraftforge.common.ForgeHooks.onLivingDrops(this, cause, capturedDrops, i, recentlyHit > 0)) { for (EntityItem item : capturedDrops) { world.spawnEntity(item); } } } this.world.setEntityState(this, (byte)3); } } /** * drops the loot of this entity upon death */ protected void dropLoot(boolean wasRecentlyHit, int lootingModifier, DamageSource source) { this.dropFewItems(wasRecentlyHit, lootingModifier); this.dropEquipment(wasRecentlyHit, lootingModifier); } /** * Drop the equipment for this entity. */ protected void dropEquipment(boolean wasRecentlyHit, int lootingModifier) { } /** * Constructs a knockback vector from the given direction ratio and magnitude and adds it to the entity's velocity. * If it is on the ground (i.e. {@code this.onGround}), the Y-velocity is increased as well, clamping it to {@code * .4}. * * The entity's existing horizontal velocity is halved, and if the entity is on the ground the Y-velocity is too. */ public void knockBack(Entity entityIn, float strength, double xRatio, double zRatio) { net.minecraftforge.event.entity.living.LivingKnockBackEvent event = net.minecraftforge.common.ForgeHooks.onLivingKnockBack(this, entityIn, strength, xRatio, zRatio); if(event.isCanceled()) return; strength = event.getStrength(); xRatio = event.getRatioX(); zRatio = event.getRatioZ(); if (this.rand.nextDouble() >= this.getEntityAttribute(SharedMonsterAttributes.KNOCKBACK_RESISTANCE).getAttributeValue()) { this.isAirBorne = true; float f = MathHelper.sqrt(xRatio * xRatio + zRatio * zRatio); this.motionX /= 2.0D; this.motionZ /= 2.0D; this.motionX -= xRatio / (double)f * (double)strength; this.motionZ -= zRatio / (double)f * (double)strength; if (this.onGround) { this.motionY /= 2.0D; this.motionY += (double)strength; if (this.motionY > 0.4000000059604645D) { this.motionY = 0.4000000059604645D; } } } } @Nullable protected SoundEvent getHurtSound(DamageSource damageSourceIn) { return SoundEvents.ENTITY_GENERIC_HURT; } @Nullable protected SoundEvent getDeathSound() { return SoundEvents.ENTITY_GENERIC_DEATH; } protected SoundEvent getFallSound(int heightIn) { return heightIn > 4 ? SoundEvents.ENTITY_GENERIC_BIG_FALL : SoundEvents.ENTITY_GENERIC_SMALL_FALL; } /** * Drop 0-2 items of this living's type */ protected void dropFewItems(boolean wasRecentlyHit, int lootingModifier) { } /** * 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() { int i = MathHelper.floor(this.posX); int j = MathHelper.floor(this.getEntityBoundingBox().minY); int k = MathHelper.floor(this.posZ); if (this instanceof EntityPlayer && ((EntityPlayer)this).isSpectator()) { return false; } else { BlockPos blockpos = new BlockPos(i, j, k); IBlockState iblockstate = this.world.getBlockState(blockpos); Block block = iblockstate.getBlock(); return net.minecraftforge.common.ForgeHooks.isLivingOnLadder(iblockstate, world, new BlockPos(i, j, k), this); } } private boolean canGoThroughtTrapDoorOnLadder(BlockPos pos, IBlockState state) { if (((Boolean)state.getValue(BlockTrapDoor.OPEN)).booleanValue()) { IBlockState iblockstate = this.world.getBlockState(pos.down()); if (iblockstate.getBlock() == Blocks.LADDER && iblockstate.getValue(BlockLadder.FACING) == state.getValue(BlockTrapDoor.FACING)) { return true; } } return false; } /** * Checks whether target entity is alive. */ public boolean isEntityAlive() { return !this.isDead && this.getHealth() > 0.0F; } public void fall(float distance, float damageMultiplier) { float[] ret = net.minecraftforge.common.ForgeHooks.onLivingFall(this, distance, damageMultiplier); if (ret == null) return; distance = ret[0]; damageMultiplier = ret[1]; super.fall(distance, damageMultiplier); PotionEffect potioneffect = this.getActivePotionEffect(MobEffects.JUMP_BOOST); float f = potioneffect == null ? 0.0F : (float)(potioneffect.getAmplifier() + 1); int i = MathHelper.ceil((distance - 3.0F - f) * damageMultiplier); if (i > 0) { this.playSound(this.getFallSound(i), 1.0F, 1.0F); this.attackEntityFrom(DamageSource.FALL, (float)i); int j = MathHelper.floor(this.posX); int k = MathHelper.floor(this.posY - 0.20000000298023224D); int l = MathHelper.floor(this.posZ); IBlockState iblockstate = this.world.getBlockState(new BlockPos(j, k, l)); if (iblockstate.getMaterial() != Material.AIR) { SoundType soundtype = iblockstate.getBlock().getSoundType(iblockstate, world, new BlockPos(j, k, l), this); this.playSound(soundtype.getFallSound(), soundtype.getVolume() * 0.5F, soundtype.getPitch() * 0.75F); } } } /** * Setups the entity to do the hurt animation. Only used by packets in multiplayer. */ @SideOnly(Side.CLIENT) public void performHurtAnimation() { this.maxHurtTime = 10; this.hurtTime = this.maxHurtTime; this.attackedAtYaw = 0.0F; } /** * Returns the current armor value as determined by a call to InventoryPlayer.getTotalArmorValue */ public int getTotalArmorValue() { IAttributeInstance iattributeinstance = this.getEntityAttribute(SharedMonsterAttributes.ARMOR); return MathHelper.floor(iattributeinstance.getAttributeValue()); } protected void damageArmor(float damage) { } protected void damageShield(float damage) { } /** * Reduces damage, depending on armor */ protected float applyArmorCalculations(DamageSource source, float damage) { if (!source.isUnblockable()) { this.damageArmor(damage); damage = CombatRules.getDamageAfterAbsorb(damage, (float)this.getTotalArmorValue(), (float)this.getEntityAttribute(SharedMonsterAttributes.ARMOR_TOUGHNESS).getAttributeValue()); } return damage; } /** * Reduces damage, depending on potions */ protected float applyPotionDamageCalculations(DamageSource source, float damage) { if (source.isDamageAbsolute()) { return damage; } else { if (this.isPotionActive(MobEffects.RESISTANCE) && source != DamageSource.OUT_OF_WORLD) { int i = (this.getActivePotionEffect(MobEffects.RESISTANCE).getAmplifier() + 1) * 5; int j = 25 - i; float f = damage * (float)j; damage = f / 25.0F; } if (damage <= 0.0F) { return 0.0F; } else { int k = EnchantmentHelper.getEnchantmentModifierDamage(this.getArmorInventoryList(), source); if (k > 0) { damage = CombatRules.getDamageAfterMagicAbsorb(damage, (float)k); } return damage; } } } /** * Deals damage to the entity. This will take the armor of the entity into consideration before damaging the health * bar. */ protected void damageEntity(DamageSource damageSrc, float damageAmount) { if (!this.isEntityInvulnerable(damageSrc)) { damageAmount = net.minecraftforge.common.ForgeHooks.onLivingHurt(this, damageSrc, damageAmount); if (damageAmount <= 0) return; damageAmount = this.applyArmorCalculations(damageSrc, damageAmount); damageAmount = this.applyPotionDamageCalculations(damageSrc, damageAmount); float f = damageAmount; damageAmount = Math.max(damageAmount - this.getAbsorptionAmount(), 0.0F); this.setAbsorptionAmount(this.getAbsorptionAmount() - (f - damageAmount)); damageAmount = net.minecraftforge.common.ForgeHooks.onLivingDamage(this, damageSrc, damageAmount); if (damageAmount != 0.0F) { float f1 = this.getHealth(); this.getCombatTracker().trackDamage(damageSrc, f1, damageAmount); this.setHealth(f1 - damageAmount); // Forge: moved to fix MC-121048 this.setAbsorptionAmount(this.getAbsorptionAmount() - damageAmount); } } } /** * 1.8.9 */ public CombatTracker getCombatTracker() { return this._combatTracker; } @Nullable public EntityLivingBase getAttackingEntity() { if (this._combatTracker.getBestAttacker() != null) { return this._combatTracker.getBestAttacker(); } else if (this.attackingPlayer != null) { return this.attackingPlayer; } else { return this.revengeTarget != null ? this.revengeTarget : null; } } /** * Returns the maximum health of the entity (what it is able to regenerate up to, what it spawned with, etc) */ public final float getMaxHealth() { return (float)this.getEntityAttribute(SharedMonsterAttributes.MAX_HEALTH).getAttributeValue(); } /** * counts the amount of arrows stuck in the entity. getting hit by arrows increases this, used in rendering */ public final int getArrowCountInEntity() { return ((Integer)this.dataManager.get(ARROW_COUNT_IN_ENTITY)).intValue(); } /** * sets the amount of arrows stuck in the entity. used for rendering those */ public final void setArrowCountInEntity(int count) { this.dataManager.set(ARROW_COUNT_IN_ENTITY, Integer.valueOf(count)); } /** * Returns an integer indicating the end point of the swing animation, used by {@link #swingProgress} to provide a * progress indicator. Takes dig speed enchantments into account. */ private int getArmSwingAnimationEnd() { if (this.isPotionActive(MobEffects.HASTE)) { return 6 - (1 + this.getActivePotionEffect(MobEffects.HASTE).getAmplifier()); } else { return this.isPotionActive(MobEffects.MINING_FATIGUE) ? 6 + (1 + this.getActivePotionEffect(MobEffects.MINING_FATIGUE).getAmplifier()) * 2 : 6; } } public void swingArm(EnumHand hand) { ItemStack stack = this.getHeldItem(hand); if (!stack.isEmpty()) { if (stack.getItem().onEntitySwing(this, stack)) return; } if (!this.isSwingInProgress || this.swingProgressInt >= this.getArmSwingAnimationEnd() / 2 || this.swingProgressInt < 0) { this.swingProgressInt = -1; this.isSwingInProgress = true; this.swingingHand = hand; if (this.world instanceof WorldServer) { ((WorldServer)this.world).getEntityTracker().sendToTracking(this, new SPacketAnimation(this, hand == EnumHand.MAIN_HAND ? 0 : 3)); } } } /** * Handler for {@link World#setEntityState} */ @SideOnly(Side.CLIENT) public void handleStatusUpdate(byte id) { boolean flag = id == 33; boolean flag1 = id == 36; boolean flag2 = id == 37; if (id != 2 && !flag && !flag1 && !flag2) { if (id == 3) { SoundEvent soundevent1 = this.getDeathSound(); if (soundevent1 != null) { this.playSound(soundevent1, this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F); } this.setHealth(0.0F); this.onDeath(DamageSource.GENERIC); } else if (id == 30) { this.playSound(SoundEvents.ITEM_SHIELD_BREAK, 0.8F, 0.8F + this.world.rand.nextFloat() * 0.4F); } else if (id == 29) { this.playSound(SoundEvents.ITEM_SHIELD_BLOCK, 1.0F, 0.8F + this.world.rand.nextFloat() * 0.4F); } else { super.handleStatusUpdate(id); } } else { this.limbSwingAmount = 1.5F; this.hurtResistantTime = this.maxHurtResistantTime; this.maxHurtTime = 10; this.hurtTime = this.maxHurtTime; this.attackedAtYaw = 0.0F; if (flag) { this.playSound(SoundEvents.ENCHANT_THORNS_HIT, this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F); } DamageSource damagesource; if (flag2) { damagesource = DamageSource.ON_FIRE; } else if (flag1) { damagesource = DamageSource.DROWN; } else { damagesource = DamageSource.GENERIC; } SoundEvent soundevent = this.getHurtSound(damagesource); if (soundevent != null) { this.playSound(soundevent, this.getSoundVolume(), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F); } this.attackEntityFrom(DamageSource.GENERIC, 0.0F); } } /** * sets the dead flag. Used when you fall off the bottom of the world. */ protected void outOfWorld() { this.attackEntityFrom(DamageSource.OUT_OF_WORLD, 4.0F); } /** * Updates the arm swing progress counters and animation progress */ protected void updateArmSwingProgress() { int i = this.getArmSwingAnimationEnd(); if (this.isSwingInProgress) { ++this.swingProgressInt; if (this.swingProgressInt >= i) { this.swingProgressInt = 0; this.isSwingInProgress = false; } } else { this.swingProgressInt = 0; } this.swingProgress = (float)this.swingProgressInt / (float)i; } public IAttributeInstance getEntityAttribute(IAttribute attribute) { return this.getAttributeMap().getAttributeInstance(attribute); } /** * Returns this entity's attribute map (where all its attributes are stored) */ public AbstractAttributeMap getAttributeMap() { if (this.attributeMap == null) { this.attributeMap = new AttributeMap(); } return this.attributeMap; } /** * Get this Entity's EnumCreatureAttribute */ public EnumCreatureAttribute getCreatureAttribute() { return EnumCreatureAttribute.UNDEFINED; } public ItemStack getHeldItemMainhand() { return this.getItemStackFromSlot(EntityEquipmentSlot.MAINHAND); } public ItemStack getHeldItemOffhand() { return this.getItemStackFromSlot(EntityEquipmentSlot.OFFHAND); } public ItemStack getHeldItem(EnumHand hand) { if (hand == EnumHand.MAIN_HAND) { return this.getItemStackFromSlot(EntityEquipmentSlot.MAINHAND); } else if (hand == EnumHand.OFF_HAND) { return this.getItemStackFromSlot(EntityEquipmentSlot.OFFHAND); } else { throw new IllegalArgumentException("Invalid hand " + hand); } } public void setHeldItem(EnumHand hand, ItemStack stack) { if (hand == EnumHand.MAIN_HAND) { this.setItemStackToSlot(EntityEquipmentSlot.MAINHAND, stack); } else { if (hand != EnumHand.OFF_HAND) { throw new IllegalArgumentException("Invalid hand " + hand); } this.setItemStackToSlot(EntityEquipmentSlot.OFFHAND, stack); } } public boolean hasItemInSlot(EntityEquipmentSlot p_190630_1_) { return !this.getItemStackFromSlot(p_190630_1_).isEmpty(); } public abstract Iterable getArmorInventoryList(); public abstract ItemStack getItemStackFromSlot(EntityEquipmentSlot slotIn); public abstract void setItemStackToSlot(EntityEquipmentSlot slotIn, ItemStack stack); /** * Set sprinting switch for Entity. */ public void setSprinting(boolean sprinting) { super.setSprinting(sprinting); IAttributeInstance iattributeinstance = this.getEntityAttribute(SharedMonsterAttributes.MOVEMENT_SPEED); if (iattributeinstance.getModifier(SPRINTING_SPEED_BOOST_ID) != null) { iattributeinstance.removeModifier(SPRINTING_SPEED_BOOST); } if (sprinting) { iattributeinstance.applyModifier(SPRINTING_SPEED_BOOST); } } /** * Returns the volume for the sounds this mob makes. */ protected float getSoundVolume() { return 1.0F; } /** * Gets the pitch of living sounds in living entities. */ protected float getSoundPitch() { return this.isChild() ? (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.5F : (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F; } /** * Dead and sleeping entities cannot move */ protected boolean isMovementBlocked() { return this.getHealth() <= 0.0F; } /** * Moves the entity to a position out of the way of its mount. */ public void dismountEntity(Entity entityIn) { if (!(entityIn instanceof EntityBoat) && !(entityIn instanceof AbstractHorse)) { double d1 = entityIn.posX; double d13 = entityIn.getEntityBoundingBox().minY + (double)entityIn.height; double d14 = entityIn.posZ; EnumFacing enumfacing1 = entityIn.getAdjustedHorizontalFacing(); if (enumfacing1 != null) { EnumFacing enumfacing = enumfacing1.rotateY(); int[][] aint1 = new int[][] {{0, 1}, {0, -1}, { -1, 1}, { -1, -1}, {1, 1}, {1, -1}, { -1, 0}, {1, 0}, {0, 1}}; double d5 = Math.floor(this.posX) + 0.5D; double d6 = Math.floor(this.posZ) + 0.5D; double d7 = this.getEntityBoundingBox().maxX - this.getEntityBoundingBox().minX; double d8 = this.getEntityBoundingBox().maxZ - this.getEntityBoundingBox().minZ; AxisAlignedBB axisalignedbb = new AxisAlignedBB(d5 - d7 / 2.0D, entityIn.getEntityBoundingBox().minY, d6 - d8 / 2.0D, d5 + d7 / 2.0D, Math.floor(entityIn.getEntityBoundingBox().minY) + (double)this.height, d6 + d8 / 2.0D); for (int[] aint : aint1) { double d9 = (double)(enumfacing1.getFrontOffsetX() * aint[0] + enumfacing.getFrontOffsetX() * aint[1]); double d10 = (double)(enumfacing1.getFrontOffsetZ() * aint[0] + enumfacing.getFrontOffsetZ() * aint[1]); double d11 = d5 + d9; double d12 = d6 + d10; AxisAlignedBB axisalignedbb1 = axisalignedbb.offset(d9, 0.0D, d10); if (!this.world.collidesWithAnyBlock(axisalignedbb1)) { if (this.world.getBlockState(new BlockPos(d11, this.posY, d12)).isSideSolid(world, new BlockPos(d11, this.posY, d12), EnumFacing.UP)) { this.setPositionAndUpdate(d11, this.posY + 1.0D, d12); return; } BlockPos blockpos = new BlockPos(d11, this.posY - 1.0D, d12); if (this.world.getBlockState(blockpos).isSideSolid(world, blockpos, EnumFacing.UP) || this.world.getBlockState(blockpos).getMaterial() == Material.WATER) { d1 = d11; d13 = this.posY + 1.0D; d14 = d12; } } else if (!this.world.collidesWithAnyBlock(axisalignedbb1.offset(0.0D, 1.0D, 0.0D)) && this.world.getBlockState(new BlockPos(d11, this.posY + 1.0D, d12)).isSideSolid(world, new BlockPos(d11, this.posY + 1.0D, d12), EnumFacing.UP)) { d1 = d11; d13 = this.posY + 2.0D; d14 = d12; } } } this.setPositionAndUpdate(d1, d13, d14); } else { double d0 = (double)(this.width / 2.0F + entityIn.width / 2.0F) + 0.4D; float f; if (entityIn instanceof EntityBoat) { f = 0.0F; } else { f = ((float)Math.PI / 2F) * (float)(this.getPrimaryHand() == EnumHandSide.RIGHT ? -1 : 1); } float f1 = -MathHelper.sin(-this.rotationYaw * 0.017453292F - (float)Math.PI + f); float f2 = -MathHelper.cos(-this.rotationYaw * 0.017453292F - (float)Math.PI + f); double d2 = Math.abs(f1) > Math.abs(f2) ? d0 / (double)Math.abs(f1) : d0 / (double)Math.abs(f2); double d3 = this.posX + (double)f1 * d2; double d4 = this.posZ + (double)f2 * d2; this.setPosition(d3, entityIn.posY + (double)entityIn.height + 0.001D, d4); if (this.world.collidesWithAnyBlock(this.getEntityBoundingBox())) { this.setPosition(d3, entityIn.posY + (double)entityIn.height + 1.001D, d4); if (this.world.collidesWithAnyBlock(this.getEntityBoundingBox())) { this.setPosition(entityIn.posX, entityIn.posY + (double)this.height + 0.001D, entityIn.posZ); } } } } @SideOnly(Side.CLIENT) public boolean getAlwaysRenderNameTagForRender() { return this.getAlwaysRenderNameTag(); } protected float getJumpUpwardsMotion() { return 0.42F; } /** * Causes this entity to do an upwards motion (jumping). */ protected void jump() { this.motionY = (double)this.getJumpUpwardsMotion(); if (this.isPotionActive(MobEffects.JUMP_BOOST)) { this.motionY += (double)((float)(this.getActivePotionEffect(MobEffects.JUMP_BOOST).getAmplifier() + 1) * 0.1F); } if (this.isSprinting()) { float f = this.rotationYaw * 0.017453292F; this.motionX -= (double)(MathHelper.sin(f) * 0.2F); this.motionZ += (double)(MathHelper.cos(f) * 0.2F); } this.isAirBorne = true; net.minecraftforge.common.ForgeHooks.onLivingJump(this); } /** * Handles the jump when the entity is in water */ protected void handleJumpWater() { this.motionY += 0.03999999910593033D * this.getEntityAttribute(SWIM_SPEED).getAttributeValue(); } protected void handleJumpLava() { this.motionY += 0.03999999910593033D * this.getEntityAttribute(SWIM_SPEED).getAttributeValue(); } protected float getWaterSlowDown() { return 0.8F; } public void travel(float strafe, float vertical, float forward) { if (this.isServerWorld() || this.canPassengerSteer()) { if (!this.isInWater() || this instanceof EntityPlayer && ((EntityPlayer)this).capabilities.isFlying) { if (!this.isInLava() || this instanceof EntityPlayer && ((EntityPlayer)this).capabilities.isFlying) { if (this.isElytraFlying()) { if (this.motionY > -0.5D) { this.fallDistance = 1.0F; } Vec3d vec3d = this.getLookVec(); float f = this.rotationPitch * 0.017453292F; double d6 = Math.sqrt(vec3d.x * vec3d.x + vec3d.z * vec3d.z); double d8 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); double d1 = vec3d.lengthVector(); float f4 = MathHelper.cos(f); f4 = (float)((double)f4 * (double)f4 * Math.min(1.0D, d1 / 0.4D)); this.motionY += -0.08D + (double)f4 * 0.06D; if (this.motionY < 0.0D && d6 > 0.0D) { double d2 = this.motionY * -0.1D * (double)f4; this.motionY += d2; this.motionX += vec3d.x * d2 / d6; this.motionZ += vec3d.z * d2 / d6; } if (f < 0.0F) { double d10 = d8 * (double)(-MathHelper.sin(f)) * 0.04D; this.motionY += d10 * 3.2D; this.motionX -= vec3d.x * d10 / d6; this.motionZ -= vec3d.z * d10 / d6; } if (d6 > 0.0D) { this.motionX += (vec3d.x / d6 * d8 - this.motionX) * 0.1D; this.motionZ += (vec3d.z / d6 * d8 - this.motionZ) * 0.1D; } this.motionX *= 0.9900000095367432D; this.motionY *= 0.9800000190734863D; this.motionZ *= 0.9900000095367432D; this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ); if (this.collidedHorizontally && !this.world.isRemote) { double d11 = Math.sqrt(this.motionX * this.motionX + this.motionZ * this.motionZ); double d3 = d8 - d11; float f5 = (float)(d3 * 10.0D - 3.0D); if (f5 > 0.0F) { this.playSound(this.getFallSound((int)f5), 1.0F, 1.0F); this.attackEntityFrom(DamageSource.FLY_INTO_WALL, f5); } } if (this.onGround && !this.world.isRemote) { this.setFlag(7, false); } } else { float f6 = 0.91F; BlockPos.PooledMutableBlockPos blockpos$pooledmutableblockpos = BlockPos.PooledMutableBlockPos.retain(this.posX, this.getEntityBoundingBox().minY - 1.0D, this.posZ); if (this.onGround) { IBlockState underState = this.world.getBlockState(blockpos$pooledmutableblockpos); f6 = underState.getBlock().getSlipperiness(underState, this.world, blockpos$pooledmutableblockpos, this) * 0.91F; } float f7 = 0.16277136F / (f6 * f6 * f6); float f8; if (this.onGround) { f8 = this.getAIMoveSpeed() * f7; } else { f8 = this.jumpMovementFactor; } this.moveRelative(strafe, vertical, forward, f8); f6 = 0.91F; if (this.onGround) { IBlockState underState = this.world.getBlockState(blockpos$pooledmutableblockpos.setPos(this.posX, this.getEntityBoundingBox().minY - 1.0D, this.posZ)); f6 = underState.getBlock().getSlipperiness(underState, this.world, blockpos$pooledmutableblockpos, this) * 0.91F; } if (this.isOnLadder()) { float f9 = 0.15F; this.motionX = MathHelper.clamp(this.motionX, -0.15000000596046448D, 0.15000000596046448D); this.motionZ = MathHelper.clamp(this.motionZ, -0.15000000596046448D, 0.15000000596046448D); this.fallDistance = 0.0F; if (this.motionY < -0.15D) { this.motionY = -0.15D; } boolean flag = this.isSneaking() && this instanceof EntityPlayer; if (flag && this.motionY < 0.0D) { this.motionY = 0.0D; } } this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ); if (this.collidedHorizontally && this.isOnLadder()) { this.motionY = 0.2D; } if (this.isPotionActive(MobEffects.LEVITATION)) { this.motionY += (0.05D * (double)(this.getActivePotionEffect(MobEffects.LEVITATION).getAmplifier() + 1) - this.motionY) * 0.2D; } else { blockpos$pooledmutableblockpos.setPos(this.posX, 0.0D, this.posZ); if (!this.world.isRemote || this.world.isBlockLoaded(blockpos$pooledmutableblockpos) && this.world.getChunkFromBlockCoords(blockpos$pooledmutableblockpos).isLoaded()) { if (!this.hasNoGravity()) { this.motionY -= 0.08D; } } else if (this.posY > 0.0D) { this.motionY = -0.1D; } else { this.motionY = 0.0D; } } this.motionY *= 0.9800000190734863D; this.motionX *= (double)f6; this.motionZ *= (double)f6; blockpos$pooledmutableblockpos.release(); } } else { double d4 = this.posY; 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; if (!this.hasNoGravity()) { this.motionY -= 0.02D; } if (this.collidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + d4, this.motionZ)) { this.motionY = 0.30000001192092896D; } } } else { double d0 = this.posY; float f1 = this.getWaterSlowDown(); float f2 = 0.02F; float f3 = (float)EnchantmentHelper.getDepthStriderModifier(this); if (f3 > 3.0F) { f3 = 3.0F; } if (!this.onGround) { f3 *= 0.5F; } if (f3 > 0.0F) { f1 += (0.54600006F - f1) * f3 / 3.0F; f2 += (this.getAIMoveSpeed() - f2) * f3 / 3.0F; } this.moveRelative(strafe, vertical, forward, f2); this.move(MoverType.SELF, this.motionX, this.motionY, this.motionZ); this.motionX *= (double)f1; this.motionY *= 0.800000011920929D; this.motionZ *= (double)f1; if (!this.hasNoGravity()) { this.motionY -= 0.02D; } if (this.collidedHorizontally && this.isOffsetPositionInLiquid(this.motionX, this.motionY + 0.6000000238418579D - this.posY + d0, this.motionZ)) { this.motionY = 0.30000001192092896D; } } } this.prevLimbSwingAmount = this.limbSwingAmount; double d5 = this.posX - this.prevPosX; double d7 = this.posZ - this.prevPosZ; double d9 = this instanceof net.minecraft.entity.passive.EntityFlying ? this.posY - this.prevPosY : 0.0D; float f10 = MathHelper.sqrt(d5 * d5 + d9 * d9 + d7 * d7) * 4.0F; if (f10 > 1.0F) { f10 = 1.0F; } this.limbSwingAmount += (f10 - this.limbSwingAmount) * 0.4F; this.limbSwing += this.limbSwingAmount; } /** * the movespeed used for the new AI system */ public float getAIMoveSpeed() { return this.landMovementFactor; } /** * set the movespeed used for the new AI system */ public void setAIMoveSpeed(float speedIn) { this.landMovementFactor = speedIn; } public boolean attackEntityAsMob(Entity entityIn) { this.setLastAttackedEntity(entityIn); return false; } /** * Returns whether player is sleeping or not */ public boolean isPlayerSleeping() { return false; } /** * Called to update the entity's position/logic. */ public void onUpdate() { if (net.minecraftforge.common.ForgeHooks.onLivingUpdate(this)) return; super.onUpdate(); this.updateActiveHand(); if (!this.world.isRemote) { int i = this.getArrowCountInEntity(); if (i > 0) { if (this.arrowHitTimer <= 0) { this.arrowHitTimer = 20 * (30 - i); } --this.arrowHitTimer; if (this.arrowHitTimer <= 0) { this.setArrowCountInEntity(i - 1); } } for (EntityEquipmentSlot entityequipmentslot : EntityEquipmentSlot.values()) { ItemStack itemstack; switch (entityequipmentslot.getSlotType()) { case HAND: itemstack = this.handInventory.get(entityequipmentslot.getIndex()); break; case ARMOR: itemstack = this.armorArray.get(entityequipmentslot.getIndex()); break; default: continue; } ItemStack itemstack1 = this.getItemStackFromSlot(entityequipmentslot); if (!ItemStack.areItemStacksEqual(itemstack1, itemstack)) { if (!ItemStack.areItemStacksEqualUsingNBTShareTag(itemstack1, itemstack)) ((WorldServer)this.world).getEntityTracker().sendToTracking(this, new SPacketEntityEquipment(this.getEntityId(), entityequipmentslot, itemstack1)); net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.living.LivingEquipmentChangeEvent(this, entityequipmentslot, itemstack, itemstack1)); if (!itemstack.isEmpty()) { this.getAttributeMap().removeAttributeModifiers(itemstack.getAttributeModifiers(entityequipmentslot)); } if (!itemstack1.isEmpty()) { this.getAttributeMap().applyAttributeModifiers(itemstack1.getAttributeModifiers(entityequipmentslot)); } switch (entityequipmentslot.getSlotType()) { case HAND: this.handInventory.set(entityequipmentslot.getIndex(), itemstack1.isEmpty() ? ItemStack.EMPTY : itemstack1.copy()); break; case ARMOR: this.armorArray.set(entityequipmentslot.getIndex(), itemstack1.isEmpty() ? ItemStack.EMPTY : itemstack1.copy()); } } } if (this.ticksExisted % 20 == 0) { this.getCombatTracker().reset(); } if (!this.glowing) { boolean flag = this.isPotionActive(MobEffects.GLOWING); if (this.getFlag(6) != flag) { this.setFlag(6, flag); } } } this.onLivingUpdate(); double d0 = this.posX - this.prevPosX; double d1 = this.posZ - this.prevPosZ; float f3 = (float)(d0 * d0 + d1 * d1); float f4 = this.renderYawOffset; float f5 = 0.0F; this.prevOnGroundSpeedFactor = this.onGroundSpeedFactor; float f = 0.0F; if (f3 > 0.0025000002F) { f = 1.0F; f5 = (float)Math.sqrt((double)f3) * 3.0F; float f1 = (float)MathHelper.atan2(d1, d0) * (180F / (float)Math.PI) - 90.0F; float f2 = MathHelper.abs(MathHelper.wrapDegrees(this.rotationYaw) - f1); if (95.0F < f2 && f2 < 265.0F) { f4 = f1 - 180.0F; } else { f4 = f1; } } if (this.swingProgress > 0.0F) { f4 = this.rotationYaw; } if (!this.onGround) { f = 0.0F; } this.onGroundSpeedFactor += (f - this.onGroundSpeedFactor) * 0.3F; this.world.profiler.startSection("headTurn"); f5 = this.updateDistance(f4, f5); this.world.profiler.endSection(); this.world.profiler.startSection("rangeChecks"); while (this.rotationYaw - this.prevRotationYaw < -180.0F) { this.prevRotationYaw -= 360.0F; } while (this.rotationYaw - this.prevRotationYaw >= 180.0F) { this.prevRotationYaw += 360.0F; } while (this.renderYawOffset - this.prevRenderYawOffset < -180.0F) { this.prevRenderYawOffset -= 360.0F; } while (this.renderYawOffset - this.prevRenderYawOffset >= 180.0F) { this.prevRenderYawOffset += 360.0F; } while (this.rotationPitch - this.prevRotationPitch < -180.0F) { this.prevRotationPitch -= 360.0F; } while (this.rotationPitch - this.prevRotationPitch >= 180.0F) { this.prevRotationPitch += 360.0F; } while (this.rotationYawHead - this.prevRotationYawHead < -180.0F) { this.prevRotationYawHead -= 360.0F; } while (this.rotationYawHead - this.prevRotationYawHead >= 180.0F) { this.prevRotationYawHead += 360.0F; } this.world.profiler.endSection(); this.movedDistance += f5; if (this.isElytraFlying()) { ++this.ticksElytraFlying; } else { this.ticksElytraFlying = 0; } } protected float updateDistance(float p_110146_1_, float p_110146_2_) { float f = MathHelper.wrapDegrees(p_110146_1_ - this.renderYawOffset); this.renderYawOffset += f * 0.3F; float f1 = MathHelper.wrapDegrees(this.rotationYaw - this.renderYawOffset); boolean flag = f1 < -90.0F || f1 >= 90.0F; if (f1 < -75.0F) { f1 = -75.0F; } if (f1 >= 75.0F) { f1 = 75.0F; } this.renderYawOffset = this.rotationYaw - f1; if (f1 * f1 > 2500.0F) { this.renderYawOffset += f1 * 0.2F; } if (flag) { p_110146_2_ *= -1.0F; } return p_110146_2_; } /** * 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() { if (this.jumpTicks > 0) { --this.jumpTicks; } if (this.newPosRotationIncrements > 0 && !this.canPassengerSteer()) { double d0 = this.posX + (this.interpTargetX - this.posX) / (double)this.newPosRotationIncrements; double d1 = this.posY + (this.interpTargetY - this.posY) / (double)this.newPosRotationIncrements; double d2 = this.posZ + (this.interpTargetZ - this.posZ) / (double)this.newPosRotationIncrements; double d3 = MathHelper.wrapDegrees(this.interpTargetYaw - (double)this.rotationYaw); this.rotationYaw = (float)((double)this.rotationYaw + d3 / (double)this.newPosRotationIncrements); this.rotationPitch = (float)((double)this.rotationPitch + (this.interpTargetPitch - (double)this.rotationPitch) / (double)this.newPosRotationIncrements); --this.newPosRotationIncrements; this.setPosition(d0, d1, d2); this.setRotation(this.rotationYaw, this.rotationPitch); } else if (!this.isServerWorld()) { this.motionX *= 0.98D; this.motionY *= 0.98D; this.motionZ *= 0.98D; } if (Math.abs(this.motionX) < 0.003D) { this.motionX = 0.0D; } if (Math.abs(this.motionY) < 0.003D) { this.motionY = 0.0D; } if (Math.abs(this.motionZ) < 0.003D) { this.motionZ = 0.0D; } this.world.profiler.startSection("ai"); if (this.isMovementBlocked()) { this.isJumping = false; this.moveStrafing = 0.0F; this.moveForward = 0.0F; this.randomYawVelocity = 0.0F; } else if (this.isServerWorld()) { this.world.profiler.startSection("newAi"); this.updateEntityActionState(); this.world.profiler.endSection(); } this.world.profiler.endSection(); this.world.profiler.startSection("jump"); if (this.isJumping) { if (this.isInWater()) { this.handleJumpWater(); } else if (this.isInLava()) { this.handleJumpLava(); } else if (this.onGround && this.jumpTicks == 0) { this.jump(); this.jumpTicks = 10; } } else { this.jumpTicks = 0; } this.world.profiler.endSection(); this.world.profiler.startSection("travel"); this.moveStrafing *= 0.98F; this.moveForward *= 0.98F; this.randomYawVelocity *= 0.9F; this.updateElytra(); this.travel(this.moveStrafing, this.moveVertical, this.moveForward); this.world.profiler.endSection(); this.world.profiler.startSection("push"); this.collideWithNearbyEntities(); this.world.profiler.endSection(); } /** * Called each tick. Updates state for the elytra. */ private void updateElytra() { boolean flag = this.getFlag(7); if (flag && !this.onGround && !this.isRiding()) { ItemStack itemstack = this.getItemStackFromSlot(EntityEquipmentSlot.CHEST); if (itemstack.getItem() == Items.ELYTRA && ItemElytra.isUsable(itemstack)) { flag = true; if (!this.world.isRemote && (this.ticksElytraFlying + 1) % 20 == 0) { itemstack.damageItem(1, this); } } else { flag = false; } } else { flag = false; } if (!this.world.isRemote) { this.setFlag(7, flag); } } protected void updateEntityActionState() { } protected void collideWithNearbyEntities() { List list = this.world.getEntitiesInAABBexcluding(this, this.getEntityBoundingBox(), EntitySelectors.getTeamCollisionPredicate(this)); if (!list.isEmpty()) { int i = this.world.getGameRules().getInt("maxEntityCramming"); if (i > 0 && list.size() > i - 1 && this.rand.nextInt(4) == 0) { int j = 0; for (int k = 0; k < list.size(); ++k) { if (!((Entity)list.get(k)).isRiding()) { ++j; } } if (j > i - 1) { this.attackEntityFrom(DamageSource.CRAMMING, 6.0F); } } for (int l = 0; l < list.size(); ++l) { Entity entity = list.get(l); this.collideWithEntity(entity); } } } protected void collideWithEntity(Entity entityIn) { entityIn.applyEntityCollision(this); } /** * Dismounts this entity from the entity it is riding. */ public void dismountRidingEntity() { Entity entity = this.getRidingEntity(); super.dismountRidingEntity(); if (entity != null && entity != this.getRidingEntity() && !this.world.isRemote) { this.dismountEntity(entity); } } /** * Handles updating while riding another entity */ public void updateRidden() { super.updateRidden(); this.prevOnGroundSpeedFactor = this.onGroundSpeedFactor; this.onGroundSpeedFactor = 0.0F; this.fallDistance = 0.0F; } /** * Set the position and rotation values directly without any clamping. */ @SideOnly(Side.CLIENT) public void setPositionAndRotationDirect(double x, double y, double z, float yaw, float pitch, int posRotationIncrements, boolean teleport) { this.interpTargetX = x; this.interpTargetY = y; this.interpTargetZ = z; this.interpTargetYaw = (double)yaw; this.interpTargetPitch = (double)pitch; this.newPosRotationIncrements = posRotationIncrements; } public void setJumping(boolean jumping) { this.isJumping = jumping; } /** * Called when the entity picks up an item. */ public void onItemPickup(Entity entityIn, int quantity) { if (!entityIn.isDead && !this.world.isRemote) { EntityTracker entitytracker = ((WorldServer)this.world).getEntityTracker(); if (entityIn instanceof EntityItem || entityIn instanceof EntityArrow || entityIn instanceof EntityXPOrb) { entitytracker.sendToTracking(entityIn, new SPacketCollectItem(entityIn.getEntityId(), this.getEntityId(), quantity)); } } } /** * returns true if the entity provided in the argument can be seen. (Raytrace) */ public boolean canEntityBeSeen(Entity entityIn) { return this.world.rayTraceBlocks(new Vec3d(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ), new Vec3d(entityIn.posX, entityIn.posY + (double)entityIn.getEyeHeight(), entityIn.posZ), false, true, false) == null; } /** * interpolated look vector */ public Vec3d getLook(float partialTicks) { if (partialTicks == 1.0F) { return this.getVectorForRotation(this.rotationPitch, this.rotationYawHead); } else { float f = this.prevRotationPitch + (this.rotationPitch - this.prevRotationPitch) * partialTicks; float f1 = this.prevRotationYawHead + (this.rotationYawHead - this.prevRotationYawHead) * partialTicks; return this.getVectorForRotation(f, f1); } } /** * Gets the progression of the swing animation, ranges from 0.0 to 1.0. */ @SideOnly(Side.CLIENT) public float getSwingProgress(float partialTickTime) { float f = this.swingProgress - this.prevSwingProgress; if (f < 0.0F) { ++f; } return this.prevSwingProgress + f * partialTickTime; } /** * Returns whether the entity is in a server world */ public boolean isServerWorld() { return !this.world.isRemote; } /** * Returns true if other Entities should be prevented from moving through this Entity. */ public boolean canBeCollidedWith() { return !this.isDead; } /** * Returns true if this entity should push and be pushed by other entities when colliding. */ public boolean canBePushed() { return this.isEntityAlive() && !this.isOnLadder(); } /** * Marks this entity's velocity as changed, so that it can be re-synced with the client later */ protected void markVelocityChanged() { this.velocityChanged = this.rand.nextDouble() >= this.getEntityAttribute(SharedMonsterAttributes.KNOCKBACK_RESISTANCE).getAttributeValue(); } public float getRotationYawHead() { return this.rotationYawHead; } /** * Sets the head's yaw rotation of the entity. */ public void setRotationYawHead(float rotation) { this.rotationYawHead = rotation; } /** * Set the render yaw offset */ public void setRenderYawOffset(float offset) { this.renderYawOffset = offset; } /** * Returns the amount of health added by the Absorption effect. */ public float getAbsorptionAmount() { return this.absorptionAmount; } public void setAbsorptionAmount(float amount) { if (amount < 0.0F) { amount = 0.0F; } this.absorptionAmount = amount; } /** * Sends an ENTER_COMBAT packet to the client */ public void sendEnterCombat() { } /** * Sends an END_COMBAT packet to the client */ public void sendEndCombat() { } protected void markPotionsDirty() { this.potionsNeedUpdate = true; } /*** * Removes all potion effects that have curativeItem as a curative item for its effect * @param curativeItem The itemstack we are using to cure potion effects */ public void curePotionEffects(ItemStack curativeItem) { if (world.isRemote) return; Iterator iterator = this.activePotionsMap.values().iterator(); while (iterator.hasNext()) { PotionEffect effect = iterator.next(); if (effect.isCurativeItem(curativeItem)) { onFinishedPotionEffect(effect); iterator.remove(); this.potionsNeedUpdate = true; } } } /** * Returns true if the entity's rider (EntityPlayer) should face forward when mounted. * currently only used in vanilla code by pigs. * * @param player The player who is riding the entity. * @return If the player should orient the same direction as this entity. */ public boolean shouldRiderFaceForward(EntityPlayer player) { return this instanceof net.minecraft.entity.passive.EntityPig; } public abstract EnumHandSide getPrimaryHand(); public boolean isHandActive() { return (((Byte)this.dataManager.get(HAND_STATES)).byteValue() & 1) > 0; } public EnumHand getActiveHand() { return (((Byte)this.dataManager.get(HAND_STATES)).byteValue() & 2) > 0 ? EnumHand.OFF_HAND : EnumHand.MAIN_HAND; } protected void updateActiveHand() { if (this.isHandActive()) { ItemStack itemstack = this.getHeldItem(this.getActiveHand()); if (itemstack == this.activeItemStack) { if (!this.activeItemStack.isEmpty()) { activeItemStackUseCount = net.minecraftforge.event.ForgeEventFactory.onItemUseTick(this, activeItemStack, activeItemStackUseCount); if (activeItemStackUseCount > 0) activeItemStack.getItem().onUsingTick(activeItemStack, this, activeItemStackUseCount); } if (this.getItemInUseCount() <= 25 && this.getItemInUseCount() % 4 == 0) { this.updateItemUse(this.activeItemStack, 5); } if (--this.activeItemStackUseCount <= 0 && !this.world.isRemote) { this.onItemUseFinish(); } } else { this.resetActiveHand(); } } } public void setActiveHand(EnumHand hand) { ItemStack itemstack = this.getHeldItem(hand); if (!itemstack.isEmpty() && !this.isHandActive()) { int duration = net.minecraftforge.event.ForgeEventFactory.onItemUseStart(this, itemstack, itemstack.getMaxItemUseDuration()); if (duration <= 0) return; this.activeItemStack = itemstack; this.activeItemStackUseCount = duration; if (!this.world.isRemote) { int i = 1; if (hand == EnumHand.OFF_HAND) { i |= 2; } this.dataManager.set(HAND_STATES, Byte.valueOf((byte)i)); } } } public void notifyDataManagerChange(DataParameter key) { super.notifyDataManagerChange(key); if (HAND_STATES.equals(key) && this.world.isRemote) { if (this.isHandActive() && this.activeItemStack.isEmpty()) { this.activeItemStack = this.getHeldItem(this.getActiveHand()); if (!this.activeItemStack.isEmpty()) { this.activeItemStackUseCount = this.activeItemStack.getMaxItemUseDuration(); } } else if (!this.isHandActive() && !this.activeItemStack.isEmpty()) { this.activeItemStack = ItemStack.EMPTY; this.activeItemStackUseCount = 0; } } } /** * Plays sounds and makes particles for item in use state */ protected void updateItemUse(ItemStack stack, int eatingParticleCount) { if (!stack.isEmpty() && this.isHandActive()) { if (stack.getItemUseAction() == EnumAction.DRINK) { this.playSound(SoundEvents.ENTITY_GENERIC_DRINK, 0.5F, this.world.rand.nextFloat() * 0.1F + 0.9F); } if (stack.getItemUseAction() == EnumAction.EAT) { for (int i = 0; i < eatingParticleCount; ++i) { Vec3d vec3d = new Vec3d(((double)this.rand.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D); vec3d = vec3d.rotatePitch(-this.rotationPitch * 0.017453292F); vec3d = vec3d.rotateYaw(-this.rotationYaw * 0.017453292F); double d0 = (double)(-this.rand.nextFloat()) * 0.6D - 0.3D; Vec3d vec3d1 = new Vec3d(((double)this.rand.nextFloat() - 0.5D) * 0.3D, d0, 0.6D); vec3d1 = vec3d1.rotatePitch(-this.rotationPitch * 0.017453292F); vec3d1 = vec3d1.rotateYaw(-this.rotationYaw * 0.017453292F); vec3d1 = vec3d1.addVector(this.posX, this.posY + (double)this.getEyeHeight(), this.posZ); if (stack.getHasSubtypes()) { this.world.spawnParticle(EnumParticleTypes.ITEM_CRACK, vec3d1.x, vec3d1.y, vec3d1.z, vec3d.x, vec3d.y + 0.05D, vec3d.z, Item.getIdFromItem(stack.getItem()), stack.getMetadata()); } else { this.world.spawnParticle(EnumParticleTypes.ITEM_CRACK, vec3d1.x, vec3d1.y, vec3d1.z, vec3d.x, vec3d.y + 0.05D, vec3d.z, Item.getIdFromItem(stack.getItem())); } } this.playSound(SoundEvents.ENTITY_GENERIC_EAT, 0.5F + 0.5F * (float)this.rand.nextInt(2), (this.rand.nextFloat() - this.rand.nextFloat()) * 0.2F + 1.0F); } } } /** * Used for when item use count runs out, ie: eating completed */ protected void onItemUseFinish() { if (!this.activeItemStack.isEmpty() && this.isHandActive()) { this.updateItemUse(this.activeItemStack, 16); ItemStack activeItemStackCopy = this.activeItemStack.copy(); ItemStack itemstack = this.activeItemStack.onItemUseFinish(this.world, this); itemstack = net.minecraftforge.event.ForgeEventFactory.onItemUseFinish(this, activeItemStackCopy, getItemInUseCount(), itemstack); this.setHeldItem(this.getActiveHand(), itemstack); this.resetActiveHand(); } } public ItemStack getActiveItemStack() { return this.activeItemStack; } public int getItemInUseCount() { return this.activeItemStackUseCount; } public int getItemInUseMaxCount() { return this.isHandActive() ? this.activeItemStack.getMaxItemUseDuration() - this.getItemInUseCount() : 0; } public void stopActiveHand() { if (!this.activeItemStack.isEmpty()) { if (!net.minecraftforge.event.ForgeEventFactory.onUseItemStop(this, activeItemStack, this.getItemInUseCount())) this.activeItemStack.onPlayerStoppedUsing(this.world, this, this.getItemInUseCount()); } this.resetActiveHand(); } public void resetActiveHand() { if (!this.world.isRemote) { this.dataManager.set(HAND_STATES, Byte.valueOf((byte)0)); } this.activeItemStack = ItemStack.EMPTY; this.activeItemStackUseCount = 0; } public boolean isActiveItemStackBlocking() { if (this.isHandActive() && !this.activeItemStack.isEmpty()) { Item item = this.activeItemStack.getItem(); if (item.getItemUseAction(this.activeItemStack) != EnumAction.BLOCK) { return false; } else { return item.getMaxItemUseDuration(this.activeItemStack) - this.activeItemStackUseCount >= 5; } } else { return false; } } public boolean isElytraFlying() { return this.getFlag(7); } @SideOnly(Side.CLIENT) public int getTicksElytraFlying() { return this.ticksElytraFlying; } /** * Teleports the entity to the specified location. Used for Enderman and Chorus Fruit teleportation */ public boolean attemptTeleport(double x, double y, double z) { double d0 = this.posX; double d1 = this.posY; double d2 = this.posZ; this.posX = x; this.posY = y; this.posZ = z; boolean flag = false; BlockPos blockpos = new BlockPos(this); World world = this.world; Random random = this.getRNG(); if (world.isBlockLoaded(blockpos)) { boolean flag1 = false; while (!flag1 && blockpos.getY() > 0) { BlockPos blockpos1 = blockpos.down(); IBlockState iblockstate = world.getBlockState(blockpos1); if (iblockstate.getMaterial().blocksMovement()) { flag1 = true; } else { --this.posY; blockpos = blockpos1; } } if (flag1) { this.setPositionAndUpdate(this.posX, this.posY, this.posZ); if (world.getCollisionBoxes(this, this.getEntityBoundingBox()).isEmpty() && !world.containsAnyLiquid(this.getEntityBoundingBox())) { flag = true; } } } if (!flag) { this.setPositionAndUpdate(d0, d1, d2); return false; } else { int i = 128; for (int j = 0; j < 128; ++j) { double d6 = (double)j / 127.0D; float f = (random.nextFloat() - 0.5F) * 0.2F; float f1 = (random.nextFloat() - 0.5F) * 0.2F; float f2 = (random.nextFloat() - 0.5F) * 0.2F; double d3 = d0 + (this.posX - d0) * d6 + (random.nextDouble() - 0.5D) * (double)this.width * 2.0D; double d4 = d1 + (this.posY - d1) * d6 + random.nextDouble() * (double)this.height; double d5 = d2 + (this.posZ - d2) * d6 + (random.nextDouble() - 0.5D) * (double)this.width * 2.0D; world.spawnParticle(EnumParticleTypes.PORTAL, d3, d4, d5, (double)f, (double)f1, (double)f2); } if (this instanceof EntityCreature) { ((EntityCreature)this).getNavigator().clearPath(); } return true; } } /** * Returns false if the entity is an armor stand. Returns true for all other entity living bases. */ public boolean canBeHitWithPotion() { return true; } // FORGE private final net.minecraftforge.items.IItemHandlerModifiable handHandler = new net.minecraftforge.items.wrapper.EntityHandsInvWrapper(this); private final net.minecraftforge.items.IItemHandlerModifiable armorHandler = new net.minecraftforge.items.wrapper.EntityArmorInvWrapper(this); private final net.minecraftforge.items.IItemHandler joinedHandler = new net.minecraftforge.items.wrapper.CombinedInvWrapper(armorHandler, handHandler); @SuppressWarnings("unchecked") @Override @Nullable public T getCapability(net.minecraftforge.common.capabilities.Capability capability, @Nullable net.minecraft.util.EnumFacing facing) { if (capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { if (facing == null) return (T) joinedHandler; else if (facing.getAxis().isVertical()) return (T) handHandler; else if (facing.getAxis().isHorizontal()) return (T) armorHandler; } return super.getCapability(capability, facing); } @Override public boolean hasCapability(net.minecraftforge.common.capabilities.Capability capability, @Nullable net.minecraft.util.EnumFacing facing) { return capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY || super.hasCapability(capability, facing); } public boolean attackable() { return true; } @SideOnly(Side.CLIENT) public void setPartying(BlockPos pos, boolean p_191987_2_) { } @Override public void moveRelative(float strafe, float up, float forward, float friction) { float f = strafe * strafe + up * up + forward * forward; if (f >= 1.0E-4F) { f = MathHelper.sqrt(f); if (f < 1.0F) f = 1.0F; f = friction / f; strafe = strafe * f; up = up * f; forward = forward * f; if(this.isInWater() || this.isInLava()) { strafe = strafe * (float)this.getEntityAttribute(SWIM_SPEED).getAttributeValue(); up = up * (float)this.getEntityAttribute(SWIM_SPEED).getAttributeValue(); forward = forward * (float)this.getEntityAttribute(SWIM_SPEED).getAttributeValue(); } float f1 = MathHelper.sin(this.rotationYaw * 0.017453292F); float f2 = MathHelper.cos(this.rotationYaw * 0.017453292F); this.motionX += (double)(strafe * f2 - forward * f1); this.motionY += (double)up; this.motionZ += (double)(forward * f2 + strafe * f1); } } }