use of org.spongepowered.common.SpongeImpl in project SpongeCommon by SpongePowered.
the class MixinEntityPlayer method attackTargetEntityWithCurrentItem.
/**
* @author gabizou - April 8th, 2016
* @author gabizou - April 11th, 2016 - Update for 1.9 - This enitre method was rewritten
*
* @reason Rewrites the attackTargetEntityWithCurrentItem to throw an {@link AttackEntityEvent} prior
* to the ensuing {@link DamageEntityEvent}. This should cover all cases where players are
* attacking entities and those entities override {@link EntityLivingBase#attackEntityFrom(DamageSource, float)}
* and effectively bypass our damage event hooks.
*
* LVT Rename Table:
* float f | damage |
* float f1 | enchantmentDamage |
* float f2 | attackStrength |
* boolean flag | isStrongAttack |
* boolean flag1 | isSprintingAttack |
* boolean flag2 | isCriticalAttack | Whether critical particles will spawn and of course, multiply the output damage
* boolean flag3 | isSweapingAttack | Whether the player is sweaping an attack and will deal AoE damage
* int i | knockbackModifier | The knockback modifier, must be set from the event after it has been thrown
* float f4 | targetOriginalHealth | This is initially set as the entity original health
* boolean flag4 | litEntityOnFire | This is an internal flag to where if the attack failed, the entity is no longer set on fire
* int j | fireAspectModifier | Literally just to check that the weapon used has fire aspect enchantments
* double d0 | distanceWalkedDelta | This checks that the distance walked delta is more than the normal walking speed to evaluate if you're making a sweaping attack
* double d1 | targetMotionX | Current target entity motion x vector
* double d2 | targetMotionY | Current target entity motion y vector
* double d3 | targetMotionZ | Current target entity motion z vector
* boolean flag5 | attackSucceeded | Whether the attack event succeeded
*
* @param targetEntity The target entity
*/
@Overwrite
public void attackTargetEntityWithCurrentItem(Entity targetEntity) {
// Sponge Start - Add SpongeImpl hook to override in forge as necessary
if (!SpongeImplHooks.checkAttackEntity((EntityPlayer) (Object) this, targetEntity)) {
return;
}
// Sponge End
if (targetEntity.canBeAttackedWithItem()) {
if (!targetEntity.hitByEntity((EntityPlayer) (Object) this)) {
// Sponge Start - Prepare our event values
// float damage = (float) this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getAttributeValue();
final double originalBaseDamage = this.getEntityAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).getAttributeValue();
float damage = (float) originalBaseDamage;
// Sponge End
float enchantmentDamage = 0.0F;
// Spogne Start - Redirect getting enchantments for our damage event handlers
// if (targetEntity instanceof EntityLivingBase) {
// enchantmentDamage = EnchantmentHelper.getModifierForCreature(this.getHeldItemMainhand(), ((EntityLivingBase) targetEntity).getCreatureAttribute());
// } else {
// enchantmentDamage = EnchantmentHelper.getModifierForCreature(this.getHeldItemMainhand(), EnumCreatureAttribute.UNDEFINED);
// }
float attackStrength = this.getCooledAttackStrength(0.5F);
final List<ModifierFunction<DamageModifier>> originalFunctions = new ArrayList<>();
final EnumCreatureAttribute creatureAttribute = targetEntity instanceof EntityLivingBase ? ((EntityLivingBase) targetEntity).getCreatureAttribute() : EnumCreatureAttribute.UNDEFINED;
final List<DamageFunction> enchantmentModifierFunctions = DamageEventHandler.createAttackEnchantmentFunction(this.getHeldItemMainhand(), creatureAttribute, attackStrength);
// This is kept for the post-damage event handling
final List<DamageModifier> enchantmentModifiers = enchantmentModifierFunctions.stream().map(ModifierFunction::getModifier).collect(Collectors.toList());
enchantmentDamage = (float) enchantmentModifierFunctions.stream().map(ModifierFunction::getFunction).mapToDouble(function -> function.applyAsDouble(originalBaseDamage)).sum();
originalFunctions.addAll(enchantmentModifierFunctions);
// Sponge End
originalFunctions.add(DamageEventHandler.provideCooldownAttackStrengthFunction((EntityPlayer) (Object) this, attackStrength));
damage = damage * (0.2F + attackStrength * attackStrength * 0.8F);
enchantmentDamage = enchantmentDamage * attackStrength;
this.resetCooldown();
if (damage > 0.0F || enchantmentDamage > 0.0F) {
boolean isStrongAttack = attackStrength > 0.9F;
boolean isSprintingAttack = false;
boolean isCriticalAttack = false;
boolean isSweapingAttack = false;
int knockbackModifier = 0;
knockbackModifier = knockbackModifier + EnchantmentHelper.getKnockbackModifier((EntityPlayer) (Object) this);
if (this.isSprinting() && isStrongAttack) {
// Sponge - Only play sound after the event has be thrown and not cancelled.
// this.world.playSound((EntityPlayer) null, this.posX, this.posY, this.posZ, SoundEvents.entity_player_attack_knockback, this.getSoundCategory(), 1.0F, 1.0F);
++knockbackModifier;
isSprintingAttack = true;
}
isCriticalAttack = isStrongAttack && this.fallDistance > 0.0F && !this.onGround && !this.isOnLadder() && !this.isInWater() && !this.isPotionActive(MobEffects.BLINDNESS) && !this.isRiding() && targetEntity instanceof EntityLivingBase;
isCriticalAttack = isCriticalAttack && !this.isSprinting();
if (isCriticalAttack) {
// Sponge Start - add critical attack tuple
// damage *= 1.5F; // Sponge - This is handled in the event
originalFunctions.add(DamageEventHandler.provideCriticalAttackTuple((EntityPlayer) (Object) this));
// Sponge End
}
// damage = damage + enchantmentDamage; // Sponge - We don't need this since our event will re-assign the damage to deal
double distanceWalkedDelta = (double) (this.distanceWalkedModified - this.prevDistanceWalkedModified);
final ItemStack heldItem = this.getHeldItem(EnumHand.MAIN_HAND);
if (isStrongAttack && !isCriticalAttack && !isSprintingAttack && this.onGround && distanceWalkedDelta < (double) this.getAIMoveSpeed()) {
ItemStack itemstack = heldItem;
if (itemstack.getItem() instanceof ItemSword) {
isSweapingAttack = true;
}
}
// Sponge Start - Create the event and throw it
final DamageSource damageSource = DamageSource.causePlayerDamage((EntityPlayer) (Object) this);
final boolean isMainthread = !this.world.isRemote;
if (isMainthread) {
Sponge.getCauseStackManager().pushCause(damageSource);
}
final Cause currentCause = isMainthread ? Sponge.getCauseStackManager().getCurrentCause() : Cause.of(EventContext.empty(), damageSource);
final AttackEntityEvent event = SpongeEventFactory.createAttackEntityEvent(currentCause, originalFunctions, EntityUtil.fromNative(targetEntity), knockbackModifier, originalBaseDamage);
SpongeImpl.postEvent(event);
if (isMainthread) {
Sponge.getCauseStackManager().popCause();
}
if (event.isCancelled()) {
return;
}
damage = (float) event.getFinalOutputDamage();
// sponge - need final for later events
final double attackDamage = damage;
knockbackModifier = event.getKnockbackModifier();
enchantmentDamage = (float) enchantmentModifiers.stream().mapToDouble(event::getOutputDamage).sum();
// Sponge End
float targetOriginalHealth = 0.0F;
boolean litEntityOnFire = false;
int fireAspectModifier = EnchantmentHelper.getFireAspectModifier((EntityPlayer) (Object) this);
if (targetEntity instanceof EntityLivingBase) {
targetOriginalHealth = ((EntityLivingBase) targetEntity).getHealth();
if (fireAspectModifier > 0 && !targetEntity.isBurning()) {
litEntityOnFire = true;
targetEntity.setFire(1);
}
}
double targetMotionX = targetEntity.motionX;
double targetMotionY = targetEntity.motionY;
double targetMotionZ = targetEntity.motionZ;
boolean attackSucceeded = targetEntity.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) (Object) this), damage);
if (attackSucceeded) {
if (knockbackModifier > 0) {
if (targetEntity instanceof EntityLivingBase) {
((EntityLivingBase) targetEntity).knockBack((EntityPlayer) (Object) this, (float) knockbackModifier * 0.5F, (double) MathHelper.sin(this.rotationYaw * 0.017453292F), (double) (-MathHelper.cos(this.rotationYaw * 0.017453292F)));
} else {
targetEntity.addVelocity((double) (-MathHelper.sin(this.rotationYaw * 0.017453292F) * (float) knockbackModifier * 0.5F), 0.1D, (double) (MathHelper.cos(this.rotationYaw * 0.017453292F) * (float) knockbackModifier * 0.5F));
}
this.motionX *= 0.6D;
this.motionZ *= 0.6D;
this.setSprinting(false);
}
if (isSweapingAttack) {
for (EntityLivingBase entitylivingbase : this.world.getEntitiesWithinAABB(EntityLivingBase.class, targetEntity.getEntityBoundingBox().grow(1.0D, 0.25D, 1.0D))) {
if (entitylivingbase != (EntityPlayer) (Object) this && entitylivingbase != targetEntity && !this.isOnSameTeam(entitylivingbase) && this.getDistanceSq(entitylivingbase) < 9.0D) {
// Sponge Start - Do a small event for these entities
// entitylivingbase.knockBack(this, 0.4F, (double)MathHelper.sin(this.rotationYaw * 0.017453292F), (double)(-MathHelper.cos(this.rotationYaw * 0.017453292F)));
// entitylivingbase.attackEntityFrom(DamageSource.causePlayerDamage(this), 1.0F);
final EntityDamageSource sweepingAttackSource = EntityDamageSource.builder().entity(this).type(DamageTypes.SWEEPING_ATTACK).build();
try (final StackFrame frame = isMainthread ? Sponge.getCauseStackManager().pushCauseFrame() : null) {
if (isMainthread) {
Sponge.getCauseStackManager().pushCause(sweepingAttackSource);
}
final ItemStackSnapshot heldSnapshot = ItemStackUtil.snapshotOf(heldItem);
if (isMainthread) {
Sponge.getCauseStackManager().addContext(EventContextKeys.WEAPON, heldSnapshot);
}
final DamageFunction sweapingFunction = DamageFunction.of(DamageModifier.builder().cause(Cause.of(EventContext.empty(), heldSnapshot)).item(heldSnapshot).type(DamageModifierTypes.SWEEPING).build(), (incoming) -> EnchantmentHelper.getSweepingDamageRatio((EntityPlayer) (Object) this) * attackDamage);
final List<DamageFunction> sweapingFunctions = new ArrayList<>();
sweapingFunctions.add(sweapingFunction);
AttackEntityEvent sweepingAttackEvent = SpongeEventFactory.createAttackEntityEvent(currentCause, sweapingFunctions, EntityUtil.fromNative(entitylivingbase), 1, 1.0D);
SpongeImpl.postEvent(sweepingAttackEvent);
if (!sweepingAttackEvent.isCancelled()) {
entitylivingbase.knockBack((EntityPlayer) (Object) this, sweepingAttackEvent.getKnockbackModifier() * 0.4F, (double) MathHelper.sin(this.rotationYaw * 0.017453292F), (double) (-MathHelper.cos(this.rotationYaw * 0.017453292F)));
entitylivingbase.attackEntityFrom(DamageSource.causePlayerDamage((EntityPlayer) (Object) this), (float) sweepingAttackEvent.getFinalOutputDamage());
}
}
// Sponge End
}
}
this.world.playSound((EntityPlayer) null, this.posX, this.posY, this.posZ, SoundEvents.ENTITY_PLAYER_ATTACK_SWEEP, this.getSoundCategory(), 1.0F, 1.0F);
this.spawnSweepParticles();
}
if (targetEntity instanceof EntityPlayerMP && targetEntity.velocityChanged) {
((EntityPlayerMP) targetEntity).connection.sendPacket(new SPacketEntityVelocity(targetEntity));
targetEntity.velocityChanged = false;
targetEntity.motionX = targetMotionX;
targetEntity.motionY = targetMotionY;
targetEntity.motionZ = targetMotionZ;
}
if (isCriticalAttack) {
this.world.playSound((EntityPlayer) null, this.posX, this.posY, this.posZ, SoundEvents.ENTITY_PLAYER_ATTACK_CRIT, this.getSoundCategory(), 1.0F, 1.0F);
this.onCriticalHit(targetEntity);
}
if (!isCriticalAttack && !isSweapingAttack) {
if (isStrongAttack) {
this.world.playSound((EntityPlayer) null, this.posX, this.posY, this.posZ, SoundEvents.ENTITY_PLAYER_ATTACK_STRONG, this.getSoundCategory(), 1.0F, 1.0F);
} else {
this.world.playSound((EntityPlayer) null, this.posX, this.posY, this.posZ, SoundEvents.ENTITY_PLAYER_ATTACK_WEAK, this.getSoundCategory(), 1.0F, 1.0F);
}
}
if (enchantmentDamage > 0.0F) {
this.onEnchantmentCritical(targetEntity);
}
this.setLastAttackedEntity(targetEntity);
if (targetEntity instanceof EntityLivingBase) {
EnchantmentHelper.applyThornEnchantments((EntityLivingBase) targetEntity, (EntityPlayer) (Object) this);
}
EnchantmentHelper.applyArthropodEnchantments((EntityPlayer) (Object) this, targetEntity);
ItemStack itemstack1 = this.getHeldItemMainhand();
Entity entity = targetEntity;
if (targetEntity instanceof MultiPartEntityPart) {
IEntityMultiPart ientitymultipart = ((MultiPartEntityPart) targetEntity).parent;
if (ientitymultipart instanceof EntityLivingBase) {
entity = (EntityLivingBase) ientitymultipart;
}
}
if (!itemstack1.isEmpty() && targetEntity instanceof EntityLivingBase) {
itemstack1.hitEntity((EntityLivingBase) targetEntity, (EntityPlayer) (Object) this);
if (itemstack1.isEmpty()) {
this.setHeldItem(EnumHand.MAIN_HAND, ItemStack.EMPTY);
}
}
if (targetEntity instanceof EntityLivingBase) {
float f5 = targetOriginalHealth - ((EntityLivingBase) targetEntity).getHealth();
this.addStat(StatList.DAMAGE_DEALT, Math.round(f5 * 10.0F));
if (fireAspectModifier > 0) {
targetEntity.setFire(fireAspectModifier * 4);
}
if (this.world instanceof WorldServer && f5 > 2.0F) {
int k = (int) ((double) f5 * 0.5D);
((WorldServer) this.world).spawnParticle(EnumParticleTypes.DAMAGE_INDICATOR, targetEntity.posX, targetEntity.posY + (double) (targetEntity.height * 0.5F), targetEntity.posZ, k, 0.1D, 0.0D, 0.1D, 0.2D, new int[0]);
}
}
this.addExhaustion(0.3F);
} else {
this.world.playSound((EntityPlayer) null, this.posX, this.posY, this.posZ, SoundEvents.ENTITY_PLAYER_ATTACK_NODAMAGE, this.getSoundCategory(), 1.0F, 1.0F);
if (litEntityOnFire) {
targetEntity.extinguish();
}
}
}
}
}
}
Aggregations