mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-08 19:34:09 +01:00
04afedcccf
This adds the ability to cancel the death events and to modify the sound an entity makes when dying. (In cases were no sound should it will be called with shouldPlaySound set to false allowing unsilencing of silent entities) It makes handling of entity deaths a lot nicer as you no longer need to listen on the damage event and calculate if the entity dies yourself to cancel the death which has the benefit of also receiving the dropped items and experience which is otherwise only properly possible by using internal code. == AT == public net.minecraft.world.entity.LivingEntity getDeathSound()Lnet/minecraft/sounds/SoundEvent; public net.minecraft.world.entity.LivingEntity getSoundVolume()F
424 lines
20 KiB
Diff
424 lines
20 KiB
Diff
--- a/net/minecraft/world/entity/Mob.java
|
|
+++ b/net/minecraft/world/entity/Mob.java
|
|
@@ -84,6 +84,17 @@
|
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
|
import net.minecraft.world.phys.AABB;
|
|
+// CraftBukkit start
|
|
+import org.bukkit.craftbukkit.event.CraftEventFactory;
|
|
+import org.bukkit.craftbukkit.entity.CraftLivingEntity;
|
|
+import org.bukkit.event.entity.CreatureSpawnEvent;
|
|
+import org.bukkit.event.entity.EntityRemoveEvent;
|
|
+import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
|
|
+import org.bukkit.event.entity.EntityTargetEvent;
|
|
+import org.bukkit.event.entity.EntityTransformEvent;
|
|
+import org.bukkit.event.entity.EntityUnleashEvent;
|
|
+import org.bukkit.event.entity.EntityUnleashEvent.UnleashReason;
|
|
+// CraftBukkit end
|
|
|
|
public abstract class Mob extends LivingEntity implements EquipmentUser, Leashable, Targeting {
|
|
|
|
@@ -112,6 +123,7 @@
|
|
private final BodyRotationControl bodyRotationControl;
|
|
protected PathNavigation navigation;
|
|
public GoalSelector goalSelector;
|
|
+ @Nullable public net.minecraft.world.entity.ai.goal.FloatGoal goalFloat; // Paper - Allow nerfed mobs to jump and float
|
|
public GoalSelector targetSelector;
|
|
@Nullable
|
|
private LivingEntity target;
|
|
@@ -132,6 +144,8 @@
|
|
private BlockPos restrictCenter;
|
|
private float restrictRadius;
|
|
|
|
+ public boolean aware = true; // CraftBukkit
|
|
+
|
|
protected Mob(EntityType<? extends Mob> type, Level world) {
|
|
super(type, world);
|
|
this.handItems = NonNullList.withSize(2, ItemStack.EMPTY);
|
|
@@ -160,6 +174,12 @@
|
|
|
|
}
|
|
|
|
+ // CraftBukkit start
|
|
+ public void setPersistenceRequired(boolean persistenceRequired) {
|
|
+ this.persistenceRequired = persistenceRequired;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+
|
|
protected void registerGoals() {}
|
|
|
|
public static AttributeSupplier.Builder createMobAttributes() {
|
|
@@ -264,11 +284,42 @@
|
|
|
|
@Nullable
|
|
protected final LivingEntity getTargetFromBrain() {
|
|
- return (LivingEntity) this.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse((Object) null);
|
|
+ return (LivingEntity) this.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null); // CraftBukkit - decompile error
|
|
}
|
|
|
|
public void setTarget(@Nullable LivingEntity target) {
|
|
- this.target = target;
|
|
+ // CraftBukkit start - fire event
|
|
+ this.setTarget(target, EntityTargetEvent.TargetReason.UNKNOWN, true);
|
|
+ }
|
|
+
|
|
+ public boolean setTarget(LivingEntity entityliving, EntityTargetEvent.TargetReason reason, boolean fireEvent) {
|
|
+ if (this.getTarget() == entityliving) return false;
|
|
+ if (fireEvent) {
|
|
+ if (reason == EntityTargetEvent.TargetReason.UNKNOWN && this.getTarget() != null && entityliving == null) {
|
|
+ reason = this.getTarget().isAlive() ? EntityTargetEvent.TargetReason.FORGOT_TARGET : EntityTargetEvent.TargetReason.TARGET_DIED;
|
|
+ }
|
|
+ if (reason == EntityTargetEvent.TargetReason.UNKNOWN) {
|
|
+ this.level().getCraftServer().getLogger().log(java.util.logging.Level.WARNING, "Unknown target reason, please report on the issue tracker", new Exception());
|
|
+ }
|
|
+ CraftLivingEntity ctarget = null;
|
|
+ if (entityliving != null) {
|
|
+ ctarget = (CraftLivingEntity) entityliving.getBukkitEntity();
|
|
+ }
|
|
+ EntityTargetLivingEntityEvent event = new EntityTargetLivingEntityEvent(this.getBukkitEntity(), ctarget, reason);
|
|
+ this.level().getCraftServer().getPluginManager().callEvent(event);
|
|
+ if (event.isCancelled()) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ if (event.getTarget() != null) {
|
|
+ entityliving = ((CraftLivingEntity) event.getTarget()).getHandle();
|
|
+ } else {
|
|
+ entityliving = null;
|
|
+ }
|
|
+ }
|
|
+ this.target = entityliving;
|
|
+ return true;
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
@Override
|
|
@@ -399,6 +450,12 @@
|
|
return null;
|
|
}
|
|
|
|
+ // CraftBukkit start - Add delegate method
|
|
+ public SoundEvent getAmbientSound0() {
|
|
+ return this.getAmbientSound();
|
|
+ }
|
|
+ // CraftBukkit end
|
|
+
|
|
@Override
|
|
public void addAdditionalSaveData(CompoundTag nbt) {
|
|
super.addAdditionalSaveData(nbt);
|
|
@@ -473,13 +530,25 @@
|
|
nbt.putBoolean("NoAI", this.isNoAi());
|
|
}
|
|
|
|
+ nbt.putBoolean("Bukkit.Aware", this.aware); // CraftBukkit
|
|
}
|
|
|
|
@Override
|
|
public void readAdditionalSaveData(CompoundTag nbt) {
|
|
super.readAdditionalSaveData(nbt);
|
|
- this.setCanPickUpLoot(nbt.getBoolean("CanPickUpLoot"));
|
|
- this.persistenceRequired = nbt.getBoolean("PersistenceRequired");
|
|
+ // CraftBukkit start - If looting or persistence is false only use it if it was set after we started using it
|
|
+ if (nbt.contains("CanPickUpLoot", 99)) {
|
|
+ boolean data = nbt.getBoolean("CanPickUpLoot");
|
|
+ if (isLevelAtLeast(nbt, 1) || data) {
|
|
+ this.setCanPickUpLoot(data);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ boolean data = nbt.getBoolean("PersistenceRequired");
|
|
+ if (isLevelAtLeast(nbt, 1) || data) {
|
|
+ this.persistenceRequired = data;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
ListTag nbttaglist;
|
|
CompoundTag nbttagcompound1;
|
|
int i;
|
|
@@ -547,6 +616,11 @@
|
|
|
|
this.lootTableSeed = nbt.getLong("DeathLootTableSeed");
|
|
this.setNoAi(nbt.getBoolean("NoAI"));
|
|
+ // CraftBukkit start
|
|
+ if (nbt.contains("Bukkit.Aware")) {
|
|
+ this.aware = nbt.getBoolean("Bukkit.Aware");
|
|
+ }
|
|
+ // CraftBukkit end
|
|
}
|
|
|
|
@Override
|
|
@@ -608,6 +682,11 @@
|
|
ItemEntity entityitem = (ItemEntity) iterator.next();
|
|
|
|
if (!entityitem.isRemoved() && !entityitem.getItem().isEmpty() && !entityitem.hasPickUpDelay() && this.wantsToPickUp(worldserver, entityitem.getItem())) {
|
|
+ // Paper start - Item#canEntityPickup
|
|
+ if (!entityitem.canMobPickup) {
|
|
+ continue;
|
|
+ }
|
|
+ // Paper end - Item#canEntityPickup
|
|
this.pickUpItem(worldserver, entityitem);
|
|
}
|
|
}
|
|
@@ -623,23 +702,29 @@
|
|
|
|
protected void pickUpItem(ServerLevel world, ItemEntity itemEntity) {
|
|
ItemStack itemstack = itemEntity.getItem();
|
|
- ItemStack itemstack1 = this.equipItemIfPossible(world, itemstack.copy());
|
|
+ ItemStack itemstack1 = this.equipItemIfPossible(world, itemstack.copy(), itemEntity); // CraftBukkit - add item
|
|
|
|
if (!itemstack1.isEmpty()) {
|
|
this.onItemPickup(itemEntity);
|
|
this.take(itemEntity, itemstack1.getCount());
|
|
itemstack.shrink(itemstack1.getCount());
|
|
if (itemstack.isEmpty()) {
|
|
- itemEntity.discard();
|
|
+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public ItemStack equipItemIfPossible(ServerLevel world, ItemStack stack) {
|
|
- EquipmentSlot enumitemslot = this.getEquipmentSlotForItem(stack);
|
|
+ // CraftBukkit start - add item
|
|
+ return this.equipItemIfPossible(world, stack, null);
|
|
+ }
|
|
+
|
|
+ public ItemStack equipItemIfPossible(ServerLevel worldserver, ItemStack itemstack, ItemEntity entityitem) {
|
|
+ // CraftBukkit end
|
|
+ EquipmentSlot enumitemslot = this.getEquipmentSlotForItem(itemstack);
|
|
ItemStack itemstack1 = this.getItemBySlot(enumitemslot);
|
|
- boolean flag = this.canReplaceCurrentItem(stack, itemstack1, enumitemslot);
|
|
+ boolean flag = this.canReplaceCurrentItem(itemstack, itemstack1, enumitemslot);
|
|
|
|
if (enumitemslot.isArmor() && !flag) {
|
|
enumitemslot = EquipmentSlot.MAINHAND;
|
|
@@ -647,14 +732,22 @@
|
|
flag = itemstack1.isEmpty();
|
|
}
|
|
|
|
- if (flag && this.canHoldItem(stack)) {
|
|
+ // CraftBukkit start
|
|
+ boolean canPickup = flag && this.canHoldItem(itemstack);
|
|
+ if (entityitem != null) {
|
|
+ canPickup = !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entityitem, 0, !canPickup).isCancelled();
|
|
+ }
|
|
+ if (canPickup) {
|
|
+ // CraftBukkit end
|
|
double d0 = (double) this.getEquipmentDropChance(enumitemslot);
|
|
|
|
if (!itemstack1.isEmpty() && (double) Math.max(this.random.nextFloat() - 0.1F, 0.0F) < d0) {
|
|
- this.spawnAtLocation(world, itemstack1);
|
|
+ this.forceDrops = true; // CraftBukkit
|
|
+ this.spawnAtLocation(worldserver, itemstack1);
|
|
+ this.forceDrops = false; // CraftBukkit
|
|
}
|
|
|
|
- ItemStack itemstack2 = enumitemslot.limit(stack);
|
|
+ ItemStack itemstack2 = enumitemslot.limit(itemstack);
|
|
|
|
this.setItemSlotAndDropWhenKilled(enumitemslot, itemstack2);
|
|
return itemstack2;
|
|
@@ -768,25 +861,29 @@
|
|
@Override
|
|
public void checkDespawn() {
|
|
if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
|
|
- this.discard();
|
|
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
|
} else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) {
|
|
- Player entityhuman = this.level().getNearestPlayer(this, -1.0D);
|
|
+ Player entityhuman = this.level().findNearbyPlayer(this, -1.0D, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper - Affects Spawning API
|
|
|
|
if (entityhuman != null) {
|
|
- double d0 = entityhuman.distanceToSqr((Entity) this);
|
|
- int i = this.getType().getCategory().getDespawnDistance();
|
|
- int j = i * i;
|
|
-
|
|
- if (d0 > (double) j && this.removeWhenFarAway(d0)) {
|
|
- this.discard();
|
|
+ // Paper start - Configurable despawn distances
|
|
+ final io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DespawnRangePair despawnRangePair = this.level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory());
|
|
+ final io.papermc.paper.configuration.type.DespawnRange.Shape shape = this.level().paperConfig().entities.spawning.despawnRangeShape;
|
|
+ final double dy = Math.abs(entityhuman.getY() - this.getY());
|
|
+ final double dySqr = Math.pow(dy, 2);
|
|
+ final double dxSqr = Math.pow(entityhuman.getX() - this.getX(), 2);
|
|
+ final double dzSqr = Math.pow(entityhuman.getZ() - this.getZ(), 2);
|
|
+ final double distanceSquared = dxSqr + dzSqr + dySqr;
|
|
+ // Despawn if hard/soft limit is exceeded
|
|
+ if (despawnRangePair.hard().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy) && this.removeWhenFarAway(distanceSquared)) {
|
|
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
|
}
|
|
-
|
|
- int k = this.getType().getCategory().getNoDespawnDistance();
|
|
- int l = k * k;
|
|
-
|
|
- if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > (double) l && this.removeWhenFarAway(d0)) {
|
|
- this.discard();
|
|
- } else if (d0 < (double) l) {
|
|
+ if (despawnRangePair.soft().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy)) {
|
|
+ if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && this.removeWhenFarAway(distanceSquared)) {
|
|
+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
|
+ }
|
|
+ } else {
|
|
+ // Paper end - Configurable despawn distances
|
|
this.noActionTime = 0;
|
|
}
|
|
}
|
|
@@ -799,6 +896,15 @@
|
|
@Override
|
|
protected final void serverAiStep() {
|
|
++this.noActionTime;
|
|
+ // Paper start - Allow nerfed mobs to jump and float
|
|
+ if (!this.aware) {
|
|
+ if (goalFloat != null) {
|
|
+ if (goalFloat.canUse()) goalFloat.tick();
|
|
+ this.getJumpControl().tick();
|
|
+ }
|
|
+ return;
|
|
+ }
|
|
+ // Paper end - Allow nerfed mobs to jump and float
|
|
ProfilerFiller gameprofilerfiller = Profiler.get();
|
|
|
|
gameprofilerfiller.push("sensing");
|
|
@@ -1011,6 +1117,12 @@
|
|
|
|
}
|
|
|
|
+ // Paper start
|
|
+ protected boolean shouldSkipLoot(EquipmentSlot slot) { // method to avoid to fallback into the global mob loot logic (i.e fox)
|
|
+ return false;
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
@Override
|
|
protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) {
|
|
super.dropCustomDeathLoot(world, source, causedByPlayer);
|
|
@@ -1018,6 +1130,7 @@
|
|
|
|
while (iterator.hasNext()) {
|
|
EquipmentSlot enumitemslot = (EquipmentSlot) iterator.next();
|
|
+ if (this.shouldSkipLoot(enumitemslot)) continue; // Paper
|
|
ItemStack itemstack = this.getItemBySlot(enumitemslot);
|
|
float f = this.getEquipmentDropChance(enumitemslot);
|
|
|
|
@@ -1042,7 +1155,13 @@
|
|
}
|
|
|
|
this.spawnAtLocation(world, itemstack);
|
|
+ if (this.clearEquipmentSlots) { // Paper
|
|
this.setItemSlot(enumitemslot, ItemStack.EMPTY);
|
|
+ // Paper start
|
|
+ } else {
|
|
+ this.clearedEquipmentSlots.add(enumitemslot);
|
|
+ }
|
|
+ // Paper end
|
|
}
|
|
}
|
|
}
|
|
@@ -1338,7 +1457,7 @@
|
|
if (itemstack.getItem() instanceof SpawnEggItem) {
|
|
if (this.level() instanceof ServerLevel) {
|
|
SpawnEggItem itemmonsteregg = (SpawnEggItem) itemstack.getItem();
|
|
- Optional<Mob> optional = itemmonsteregg.spawnOffspringFromSpawnEgg(player, this, this.getType(), (ServerLevel) this.level(), this.position(), itemstack);
|
|
+ Optional<Mob> optional = itemmonsteregg.spawnOffspringFromSpawnEgg(player, this, (EntityType<? extends Mob>) this.getType(), (ServerLevel) this.level(), this.position(), itemstack); // CraftBukkit - decompile error
|
|
|
|
optional.ifPresent((entityinsentient) -> {
|
|
this.onOffspringSpawnedFromEgg(player, entityinsentient);
|
|
@@ -1389,28 +1508,51 @@
|
|
return this.restrictRadius != -1.0F;
|
|
}
|
|
|
|
+ // CraftBukkit start
|
|
@Nullable
|
|
public <T extends Mob> T convertTo(EntityType<T> entityType, ConversionParams context, EntitySpawnReason reason, ConversionParams.AfterConversion<T> finalizer) {
|
|
+ return this.convertTo(entityType, context, reason, finalizer, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT);
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, EntitySpawnReason entityspawnreason, ConversionParams.AfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) {
|
|
+ // Paper start - entity zap event - allow cancellation of conversion post creation
|
|
+ return this.convertTo(entitytypes, conversionparams, entityspawnreason, e -> { conversionparams_a.finalizeConversion(e); return true; }, transformReason, spawnReason);
|
|
+ }
|
|
+ @Nullable
|
|
+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, EntitySpawnReason entityspawnreason, ConversionParams.CancellingAfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) {
|
|
+ // Paper end - entity zap event - allow cancellation of conversion post creation
|
|
+ // CraftBukkit end
|
|
if (this.isRemoved()) {
|
|
return null;
|
|
} else {
|
|
- T t0 = (Mob) entityType.create(this.level(), reason);
|
|
+ T t0 = entitytypes.create(this.level(), EntitySpawnReason.CONVERSION); // CraftBukkit - decompile error
|
|
|
|
if (t0 == null) {
|
|
return null;
|
|
} else {
|
|
- context.type().convert(this, t0, context);
|
|
- finalizer.finalizeConversion(t0);
|
|
+ conversionparams.type().convert(this, t0, conversionparams);
|
|
+ if (!conversionparams_a.finalizeConversionOrCancel(t0)) return null; // Paper - entity zap event - return null if conversion was cancelled
|
|
Level world = this.level();
|
|
+
|
|
+ // CraftBukkit start
|
|
+ if (transformReason == null) {
|
|
+ // Special handling for slime split and pig lightning
|
|
+ return t0;
|
|
+ }
|
|
|
|
+ if (CraftEventFactory.callEntityTransformEvent(this, t0, transformReason).isCancelled()) {
|
|
+ return null;
|
|
+ }
|
|
+ // CraftBukkit end
|
|
if (world instanceof ServerLevel) {
|
|
ServerLevel worldserver = (ServerLevel) world;
|
|
|
|
- worldserver.addFreshEntity(t0);
|
|
+ worldserver.addFreshEntity(t0, spawnReason); // CraftBukkit
|
|
}
|
|
|
|
- if (context.type().shouldDiscardAfterConversion()) {
|
|
- this.discard();
|
|
+ if (conversionparams.type().shouldDiscardAfterConversion()) {
|
|
+ this.discard(EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause
|
|
}
|
|
|
|
return t0;
|
|
@@ -1420,10 +1562,22 @@
|
|
|
|
@Nullable
|
|
public <T extends Mob> T convertTo(EntityType<T> entityType, ConversionParams context, ConversionParams.AfterConversion<T> finalizer) {
|
|
- return this.convertTo(entityType, context, EntitySpawnReason.CONVERSION, finalizer);
|
|
+ // CraftBukkit start
|
|
+ return this.convertTo(entityType, context, finalizer, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT);
|
|
}
|
|
|
|
@Nullable
|
|
+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, ConversionParams.AfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) {
|
|
+ // Paper start - entity zap event - allow cancellation of conversion post creation
|
|
+ return this.convertTo(entitytypes, conversionparams, e -> { conversionparams_a.finalizeConversion(e); return true; }, transformReason, spawnReason);
|
|
+ }
|
|
+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, ConversionParams.CancellingAfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) {
|
|
+ // Paper start - entity zap event - allow cancellation of conversion post creation
|
|
+ return this.convertTo(entitytypes, conversionparams, EntitySpawnReason.CONVERSION, conversionparams_a, transformReason, spawnReason);
|
|
+ // CraftBukkit end
|
|
+ }
|
|
+
|
|
+ @Nullable
|
|
@Override
|
|
public Leashable.LeashData getLeashData() {
|
|
return this.leashData;
|
|
@@ -1458,6 +1612,7 @@
|
|
boolean flag1 = super.startRiding(entity, force);
|
|
|
|
if (flag1 && this.isLeashed()) {
|
|
+ this.level().getCraftServer().getPluginManager().callEvent(new EntityUnleashEvent(this.getBukkitEntity(), UnleashReason.UNKNOWN)); // CraftBukkit
|
|
this.dropLeash();
|
|
}
|
|
|
|
@@ -1542,7 +1697,7 @@
|
|
|
|
if (f1 > 0.0F && target instanceof LivingEntity) {
|
|
entityliving = (LivingEntity) target;
|
|
- entityliving.knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)));
|
|
+ entityliving.knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events
|
|
this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D));
|
|
}
|
|
|