--- ../src-base/minecraft/net/minecraft/entity/player/EntityPlayer.java
+++ ../src-work/minecraft/net/minecraft/entity/player/EntityPlayer.java
@@ -92,6 +92,22 @@
 import net.minecraftforge.event.entity.player.PlayerFlyableFallEvent;
 import net.minecraftforge.event.entity.player.PlayerSleepInBedEvent;
 
+// CraftBukkit start
+import net.minecraft.network.play.server.S2FPacketSetSlot;
+
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.craftbukkit.entity.CraftItem;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.entity.Player;
+import org.bukkit.event.entity.EntityCombustByEntityEvent;
+import org.bukkit.event.inventory.InventoryCloseEvent;
+import org.bukkit.event.player.PlayerBedEnterEvent;
+import org.bukkit.event.player.PlayerBedLeaveEvent;
+import org.bukkit.event.player.PlayerDropItemEvent;
+import org.bukkit.event.player.PlayerItemConsumeEvent;
+// CraftBukkit end
+
 public abstract class EntityPlayer extends EntityLivingBase implements ICommandSender
 {
     public static final String PERSISTED_NBT_TAG = "PlayerPersisted";
@@ -102,7 +118,7 @@
     private InventoryEnderChest theInventoryEnderChest = new InventoryEnderChest();
     public Container inventoryContainer;
     public Container openContainer;
-    protected FoodStats foodStats = new FoodStats();
+    protected FoodStats foodStats = new FoodStats(this); // CraftBukkit - add this argument
     protected int flyToggleTimer;
     public float prevCameraYaw;
     public float cameraYaw;
@@ -113,9 +129,19 @@
     public double field_71094_bP;
     public double field_71095_bQ;
     public double field_71085_bR;
-    protected boolean sleeping;
+    // CraftBukkit start
+    public boolean sleeping; // protected -> public
+    public boolean fauxSleeping;
+    public String spawnWorld = "";
+
+    @Override
+    public CraftHumanEntity getBukkitEntity()
+    {
+        return (CraftHumanEntity) super.getBukkitEntity();
+    }
+    // CraftBukkit end
     public ChunkCoordinates playerLocation;
-    private int sleepTimer;
+    public int sleepTimer; // CraftBukkit - private -> public
     public float field_71079_bU;
     @SideOnly(Side.CLIENT)
     public float field_71082_cx;
@@ -124,6 +150,7 @@
     private boolean spawnForced;
     private ChunkCoordinates startMinecartRidingCoordinate;
     public PlayerCapabilities capabilities = new PlayerCapabilities();
+    public int oldLevel = -1; // CraftBukkit
     public int experienceLevel;
     public int experienceTotal;
     public float experience;
@@ -416,6 +443,42 @@
         {
             this.updateItemUse(this.itemInUse, 16);
             int i = this.itemInUse.stackSize;
+            // CraftBukkit start
+            org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitCopy(this.itemInUse);
+            PlayerItemConsumeEvent event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem);
+            worldObj.getServer().getPluginManager().callEvent(event);
+
+            if (event.isCancelled())
+            {
+                // Update client
+                if (this instanceof EntityPlayerMP)
+                {
+                    ((EntityPlayerMP) this).playerNetServerHandler.sendPacket(new S2FPacketSetSlot((byte) 0, openContainer.getSlotFromInventory(
+                            (IInventory) this.inventory, this.inventory.currentItem).slotIndex, this.itemInUse));
+                    // Spigot Start
+                    ((EntityPlayerMP) this).getBukkitEntity().updateInventory();
+                    ((EntityPlayerMP) this).getBukkitEntity().updateScaledHealth();
+                    // Spigot End
+                }
+
+                return;
+            }
+
+            // Plugin modified the item, process it but don't remove it
+            if (!craftItem.equals(event.getItem()))
+            {
+                CraftItemStack.asNMSCopy(event.getItem()).onFoodEaten(this.worldObj, this);
+
+                // Update client
+                if (this instanceof EntityPlayerMP)
+                {
+                    ((EntityPlayerMP) this).playerNetServerHandler.sendPacket(new S2FPacketSetSlot((byte) 0, openContainer.getSlotFromInventory(
+                            (IInventory) this.inventory, this.inventory.currentItem).slotIndex, this.itemInUse));
+                }
+
+                return;
+            }
+            // CraftBukkit end
             ItemStack itemstack = this.itemInUse.onFoodEaten(this.worldObj, this);
 
             itemstack = ForgeEventFactory.onItemUseFinish(this, itemInUse, itemInUseCount, itemstack);
@@ -452,6 +515,7 @@
         return this.getHealth() <= 0.0F || this.isPlayerSleeping();
     }
 
