--- ../src-base/minecraft/net/minecraft/entity/player/EntityPlayerMP.java +++ ../src-work/minecraft/net/minecraft/entity/player/EntityPlayerMP.java @@ -2,6 +2,7 @@ import com.google.common.collect.Sets; import com.mojang.authlib.GameProfile; + import io.netty.buffer.Unpooled; import java.io.IOException; import java.util.ArrayList; @@ -83,6 +84,7 @@ import net.minecraft.tileentity.TileEntityFurnace; import net.minecraft.tileentity.TileEntityHopper; import net.minecraft.tileentity.TileEntitySign; +import net.minecraft.util.ChatComponentTranslation; import net.minecraft.util.ChunkCoordinates; import net.minecraft.util.DamageSource; import net.minecraft.util.EntityDamageSource; @@ -106,24 +108,38 @@ import net.minecraftforge.event.entity.player.PlayerDropsEvent; import net.minecraftforge.event.world.ChunkWatchEvent; +// CraftBukkit start +import net.minecraft.util.CombatTracker; +import net.minecraft.util.FoodStats; +import net.minecraft.world.World; +import org.bukkit.Bukkit; +import org.bukkit.WeatherType; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; +// CraftBukkit end + public class EntityPlayerMP extends EntityPlayer implements ICrafting { private static final Logger logger = LogManager.getLogger(); - private String translator = "en_US"; + public String translator = "en_US"; // CraftBukkit - private -> public public NetHandlerPlayServer playerNetServerHandler; public final MinecraftServer mcServer; public final ItemInWorldManager theItemInWorldManager; public double managedPosX; public double managedPosZ; public final List loadedChunks = new LinkedList(); - private final List destroyedItemsNetCache = new LinkedList(); + public final List destroyedItemsNetCache = new LinkedList(); private final StatisticsFile field_147103_bO; private float field_130068_bO = Float.MIN_VALUE; private float lastHealth = -1.0E8F; private int lastFoodLevel = -99999999; private boolean wasHungry = true; - private int lastExperience = -99999999; - private int field_147101_bU = 60; + public int lastExperience = -99999999; // CraftBukkit - private -> public + public int field_147101_bU = 60; // CraftBukkit - private -> public private EntityPlayer.EnumChatVisibility chatVisibility; private boolean chatColours = true; private long field_143005_bX = System.currentTimeMillis(); @@ -131,6 +147,39 @@ public boolean isChangingQuantityOnly; public int ping; public boolean playerConqueredTheEnd; + // CraftBukkit start + public String displayName; + public String listName; + public org.bukkit.Location compassTarget; + public int newExp = 0; + public int newLevel = 0; + public int newTotalExp = 0; + public boolean keepLevel = false; + public double maxHealthCache; + // CraftBukkit end + // Spigot start + public boolean collidesWithEntities = true; + + @Override + + /** + * Returns true if other Entities should be prevented from moving through this Entity. + */ + public boolean canBeCollidedWith() + { + return this.collidesWithEntities && super.canBeCollidedWith(); + } + + @Override + + /** + * Returns true if this entity should push and be pushed by other entities when colliding. + */ + public boolean canBePushed() + { + return this.collidesWithEntities && super.canBePushed(); + } + // Spigot end private static final String __OBFID = "CL_00001440"; public EntityPlayerMP(MinecraftServer p_i45285_1_, WorldServer p_i45285_2_, GameProfile p_i45285_3_, ItemInWorldManager p_i45285_4_) @@ -153,6 +202,13 @@ { this.setPosition(this.posX, this.posY + 1.0D, this.posZ); } + + // CraftBukkit start + this.displayName = this.getCommandSenderName(); + this.listName = this.getCommandSenderName(); + // this.canPickUpLoot = true; TODO + this.maxHealthCache = this.getMaxHealth(); + // CraftBukkit end } public void readEntityFromNBT(NBTTagCompound p_70037_1_) @@ -170,14 +226,57 @@ this.theItemInWorldManager.setGameType(WorldSettings.GameType.getByID(p_70037_1_.getInteger("playerGameType"))); } } + + this.getBukkitEntity().readExtraData(p_70037_1_); // CraftBukkit } public void writeEntityToNBT(NBTTagCompound p_70014_1_) { super.writeEntityToNBT(p_70014_1_); p_70014_1_.setInteger("playerGameType", this.theItemInWorldManager.getGameType().getID()); + this.getBukkitEntity().setExtraData(p_70014_1_); // CraftBukkit } + // CraftBukkit start - World fallback code, either respawn location or global spawn + + /** + * Sets the reference to the World object. + */ + public void setWorld(World world) + { + super.setWorld(world); + + if (world == null) + { + this.isDead = false; + ChunkCoordinates position = null; + + if (this.spawnWorld != null && !this.spawnWorld.equals("")) + { + CraftWorld cworld = (CraftWorld) Bukkit.getServer().getWorld(this.spawnWorld); + + if (cworld != null && this.getBedLocation() != null) + { + world = cworld.getHandle(); + position = EntityPlayer.verifyRespawnCoordinates(cworld.getHandle(), this.getBedLocation(), false); + } + } + + if (world == null || position == null) + { + world = ((CraftWorld) Bukkit.getServer().getWorlds().get(0)).getHandle(); + position = world.getSpawnPoint(); + } + + this.worldObj = world; + this.setPosition(position.posX + 0.5, position.posY, position.posZ + 0.5); + } + + this.dimension = ((WorldServer) this.worldObj).provider.dimensionId; + this.theItemInWorldManager.setWorld((WorldServer) world); + } + // CraftBukkit end + public void addExperienceLevel(int p_82242_1_) { super.addExperienceLevel(p_82242_1_); @@ -240,7 +339,7 @@ ArrayList arraylist1 = new ArrayList(); Chunk chunk; - while (iterator1.hasNext() && arraylist.size() < S26PacketMapChunkBulk.func_149258_c()) + while (iterator1.hasNext() && arraylist.size() < this.worldObj.getSpigotConfig().maxBulkChunk) // Spigot // Cauldron { ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair)iterator1.next(); @@ -253,8 +352,7 @@ if (chunk.func_150802_k()) { arraylist.add(chunk); - arraylist1.addAll(((WorldServer)this.worldObj).func_147486_a(chunkcoordintpair.chunkXPos * 16, 0, chunkcoordintpair.chunkZPos * 16, chunkcoordintpair.chunkXPos * 16 + 15, 256, chunkcoordintpair.chunkZPos * 16 + 15)); - //BugFix: 16 makes it load an extra chunk, which isn't associated with a player, which makes it not unload unless a player walks near it. + arraylist1.addAll(chunk.chunkTileEntityMap.values()); // CraftBukkit - Get tile entities directly from the chunk instead of the world iterator1.remove(); } } @@ -309,9 +407,10 @@ } } + // CraftBukkit - Optionally scale health if (this.getHealth() != this.lastHealth || this.lastFoodLevel != this.foodStats.getFoodLevel() || this.foodStats.getSaturationLevel() == 0.0F != this.wasHungry) { - this.playerNetServerHandler.sendPacket(new S06PacketUpdateHealth(this.getHealth(), this.foodStats.getFoodLevel(), this.foodStats.getSaturationLevel())); + this.playerNetServerHandler.sendPacket(new S06PacketUpdateHealth(this.getBukkitEntity().getScaledHealth(), this.foodStats.getFoodLevel(), this.foodStats.getSaturationLevel())); this.lastHealth = this.getHealth(); this.lastFoodLevel = this.foodStats.getFoodLevel(); this.wasHungry = this.foodStats.getSaturationLevel() == 0.0F; @@ -320,16 +419,18 @@ if (this.getHealth() + this.getAbsorptionAmount() != this.field_130068_bO) { this.field_130068_bO = this.getHealth() + this.getAbsorptionAmount(); - Collection collection = this.getWorldScoreboard().func_96520_a(IScoreObjectiveCriteria.health); - Iterator iterator = collection.iterator(); + // CraftBukkit - Update ALL the scores! + this.worldObj.getServer().getScoreboardManager().updateAllScoresForList(IScoreObjectiveCriteria.health, this.getCommandSenderName(), com.google.common.collect.ImmutableList.of(this)); + } - while (iterator.hasNext()) - { - ScoreObjective scoreobjective = (ScoreObjective)iterator.next(); - this.getWorldScoreboard().func_96529_a(this.getCommandSenderName(), scoreobjective).func_96651_a(Arrays.asList(new EntityPlayer[] {this})); - } + // CraftBukkit start - Force max health updates + if (this.maxHealthCache != this.getMaxHealth()) + { + this.getBukkitEntity().updateScaledHealth(); } + // CraftBukkit end + if (this.experienceTotal != this.lastExperience) { this.lastExperience = this.experienceTotal; @@ -340,6 +441,20 @@ { this.func_147098_j(); } + + // CraftBukkit start + if (this.oldLevel == -1) + { + this.oldLevel = this.experienceLevel; + } + + if (this.oldLevel != this.experienceLevel) + { + CraftEventFactory.callPlayerLevelChangeEvent(this.worldObj.getServer().getPlayer((EntityPlayerMP) this), this.oldLevel, this.experienceLevel); + this.oldLevel = this.experienceLevel; + } + + // CraftBukkit end } catch (Throwable throwable) { @@ -402,34 +517,74 @@ public void onDeath(DamageSource p_70645_1_) { - if (ForgeHooks.onLivingDeath(this, p_70645_1_)) return; - this.mcServer.getConfigurationManager().sendChatMsg(this.func_110142_aN().func_151521_b()); + // CraftBukkit start + if (this.isDead || ForgeHooks.onLivingDeath(this, p_70645_1_)) // Cauldron - call Forge hook + { + return; + } - if (!this.worldObj.getGameRules().getGameRuleBooleanValue("keepInventory")) + java.util.List loot = new java.util.ArrayList(); + boolean keepInventory = this.worldObj.getGameRules().getGameRuleBooleanValue("keepInventory"); + + if (!keepInventory) { + // Cauldron start - rework CraftBukkit logic to support Forge better captureDrops = true; capturedDrops.clear(); - this.inventory.dropAllItems(); + for (int i = 0; i < capturedDrops.size(); ++i) + { + if (capturedDrops.get(i) != null) + { + loot.add(CraftItemStack.asCraftMirror(capturedDrops.get(i).getEntityItem())); + } + } + // Cauldron end + } + IChatComponent chatmessage = this.func_110142_aN().func_151521_b(); + String deathmessage = chatmessage.getUnformattedText(); + org.bukkit.event.entity.PlayerDeathEvent event = CraftEventFactory.callPlayerDeathEvent(this, loot, deathmessage, keepInventory); + String deathMessage = event.getDeathMessage(); + + if (deathMessage != null && deathMessage.length() > 0) + { + if (deathMessage.equals(deathmessage)) + { + this.mcServer.getConfigurationManager().sendChatMsg(chatmessage); + } + else + { + this.mcServer.getConfigurationManager().sendMessage(org.bukkit.craftbukkit.util.CraftChatMessage.fromString(deathMessage)); + } + } + + if (!event.getKeepInventory()) + { + // Cauldron start - rework CraftBukkit logic to support Forge better + this.inventory.clearInventory(null, -1); // CraftBukkit - we clean the player's inventory after the EntityDeathEvent is called so plugins can get the exact state of the inventory. captureDrops = false; - PlayerDropsEvent event = new PlayerDropsEvent(this, p_70645_1_, capturedDrops, recentlyHit > 0); - if (!MinecraftForge.EVENT_BUS.post(event)) + PlayerDropsEvent forgeEvent = new PlayerDropsEvent(this, p_70645_1_, capturedDrops, recentlyHit > 0); + + if (!MinecraftForge.EVENT_BUS.post(forgeEvent)) { for (EntityItem item : capturedDrops) { joinEntityItemWithWorld(item); } } + // Cauldron end } - Collection collection = this.worldObj.getScoreboard().func_96520_a(IScoreObjectiveCriteria.deathCount); + this.closeScreen(); + // CraftBukkit end + // CraftBukkit - Get our scores instead + Collection collection = this.worldObj.getServer().getScoreboardManager().getScoreboardScores(IScoreObjectiveCriteria.deathCount, this.getCommandSenderName(), new java.util.ArrayList()); Iterator iterator = collection.iterator(); 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(); } @@ -495,7 +650,8 @@ public boolean canAttackPlayer(EntityPlayer p_96122_1_) { - return !this.mcServer.isPVPEnabled() ? false : super.canAttackPlayer(p_96122_1_); + // CraftBukkit - this.mcServer.isPVPEnabled() -> this.world.pvpMode + return !this.worldObj.pvpMode ? false : super.canAttackPlayer(p_96122_1_); } public void travelToDimension(int p_71027_1_) @@ -526,7 +682,10 @@ this.triggerAchievement(AchievementList.portal); } - this.mcServer.getConfigurationManager().transferPlayerToDimension(this, p_71027_1_); + // CraftBukkit start + TeleportCause cause = (this.dimension == 1 || p_71027_1_ == 1) ? TeleportCause.END_PORTAL : TeleportCause.NETHER_PORTAL; + this.mcServer.getConfigurationManager().transferPlayerToDimension(this, p_71027_1_, cause); // Cauldron + // CraftBukkit end this.lastExperience = -1; this.lastHealth = -1.0F; this.lastFoodLevel = -1; @@ -569,6 +728,11 @@ public void wakeUpPlayer(boolean p_70999_1_, boolean p_70999_2_, boolean p_70999_3_) { + if (this.fauxSleeping && !this.sleeping) + { + return; // CraftBukkit - Can't leave bed if not in one! + } + if (this.isPlayerSleeping()) { this.getServerForPlayer().getEntityTracker().func_151248_b(this, new S0BPacketAnimation(this, 2)); @@ -584,11 +748,27 @@ public void mountEntity(Entity p_70078_1_) { - super.mountEntity(p_70078_1_); - this.playerNetServerHandler.sendPacket(new S1BPacketEntityAttach(0, this, this.ridingEntity)); - this.playerNetServerHandler.setPlayerLocation(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch); + // CraftBukkit start + this.setPassengerOf(p_70078_1_); } + public void setPassengerOf(Entity entity) + { + // mount(null) doesn't really fly for overloaded methods, + // so this method is needed + Entity currentVehicle = this.ridingEntity; + super.setPassengerOf(entity); + + // Check if the vehicle actually changed. + if (currentVehicle != this.ridingEntity) + { + this.playerNetServerHandler.sendPacket(new S1BPacketEntityAttach(0, this, this.ridingEntity)); + this.playerNetServerHandler.setPlayerLocation(this.posX, this.posY, this.posZ, this.rotationYaw, this.rotationPitch); + } + + // CraftBukkit end + } + protected void updateFallState(double p_70064_1_, boolean p_70064_3_) {} public void handleFalling(double p_71122_1_, boolean p_71122_3_) @@ -610,29 +790,64 @@ this.currentWindowId = this.currentWindowId % 100 + 1; } + // CraftBukkit start - change signature from void to int + public int nextContainerCounter() + { + this.currentWindowId = this.currentWindowId % 100 + 1; + return this.currentWindowId; + } + // CraftBukkit end + public void displayGUIWorkbench(int p_71058_1_, int p_71058_2_, int p_71058_3_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerWorkbench(this.inventory, this.worldObj, p_71058_1_, p_71058_2_, p_71058_3_)); + + if (container == null) + { + return; + } + + // CraftBukkit end this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, 1, "Crafting", 9, true)); - this.openContainer = new ContainerWorkbench(this.inventory, this.worldObj, p_71058_1_, p_71058_2_, p_71058_3_); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } public void displayGUIEnchantment(int p_71002_1_, int p_71002_2_, int p_71002_3_, String p_71002_4_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerEnchantment(this.inventory, this.worldObj, p_71002_1_, p_71002_2_, p_71002_3_)); + + if (container == null) + { + return; + } + + // CraftBukkit end this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, 4, p_71002_4_ == null ? "" : p_71002_4_, 9, p_71002_4_ != null)); - this.openContainer = new ContainerEnchantment(this.inventory, this.worldObj, p_71002_1_, p_71002_2_, p_71002_3_); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } public void displayGUIAnvil(int p_82244_1_, int p_82244_2_, int p_82244_3_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerRepair(this.inventory, this.worldObj, p_82244_1_, p_82244_2_, p_82244_3_, this)); + + if (container == null) + { + return; + } + + // CraftBukkit end this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, 8, "Repairing", 9, true)); - this.openContainer = new ContainerRepair(this.inventory, this.worldObj, p_82244_1_, p_82244_2_, p_82244_3_, this); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } @@ -644,71 +859,150 @@ this.closeScreen(); } + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerChest(this.inventory, p_71007_1_)); + + if (container == null) + { + p_71007_1_.closeInventory(); // Cauldron - prevent chest from being stuck in open state on clients + return; + } + + // CraftBukkit end this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, 0, p_71007_1_.getInventoryName(), p_71007_1_.getSizeInventory(), p_71007_1_.hasCustomInventoryName())); - this.openContainer = new ContainerChest(this.inventory, p_71007_1_); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } public void func_146093_a(TileEntityHopper p_146093_1_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerHopper(this.inventory, p_146093_1_)); + + if (container == null) + { + p_146093_1_.closeInventory(); // Cauldron - prevent chest from being stuck in open state on clients + return; + } + + // CraftBukkit end this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, 9, p_146093_1_.getInventoryName(), p_146093_1_.getSizeInventory(), p_146093_1_.hasCustomInventoryName())); - this.openContainer = new ContainerHopper(this.inventory, p_146093_1_); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } public void displayGUIHopperMinecart(EntityMinecartHopper p_96125_1_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerHopper(this.inventory, p_96125_1_)); + + if (container == null) + { + p_96125_1_.closeInventory(); // Cauldron - prevent chest from being stuck in open state on clients + return; + } + + // CraftBukkit end this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, 9, p_96125_1_.getInventoryName(), p_96125_1_.getSizeInventory(), p_96125_1_.hasCustomInventoryName())); - this.openContainer = new ContainerHopper(this.inventory, p_96125_1_); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } public void func_146101_a(TileEntityFurnace p_146101_1_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerFurnace(this.inventory, p_146101_1_)); + + if (container == null) + { + p_146101_1_.closeInventory(); // Cauldron - prevent chests from being stuck in open state on clients + return; + } + + // CraftBukkit end this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, 2, p_146101_1_.getInventoryName(), p_146101_1_.getSizeInventory(), p_146101_1_.hasCustomInventoryName())); - this.openContainer = new ContainerFurnace(this.inventory, p_146101_1_); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } public void func_146102_a(TileEntityDispenser p_146102_1_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerDispenser(this.inventory, p_146102_1_)); + + if (container == null) + { + p_146102_1_.closeInventory(); // Cauldron - prevent chests from being stuck in open state on clients + return; + } + + // CraftBukkit end this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, p_146102_1_ instanceof TileEntityDropper ? 10 : 3, p_146102_1_.getInventoryName(), p_146102_1_.getSizeInventory(), p_146102_1_.hasCustomInventoryName())); - this.openContainer = new ContainerDispenser(this.inventory, p_146102_1_); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } public void func_146098_a(TileEntityBrewingStand p_146098_1_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerBrewingStand(this.inventory, p_146098_1_)); + + if (container == null) + { + p_146098_1_.closeInventory(); // Cauldron - prevent chests from being stuck in open state on clients + return; + } + + // CraftBukkit end this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, 5, p_146098_1_.getInventoryName(), p_146098_1_.getSizeInventory(), p_146098_1_.hasCustomInventoryName())); - this.openContainer = new ContainerBrewingStand(this.inventory, p_146098_1_); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } public void func_146104_a(TileEntityBeacon p_146104_1_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerBeacon(this.inventory, p_146104_1_)); + + if (container == null) + { + p_146104_1_.closeInventory(); // Cauldron - prevent chests from being stuck in open state on clients + return; + } + + // CraftBukkit end this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, 7, p_146104_1_.getInventoryName(), p_146104_1_.getSizeInventory(), p_146104_1_.hasCustomInventoryName())); - this.openContainer = new ContainerBeacon(this.inventory, p_146104_1_); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } public void displayGUIMerchant(IMerchant p_71030_1_, String p_71030_2_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerMerchant(this.inventory, p_71030_1_, this.worldObj)); + + if (container == null) + { + return; + } + + // CraftBukkit end this.getNextWindowId(); - this.openContainer = new ContainerMerchant(this.inventory, p_71030_1_, this.worldObj); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); InventoryMerchant inventorymerchant = ((ContainerMerchant)this.openContainer).getMerchantInventory(); @@ -725,7 +1019,7 @@ merchantrecipelist.func_151391_a(packetbuffer); this.playerNetServerHandler.sendPacket(new S3FPacketCustomPayload("MC|TrList", packetbuffer)); } - catch (IOException ioexception) + catch (Exception ioexception) // CraftBukkit - IOException -> Exception { logger.error("Couldn\'t send trade list", ioexception); } @@ -738,6 +1032,17 @@ public void displayGUIHorse(EntityHorse p_110298_1_, IInventory p_110298_2_) { + // CraftBukkit start - Inventory open hook + Container container = CraftEventFactory.callInventoryOpenEvent(this, new ContainerHorseInventory(this.inventory, p_110298_2_, p_110298_1_)); + + if (container == null) + { + p_110298_2_.closeInventory(); // Cauldron - prevent chests from being stuck in open state on clients + return; + } + + // CraftBukkit end + if (this.openContainer != this.inventoryContainer) { this.closeScreen(); @@ -745,7 +1050,7 @@ this.getNextWindowId(); this.playerNetServerHandler.sendPacket(new S2DPacketOpenWindow(this.currentWindowId, 11, p_110298_2_.getInventoryName(), p_110298_2_.getSizeInventory(), p_110298_2_.hasCustomInventoryName(), p_110298_1_.getEntityId())); - this.openContainer = new ContainerHorseInventory(this.inventory, p_110298_2_, p_110298_1_); + this.openContainer = container; // CraftBukkit - Use container we passed to event this.openContainer.windowId = this.currentWindowId; this.openContainer.addCraftingToCrafters(this); } @@ -770,6 +1075,15 @@ { this.playerNetServerHandler.sendPacket(new S30PacketWindowItems(p_71110_1_.windowId, p_71110_2_)); this.playerNetServerHandler.sendPacket(new S2FPacketSetSlot(-1, -1, this.inventory.getItemStack())); + + if (p_71110_1_.getBukkitView() == null) return; // Cauldron - allow vanilla mods to bypass + // CraftBukkit start - Send a Set Slot to update the crafting result slot + if (java.util.EnumSet.of(InventoryType.CRAFTING, InventoryType.WORKBENCH).contains(p_71110_1_.getBukkitView().getType())) + { + this.playerNetServerHandler.sendPacket(new S2FPacketSetSlot(p_71110_1_.windowId, 0, p_71110_1_.getSlot(0).getStack())); + } + + // CraftBukkit end } public void sendProgressBarUpdate(Container p_71112_1_, int p_71112_2_, int p_71112_3_) @@ -779,6 +1093,7 @@ public void closeScreen() { + CraftEventFactory.handleInventoryCloseEvent(this); // CraftBukkit this.playerNetServerHandler.sendPacket(new S2EPacketCloseWindow(this.openContainer.windowId)); this.closeContainer(); } @@ -853,8 +1168,19 @@ public void setPlayerHealthUpdated() { this.lastHealth = -1.0E8F; + this.lastExperience = -1; // CraftBukkit - Added to reset } + // CraftBukkit start - Support multi-line messages + public void sendMessage(IChatComponent[] ichatcomponent) + { + for (IChatComponent component : ichatcomponent) + { + this.addChatComponentMessage(component); + } + } + // CraftBukkit end + public void addChatComponentMessage(IChatComponent p_146105_1_) { this.playerNetServerHandler.sendPacket(new S02PacketChat(p_146105_1_)); @@ -1037,6 +1363,114 @@ return this.field_143005_bX; } + // CraftBukkit start + public long timeOffset = 0; + public boolean relativeTime = true; + + public long getPlayerTime() + { + if (this.relativeTime) + { + // Adds timeOffset to the current server time. + return this.worldObj.getWorldTime() + this.timeOffset; + } + else + { + // Adds timeOffset to the beginning of this day. + return this.worldObj.getWorldTime() - (this.worldObj.getWorldTime() % 24000) + this.timeOffset; + } + } + + public WeatherType weather = null; + + public WeatherType getPlayerWeather() + { + return this.weather; + } + + public void setPlayerWeather(WeatherType type, boolean plugin) + { + if (!plugin && this.weather != null) + { + return; + } + + if (plugin) + { + this.weather = type; + } + + if (type == WeatherType.DOWNFALL) + { + this.playerNetServerHandler.sendPacket(new S2BPacketChangeGameState(2, 0)); + // this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(7, this.world.j(1.0F))); + // this.playerConnection.sendPacket(new PacketPlayOutGameStateChange(8, this.world.h(1.0F))); + } + else + { + this.playerNetServerHandler.sendPacket(new S2BPacketChangeGameState(1, 0)); + } + } + + public void resetPlayerWeather() + { + this.weather = null; + this.setPlayerWeather(this.worldObj.getWorldInfo().isRaining() ? WeatherType.DOWNFALL : WeatherType.CLEAR, false); + } + + @Override + public String toString() + { + return super.toString() + "(" + this.getCommandSenderName() + " at " + this.posX + "," + this.posY + "," + this.posZ + ")"; + } + + public void reset() + { + float exp = 0; + boolean keepInventory = this.worldObj.getGameRules().getGameRuleBooleanValue("keepInventory"); + + if (this.keepLevel || keepInventory) + { + exp = this.experience; + this.newTotalExp = this.experienceTotal; + this.newLevel = this.experienceLevel; + } + + this.setHealth(this.getMaxHealth()); + this.fire = 0; + this.fallDistance = 0; + this.foodStats = new FoodStats(this); + this.experienceLevel = this.newLevel; + this.experienceTotal = this.newTotalExp; + this.experience = 0; + this.deathTime = 0; + this.clearActivePotions(); // Should be remapped: removeAllEffects should be remapped to this. + super.potionsNeedUpdate = true; // Cauldron - change to super to temporarily workaround remapping bug with SpecialSource + this.openContainer = this.inventoryContainer; + this.attackingPlayer = null; + this.entityLivingToAttack = null; + this._combatTracker = new CombatTracker(this); + this.lastExperience = -1; + + if (this.keepLevel || keepInventory) + { + this.experience = exp; + } + else + { + this.addExperience(this.newExp); + } + + this.keepLevel = false; + } + + @Override + public CraftPlayer getBukkitEntity() + { + return (CraftPlayer) super.getBukkitEntity(); + } + // CraftBukkit end + /* ===================================== FORGE START =====================================*/ /** * Returns the default eye height of the player