From eec23b52dfd36439f4b62048091a8781fd5c0c52 Mon Sep 17 00:00:00 2001 From: Hexeption Date: Sat, 24 Aug 2019 01:22:48 +0100 Subject: [PATCH] Cleaning up Patches, Added EntityDeathEvent Paper Patch --- .../minecraft/block/BlockFarmland.java.patch | 9 - .../net/minecraft/entity/Entity.java.patch | 143 ++--- .../entity/EntityLivingBase.java.patch | 533 +++++++++++------- .../entity/item/EntityArmorStand.java.patch | 15 +- .../entity/item/EntityItemFrame.java.patch | 22 +- .../network/NetHandlerPlayServer.java.patch | 77 ++- .../common/ISpecialArmor.java.patch | 28 + .../org/bukkit/craftbukkit/CraftSound.java | 25 + .../bukkit/craftbukkit/block/CraftBlock.java | 177 +++--- .../craftbukkit/event/CraftEventFactory.java | 171 +++++- .../bukkit/event/entity/EntityDeathEvent.java | 139 ++++- src/main/java/org/spigotmc/AsyncCatcher.java | 18 +- 12 files changed, 931 insertions(+), 426 deletions(-) create mode 100644 patches/net/minecraftforge/common/ISpecialArmor.java.patch diff --git a/patches/net/minecraft/block/BlockFarmland.java.patch b/patches/net/minecraft/block/BlockFarmland.java.patch index 4668c3c..33ac0e6 100644 --- a/patches/net/minecraft/block/BlockFarmland.java.patch +++ b/patches/net/minecraft/block/BlockFarmland.java.patch @@ -56,12 +56,3 @@ } private boolean hasWater(World worldIn, BlockPos pos) -@@ -108,7 +130,7 @@ - } - } - -- return net.minecraftforge.common.FarmlandWaterManager.hasBlockWaterTicket(worldIn, pos); -+ return false; - } - - public void neighborChanged(IBlockState state, World worldIn, BlockPos pos, Block blockIn, BlockPos fromPos) diff --git a/patches/net/minecraft/entity/Entity.java.patch b/patches/net/minecraft/entity/Entity.java.patch index 66dd65c..9f32492 100644 --- a/patches/net/minecraft/entity/Entity.java.patch +++ b/patches/net/minecraft/entity/Entity.java.patch @@ -175,7 +175,7 @@ + } + + if (yaw == Float.POSITIVE_INFINITY || yaw == Float.NEGATIVE_INFINITY) { -+ if (this instanceof EntityPlayer) { ++ if (this instanceof EntityPlayerMP) { + this.world.getServer().getLogger().warning(this.getName() + " was caught trying to crash the server with an invalid yaw"); + ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Nope"); + } @@ -188,7 +188,7 @@ + } + + if (pitch == Float.POSITIVE_INFINITY || pitch == Float.NEGATIVE_INFINITY) { -+ if (this instanceof EntityPlayer) { ++ if (this instanceof EntityPlayerMP) { + this.world.getServer().getLogger().warning(this.getName() + " was caught trying to crash the server with an invalid pitch"); + ((CraftPlayer) this.getBukkitEntity()).kickPlayer("Nope"); + } @@ -322,7 +322,7 @@ { this.attackEntityFrom(DamageSource.LAVA, 4.0F); + // CraftBukkit start - Fallen in lava TODO: this event spams! -+ if (this instanceof EntityLiving) { ++ if (this instanceof EntityLivingBase) { + if (fire <= 0) { + // not on fire yet + // TODO: shouldn't be sending null for the block @@ -564,17 +564,18 @@ this.posX = nbttaglist.getDoubleAt(0); this.posY = nbttaglist.getDoubleAt(1); this.posZ = nbttaglist.getDoubleAt(2); -@@ -1869,6 +2031,50 @@ +@@ -1869,6 +2031,54 @@ { this.setPosition(this.posX, this.posY, this.posZ); } + -+ if (this instanceof EntityLiving) { -+ EntityLiving entity = (EntityLiving) this; -+ ++ if (this instanceof EntityLivingBase) { ++ EntityLivingBase entity = (EntityLivingBase) this; ++ this.ticksExisted = compound.getInteger("Spigot.ticksLived"); + // Reset the persistence for tamed animals + if (entity instanceof EntityTameable && !isLevelAtLeast(compound, 2) && !compound.getBoolean("PersistenceRequired")) { -+ ((EntityLiving) entity).persistenceRequired = !(entity).canDespawn(); ++ EntityLiving entityliving = (EntityLiving) entity; ++ entityliving.persistenceRequired = !entityliving.canDespawn(); + } + } + double limit = getBukkitEntity() instanceof Vehicle ? 100.0D : 10.0D; @@ -591,7 +592,7 @@ + } + + // Reset world -+ if (this instanceof EntityPlayer) { ++ if (this instanceof EntityPlayerMP) { + Server server = Bukkit.getServer(); + org.bukkit.World bworld = null; + @@ -606,16 +607,19 @@ + } + + if (bworld == null) { -+ EntityPlayer entityPlayer = (EntityPlayer) this; -+ bworld = ((org.bukkit.craftbukkit.CraftServer) server).getServer().getWorldServer(entityPlayer.dimension).getWorld(); ++ EntityPlayerMP entityPlayer = (EntityPlayerMP) this; ++ // Magma start - use CraftBukkit's fallback world code if no valid world is found. ++ entityPlayer.setWorld(MinecraftServer.getServerInstance().getWorldServer(entityPlayer.dimension)); ++ } ++ else { ++ this.setWorld(((CraftWorld) bworld).getHandle()); ++ // Magma end + } -+ -+ setWorld(bworld == null? null : ((CraftWorld) bworld).getHandle()); + } } catch (Throwable throwable) { -@@ -1885,7 +2091,7 @@ +@@ -1885,7 +2095,7 @@ } @Nullable @@ -624,7 +628,7 @@ { ResourceLocation resourcelocation = EntityList.getKey(this); return resourcelocation == null ? null : resourcelocation.toString(); -@@ -1945,7 +2151,9 @@ +@@ -1945,7 +2155,9 @@ if (captureDrops) this.capturedDrops.add(entityitem); else @@ -635,7 +639,7 @@ return entityitem; } } -@@ -2013,7 +2221,7 @@ +@@ -2013,7 +2225,7 @@ this.motionY = 0.0D; this.motionZ = 0.0D; if(!updateBlocked) @@ -644,7 +648,7 @@ if (this.isRiding()) { -@@ -2110,6 +2318,29 @@ +@@ -2110,6 +2322,29 @@ } else { @@ -674,7 +678,7 @@ if (!this.world.isRemote && passenger instanceof EntityPlayer && !(this.getControllingPassenger() instanceof EntityPlayer)) { this.riddenByEntities.add(0, passenger); -@@ -2129,6 +2360,27 @@ +@@ -2129,6 +2364,27 @@ } else { @@ -702,7 +706,7 @@ this.riddenByEntities.remove(passenger); passenger.rideCooldown = 60; } -@@ -2325,12 +2577,12 @@ +@@ -2325,12 +2581,12 @@ this.setFlag(5, invisible); } @@ -717,7 +721,7 @@ { byte b0 = ((Byte)this.dataManager.get(FLAGS)).byteValue(); -@@ -2351,17 +2603,52 @@ +@@ -2351,17 +2607,52 @@ public void setAir(int air) { @@ -773,7 +777,7 @@ } } -@@ -2502,7 +2789,7 @@ +@@ -2502,7 +2793,7 @@ public String toString() { @@ -782,7 +786,7 @@ } public boolean isEntityInvulnerable(DamageSource source) -@@ -2540,7 +2827,7 @@ +@@ -2540,7 +2831,7 @@ public Entity changeDimension(int dimensionIn) { if (this.world.isRemote || this.isDead) return null; @@ -791,7 +795,7 @@ } @Nullable // Forge: Entities that require custom handling should override this method, not the other -@@ -2551,53 +2838,67 @@ +@@ -2551,53 +2842,73 @@ if (!net.minecraftforge.common.ForgeHooks.onTravelToDimension(this, dimensionIn)) return null; this.world.profiler.startSection("changeDimension"); MinecraftServer minecraftserver = this.getServer(); @@ -799,11 +803,6 @@ - WorldServer worldserver = minecraftserver.getWorld(i); - WorldServer worldserver1 = minecraftserver.getWorld(dimensionIn); - this.dimension = dimensionIn; -- -- if (i == 1 && dimensionIn == 1 && teleporter.isVanilla()) -- { -- worldserver1 = minecraftserver.getWorld(0); -- this.dimension = 0; + // CraftBukkit start - Move logic into new function "teleportTo(Location,boolean)" + // int i = this.dimension; + // WorldServer worldserver = minecraftserver.getWorld(i); @@ -816,16 +815,12 @@ + exitWorld = world; + } + } - } ++ } -- this.world.removeEntity(this); -- this.isDead = false; -- this.world.profiler.startSection("reposition"); -- BlockPos blockpos; -- -- if (dimensionIn == 1 && teleporter.isVanilla()) +- if (i == 1 && dimensionIn == 1 && teleporter.isVanilla()) - { -- blockpos = worldserver1.getSpawnCoordinate(); +- worldserver1 = minecraftserver.getWorld(0); +- this.dimension = 0; + BlockPos blockposition = null; // PAIL: CHECK + Location enter = this.getBukkitEntity().getLocation(); + Location exit; @@ -836,37 +831,22 @@ + exit = minecraftserver.getPlayerList().calculateTarget(enter, minecraftserver.getWorld(dimensionIn)); + } } -- else -- { -- double moveFactor = worldserver.provider.getMovementFactor() / worldserver1.provider.getMovementFactor(); -- double d0 = MathHelper.clamp(this.posX * moveFactor, worldserver1.getWorldBorder().minX() + 16.0D, worldserver1.getWorldBorder().maxX() - 16.0D); -- double d1 = MathHelper.clamp(this.posZ * moveFactor, worldserver1.getWorldBorder().minZ() + 16.0D, worldserver1.getWorldBorder().maxZ() - 16.0D); -- double d2 = 8.0D; + else { + exit = null; + } + boolean useTravelAgent = exitWorld != null && !(this.dimension == 1 && exitWorld.dimension == 1); // don't use agent for custom worlds or return from THE_END -- if (false && dimensionIn == -1) -- { -- d0 = MathHelper.clamp(d0 / 8.0D, worldserver1.getWorldBorder().minX() + 16.0D, worldserver1.getWorldBorder().maxX() - 16.0D); -- d1 = MathHelper.clamp(d1 / 8.0D, worldserver1.getWorldBorder().minZ() + 16.0D, worldserver1.getWorldBorder().maxZ() - 16.0D); -- } -- else if (false && dimensionIn == 0) -- { -- d0 = MathHelper.clamp(d0 * 8.0D, worldserver1.getWorldBorder().minX() + 16.0D, worldserver1.getWorldBorder().maxX() - 16.0D); -- d1 = MathHelper.clamp(d1 * 8.0D, worldserver1.getWorldBorder().minZ() + 16.0D, worldserver1.getWorldBorder().maxZ() - 16.0D); -- } +- this.world.removeEntity(this); +- this.isDead = false; +- this.world.profiler.startSection("reposition"); +- BlockPos blockpos; + TravelAgent agent = exit != null ? (TravelAgent) ((CraftWorld) exit.getWorld()).getHandle().getDefaultTeleporter() : org.bukkit.craftbukkit.CraftTravelAgent.DEFAULT; // return arbitrary TA to compensate for implementation dependent plugins + boolean oldCanCreate = agent.getCanCreatePortal(); + agent.setCanCreatePortal(false); // General entities cannot create portals -- d0 = (double)MathHelper.clamp((int)d0, -29999872, 29999872); -- d1 = (double)MathHelper.clamp((int)d1, -29999872, 29999872); -- float f = this.rotationYaw; -- this.setLocationAndAngles(d0, this.posY, d1, 90.0F, 0.0F); -- teleporter.placeEntity(worldserver1, this, f); -- blockpos = new BlockPos(this); +- if (dimensionIn == 1 && teleporter.isVanilla()) +- { +- blockpos = worldserver1.getSpawnCoordinate(); + EntityPortalEvent event = new EntityPortalEvent(this.getBukkitEntity(), enter, exit, agent); + event.useTravelAgent(useTravelAgent); + event.getEntity().getServer().getPluginManager().callEvent(event); @@ -874,10 +854,25 @@ + agent.setCanCreatePortal(oldCanCreate); + return null; } +- else +- { +- double moveFactor = worldserver.provider.getMovementFactor() / worldserver1.provider.getMovementFactor(); +- double d0 = MathHelper.clamp(this.posX * moveFactor, worldserver1.getWorldBorder().minX() + 16.0D, worldserver1.getWorldBorder().maxX() - 16.0D); +- double d1 = MathHelper.clamp(this.posZ * moveFactor, worldserver1.getWorldBorder().minZ() + 16.0D, worldserver1.getWorldBorder().maxZ() - 16.0D); +- double d2 = 8.0D; + exit = event.useTravelAgent() ? event.getPortalTravelAgent().findOrCreate(event.getTo()) : event.getTo(); + agent.setCanCreatePortal(oldCanCreate); -- worldserver.updateEntityWithOptionalForce(this, false); +- if (false && dimensionIn == -1) +- { +- d0 = MathHelper.clamp(d0 / 8.0D, worldserver1.getWorldBorder().minX() + 16.0D, worldserver1.getWorldBorder().maxX() - 16.0D); +- d1 = MathHelper.clamp(d1 / 8.0D, worldserver1.getWorldBorder().minZ() + 16.0D, worldserver1.getWorldBorder().maxZ() - 16.0D); +- } +- else if (false && dimensionIn == 0) +- { +- d0 = MathHelper.clamp(d0 * 8.0D, worldserver1.getWorldBorder().minX() + 16.0D, worldserver1.getWorldBorder().maxX() - 16.0D); +- d1 = MathHelper.clamp(d1 * 8.0D, worldserver1.getWorldBorder().minZ() + 16.0D, worldserver1.getWorldBorder().maxZ() - 16.0D); +- } + // Need to make sure the profiler state is reset afterwards (but we still want to time the call) + Entity entity = this.teleportTo(exit, true); + this.world.profiler.endSection(); @@ -885,7 +880,13 @@ + } + return null; + } -+ + +- d0 = (double)MathHelper.clamp((int)d0, -29999872, 29999872); +- d1 = (double)MathHelper.clamp((int)d1, -29999872, 29999872); +- float f = this.rotationYaw; +- this.setLocationAndAngles(d0, this.posY, d1, 90.0F, 0.0F); +- teleporter.placeEntity(worldserver1, this, f); +- blockpos = new BlockPos(this); + public Entity teleportTo(Location exit, boolean portal) { + if (true) { // Paper + WorldServer worldserver = ((CraftWorld) getBukkitEntity().getLocation().getWorld()).getHandle(); @@ -893,13 +894,21 @@ + int i = worldserver1.dimension; + this.dimension = i; + this.world.removeEntity(this); // Paper - Fully remove entity, can't have dupes in the UUID map ++ // Kettle silently remove the entity so it can be transported to another world. ++ if (!(this instanceof EntityLivingBase) && this.addedToChunk && this.world.isChunkLoaded(this.chunkCoordX, this.chunkCoordZ, true)) ++ { ++ this.world.getChunkFromChunkCoords(this.chunkCoordX, this.chunkCoordZ).removeEntity(this); ++ this.world.loadedEntityList.remove(this); + } +- +- worldserver.updateEntityWithOptionalForce(this, false); + this.isDead = false; + this.world.profiler.startSection("reposition"); + worldserver1.getMinecraftServer().getPlayerList().repositionEntity(this, exit, portal); this.world.profiler.endStartSection("reloading"); Entity entity = EntityList.newEntity(this.getClass(), worldserver1); -@@ -2605,28 +2906,26 @@ +@@ -2605,28 +2916,26 @@ { entity.copyDataFromOld(this); @@ -937,7 +946,7 @@ return entity; } else -@@ -2755,6 +3054,11 @@ +@@ -2755,6 +3064,11 @@ public void setCustomNameTag(String name) { @@ -949,7 +958,7 @@ this.dataManager.set(CUSTOM_NAME, name); } -@@ -2838,7 +3142,25 @@ +@@ -2838,7 +3152,25 @@ public void setEntityBoundingBox(AxisAlignedBB bb) { @@ -976,7 +985,7 @@ } public float getEyeHeight() -@@ -2870,6 +3192,11 @@ +@@ -2870,6 +3202,11 @@ return true; } @@ -988,7 +997,7 @@ public BlockPos getPosition() { return new BlockPos(this.posX, this.posY + 0.5D, this.posZ); -@@ -3030,7 +3357,7 @@ +@@ -3030,7 +3367,7 @@ { return ((net.minecraft.entity.item.EntityMinecart)this).getCartItem(); } @@ -997,7 +1006,7 @@ { return new ItemStack(((EntityBoat)this).getItemBoat()); } -@@ -3109,14 +3436,14 @@ +@@ -3109,14 +3446,14 @@ } @Override @@ -1014,7 +1023,7 @@ { return capabilities == null ? null : capabilities.getCapability(capability, facing); } -@@ -3319,7 +3646,7 @@ +@@ -3319,7 +3656,7 @@ return SoundCategory.NEUTRAL; } diff --git a/patches/net/minecraft/entity/EntityLivingBase.java.patch b/patches/net/minecraft/entity/EntityLivingBase.java.patch index a3eeabd..855b06a 100644 --- a/patches/net/minecraft/entity/EntityLivingBase.java.patch +++ b/patches/net/minecraft/entity/EntityLivingBase.java.patch @@ -1,26 +1,35 @@ --- ../src-base/minecraft/net/minecraft/entity/EntityLivingBase.java +++ ../src-work/minecraft/net/minecraft/entity/EntityLivingBase.java -@@ -1,7 +1,11 @@ +@@ -1,15 +1,9 @@ package net.minecraft.entity; +import com.google.common.base.Function; import com.google.common.base.Objects; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; -+ -+import java.util.ArrayList; - import java.util.Collection; - import java.util.ConcurrentModificationException; - import java.util.Iterator; -@@ -19,6 +23,7 @@ +-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; +@@ -19,32 +13,21 @@ 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.ai.EntityAISit; - import net.minecraft.entity.ai.attributes.AbstractAttributeMap; - import net.minecraft.entity.ai.attributes.AttributeMap; - import net.minecraft.entity.ai.attributes.AttributeModifier; -@@ -28,7 +33,8 @@ ++import net.minecraft.entity.ai.attributes.*; + import net.minecraft.entity.item.EntityBoat; import net.minecraft.entity.item.EntityItem; import net.minecraft.entity.item.EntityXPOrb; import net.minecraft.entity.passive.AbstractHorse; @@ -30,18 +39,50 @@ import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; import net.minecraft.entity.projectile.EntityArrow; -@@ -43,7 +49,10 @@ - import net.minecraft.item.ItemArmor; - import net.minecraft.item.ItemElytra; - import net.minecraft.item.ItemStack; -+import net.minecraft.nbt.NBTBase; - import net.minecraft.nbt.NBTTagCompound; -+import net.minecraft.nbt.NBTTagFloat; -+import net.minecraft.nbt.NBTTagInt; - import net.minecraft.nbt.NBTTagList; +-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.init.*; + 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.item.*; ++import net.minecraft.nbt.*; import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; -@@ -76,21 +85,32 @@ + import net.minecraft.network.datasync.EntityDataManager; +@@ -55,42 +38,48 @@ + 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.*; + 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.common.ForgeHooks; ++import net.minecraftforge.common.ISpecialArmor; + import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -57,6 +98,9 @@ +import org.bukkit.event.entity.EntityTeleportEvent; +import org.bukkit.event.player.PlayerItemConsumeEvent; ++import javax.annotation.Nullable; ++import java.util.*; ++ public abstract class EntityLivingBase extends Entity { private static final Logger LOGGER = LogManager.getLogger(); @@ -78,7 +122,7 @@ private final NonNullList handInventory = NonNullList.withSize(2, ItemStack.EMPTY); private final NonNullList armorArray = NonNullList.withSize(4, ItemStack.EMPTY); public boolean isSwingInProgress; -@@ -117,7 +137,7 @@ +@@ -117,7 +106,7 @@ public float rotationYawHead; public float prevRotationYawHead; public float jumpMovementFactor = 0.02F; @@ -87,7 +131,7 @@ protected int recentlyHit; protected boolean dead; protected int idleTime; -@@ -127,7 +147,7 @@ +@@ -127,7 +116,7 @@ protected float prevMovedDistance; protected float unused180; protected int scoreValue; @@ -96,7 +140,7 @@ protected boolean isJumping; public float moveStrafing; public float moveVertical; -@@ -139,9 +159,9 @@ +@@ -139,9 +128,9 @@ protected double interpTargetZ; protected double interpTargetYaw; protected double interpTargetPitch; @@ -109,7 +153,7 @@ private EntityLivingBase lastAttackedEntity; private int lastAttackedEntityTime; private float landMovementFactor; -@@ -154,6 +174,23 @@ +@@ -154,6 +143,25 @@ private DamageSource lastDamageSource; private long lastDamageStamp; @@ -121,6 +165,8 @@ + public boolean collides = true; + public boolean canPickUpLoot; + // CraftBukkit end ++ public boolean silentDeath = false; // Paper - mark entity as dying silently for cancellable death event ++ + + // Spigot start + public void inactiveTick() @@ -133,7 +179,7 @@ public void onKillCommand() { this.attackEntityFrom(DamageSource.OUT_OF_WORLD, Float.MAX_VALUE); -@@ -163,7 +200,9 @@ +@@ -163,7 +171,9 @@ { super(worldIn); this.applyEntityAttributes(); @@ -144,7 +190,7 @@ this.preventEntitySpawning = true; this.randomUnused1 = (float)((Math.random() + 1.0D) * 0.009999999776482582D); this.setPosition(this.posX, this.posY, this.posZ); -@@ -207,8 +246,17 @@ +@@ -207,8 +217,17 @@ { double d0 = Math.min((double)(0.2F + f / 15.0F), 2.5D); int i = (int)(150.0D * d0); @@ -164,7 +210,7 @@ } } -@@ -258,9 +306,13 @@ +@@ -258,9 +277,13 @@ if (this.isEntityAlive()) { @@ -181,7 +227,7 @@ } else { -@@ -359,6 +411,18 @@ +@@ -359,6 +382,18 @@ this.world.profiler.endSection(); } @@ -200,7 +246,7 @@ protected void frostWalk(BlockPos pos) { int i = EnchantmentHelper.getMaxEnchantmentLevel(Enchantments.FROST_WALKER, this); -@@ -378,11 +442,10 @@ +@@ -378,11 +413,10 @@ { ++this.deathTime; @@ -215,7 +261,7 @@ i = net.minecraftforge.event.ForgeEventFactory.getExperienceDrop(this, this.attackingPlayer, i); while (i > 0) { -@@ -390,7 +453,7 @@ +@@ -390,7 +424,7 @@ i -= j; this.world.spawnEntity(new EntityXPOrb(this.world, this.posX, this.posY, this.posZ, j)); } @@ -224,7 +270,7 @@ this.setDead(); -@@ -445,6 +508,7 @@ +@@ -445,6 +479,7 @@ { this.revengeTarget = livingBase; this.revengeTimer = this.ticksExisted; @@ -232,7 +278,7 @@ } public EntityLivingBase getLastAttackedEntity() -@@ -566,6 +630,17 @@ +@@ -566,6 +601,17 @@ } } @@ -250,7 +296,7 @@ if (compound.hasKey("Health", 99)) { this.setHealth(compound.getFloat("Health")); -@@ -592,9 +667,15 @@ +@@ -592,9 +638,15 @@ } } @@ -266,7 +312,7 @@ try { -@@ -622,6 +703,18 @@ +@@ -622,6 +674,18 @@ ; } @@ -285,7 +331,7 @@ if (this.potionsNeedUpdate) { if (!this.world.isRemote) -@@ -712,6 +805,7 @@ +@@ -712,6 +776,7 @@ if(net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.living.PotionEvent.PotionRemoveEvent(this, effect))) continue; this.onFinishedPotionEffect(effect); @@ -293,7 +339,7 @@ iterator.remove(); } } -@@ -740,6 +834,12 @@ +@@ -740,6 +805,12 @@ public void addPotionEffect(PotionEffect potioneffectIn) { @@ -306,7 +352,7 @@ if (this.isPotionApplicable(potioneffectIn)) { PotionEffect potioneffect = this.activePotionsMap.get(potioneffectIn.getPotion()); -@@ -784,6 +884,12 @@ +@@ -784,6 +855,12 @@ @Nullable public PotionEffect removeActivePotionEffect(@Nullable Potion potioneffectin) { @@ -319,7 +365,7 @@ return this.activePotionsMap.remove(potioneffectin); } -@@ -830,25 +936,57 @@ +@@ -830,25 +907,57 @@ } } @@ -360,7 +406,7 @@ public void setHealth(float health) { + // CraftBukkit start - Handle scaled health -+ if (this instanceof EntityPlayer) { ++ if (this instanceof EntityPlayerMP && ((EntityPlayerMP)this).getGameProfile() != null) { + org.bukkit.craftbukkit.entity.CraftPlayer player = ((EntityPlayerMP) this).getBukkitEntity(); + // Squeeze + if (health < 0.0F) { @@ -378,7 +424,7 @@ this.dataManager.set(HEALTH, Float.valueOf(MathHelper.clamp(health, 0.0F, this.getMaxHealth()))); } -@@ -879,15 +1017,17 @@ +@@ -879,15 +988,17 @@ { float f = amount; @@ -399,7 +445,7 @@ { this.damageShield(amount); amount = 0.0F; -@@ -912,22 +1052,42 @@ +@@ -912,22 +1023,42 @@ { if (amount <= this.lastDamage) { @@ -444,7 +490,7 @@ this.attackedAtYaw = 0.0F; Entity entity1 = source.getTrueSource(); -@@ -943,9 +1103,9 @@ +@@ -943,9 +1074,9 @@ this.recentlyHit = 100; this.attackingPlayer = (EntityPlayer)entity1; } @@ -456,7 +502,24 @@ if (entitywolf.isTamed()) { -@@ -1065,22 +1225,30 @@ +@@ -1013,14 +1144,10 @@ + { + if (!this.checkTotemDeathProtection(source)) + { +- SoundEvent soundevent = this.getDeathSound(); ++ this.silentDeath = !flag1; // mark entity as dying silently + +- if (flag1 && soundevent != null) +- { +- this.playSound(soundevent, this.getSoundVolume(), this.getSoundPitch()); +- } +- + this.onDeath(source); ++ this.silentDeath = false; // Paper - cancellable death event - reset to default + } + } + else if (flag1) +@@ -1065,22 +1192,30 @@ else { ItemStack itemstack = null; @@ -492,7 +555,7 @@ { EntityPlayerMP entityplayermp = (EntityPlayerMP)this; entityplayermp.addStat(StatList.getObjectUseStats(Items.TOTEM_OF_UNDYING)); -@@ -1094,7 +1262,8 @@ +@@ -1094,7 +1229,8 @@ this.world.setEntityState(this, (byte)35); } @@ -502,7 +565,28 @@ } } -@@ -1196,11 +1365,25 @@ +@@ -1171,19 +1307,8 @@ + 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(); +- ++ org.bukkit.event.entity.EntityDeathEvent deathEvent = null; + if (!this.world.isRemote) + { + int i = net.minecraftforge.common.ForgeHooks.getLootingLevel(this, entity, cause); +@@ -1196,11 +1321,27 @@ boolean flag = this.recentlyHit > 0; this.dropLoot(flag, i, cause); } @@ -520,16 +604,52 @@ + { + this.drops.add(CraftItemStack.asCraftMirror(item.getItem())); + } -+ CraftEventFactory.callEntityDeathEvent(this, this.drops); -+ } else { -+ CraftEventFactory.callEntityDeathEvent(this); -+ // Magma end ++ deathEvent = CraftEventFactory.callEntityDeathEvent(this, this.drops); // Paper - cancellable death event ++ } ++ else ++ { ++ deathEvent = CraftEventFactory.callEntityDeathEvent(this); // Paper - cancellable death event ++ // CraftBukkit end + } + for (EntityItem item : capturedDrops) { world.spawnEntity(item); -@@ -1321,8 +1504,13 @@ +@@ -1208,7 +1349,25 @@ + } + } + ++ // Paper start - cancellable death event ++ if (deathEvent == null || !deathEvent.isCancelled()) { ++ // triggers and stats got moved down ++ if (this.scoreValue >= 0 && entitylivingbase != null) { ++ entitylivingbase.awardKillScore(this, this.scoreValue, cause); ++ } ++ ++ if (entity != null) { ++ entity.onKillEntity(this); ++ } ++ ++ this.getCombatTracker().reset(); ++ this.dead = true; + this.world.setEntityState(this, (byte)3); ++ } else { ++ this.dead = false; // Paper - reset if cancelled ++ this.setHealth((float) deathEvent.getReviveHealth()); ++ } ++ // Paper end + } + } + +@@ -1255,6 +1414,7 @@ + return SoundEvents.ENTITY_GENERIC_HURT; + } + ++ @Nullable public SoundEvent getDeathSoundEffect() { return getDeathSound();} // Paper - OBFHELPER + @Nullable + protected SoundEvent getDeathSound() + { +@@ -1321,8 +1481,13 @@ if (i > 0) { @@ -544,7 +664,7 @@ int j = MathHelper.floor(this.posX); int k = MathHelper.floor(this.posY - 0.20000000298023224D); int l = MathHelper.floor(this.posZ); -@@ -1362,7 +1550,7 @@ +@@ -1362,7 +1527,7 @@ { if (!source.isUnblockable()) { @@ -553,7 +673,7 @@ damage = CombatRules.getDamageAfterAbsorb(damage, (float)this.getTotalArmorValue(), (float)this.getEntityAttribute(SharedMonsterAttributes.ARMOR_TOUGHNESS).getAttributeValue()); } -@@ -1377,7 +1565,8 @@ +@@ -1377,7 +1542,8 @@ } else { @@ -563,133 +683,153 @@ { int i = (this.getActivePotionEffect(MobEffects.RESISTANCE).getAmplifier() + 1) * 5; int j = 25 - i; -@@ -1405,6 +1594,8 @@ +@@ -1405,25 +1571,151 @@ 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); + this.damageEntity_CB(damageSrc, damageAmount); -+ /* - if (!this.isEntityInvulnerable(damageSrc)) - { - damageAmount = net.minecraftforge.common.ForgeHooks.onLivingHurt(this, damageSrc, damageAmount); -@@ -1424,8 +1615,153 @@ - this.setAbsorptionAmount(this.getAbsorptionAmount() - 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); ++ private EntityDamageEvent calculateDebuffsAndCallCB(final DamageSource damagesource, float f) { ++ final boolean human = this instanceof EntityPlayer; ++ final float originalDamage = f; ++ // Calculates the damage debuff that occurs when an entity has something on his/her head ++ Function hardHat = f12 -> { ++ if ((damagesource == DamageSource.ANVIL || damagesource == DamageSource.FALLING_BLOCK) ++ && EntityLivingBase.this.getItemStackFromSlot(EntityEquipmentSlot.HEAD) != null) { ++ // Saves you from 1/4 damage ++ return -(f12 * 0.25F); + } ++ return -0.0; ++ }; ++ float hardHatModifier = hardHat.apply((double) f).floatValue(); ++ f += hardHatModifier; ++ ++ // Calculates the damage debuff that occurs when a player is blocking and can block the damage source ++ Function blocking = f13 -> { ++ if (human) { ++ if (!damagesource.isUnblockable() && ((EntityPlayer) EntityLivingBase.this).isActiveItemStackBlocking() && f13 > 0.0F) { ++ //Reduce by a bit more than half ++ return -(f13 - ((1.0F + f13) * 0.5F)); ++ } ++ } ++ return -0.0; ++ }; ++ float blockingModifier = blocking.apply((double) f).floatValue(); ++ f += blockingModifier; ++ ++ // Calculates the damage debuff that occurs when a player (or entity) is wearing armor...this is damn problematic ++ Function armor = f14 -> { ++ // Cauldron start - apply forge armor hook ++ if (human) { ++ return -(f14 - ISpecialArmor.ArmorProperties.ApplyArmor(EntityLivingBase.this, ((EntityPlayer) EntityLivingBase.this).inventory.armorInventory, damagesource, f14.floatValue(), false)); ++ } ++ // Cauldron end ++ return -(f14 - EntityLivingBase.this.applyArmorCalculations(damagesource, f14.floatValue())); ++ }; ++ float armorModifier = armor.apply((double) f).floatValue(); ++ f += armorModifier; ++ ++ // Calculates potion effect debuffs ++ Function resistance = f15 -> { ++ if (!damagesource.isDamageAbsolute() && EntityLivingBase.this.isPotionActive(MobEffects.RESISTANCE) && damagesource != DamageSource.OUT_OF_WORLD) { ++ int i = (EntityLivingBase.this.getActivePotionEffect(MobEffects.RESISTANCE).getAmplifier() + 1) * 5; ++ int j = 25 - i; ++ float f1 = f15.floatValue() * (float) j; ++ return -(f15 - (f1 / 25.0F)); ++ } ++ return -0.0; ++ }; ++ float resistanceModifier = resistance.apply((double) f).floatValue(); ++ f += resistanceModifier; ++ ++ // Calculates other potion effect debuffs ++ Function magic = new Function() { ++ @Override ++ public Double apply(Double f) { ++ return -(f - EntityLivingBase.this.applyPotionDamageCalculations(damagesource, f.floatValue())); ++ } ++ }; ++ float magicModifier = magic.apply((double) f).floatValue(); ++ f += magicModifier; ++ ++ // Calculates "damage absorption ability" debuffs ++ Function absorption = new Function() { ++ @Override ++ public Double apply(Double f) { ++ return -(Math.max(f - Math.max(f - EntityLivingBase.this.getAbsorptionAmount(), 0.0F), 0.0F)); ++ } ++ }; ++ float absorptionModifier = absorption.apply((double) f).floatValue(); ++ ++ EntityDamageEvent event = CraftEventFactory.handleLivingEntityDamageEvent(this, damagesource, originalDamage, hardHatModifier, blockingModifier, armorModifier, resistanceModifier, magicModifier, absorptionModifier, hardHat, blocking, armor, resistance, magic, absorption); ++ ++ return event; ++ } ++ + // CraftBukkit start + protected boolean damageEntity_CB(final DamageSource damagesource, float f) { // void -> boolean, add final + if (!this.isEntityInvulnerable(damagesource)) { ++ // Check if entity is a "human" aka player + final boolean human = this instanceof EntityPlayer; -+ f = net.minecraftforge.common.ForgeHooks.onLivingHurt(this, damagesource, f); ++ final float originalDamage = f; ++ // Cauldron start - apply forge damage hook ++ f = ForgeHooks.onLivingHurt(this, damagesource, f); ++ // If the damage is negative return true + if (f < 0) return true; -+ if (human) { -+ f = net.minecraftforge.common.ISpecialArmor.ArmorProperties.applyArmor(this, ((EntityPlayer)this).inventory.armorInventory, damagesource, f); -+ if (f <= 0) return false; -+ } -+ float originalDamage = f; -+ Function hardHat = new Function() { -+ @Override -+ public Double apply(Double f) { -+ if ((damagesource == DamageSource.ANVIL || damagesource == DamageSource.FALLING_BLOCK) && !EntityLivingBase.this.getItemStackFromSlot(EntityEquipmentSlot.HEAD).isEmpty()) { -+ return -(f - (f * 0.75F)); ++ // Thermos detect null damage ++ final boolean nulldmg = f == 0; ++ // Cauldron end + -+ } -+ return -0.0; -+ } -+ }; -+ float hardHatModifier = hardHat.apply((double) f).floatValue(); -+ f += hardHatModifier; -+ -+ Function blocking = new Function() { -+ @Override -+ public Double apply(Double f) { -+ return -((EntityLivingBase.this.canBlockDamageSource(damagesource)) ? f : 0.0); -+ } -+ }; -+ float blockingModifier = blocking.apply((double) f).floatValue(); -+ f += blockingModifier; -+ -+ Function armor = new Function() { -+ @Override -+ public Double apply(Double f) { -+ return -(f - EntityLivingBase.this.applyArmorCalculations(damagesource, f.floatValue())); -+ } -+ }; -+ float armorModifier = armor.apply((double) f).floatValue(); -+ f += armorModifier; -+ -+ Function resistance = new Function() { -+ @Override -+ public Double apply(Double f) { -+ if (!damagesource.isDamageAbsolute() && EntityLivingBase.this.isPotionActive(MobEffects.RESISTANCE) && damagesource != DamageSource.OUT_OF_WORLD) { -+ int i = (EntityLivingBase.this.getActivePotionEffect(MobEffects.RESISTANCE).getAmplifier() + 1) * 5; -+ int j = 25 - i; -+ float f1 = f.floatValue() * (float) j; -+ return -(f - (f1 / 25.0F)); -+ } -+ return -0.0; -+ } -+ }; -+ float resistanceModifier = resistance.apply((double) f).floatValue(); -+ f += resistanceModifier; -+ -+ Function magic = new Function() { -+ @Override -+ public Double apply(Double f) { -+ return -(f - EntityLivingBase.this.applyPotionDamageCalculations(damagesource, f.floatValue())); -+ } -+ }; -+ float magicModifier = magic.apply((double) f).floatValue(); -+ f += magicModifier; -+ -+ Function absorption = new Function() { -+ @Override -+ public Double apply(Double f) { -+ return -(Math.max(f - Math.max(f - EntityLivingBase.this.getAbsorptionAmount(), 0.0F), 0.0F)); -+ } -+ }; -+ float absorptionModifier = absorption.apply((double) f).floatValue(); + -+ EntityDamageEvent event = CraftEventFactory.handleLivingEntityDamageEvent(this, damagesource, originalDamage, hardHatModifier, blockingModifier, armorModifier, resistanceModifier, magicModifier, absorptionModifier, hardHat, blocking, armor, resistance, magic, absorption); -+ if (event.isCancelled()) { ++ EntityDamageEvent ede = calculateDebuffsAndCallCB(damagesource, f); ++ ++ if (ede.isCancelled()) { + return false; + } ++ f = (float) ede.getFinalDamage(); + -+ f = (float) event.getFinalDamage(); ++ if (nulldmg) return true; // Preclude any stupidity with null head items + + // Apply damage to helmet + if ((damagesource == DamageSource.ANVIL || damagesource == DamageSource.FALLING_BLOCK) && this.getItemStackFromSlot(EntityEquipmentSlot.HEAD) != null) { -+ this.getItemStackFromSlot(EntityEquipmentSlot.HEAD).damageItem((int) (event.getDamage() * 4.0F + this.rand.nextFloat() * event.getDamage() * 2.0F), this); ++ this.getItemStackFromSlot(EntityEquipmentSlot.HEAD).damageItem((int) (ede.getDamage() * 4.0F + this.rand.nextFloat() * ede.getDamage() * 2.0F), this); + } + + // Apply damage to armor + if (!damagesource.isUnblockable()) { -+ float armorDamage = (float) (event.getDamage() + event.getDamage(EntityDamageEvent.DamageModifier.BLOCKING) + event.getDamage(EntityDamageEvent.DamageModifier.HARD_HAT)); -+ this.damageArmor(armorDamage); -+ } -+ -+ // Apply blocking code // PAIL: steal from above -+ if (event.getDamage(EntityDamageEvent.DamageModifier.BLOCKING) < 0) { -+ this.damageShield((float) -event.getDamage(EntityDamageEvent.DamageModifier.BLOCKING)); -+ Entity entity = damagesource.getImmediateSource(); -+ -+ if (entity instanceof EntityLivingBase) { -+ this.blockUsingShield((EntityLivingBase) entity); ++ float armorDamage = (float) (ede.getDamage() + ede.getDamage(EntityDamageEvent.DamageModifier.BLOCKING) + ede.getDamage(EntityDamageEvent.DamageModifier.HARD_HAT)); ++ if (human) { ++ EntityPlayer player = (EntityPlayer) this; ++ armorDamage = ISpecialArmor.ArmorProperties.ApplyArmor(player, player.inventory.armorInventory, damagesource, armorDamage, true); ++ } else { ++ this.damageArmor(armorDamage); + } -+ } + -+ absorptionModifier = (float) -event.getDamage(EntityDamageEvent.DamageModifier.ABSORPTION); ++ // Thermos AVOID DAMAGE if armor nullifies it (CraftBukkit failed to include this, this is why TFC bug happened) ++ if (armorDamage <= 0) return true; ++ } ++ float absorptionModifier = (float) -ede.getDamage(EntityDamageEvent.DamageModifier.ABSORPTION); + this.setAbsorptionAmount(Math.max(this.getAbsorptionAmount() - absorptionModifier, 0.0F)); -+ if (f > 0 || !human) { ++ if (f != 0.0F) { + if (human) { -+ // PAIL: Be sure to drag all this code from the EntityPlayer subclass each update. + ((EntityPlayer) this).addExhaustion(damagesource.getHungerDamage()); -+ if (f < 3.4028235E37F) { -+ ((EntityPlayer) this).addStat(StatList.DAMAGE_TAKEN, Math.round(f * 10.0F)); -+ } + } + // CraftBukkit end + float f2 = this.getHealth(); @@ -697,36 +837,21 @@ + this.setHealth(f2 - f); + this.getCombatTracker().trackDamage(damagesource, f2, f); + // CraftBukkit start -+ if (!human) { -+ this.setAbsorptionAmount(this.getAbsorptionAmount() - f); -+ } -+ -+ return true; -+ } else { -+ // Duplicate triggers if blocking -+ if (event.getDamage(EntityDamageEvent.DamageModifier.BLOCKING) < 0) { -+ if (this instanceof EntityPlayerMP) { -+ CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((EntityPlayerMP) this, damagesource, f, originalDamage, true); -+ } -+ -+ if (damagesource.getTrueSource() instanceof EntityPlayerMP) { -+ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((EntityPlayerMP) damagesource.getTrueSource(), this, damagesource, f, originalDamage, true); -+ } -+ -+ return false; -+ } else { -+ return originalDamage > 0; ++ if (human) { ++ return true; + } + // CraftBukkit end ++ // CraftBukkit start ++ this.setAbsorptionAmount(this.getAbsorptionAmount() - f); ++ // CraftBukkit end + } -+ } ++ return true; // CraftBukkit + } + return false; // CraftBukkit -+ } -+ + } + public CombatTracker getCombatTracker() - { - return this._combatTracker; -@@ -1605,6 +1941,7 @@ +@@ -1605,6 +1897,7 @@ if (this.attributeMap == null) { this.attributeMap = new AttributeMap(); @@ -734,7 +859,21 @@ } return this.attributeMap; -@@ -1900,7 +2237,8 @@ +@@ -1685,11 +1978,13 @@ + } + } + ++ public float getDeathSoundVolume() { return getSoundVolume();} // Paper - OBFHELPER + protected float getSoundVolume() + { + return 1.0F; + } + ++ public float getDeathSoundPitch() { return getSoundPitch();} // Paper - OBFHELPER + 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; +@@ -1900,7 +2195,8 @@ if (this.onGround && !this.world.isRemote) { @@ -744,7 +883,7 @@ } } else -@@ -2345,7 +2683,6 @@ +@@ -2345,7 +2641,6 @@ } this.world.profiler.startSection("ai"); @@ -752,7 +891,7 @@ if (this.isMovementBlocked()) { this.isJumping = false; -@@ -2426,6 +2763,7 @@ +@@ -2426,6 +2721,7 @@ if (!this.world.isRemote) { @@ -760,7 +899,7 @@ this.setFlag(7, flag); } } -@@ -2560,12 +2898,12 @@ +@@ -2560,12 +2856,12 @@ public boolean canBeCollidedWith() { @@ -775,7 +914,7 @@ } protected void markVelocityChanged() -@@ -2629,7 +2967,7 @@ +@@ -2629,7 +2925,7 @@ { PotionEffect effect = iterator.next(); @@ -784,7 +923,7 @@ { onFinishedPotionEffect(effect); iterator.remove(); -@@ -2667,7 +3005,8 @@ +@@ -2667,7 +2963,8 @@ if (this.isHandActive()) { ItemStack itemstack = this.getHeldItem(this.getActiveHand()); @@ -794,15 +933,16 @@ if (itemstack == this.activeItemStack) { -@@ -2786,7 +3125,24 @@ +@@ -2785,8 +3082,25 @@ + if (!this.activeItemStack.isEmpty() && this.isHandActive()) { this.updateItemUse(this.activeItemStack, 16); - ItemStack activeItemStackCopy = this.activeItemStack.copy(); +- ItemStack activeItemStackCopy = this.activeItemStack.copy(); - ItemStack itemstack = this.activeItemStack.onItemUseFinish(this.world, this); -+ // CraftBukkit start - fire PlayerItemConsumeEvent -+ ItemStack itemstack; ++ ItemStack itemstack = this.activeItemStack; ++ + if (this instanceof EntityPlayer) { -+ org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitCopy(this.activeItemStack); ++ org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitCopy(itemstack); + PlayerItemConsumeEvent event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem); + world.getServer().getPluginManager().callEvent(event); + @@ -813,14 +953,15 @@ + return; + } + -+ itemstack = (craftItem.equals(event.getItem())) ? this.activeItemStack.onItemUseFinish(this.world, this) : CraftItemStack.asNMSCopy(event.getItem()).onItemUseFinish(world, this); -+ } else { -+ itemstack = this.activeItemStack.onItemUseFinish(this.world, this); ++ itemstack = CraftItemStack.asNMSCopy(event.getItem()); + } ++ ++ ItemStack activeItemStackCopy = activeItemStack.copy(); ++ itemstack = itemstack.onItemUseFinish(world, this); itemstack = net.minecraftforge.event.ForgeEventFactory.onItemUseFinish(this, activeItemStackCopy, getItemInUseCount(), itemstack); this.setHeldItem(this.getActiveHand(), itemstack); this.resetActiveHand(); -@@ -2897,12 +3253,17 @@ +@@ -2897,12 +3211,17 @@ if (flag1) { @@ -843,7 +984,7 @@ } } -@@ -2936,6 +3297,11 @@ +@@ -2936,6 +3255,11 @@ } } @@ -855,7 +996,7 @@ public boolean canBeHitWithPotion() { return true; -@@ -2949,7 +3315,7 @@ +@@ -2949,7 +3273,7 @@ @SuppressWarnings("unchecked") @Override @Nullable @@ -864,7 +1005,7 @@ { if (capability == net.minecraftforge.items.CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) { -@@ -2961,7 +3327,7 @@ +@@ -2961,7 +3285,7 @@ } @Override diff --git a/patches/net/minecraft/entity/item/EntityArmorStand.java.patch b/patches/net/minecraft/entity/item/EntityArmorStand.java.patch index cafed87..c475fb1 100644 --- a/patches/net/minecraft/entity/item/EntityArmorStand.java.patch +++ b/patches/net/minecraft/entity/item/EntityArmorStand.java.patch @@ -160,15 +160,16 @@ this.armorItems.set(j, ItemStack.EMPTY); } } -@@ -791,6 +827,7 @@ +@@ -791,6 +827,8 @@ public void onKillCommand() { -+ org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, drops); // CraftBukkit - call event ++ org.bukkit.event.entity.EntityDeathEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityDeathEvent(this, drops); // CraftBukkit - call event // Paper - make cancellable ++ if (event.isCancelled()) return; // Paper - make cancellable this.setDead(); } -@@ -804,7 +841,7 @@ +@@ -804,7 +842,7 @@ return this.hasMarker() ? EnumPushReaction.IGNORE : super.getPushReaction(); } @@ -177,7 +178,7 @@ { this.dataManager.set(STATUS, Byte.valueOf(this.setBit(((Byte)this.dataManager.get(STATUS)).byteValue(), 1, small))); this.setSize(0.5F, 1.975F); -@@ -815,7 +852,7 @@ +@@ -815,7 +853,7 @@ return (((Byte)this.dataManager.get(STATUS)).byteValue() & 1) != 0; } @@ -186,7 +187,7 @@ { this.dataManager.set(STATUS, Byte.valueOf(this.setBit(((Byte)this.dataManager.get(STATUS)).byteValue(), 4, showArms))); } -@@ -825,7 +862,7 @@ +@@ -825,7 +863,7 @@ return (((Byte)this.dataManager.get(STATUS)).byteValue() & 4) != 0; } @@ -195,7 +196,7 @@ { this.dataManager.set(STATUS, Byte.valueOf(this.setBit(((Byte)this.dataManager.get(STATUS)).byteValue(), 8, noBasePlate))); } -@@ -835,7 +872,7 @@ +@@ -835,7 +873,7 @@ return (((Byte)this.dataManager.get(STATUS)).byteValue() & 8) != 0; } @@ -204,7 +205,7 @@ { this.dataManager.set(STATUS, Byte.valueOf(this.setBit(((Byte)this.dataManager.get(STATUS)).byteValue(), 16, marker))); this.setSize(0.5F, 1.975F); -@@ -957,7 +994,7 @@ +@@ -957,7 +995,7 @@ return SoundEvents.ENTITY_ARMORSTAND_BREAK; } diff --git a/patches/net/minecraft/entity/item/EntityItemFrame.java.patch b/patches/net/minecraft/entity/item/EntityItemFrame.java.patch index 1146b0a..df4af2a 100644 --- a/patches/net/minecraft/entity/item/EntityItemFrame.java.patch +++ b/patches/net/minecraft/entity/item/EntityItemFrame.java.patch @@ -1,6 +1,17 @@ --- ../src-base/minecraft/net/minecraft/entity/item/EntityItemFrame.java +++ ../src-work/minecraft/net/minecraft/entity/item/EntityItemFrame.java -@@ -63,6 +63,9 @@ +@@ -24,7 +24,10 @@ + import net.minecraft.world.storage.MapData; + import net.minecraftforge.fml.relauncher.Side; + import net.minecraftforge.fml.relauncher.SideOnly; ++import org.apache.commons.io.Charsets; + ++import java.util.UUID; ++ + public class EntityItemFrame extends EntityHanging + { + private static final DataParameter ITEM = EntityDataManager.createKey(EntityItemFrame.class, DataSerializers.ITEM_STACK); +@@ -63,6 +66,9 @@ { if (!this.world.isRemote) { @@ -10,3 +21,12 @@ this.dropItemOrSelf(source.getTrueSource(), false); this.playSound(SoundEvents.ENTITY_ITEMFRAME_REMOVE_ITEM, 1.0F, 1.0F); this.setDisplayedItem(ItemStack.EMPTY); +@@ -143,7 +149,7 @@ + if (stack.getItem() instanceof net.minecraft.item.ItemMap) + { + MapData mapdata = ((ItemMap)stack.getItem()).getMapData(stack, this.world); +- mapdata.mapDecorations.remove("frame-" + this.getEntityId()); ++ mapdata.mapDecorations.remove(UUID.nameUUIDFromBytes(("frame-" + this.getEntityId()).getBytes(Charsets.US_ASCII))); // Spigot + } + + stack.setItemFrame((EntityItemFrame)null); diff --git a/patches/net/minecraft/network/NetHandlerPlayServer.java.patch b/patches/net/minecraft/network/NetHandlerPlayServer.java.patch index fe50d4b..578b192 100644 --- a/patches/net/minecraft/network/NetHandlerPlayServer.java.patch +++ b/patches/net/minecraft/network/NetHandlerPlayServer.java.patch @@ -1290,12 +1290,23 @@ CriteriaTriggers.CHANGED_DIMENSION.trigger(this.player, DimensionType.THE_END, DimensionType.OVERWORLD); } else -@@ -1136,17 +1897,21 @@ +@@ -1136,17 +1897,32 @@ public void processCloseWindow(CPacketCloseWindow packetIn) { PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.player.getServerWorld()); + if (this.player.isMovementBlocked()) return; -+ CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit ++ // Cauldron start - vanilla compatibility ++ try ++ { ++ if (this.player.openContainer.getBukkitView() != null) ++ { ++ CraftEventFactory.handleInventoryCloseEvent(this.player); // CraftBukkit ++ } ++ } ++ catch (AbstractMethodError e) ++ { ++ } ++ // Cauldron end this.player.closeContainer(); } @@ -1314,7 +1325,7 @@ { NonNullList nonnulllist = NonNullList.create(); -@@ -1159,9 +1924,286 @@ +@@ -1159,9 +1935,304 @@ } else { @@ -1500,9 +1511,17 @@ + ItemStack cursor = this.player.inventory.getItemStack(); + action = InventoryAction.NOTHING; + // Quick check for if we have any of the item -+ if (inventory.getTopInventory().contains(org.bukkit.Material.getMaterial(Item.getIdFromItem(cursor.getItem()))) || inventory.getBottomInventory().contains(org.bukkit.Material.getMaterial(Item.getIdFromItem(cursor.getItem())))) { -+ action = InventoryAction.COLLECT_TO_CURSOR; ++ // Cauldron start - can't call getContents() on modded IInventory; CB-added method ++ try ++ { ++ if (inventory.getTopInventory().contains(org.bukkit.Material.getMaterial(Item.getIdFromItem(cursor.getItem()))) || inventory.getBottomInventory().contains(org.bukkit.Material.getMaterial(Item.getIdFromItem(cursor.getItem())))) { ++ action = InventoryAction.COLLECT_TO_CURSOR; ++ } ++ } ++ catch (AbstractMethodError ex) { ++ // nothing we can do + } ++ // Cauldron end + } + break; + default: @@ -1518,7 +1537,17 @@ + + org.bukkit.inventory.Inventory top = inventory.getTopInventory(); + if (packetIn.getSlotId() == 0 && top instanceof CraftingInventory) { -+ org.bukkit.inventory.Recipe recipe = ((CraftingInventory) top).getRecipe(); ++ // Cauldron start - vanilla compatibility (mod recipes) ++ org.bukkit.inventory.Recipe recipe = null; ++ try ++ { ++ recipe = ((CraftingInventory) top).getRecipe(); ++ } ++ catch (AbstractMethodError e) ++ { ++ // do nothing ++ } ++ // Cauldron end + if (recipe != null) { + if (click == ClickType.NUMBER_KEY) { + event = new CraftItemEvent(recipe, inventory, type, packetIn.getSlotId(), click, action, packetIn.getUsedButton()); @@ -1603,7 +1632,7 @@ { this.player.connection.sendPacket(new SPacketConfirmTransaction(packetIn.getWindowId(), packetIn.getActionNumber(), true)); this.player.isChangingQuantityOnly = true; -@@ -1178,8 +2220,8 @@ +@@ -1178,8 +2249,8 @@ for (int j = 0; j < this.player.openContainer.inventorySlots.size(); ++j) { @@ -1614,7 +1643,7 @@ nonnulllist1.add(itemstack1); } -@@ -1203,6 +2245,7 @@ +@@ -1203,6 +2274,7 @@ public void processEnchantItem(CPacketEnchantItem packetIn) { PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.player.getServerWorld()); @@ -1622,7 +1651,7 @@ this.player.markPlayerActive(); if (this.player.openContainer.windowId == packetIn.getWindowId() && this.player.openContainer.getCanCraft(this.player) && !this.player.isSpectator()) -@@ -1242,8 +2285,47 @@ +@@ -1242,8 +2314,47 @@ } boolean flag1 = packetIn.getSlotId() >= 1 && packetIn.getSlotId() <= 45; @@ -1671,7 +1700,7 @@ if (flag1 && flag2) { if (itemstack.isEmpty()) -@@ -1273,6 +2355,7 @@ +@@ -1273,6 +2384,7 @@ public void processConfirmTransaction(CPacketConfirmTransaction packetIn) { PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.player.getServerWorld()); @@ -1679,7 +1708,7 @@ Short oshort = this.pendingTransactions.lookup(this.player.openContainer.windowId); if (oshort != null && packetIn.getUid() == oshort.shortValue() && this.player.openContainer.windowId == packetIn.getWindowId() && !this.player.openContainer.getCanCraft(this.player) && !this.player.isSpectator()) -@@ -1284,6 +2367,7 @@ +@@ -1284,6 +2396,7 @@ public void processUpdateSign(CPacketUpdateSign packetIn) { PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.player.getServerWorld()); @@ -1687,7 +1716,7 @@ this.player.markPlayerActive(); WorldServer worldserver = this.serverController.getWorld(this.player.dimension); BlockPos blockpos = packetIn.getPosition(); -@@ -1300,19 +2384,35 @@ +@@ -1300,19 +2413,35 @@ TileEntitySign tileentitysign = (TileEntitySign)tileentity; @@ -1725,7 +1754,7 @@ tileentitysign.markDirty(); worldserver.notifyBlockUpdate(blockpos, iblockstate, iblockstate, 3); } -@@ -1320,6 +2420,7 @@ +@@ -1320,6 +2449,7 @@ public void processKeepAlive(CPacketKeepAlive packetIn) { @@ -1733,7 +1762,7 @@ if (this.field_194403_g && packetIn.getKey() == this.field_194404_h) { int i = (int)(this.currentTimeMillis() - this.field_194402_f); -@@ -1328,7 +2429,11 @@ +@@ -1328,7 +2458,11 @@ } else if (!this.player.getName().equals(this.serverController.getServerOwner())) { @@ -1746,7 +1775,7 @@ } } -@@ -1340,12 +2445,25 @@ +@@ -1340,12 +2474,25 @@ public void processPlayerAbilities(CPacketPlayerAbilities packetIn) { PacketThreadUtil.checkThreadAndEnqueue(packetIn, this, this.player.getServerWorld()); @@ -1773,7 +1802,7 @@ List list = Lists.newArrayList(); for (String s : this.serverController.getTabCompletions(this.player, packetIn.getMessage(), packetIn.getTargetBlock(), packetIn.hasTargetBlock())) -@@ -1369,6 +2487,11 @@ +@@ -1369,6 +2516,11 @@ if ("MC|BEdit".equals(s)) { @@ -1785,7 +1814,7 @@ PacketBuffer packetbuffer = packetIn.getBufferData(); try -@@ -1395,15 +2518,22 @@ +@@ -1395,15 +2547,22 @@ if (itemstack.getItem() == Items.WRITABLE_BOOK && itemstack.getItem() == itemstack1.getItem()) { itemstack1.setTagInfo("pages", itemstack.getTagCompound().getTagList("pages", 8)); @@ -1808,7 +1837,7 @@ PacketBuffer packetbuffer1 = packetIn.getBufferData(); try -@@ -1443,12 +2573,14 @@ +@@ -1443,12 +2602,14 @@ } itemstack2.setTagInfo("pages", nbttaglist); @@ -1824,7 +1853,7 @@ } } else if ("MC|TrSel".equals(s)) -@@ -1466,6 +2598,7 @@ +@@ -1466,6 +2627,7 @@ catch (Exception exception5) { LOGGER.error("Couldn't select trade", (Throwable)exception5); @@ -1832,7 +1861,7 @@ } } else if ("MC|AdvCmd".equals(s)) -@@ -1528,6 +2661,7 @@ +@@ -1528,6 +2690,7 @@ catch (Exception exception4) { LOGGER.error("Couldn't set command block", (Throwable)exception4); @@ -1840,7 +1869,7 @@ } } else if ("MC|AutoCmd".equals(s)) -@@ -1606,6 +2740,7 @@ +@@ -1606,6 +2769,7 @@ catch (Exception exception3) { LOGGER.error("Couldn't set command block", (Throwable)exception3); @@ -1848,7 +1877,7 @@ } } else if ("MC|Beacon".equals(s)) -@@ -1632,6 +2767,7 @@ +@@ -1632,6 +2796,7 @@ catch (Exception exception2) { LOGGER.error("Couldn't set beacon", (Throwable)exception2); @@ -1856,7 +1885,7 @@ } } } -@@ -1743,6 +2879,7 @@ +@@ -1743,6 +2908,7 @@ catch (Exception exception1) { LOGGER.error("Couldn't set structure block", (Throwable)exception1); @@ -1864,7 +1893,7 @@ } } else if ("MC|PickItem".equals(s)) -@@ -1760,7 +2897,43 @@ +@@ -1760,7 +2926,43 @@ catch (Exception exception) { LOGGER.error("Couldn't pick item", (Throwable)exception); diff --git a/patches/net/minecraftforge/common/ISpecialArmor.java.patch b/patches/net/minecraftforge/common/ISpecialArmor.java.patch new file mode 100644 index 0000000..8773a17 --- /dev/null +++ b/patches/net/minecraftforge/common/ISpecialArmor.java.patch @@ -0,0 +1,28 @@ +--- ../src-base/minecraft/net/minecraftforge/common/ISpecialArmor.java ++++ ../src-work/minecraft/net/minecraftforge/common/ISpecialArmor.java +@@ -131,6 +131,11 @@ + */ + public static float applyArmor(EntityLivingBase entity, NonNullList inventory, DamageSource source, double damage) + { ++ return ApplyArmor(entity, inventory, source, damage, true); ++ } ++ ++ public static float ApplyArmor(EntityLivingBase entity, NonNullList inventory, DamageSource source, double damage, boolean applyDamage) ++ { + if (DEBUG) + { + System.out.println("Start: " + damage); +@@ -201,9 +206,12 @@ + int itemDamage = (int)Math.max(1, absorb); + if (stack.getItem() instanceof ISpecialArmor) + { ++ if (applyDamage) ++ { + ((ISpecialArmor)stack.getItem()).damageArmor(entity, stack, source, itemDamage, prop.Slot); + } +- else ++ } ++ else if(applyDamage) + { + if (DEBUG) + { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftSound.java b/src/main/java/org/bukkit/craftbukkit/CraftSound.java index be48f6e..a273e39 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftSound.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftSound.java @@ -4,6 +4,8 @@ import net.minecraft.util.ResourceLocation; import net.minecraft.util.SoundEvent; +import net.minecraftforge.common.util.EnumHelper; +import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.Validate; import org.bukkit.Sound; @@ -560,6 +562,29 @@ public enum CraftSound { WEATHER_RAIN_ABOVE("weather.rain.above"); private final String minecraftKey; + // Paper start - cancellable death event + public static CraftSound getBySoundEffect(final SoundEvent effect) { + ResourceLocation key = SoundEvent.REGISTRY.getNameForObject(effect); + Preconditions.checkArgument(key != null, "Key for sound effect %s not found?", effect.toString()); + String cs = key.getResourcePath().replace('.', '_').toUpperCase(java.util.Locale.ENGLISH); + String cskey = key.toString().replace(':', '.'); + if (!EnumUtils.isValidEnum(Sound.class, cs)) { + EnumHelper.addEnum(Sound.class, cs, new Class[0], new Object[0]); + } + if (!EnumUtils.isValidEnum(CraftSound.class, cs)) { + EnumHelper.addEnum(CraftSound.class, cs, new Class[] {String.class}, new Object[] {key.toString()}); + } + return valueOf(cs); + } + + public static Sound getSoundByEffect(final SoundEvent effect) { + return Sound.valueOf(getBySoundEffect(effect).name()); + } + + public static SoundEvent getSoundEffect(final Sound sound) { + return getSoundEffect(getSound(sound)); + } + // Paper end CraftSound(String minecraftKey) { this.minecraftKey = minecraftKey; } diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java index fcab1d7..698c91d 100644 --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java @@ -49,14 +49,71 @@ public CraftBlock(CraftChunk chunk, int x, int y, int z) { this.chunk = chunk; } - private net.minecraft.block.Block getNMSBlock() { - return CraftMagicNumbers.getBlock(this); // TODO: UPDATE THIS - } - private static net.minecraft.block.Block getNMSBlock(int type) { return CraftMagicNumbers.getBlock(type); } + public static BlockFace notchToBlockFace(EnumFacing notch) { + if (notch == null) { + return BlockFace.SELF; + } + switch (notch) { + case DOWN: + return BlockFace.DOWN; + case UP: + return BlockFace.UP; + case NORTH: + return BlockFace.NORTH; + case SOUTH: + return BlockFace.SOUTH; + case WEST: + return BlockFace.WEST; + case EAST: + return BlockFace.EAST; + default: + return BlockFace.SELF; + } + } + + public static EnumFacing blockFaceToNotch(BlockFace face) { + switch (face) { + case DOWN: + return EnumFacing.DOWN; + case UP: + return EnumFacing.UP; + case NORTH: + return EnumFacing.NORTH; + case SOUTH: + return EnumFacing.SOUTH; + case WEST: + return EnumFacing.WEST; + case EAST: + return EnumFacing.EAST; + default: + return null; + } + } + + public static Biome biomeBaseToBiome(net.minecraft.world.biome.Biome base) { + if (base == null) { + return null; + } + + return Biome.valueOf(net.minecraft.world.biome.Biome.REGISTRY.getNameForObject(base).getResourcePath().toUpperCase(java.util.Locale.ENGLISH)); + } + + public static net.minecraft.world.biome.Biome biomeToBiomeBase(Biome bio) { + if (bio == null) { + return null; + } + + return net.minecraft.world.biome.Biome.REGISTRY.getObject(new ResourceLocation(bio.name().toLowerCase(java.util.Locale.ENGLISH))); + } + + private net.minecraft.block.Block getNMSBlock() { + return CraftMagicNumbers.getBlock(this); // TODO: UPDATE THIS + } + public World getWorld() { return chunk.getWorld(); } @@ -98,10 +155,6 @@ public Chunk getChunk() { return chunk; } - public void setData(final byte data) { - setData(data, 3); - } - public void setData(final byte data, boolean applyPhysics) { if (applyPhysics) { setData(data, 3); @@ -126,8 +179,8 @@ public byte getData() { return (byte) blockData.getBlock().getMetaFromState(blockData); } - public void setType(final Material type) { - setType(type, true); + public void setData(final byte data) { + setData(data, 3); } @Override @@ -174,6 +227,10 @@ public Material getType() { return Material.getMaterial(getTypeId()); } + public void setType(final Material type) { + setType(type, true); + } + @Deprecated @Override public int getTypeId() { @@ -233,63 +290,19 @@ public String toString() { return "CraftBlock{" + "chunk=" + chunk + ",x=" + x + ",y=" + y + ",z=" + z + ",type=" + getType() + ",data=" + getData() + '}'; } - public static BlockFace notchToBlockFace(EnumFacing notch) { - if (notch == null) return BlockFace.SELF; - switch (notch) { - case DOWN: - return BlockFace.DOWN; - case UP: - return BlockFace.UP; - case NORTH: - return BlockFace.NORTH; - case SOUTH: - return BlockFace.SOUTH; - case WEST: - return BlockFace.WEST; - case EAST: - return BlockFace.EAST; - default: - return BlockFace.SELF; - } - } - - public static EnumFacing blockFaceToNotch(BlockFace face) { - switch (face) { - case DOWN: - return EnumFacing.DOWN; - case UP: - return EnumFacing.UP; - case NORTH: - return EnumFacing.NORTH; - case SOUTH: - return EnumFacing.SOUTH; - case WEST: - return EnumFacing.WEST; - case EAST: - return EnumFacing.EAST; - default: - return null; - } - } - public BlockState getState() { Material material = getType(); - - // Magma start - if null, check for TE that implements IInventory (cauldron stuff) - if (material == null) - { - TileEntity te = ((CraftWorld)this.getWorld()).getHandle().getTileEntity(new BlockPos(this.getX(), this.getY(), this.getZ())); - if (te != null && te instanceof IInventory) - { - // In order to allow plugins to properly grab the container location, we must pass a class that extends CraftBlockState and implements InventoryHolder. - // Note: This will be returned when TileEntity.getOwner() is called + // Megma start - if null, check for TE that implements IInventory + if (material == null) { + TileEntity tileEntity = chunk.getCraftWorld().getTileEntityAt(x, y, z); + if (tileEntity == null) { + return new CraftBlockState(this); + } + if (tileEntity instanceof IInventory) { return new CraftCustomContainer(this); } - // pass default state - return new CraftBlockState(this); + return new CraftBlockEntityState(this, (Class) tileEntity.getClass()); } - // Magma end - switch (material) { case SIGN: case SIGN_POST: @@ -363,14 +376,17 @@ public BlockState getState() { case BED_BLOCK: return new CraftBed(this); default: + // Magma start TileEntity tileEntity = chunk.getCraftWorld().getTileEntityAt(x, y, z); - if (tileEntity != null) { - // block with unhandled TileEntity: - return new CraftBlockEntityState(this, (Class) tileEntity.getClass()); - } else { - // Block without TileEntity: + if (tileEntity == null) { return new CraftBlockState(this); } + if (tileEntity instanceof IInventory) { + // In order to allow plugins to properly grab the container location, we must pass a class that extends CraftBlockState and implements InventoryHolder. + // Note: This will be returned when TileEntity.getOwner() is called + return new CraftCustomContainer(this); + } + return new CraftBlockEntityState(this, (Class) tileEntity.getClass()); } } @@ -382,22 +398,6 @@ public void setBiome(Biome bio) { getWorld().setBiome(x, z, bio); } - public static Biome biomeBaseToBiome(net.minecraft.world.biome.Biome base) { - if (base == null) { - return null; - } - - return Biome.valueOf(net.minecraft.world.biome.Biome.REGISTRY.getNameForObject(base).getResourcePath().toUpperCase(java.util.Locale.ENGLISH)); - } - - public static net.minecraft.world.biome.Biome biomeToBiomeBase(Biome bio) { - if (bio == null) { - return null; - } - - return net.minecraft.world.biome.Biome.REGISTRY.getObject(new ResourceLocation(bio.name().toLowerCase(java.util.Locale.ENGLISH))); - } - public double getTemperature() { return getWorld().getTemperature(x, z); } @@ -461,7 +461,16 @@ public int getBlockPower() { } public boolean isEmpty() { - return getType() == Material.AIR; + // Magma start - support custom air blocks (Railcraft player aura tracking block) + //return getType() == Material.AIR; + if (getType() == Material.AIR) { + return true; + } + if (!(getWorld() instanceof CraftWorld)) { + return false; + } + return ((CraftWorld) getWorld()).getHandle().isAirBlock(new BlockPos(getX(), getY(), getZ())); + // Magma end } public boolean isLiquid() { diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index d5b8f3d..e8db920 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -75,6 +75,7 @@ import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.meta.BookMeta; +import org.spigotmc.AsyncCatcher; import javax.annotation.Nullable; import java.net.InetAddress; @@ -86,6 +87,7 @@ public class CraftEventFactory { public static final DamageSource MELTING = CraftDamageSource.copyOf(DamageSource.ON_FIRE); public static final DamageSource POISON = CraftDamageSource.copyOf(DamageSource.MAGIC); + private static final Function ZERO = Functions.constant(-0.0); public static Block blockDamage; // For use in EntityDamageByBlockEvent public static Entity entityDamage; // For use in EntityDamageByEntityEvent @@ -94,10 +96,18 @@ private static boolean canBuild(CraftWorld world, Player player, int x, int z) { WorldServer worldServer = world.getHandle(); int spawnSize = Bukkit.getServer().getSpawnRadius(); - if (world.getHandle().dimension != 0) return true; - if (spawnSize <= 0) return true; - if (((CraftServer) Bukkit.getServer()).getHandle().getOppedPlayers().isEmpty()) return true; - if (player.isOp()) return true; + if (world.getHandle().dimension != 0) { + return true; + } + if (spawnSize <= 0) { + return true; + } + if (((CraftServer) Bukkit.getServer()).getHandle().getOppedPlayers().isEmpty()) { + return true; + } + if (player.isOp()) { + return true; + } BlockPos chunkcoordinates = worldServer.getSpawnPoint(); @@ -121,8 +131,8 @@ public static BlockMultiPlaceEvent callBlockMultiPlaceEvent(World world, EntityP Block blockClicked = craftWorld.getBlockAt(clickedX, clickedY, clickedZ); boolean canBuild = true; - for (int i = 0; i < blockStates.size(); i++) { - if (!canBuild(craftWorld, player, blockStates.get(i).getX(), blockStates.get(i).getZ())) { + for (BlockState blockState : blockStates) { + if (!canBuild(craftWorld, player, blockState.getX(), blockState.getZ())) { canBuild = false; break; } @@ -407,19 +417,25 @@ public static EntityDeathEvent callEntityDeathEvent(EntityLivingBase victim) { public static EntityDeathEvent callEntityDeathEvent(EntityLivingBase victim, List drops) { CraftLivingEntity entity = (CraftLivingEntity) victim.getBukkitEntity(); EntityDeathEvent event = new EntityDeathEvent(entity, drops, victim.getExpReward()); - // CraftWorld world = (CraftWorld) entity.getWorld(); + populateFields(victim, event); // Paper - make cancellable Bukkit.getServer().getPluginManager().callEvent(event); - + // Paper start - make cancellable + if (event.isCancelled()) { + return event; + } + playDeathSound(victim, event); + // Paper end victim.expToDrop = event.getDroppedExp(); - //Magma start - clear captured drops to allow plugins make changes to them + // Magma start - handle any drop changes from plugins victim.capturedDrops.clear(); for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { - if (stack == null || stack.getType() == Material.AIR || stack.getAmount() == 0) continue; net.minecraft.entity.item.EntityItem entityitem = new net.minecraft.entity.item.EntityItem(victim.world, entity.getLocation().getX(), entity.getLocation().getY(), entity.getLocation().getZ(), CraftItemStack.asNMSCopy(stack)); - // world.dropItemNaturally(entity.getLocation(), stack); we don't want this, spawn items in EntityLivingBase.onDeath() (cauldron stuff) - victim.capturedDrops.add(entityitem); + if (entityitem != null) { + victim.capturedDrops.add((EntityItem) entityitem); } - //Magma end + } + // Magma end + return event; } @@ -427,8 +443,14 @@ public static PlayerDeathEvent callPlayerDeathEvent(EntityPlayerMP victim, List< CraftPlayer entity = victim.getBukkitEntity(); PlayerDeathEvent event = new PlayerDeathEvent(entity, drops, victim.getExpReward(), 0, deathMessage); event.setKeepInventory(keepInventory); - org.bukkit.World world = entity.getWorld(); + populateFields(victim, event); // Paper - make cancellable Bukkit.getServer().getPluginManager().callEvent(event); + // Paper start - make cancellable + if (event.isCancelled()) { + return event; + } + playDeathSound(victim, event); + // Paper end victim.keepLevel = event.getKeepLevel(); victim.newLevel = event.getNewLevel(); @@ -439,16 +461,49 @@ public static PlayerDeathEvent callPlayerDeathEvent(EntityPlayerMP victim, List< if (event.getKeepInventory()) { return event; } - - for (org.bukkit.inventory.ItemStack stack : event.getDrops()) { - if (stack == null || stack.getType() == Material.AIR) continue; - - world.dropItemNaturally(entity.getLocation(), stack); + victim.capturedDrops.clear(); // Cauldron - we must clear pre-capture to avoid duplicates + for (final org.bukkit.inventory.ItemStack stack : event.getDrops()) { + if (stack == null || stack.getType() == Material.AIR) { + continue; + } + // Cauldron start - add support for Forge's PlayerDropsEvent + if (victim.captureDrops) { + net.minecraft.entity.item.EntityItem entityitem = new net.minecraft.entity.item.EntityItem(victim.world, entity.getLocation().getX(), entity.getLocation().getY(), entity.getLocation().getZ(), CraftItemStack.asNMSCopy(stack)); + if (entityitem != null) { + victim.capturedDrops.add((EntityItem) entityitem); + } + } + // Cauldron end } - return event; } + // Paper start - helper methods for making death event cancellable + // Add information to death event + private static void populateFields(EntityLivingBase victim, EntityDeathEvent event) { + event.setReviveHealth(event.getEntity().getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue()); + event.setShouldPlayDeathSound(!victim.silentDeath && !victim.isSilent()); + SoundEvent soundEffect = victim.getDeathSoundEffect(); + event.setDeathSound(soundEffect != null ? org.bukkit.craftbukkit.CraftSound.getSoundByEffect(soundEffect) : null); + event.setDeathSoundCategory(org.bukkit.SoundCategory.valueOf(victim.getSoundCategory().name())); + event.setDeathSoundVolume(victim.getDeathSoundVolume()); + event.setDeathSoundPitch(victim.getDeathSoundPitch()); + } + + // Play death sound manually + private static void playDeathSound(EntityLivingBase victim, EntityDeathEvent event) { + if (event.shouldPlayDeathSound() && event.getDeathSound() != null && event.getDeathSoundCategory() != null) { + EntityPlayer source = victim instanceof EntityPlayer ? (EntityPlayer) victim : null; + double x = event.getEntity().getLocation().getX(); + double y = event.getEntity().getLocation().getY(); + double z = event.getEntity().getLocation().getZ(); + SoundEvent soundEffect = org.bukkit.craftbukkit.CraftSound.getSoundEffect(event.getDeathSound()); + SoundCategory soundCategory = SoundCategory.valueOf(event.getDeathSoundCategory().name()); + victim.world.playSound(source, x, y, z, soundEffect, soundCategory, event.getDeathSoundVolume(), event.getDeathSoundPitch()); + } + } + // Paper end + /** * Server methods */ @@ -489,11 +544,14 @@ private static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSo if (source instanceof EntityDamageSourceIndirect) { damager = ((EntityDamageSourceIndirect) source).getProximateDamageSource(); + // Cauldron start - vanilla compatibility + if (damager != null) { if (damager.getBukkitEntity() instanceof ThrownPotion) { cause = DamageCause.MAGIC; } else if (damager.getBukkitEntity() instanceof Projectile) { cause = DamageCause.PROJECTILE; } + } } else if ("thorns".equals(source.damageType)) { cause = DamageCause.THORNS; } @@ -512,13 +570,33 @@ private static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSo } return event; } else if (blockDamage != null) { - DamageCause cause; + DamageCause cause = null; Block damager = blockDamage; blockDamage = null; if (source == DamageSource.CACTUS) { cause = DamageCause.CONTACT; } else if (source == DamageSource.HOT_FLOOR) { cause = DamageCause.HOT_FLOOR; + } else if (source == DamageSource.FALL) { + cause = DamageCause.FALL; + } else if (source == DamageSource.ANVIL || source == DamageSource.FALLING_BLOCK) { + cause = DamageCause.FALLING_BLOCK; + } else if (source == DamageSource.IN_FIRE) { + cause = DamageCause.FIRE; + } else if (source == DamageSource.ON_FIRE) { + cause = DamageCause.FIRE_TICK; + } else if (source == DamageSource.LAVA) { + cause = DamageCause.LAVA; + } else if (damager instanceof LightningStrike) { + cause = DamageCause.LIGHTNING; + } else if (source == DamageSource.MAGIC) { + cause = DamageCause.MAGIC; + } else if (source == MELTING) { + cause = DamageCause.MELTING; + } else if (source == POISON) { + cause = DamageCause.POISON; + } else if (source == DamageSource.GENERIC) { + cause = DamageCause.CUSTOM; } else { cause = DamageCause.CUSTOM; } @@ -528,7 +606,7 @@ private static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSo } return event; } else if (entityDamage != null) { - DamageCause cause; + DamageCause cause = null; CraftEntity damager = entityDamage.getBukkitEntity(); entityDamage = null; if (source == DamageSource.ANVIL || source == DamageSource.FALLING_BLOCK) { @@ -541,6 +619,18 @@ private static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSo cause = DamageCause.DRAGON_BREATH; } else if (source == DamageSource.MAGIC) { cause = DamageCause.MAGIC; + } else if (source == DamageSource.CACTUS) { + cause = DamageCause.CONTACT; + } else if (source == DamageSource.IN_FIRE) { + cause = DamageCause.FIRE; + } else if (source == DamageSource.ON_FIRE) { + cause = DamageCause.FIRE_TICK; + } else if (source == DamageSource.LAVA) { + cause = DamageCause.LAVA; + } else if (source == MELTING) { + cause = DamageCause.MELTING; + } else if (source == POISON) { + cause = DamageCause.POISON; } else { cause = DamageCause.CUSTOM; } @@ -551,7 +641,7 @@ private static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSo return event; } - DamageCause cause; + DamageCause cause = null; if (source == DamageSource.IN_FIRE) { cause = DamageCause.FIRE; } else if (source == DamageSource.STARVE) { @@ -578,11 +668,13 @@ private static EntityDamageEvent handleEntityDamageEvent(Entity entity, DamageSo cause = DamageCause.CRAMMING; } else if (source == DamageSource.GENERIC) { cause = DamageCause.CUSTOM; - } else { - cause = DamageCause.CUSTOM; } + if (cause != null) { return callEntityDamageEvent(null, entity, cause, modifiers, modifierFunctions); + } else { + return new EntityDamageEvent(entity.getBukkitEntity(), DamageCause.CUSTOM, modifiers, modifierFunctions); // use custom + } } private static EntityDamageEvent callEntityDamageEvent(Entity damager, Entity damagee, DamageCause cause, Map modifiers, Map> modifierFunctions) { @@ -602,8 +694,6 @@ private static EntityDamageEvent callEntityDamageEvent(Entity damager, Entity da return event; } - private static final Function ZERO = Functions.constant(-0.0); - public static EntityDamageEvent handleLivingEntityDamageEvent(Entity damagee, DamageSource source, double rawDamage, double hardHatModifier, double blockingModifier, double armorModifier, double resistanceModifier, double magicModifier, double absorptionModifier, Function hardHat, Function blocking, Function armor, Function resistance, Function magic, Function absorption) { Map modifiers = new EnumMap(DamageModifier.class); Map> modifierFunctions = new EnumMap>(DamageModifier.class); @@ -769,20 +859,36 @@ public static Container callInventoryOpenEvent(EntityPlayerMP player, Container } public static Container callInventoryOpenEvent(EntityPlayerMP player, Container container, boolean cancelled) { - if (player.openContainer != player.inventoryContainer) { // fire INVENTORY_CLOSE if one already open + if (AsyncCatcher.catchInv()) { + return container; + } + if (player.openContainer != player.inventoryContainer && cancelled) { // fire INVENTORY_CLOSE if one already open player.connection.processCloseWindow(new CPacketCloseWindow(player.openContainer.windowId)); } CraftServer server = player.world.getServer(); + // Cauldron start - vanilla compatibility CraftPlayer craftPlayer = player.getBukkitEntity(); + try { player.openContainer.transferTo(container, craftPlayer); - + } catch (AbstractMethodError e) { + } + // Cauldron end InventoryOpenEvent event = new InventoryOpenEvent(container.getBukkitView()); event.setCancelled(cancelled); - server.getPluginManager().callEvent(event); + if (container.getBukkitView() != null) { + server.getPluginManager().callEvent(event); // Cauldron - allow vanilla mods to bypass + } if (event.isCancelled()) { container.transferTo(player.openContainer, craftPlayer); + // Cauldron start - handle close for modded containers + if (!cancelled) { // fire INVENTORY_CLOSE if one already open + player.openContainer = container; // make sure the right container is processed + player.closeScreen(); + player.openContainer = player.inventoryContainer; + } + // Cauldron end return null; } @@ -907,8 +1013,13 @@ public static BlockIgniteEvent callBlockIgniteEvent(World world, int x, int y, i } public static void handleInventoryCloseEvent(EntityPlayer human) { + if (AsyncCatcher.catchInv()) { + return; + } InventoryCloseEvent event = new InventoryCloseEvent(human.openContainer.getBukkitView()); + if (human.openContainer.getBukkitView() != null) { human.world.getServer().getPluginManager().callEvent(event); + } human.openContainer.transferTo(human.inventoryContainer, human.getBukkitEntity()); } diff --git a/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java b/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java index ab9e81f..ce20a08 100644 --- a/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java +++ b/src/main/java/org/bukkit/event/entity/EntityDeathEvent.java @@ -8,10 +8,19 @@ /** * Thrown whenever a LivingEntity dies */ -public class EntityDeathEvent extends EntityEvent { +public class EntityDeathEvent extends EntityEvent implements org.bukkit.event.Cancellable { // Paper - make cancellable private static final HandlerList handlers = new HandlerList(); private final List drops; private int dropExp = 0; + // Paper start - make cancellable + private boolean cancelled; + private double reviveHealth = 0; + private boolean shouldPlayDeathSound; + private org.bukkit.Sound deathSound; + private org.bukkit.SoundCategory deathSoundCategory; + private float deathSoundVolume; + private float deathSoundPitch; + // Paper end public EntityDeathEvent(final LivingEntity entity, final List drops) { this(entity, drops, 0); @@ -69,4 +78,132 @@ public HandlerList getHandlers() { public static HandlerList getHandlerList() { return handlers; } + + // Paper start - make cancellable + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancel) { + cancelled = cancel; + } + + /** + * Get the amount of health that the entity should revive with after cancelling the event. + * Set to the entity's max health by default. + * + * @return The amount of health + */ + public double getReviveHealth() { + return reviveHealth; + } + + /** + * Set the amount of health that the entity should revive with after cancelling the event. + * Revive health value must be between 0 (exclusive) and the entity's max health (inclusive). + * + * @param reviveHealth The amount of health + * @throws IllegalArgumentException Thrown if the health is {@literal <= 0 or >} max health + */ + public void setReviveHealth(double reviveHealth) throws IllegalArgumentException { + double maxHealth = ((LivingEntity) entity).getAttribute(org.bukkit.attribute.Attribute.GENERIC_MAX_HEALTH).getValue(); + if ((maxHealth != 0 && reviveHealth <= 0) || (reviveHealth > maxHealth)) { + throw new IllegalArgumentException("Health must be between 0 (exclusive) and " + maxHealth + " (inclusive), but was " + reviveHealth); + } + this.reviveHealth = reviveHealth; } + + + /** + * Whether or not the death sound should play when the entity dies. If the event is cancelled it does not play! + * + * @return Whether or not the death sound should play. Event is called with this set to false if the entity is silent. + */ + public boolean shouldPlayDeathSound() { + return shouldPlayDeathSound; + } + + /** + * Set whether or not the death sound should play when the entity dies. If the event is cancelled it does not play! + * + * @param playDeathSound Enable or disable the death sound + */ + public void setShouldPlayDeathSound(boolean playDeathSound) { + this.shouldPlayDeathSound = playDeathSound; + } + + /** + * Get the sound that the entity makes when dying + * + * @return The sound that the entity makes + */ + public org.bukkit.Sound getDeathSound() { + return deathSound; + } + + /** + * Set the sound that the entity makes when dying + * + * @param sound The sound that the entity should make when dying + */ + public void setDeathSound(org.bukkit.Sound sound) { + deathSound = sound; + } + + /** + * Get the sound category that the death sound should play in + * + * @return The sound category + */ + public org.bukkit.SoundCategory getDeathSoundCategory() { + return deathSoundCategory; + } + + /** + * Set the sound category that the death sound should play in. + * + * @param soundCategory The sound category + */ + public void setDeathSoundCategory(org.bukkit.SoundCategory soundCategory) { + this.deathSoundCategory = soundCategory; + } + + /** + * Get the volume that the death sound will play at. + * + * @return The volume the death sound will play at + */ + public float getDeathSoundVolume() { + return deathSoundVolume; + } + + /** + * Set the volume the death sound should play at. If the event is cancelled this will not play the sound! + * + * @param volume The volume the death sound should play at + */ + public void setDeathSoundVolume(float volume) { + this.deathSoundVolume = volume; + } + + /** + * Get the pitch that the death sound will play with. + * + * @return The pitch the death sound will play with + */ + public float getDeathSoundPitch() { + return deathSoundPitch; + } + + /** + * GSetet the pitch that the death sound should play with. + * + * @param pitch The pitch the death sound should play with + */ + public void setDeathSoundPitch(float pitch) { + this.deathSoundPitch = pitch; + } + // Paper end +} \ No newline at end of file diff --git a/src/main/java/org/spigotmc/AsyncCatcher.java b/src/main/java/org/spigotmc/AsyncCatcher.java index 360fe37..85dcf62 100644 --- a/src/main/java/org/spigotmc/AsyncCatcher.java +++ b/src/main/java/org/spigotmc/AsyncCatcher.java @@ -2,16 +2,20 @@ import net.minecraft.server.MinecraftServer; -public class AsyncCatcher -{ +public class AsyncCatcher { public static boolean enabled = true; - public static void catchOp(String reason) - { - if ( enabled && Thread.currentThread() != MinecraftServer.getServerInstance().primaryThread ) - { - throw new IllegalStateException( "Asynchronous " + reason + "!" ); + public static void catchOp(String reason) { + if (enabled && Thread.currentThread() != MinecraftServer.getServerInstance().primaryThread) { + throw new IllegalStateException("Asynchronous " + reason + "!"); } } + + public static boolean catchInv() { + if (enabled && Thread.currentThread() != MinecraftServer.getServerInstance().primaryThread) { + return true; + } + return false; + } }