+    // CraftBukkit - protected -> public
     public void closeScreen()
     {
         this.openContainer = this.inventoryContainer;
@@ -459,23 +523,40 @@
 
     public void mountEntity(Entity p_70078_1_)
     {
+        // CraftBukkit start - mirror Entity mount changes
+        this.setPassengerOf(p_70078_1_);
+    }
+
+    public void setPassengerOf(Entity p_70078_1_)
+    {
+        // CraftBukkit end
         if (this.ridingEntity != null && p_70078_1_ == null)
         {
-            if (!this.worldObj.isRemote)
-            {
-                this.dismountEntity(this.ridingEntity);
-            }
+            worldObj.getServer().getPluginManager()
+                    .callEvent(new org.spigotmc.event.entity.EntityDismountEvent(this.getBukkitEntity(), this.ridingEntity.getBukkitEntity())); // Spigot
+            // CraftBukkit start - use parent method instead to correctly fire
+            // VehicleExitEvent
+            Entity originalVehicle = this.ridingEntity;
+            // First statement moved down, second statement handled in parent
+            // method.
+            /*
+             * if (!this.world.isStatic) { this.l(this.vehicle); }
+             * 
+             * if (this.vehicle != null) { this.vehicle.passenger = null; }
+             * 
+             * this.vehicle = null;
+             */
+            super.setPassengerOf(p_70078_1_);
 
-            if (this.ridingEntity != null)
+            if (!this.worldObj.isRemote && this.ridingEntity == null)
             {
-                this.ridingEntity.riddenByEntity = null;
+                this.dismountEntity(originalVehicle);
             }
-
-            this.ridingEntity = null;
+            // CraftBukkit end
         }
         else
         {
-            super.mountEntity(p_70078_1_);
+            super.setPassengerOf(p_70078_1_); // CraftBukkit - call new parent
         }
     }
 
@@ -532,7 +613,8 @@
 
         if (this.worldObj.difficultySetting == EnumDifficulty.PEACEFUL && this.getHealth() < this.getMaxHealth() && this.worldObj.getGameRules().getGameRuleBooleanValue("naturalRegeneration") && this.ticksExisted % 20 * 12 == 0)
         {
-            this.heal(1.0F);
+            // CraftBukkit - added regain reason of "REGEN" for filtering purposes.
+            this.heal(1.0F, org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.REGEN);
         }
 
         this.inventory.decrementAnimations();
@@ -554,7 +636,8 @@
 
         this.setAIMoveSpeed((float)iattributeinstance.getAttributeValue());
         float f = MathHelper.sqrt_double(this.motionX * this.motionX + this.motionZ * this.motionZ);
-        float f1 = (float)Math.atan(-this.motionY * 0.20000000298023224D) * 15.0F;
+        // CraftBukkit - Math -> TrigMath
+        float f1 = (float) org.bukkit.craftbukkit.TrigMath.atan(-this.motionY * 0.20000000298023224D) * 15.0F;
 
         if (f > 0.1F)
         {
@@ -589,7 +672,7 @@
 
             List list = this.worldObj.getEntitiesWithinAABBExcludingEntity(this, axisalignedbb);
 
-            if (list != null)
+            if (list != null && this.canBeCollidedWith()) // Spigot: this.canBeCollidedWith() condition
             {
                 for (int i = 0; i < list.size(); ++i)
                 {
@@ -687,12 +770,14 @@
     public void addToPlayerScore(Entity p_70084_1_, int p_70084_2_)
     {
         this.addScore(p_70084_2_);
-        Collection collection = this.getWorldScoreboard().func_96520_a(IScoreObjectiveCriteria.totalKillCount);
+        // CraftBukkit - Get our scores instead
+        Collection<Score> collection = this.worldObj.getServer().getScoreboardManager().getScoreboardScores(IScoreObjectiveCriteria.totalKillCount, this.getCommandSenderName(), new java.util.ArrayList<Score>());
 
         if (p_70084_1_ instanceof EntityPlayer)
         {
             this.addStat(StatList.playerKillsStat, 1);
-            collection.addAll(this.getWorldScoreboard().func_96520_a(IScoreObjectiveCriteria.playerKillCount));
+            // CraftBukkit - Get our scores instead
+            this.worldObj.getServer().getScoreboardManager().getScoreboardScores(IScoreObjectiveCriteria.playerKillCount, this.getCommandSenderName(), collection);
         }
         else
         {
@@ -703,8 +788,7 @@
 
         while (iterator.hasNext())
         {
-            ScoreObjective scoreobjective = (ScoreObjective)iterator.next();
-            Score score = this.getWorldScoreboard().func_96529_a(this.getCommandSenderName(), scoreobjective);
+            Score score = (Score) iterator.next(); // CraftBukkit - Use our scores instead
             score.func_96648_a();
         }
     }
@@ -777,6 +861,36 @@
                 entityitem.motionZ += Math.sin((double)f1) * (double)f;
             }
 
+            // CraftBukkit start
+            Player player = (Player) this.getBukkitEntity();
+            CraftItem drop = new CraftItem(this.worldObj.getServer(), entityitem);
+            PlayerDropItemEvent event = new PlayerDropItemEvent(player, drop);
+            this.worldObj.getServer().getPluginManager().callEvent(event);
+
+            if (event.isCancelled())
+            {
+                // player.getInventory().addItem(drop.getItemStack());
+                org.bukkit.inventory.ItemStack cur = player.getInventory().getItemInHand();
+                if (p_146097_3_ && (cur == null || cur.getAmount() == 0))
+                {
+                    // The complete stack was dropped
+                    player.getInventory().setItemInHand(drop.getItemStack());
+                }
+                else if (p_146097_3_ && cur.isSimilar(drop.getItemStack()) && drop.getItemStack().getAmount() == 1)
+                {
+                    // Only one item is dropped
+                    cur.setAmount(cur.getAmount() + 1);
+                    player.getInventory().setItemInHand(cur);
+                }
+                else
+                {
+                    // Fallback
+                    player.getInventory().addItem(drop.getItemStack());
+                }
+                return null;
+            }
+            // CraftBukkit end
+
             this.joinEntityItemWithWorld(entityitem);
             this.addStat(StatList.dropStat, 1);
             return entityitem;
@@ -881,6 +995,15 @@
             this.wakeUpPlayer(true, true, false);
         }
 
+        // CraftBukkit start
+        this.spawnWorld = p_70037_1_.getString("SpawnWorld");
+
+        if ("".equals(spawnWorld))
+        {
+            this.spawnWorld = this.worldObj.getServer().getWorlds().get(0).getName();
+        }
+        // CraftBukkit end
+
         if (p_70037_1_.hasKey("SpawnX", 99) && p_70037_1_.hasKey("SpawnY", 99) && p_70037_1_.hasKey("SpawnZ", 99))
         {
             this.spawnChunk = new ChunkCoordinates(p_70037_1_.getInteger("SpawnX"), p_70037_1_.getInteger("SpawnY"), p_70037_1_.getInteger("SpawnZ"));
@@ -925,6 +1048,7 @@
             p_70014_1_.setInteger("SpawnY", this.spawnChunk.posY);
             p_70014_1_.setInteger("SpawnZ", this.spawnChunk.posZ);
             p_70014_1_.setBoolean("SpawnForced", this.spawnForced);
+            p_70014_1_.setString("SpawnWorld", spawnWorld); // CraftBukkit - fixes bed spawns for multiworld worlds
         }
 
         NBTTagList spawnlist = new NBTTagList();
@@ -1003,7 +1127,7 @@
                 {
                     if (this.worldObj.difficultySetting == EnumDifficulty.PEACEFUL)
                     {
-                        p_70097_2_ = 0.0F;
+                        return false; // CraftBukkit - p_70097_2_ = 0.0F; -> return false
                     }
 
                     if (this.worldObj.difficultySetting == EnumDifficulty.EASY)
@@ -1017,7 +1141,7 @@
                     }
                 }
 
-                if (p_70097_2_ == 0.0F)
+                if (false && p_70097_2_ == 0.0F)   // CraftBukkit - Don't filter out 0 damage
                 {
                     return false;
                 }
@@ -1039,9 +1163,40 @@
 
     public boolean canAttackPlayer(EntityPlayer p_96122_1_)
     {
-        Team team = this.getTeam();
-        Team team1 = p_96122_1_.getTeam();
-        return team == null ? true : (!team.isSameTeam(team1) ? true : team.getAllowFriendlyFire());
+        // CraftBukkit start - Change to check OTHER player's scoreboard team
+        // according to API
+        // To summarize this method's logic, it's "Can parameter hurt this"
+        org.bukkit.scoreboard.Team team;
+
+        if (p_96122_1_ instanceof EntityPlayerMP)
+        {
+            EntityPlayerMP thatPlayer = (EntityPlayerMP) p_96122_1_;
+            team = thatPlayer.getBukkitEntity().getScoreboard().getPlayerTeam(thatPlayer.getBukkitEntity());
+
+            if (team == null || team.allowFriendlyFire())
+            {
+                return true;
+            }
+        }
+        else
+        {
+            // This should never be called, but is implemented anyway
+            org.bukkit.OfflinePlayer thisPlayer = p_96122_1_.worldObj.getServer().getOfflinePlayer(p_96122_1_.getCommandSenderName());
+            team = p_96122_1_.worldObj.getServer().getScoreboardManager().getMainScoreboard().getPlayerTeam(thisPlayer);
+
+            if (team == null || team.allowFriendlyFire())
+            {
+                return true;
+            }
+        }
+
+        if (this instanceof EntityPlayerMP)
+        {
+            return !team.hasPlayer(((EntityPlayerMP) this).getBukkitEntity());
+        }
+
+        return !team.hasPlayer(this.worldObj.getServer().getOfflinePlayer(this.getCommandSenderName()));
+        // CraftBukkit end
     }
 
     protected void damageArmor(float p_70675_1_)
@@ -1073,19 +1228,34 @@
         return (float)i / (float)this.inventory.armorInventory.length;
     }
 
+    // Cauldron start - vanilla compatibility
     protected void damageEntity(DamageSource p_70665_1_, float p_70665_2_)
     {
+        this.damageEntity_CB(p_70665_1_, p_70665_2_);
+    }
+    // Cauldron end
+
+    // CraftBukkit start
+    protected boolean damageEntity_CB(DamageSource p_70665_1_, float p_70665_2_) // void
+                                                                                 // ->
+                                                                                 // boolean
+    {
+        if (true)
+        {
+            return super.damageEntity_CB(p_70665_1_, p_70665_2_);
+        }
+        // CraftBukkit end
         if (!this.isEntityInvulnerable())
         {
             p_70665_2_ = ForgeHooks.onLivingHurt(this, p_70665_1_, p_70665_2_);
-            if (p_70665_2_ <= 0) return;
+            if (p_70665_2_ <= 0) return false;
             if (!p_70665_1_.isUnblockable() && this.isBlocking() && p_70665_2_ > 0.0F)
             {
                 p_70665_2_ = (1.0F + p_70665_2_) * 0.5F;
             }
 
             p_70665_2_ = ArmorProperties.ApplyArmor(this, inventory.armorInventory, p_70665_1_, p_70665_2_);
-            if (p_70665_2_ <= 0) return;
+            if (p_70665_2_ <= 0) return false;
             p_70665_2_ = this.applyPotionDamageCalculations(p_70665_1_, p_70665_2_);
             float f1 = p_70665_2_;
             p_70665_2_ = Math.max(p_70665_2_ - this.getAbsorptionAmount(), 0.0F);
@@ -1099,6 +1269,7 @@
                 this.func_110142_aN().func_94547_a(p_70665_1_, f2, p_70665_2_);
             }
         }
+        return true;
     }
 
     public void func_146101_a(TileEntityFurnace p_146101_1_) {}
@@ -1134,7 +1305,8 @@
 
                 if (itemstack.interactWithEntity(this, (EntityLivingBase)p_70998_1_))
                 {
-                    if (itemstack.stackSize <= 0 && !this.capabilities.isCreativeMode)
+                    // CraftBukkit - bypass infinite items; <= 0 -> == 0
+                    if (itemstack.stackSize == 0 && !this.capabilities.isCreativeMode)
                     {
                         this.destroyCurrentEquippedItem();
                     }
@@ -1281,7 +1453,8 @@
                         {
                             itemstack.hitEntity((EntityLivingBase)object, this);
 
-                            if (itemstack.stackSize <= 0)
+                            // CraftBukkit - bypass infinite items; <= 0 -> == 0
+                            if (itemstack.stackSize == 0)
                             {
                                 this.destroyCurrentEquippedItem();
                             }
@@ -1293,7 +1466,17 @@
 
                             if (j > 0)
                             {
-                                p_71059_1_.setFire(j * 4);
+                                // CraftBukkit start - Call a combust event when
+                                // somebody hits with a fire enchanted item
+                                EntityCombustByEntityEvent combustEvent = new EntityCombustByEntityEvent(this.getBukkitEntity(), p_71059_1_.getBukkitEntity(),
+                                        j * 4);
+                                org.bukkit.Bukkit.getPluginManager().callEvent(combustEvent);
+
+                                if (!combustEvent.isCancelled())
+                                {
+                                    p_71059_1_.setFire(combustEvent.getDuration());
+                                }
+                                // CraftBukkit end
                             }
                         }
 
@@ -1322,6 +1505,10 @@
 
         if (this.openContainer != null)
         {
+            // CraftBukkit start
+            InventoryCloseEvent event = new InventoryCloseEvent(this.openContainer.getBukkitView());
+            if (this.openContainer.getBukkitView() != null) Bukkit.getServer().getPluginManager().callEvent(event); // Cauldron - allow vanilla mods to bypass
+            // CraftBukkit end
             this.openContainer.onContainerClosed(this);
         }
     }
@@ -1381,6 +1568,20 @@
             this.mountEntity((Entity)null);
         }
 
+        // CraftBukkit start
+        if (this.getBukkitEntity() instanceof Player)
+        {
+            Player player = (Player) this.getBukkitEntity();
+            org.bukkit.block.Block bed = this.worldObj.getWorld().getBlockAt(p_71018_1_, p_71018_2_, p_71018_3_);
+            PlayerBedEnterEvent cbEvent = new PlayerBedEnterEvent(player, bed);
+            this.worldObj.getServer().getPluginManager().callEvent(cbEvent);
+
+            if (cbEvent.isCancelled())
+            {
+                return EntityPlayer.EnumStatus.OTHER_PROBLEM;
+            }
+        }
+        // CraftBukkit end
         this.setSize(0.2F, 0.2F);
         this.yOffset = 0.2F;
 
@@ -1476,6 +1677,26 @@
             this.worldObj.updateAllPlayersSleepingFlag();
         }
 
+        // CraftBukkit start
+        if (this.getBukkitEntity() instanceof Player)
+        {
+            Player player = (Player) this.getBukkitEntity();
+            org.bukkit.block.Block bed;
+
+            if (chunkcoordinates != null)
+            {
+                bed = this.worldObj.getWorld().getBlockAt(chunkcoordinates.posX, chunkcoordinates.posY, chunkcoordinates.posZ);
+            }
+            else
+            {
+                bed = this.worldObj.getWorld().getBlockAt(player.getLocation());
+            }
+
+            PlayerBedLeaveEvent event = new PlayerBedLeaveEvent(player, bed);
+            this.worldObj.getServer().getPluginManager().callEvent(event);
+        }
+        // CraftBukkit end
+
         if (p_70999_1_)
         {
             this.sleepTimer = 0;
@@ -1606,11 +1827,13 @@
         {
             this.spawnChunk = new ChunkCoordinates(p_71063_1_);
             this.spawnForced = p_71063_2_;
+            this.spawnWorld = this.worldObj.worldInfo.getWorldName(); // CraftBukkit
         }
         else
         {
             this.spawnChunk = null;
             this.spawnForced = false;
+            this.spawnWorld = ""; // CraftBukkit
         }
     }
 
