001package net.minecraft.item; 002 003import net.minecraft.block.Block; 004import net.minecraft.entity.player.EntityPlayer; 005import net.minecraft.entity.player.EntityPlayerMP; 006import net.minecraft.network.packet.Packet53BlockChange; 007import net.minecraft.world.EnumGameType; 008import net.minecraft.world.World; 009import net.minecraft.world.WorldServer; 010 011import net.minecraftforge.common.ForgeHooks; 012import net.minecraftforge.common.MinecraftForge; 013import net.minecraftforge.event.Event; 014import net.minecraftforge.event.ForgeEventFactory; 015import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent; 016import net.minecraftforge.event.entity.player.PlayerInteractEvent; 017import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; 018 019public class ItemInWorldManager 020{ 021 /** Forge reach distance */ 022 private double blockReachDistance = 5.0d; 023 024 /** The world object that this object is connected to. */ 025 public World theWorld; 026 027 /** The EntityPlayerMP object that this object is connected to. */ 028 public EntityPlayerMP thisPlayerMP; 029 private EnumGameType gameType; 030 031 /** True if the player is destroying a block */ 032 private boolean isDestroyingBlock; 033 private int initialDamage; 034 private int partiallyDestroyedBlockX; 035 private int partiallyDestroyedBlockY; 036 private int partiallyDestroyedBlockZ; 037 private int curblockDamage; 038 039 /** 040 * Set to true when the "finished destroying block" packet is received but the block wasn't fully damaged yet. The 041 * block will not be destroyed while this is false. 042 */ 043 private boolean receivedFinishDiggingPacket; 044 private int posX; 045 private int posY; 046 private int posZ; 047 private int field_73093_n; 048 private int durabilityRemainingOnBlock; 049 050 public ItemInWorldManager(World par1World) 051 { 052 this.gameType = EnumGameType.NOT_SET; 053 this.durabilityRemainingOnBlock = -1; 054 this.theWorld = par1World; 055 } 056 057 public void setGameType(EnumGameType par1EnumGameType) 058 { 059 this.gameType = par1EnumGameType; 060 par1EnumGameType.configurePlayerCapabilities(this.thisPlayerMP.capabilities); 061 this.thisPlayerMP.sendPlayerAbilities(); 062 } 063 064 public EnumGameType getGameType() 065 { 066 return this.gameType; 067 } 068 069 /** 070 * Get if we are in creative game mode. 071 */ 072 public boolean isCreative() 073 { 074 return this.gameType.isCreative(); 075 } 076 077 /** 078 * if the gameType is currently NOT_SET then change it to par1 079 */ 080 public void initializeGameType(EnumGameType par1EnumGameType) 081 { 082 if (this.gameType == EnumGameType.NOT_SET) 083 { 084 this.gameType = par1EnumGameType; 085 } 086 087 this.setGameType(this.gameType); 088 } 089 090 public void updateBlockRemoving() 091 { 092 ++this.curblockDamage; 093 int i; 094 float f; 095 int j; 096 097 if (this.receivedFinishDiggingPacket) 098 { 099 i = this.curblockDamage - this.field_73093_n; 100 int k = this.theWorld.getBlockId(this.posX, this.posY, this.posZ); 101 102 if (k == 0) 103 { 104 this.receivedFinishDiggingPacket = false; 105 } 106 else 107 { 108 Block block = Block.blocksList[k]; 109 f = block.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, this.posX, this.posY, this.posZ) * (float)(i + 1); 110 j = (int)(f * 10.0F); 111 112 if (j != this.durabilityRemainingOnBlock) 113 { 114 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.posX, this.posY, this.posZ, j); 115 this.durabilityRemainingOnBlock = j; 116 } 117 118 if (f >= 1.0F) 119 { 120 this.receivedFinishDiggingPacket = false; 121 this.tryHarvestBlock(this.posX, this.posY, this.posZ); 122 } 123 } 124 } 125 else if (this.isDestroyingBlock) 126 { 127 i = this.theWorld.getBlockId(this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ); 128 Block block1 = Block.blocksList[i]; 129 130 if (block1 == null) 131 { 132 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ, -1); 133 this.durabilityRemainingOnBlock = -1; 134 this.isDestroyingBlock = false; 135 } 136 else 137 { 138 int l = this.curblockDamage - this.initialDamage; 139 f = block1.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ) * (float)(l + 1); 140 j = (int)(f * 10.0F); 141 142 if (j != this.durabilityRemainingOnBlock) 143 { 144 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ, j); 145 this.durabilityRemainingOnBlock = j; 146 } 147 } 148 } 149 } 150 151 /** 152 * if not creative, it calls destroyBlockInWorldPartially untill the block is broken first. par4 is the specific 153 * side. tryHarvestBlock can also be the result of this call 154 */ 155 public void onBlockClicked(int par1, int par2, int par3, int par4) 156 { 157 if (!this.gameType.isAdventure() || this.thisPlayerMP.canCurrentToolHarvestBlock(par1, par2, par3)) 158 { 159 PlayerInteractEvent event = ForgeEventFactory.onPlayerInteract(thisPlayerMP, Action.LEFT_CLICK_BLOCK, par1, par2, par3, par4); 160 if (event.isCanceled()) 161 { 162 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, theWorld)); 163 return; 164 } 165 166 if (this.isCreative()) 167 { 168 if (!this.theWorld.extinguishFire((EntityPlayer)null, par1, par2, par3, par4)) 169 { 170 this.tryHarvestBlock(par1, par2, par3); 171 } 172 } 173 else 174 { 175 this.initialDamage = this.curblockDamage; 176 float f = 1.0F; 177 int i1 = this.theWorld.getBlockId(par1, par2, par3); 178 179 Block block = Block.blocksList[i1]; 180 181 if (block != null) 182 { 183 if (event.useBlock != Event.Result.DENY) 184 { 185 block.onBlockClicked(theWorld, par1, par2, par3, thisPlayerMP); 186 theWorld.extinguishFire(thisPlayerMP, par1, par2, par3, par4); 187 } 188 else 189 { 190 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, theWorld)); 191 } 192 f = block.getPlayerRelativeBlockHardness(thisPlayerMP, thisPlayerMP.worldObj, par1, par2, par3); 193 } 194 195 if (event.useItem == Event.Result.DENY) 196 { 197 if (f >= 1.0f) 198 { 199 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, theWorld)); 200 } 201 return; 202 } 203 204 if (i1 > 0 && f >= 1.0F) 205 { 206 this.tryHarvestBlock(par1, par2, par3); 207 } 208 else 209 { 210 this.isDestroyingBlock = true; 211 this.partiallyDestroyedBlockX = par1; 212 this.partiallyDestroyedBlockY = par2; 213 this.partiallyDestroyedBlockZ = par3; 214 int j1 = (int)(f * 10.0F); 215 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, par1, par2, par3, j1); 216 this.durabilityRemainingOnBlock = j1; 217 } 218 } 219 } 220 } 221 222 public void uncheckedTryHarvestBlock(int par1, int par2, int par3) 223 { 224 if (par1 == this.partiallyDestroyedBlockX && par2 == this.partiallyDestroyedBlockY && par3 == this.partiallyDestroyedBlockZ) 225 { 226 int l = this.curblockDamage - this.initialDamage; 227 int i1 = this.theWorld.getBlockId(par1, par2, par3); 228 229 if (i1 != 0) 230 { 231 Block block = Block.blocksList[i1]; 232 float f = block.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, par1, par2, par3) * (float)(l + 1); 233 234 if (f >= 0.7F) 235 { 236 this.isDestroyingBlock = false; 237 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, par1, par2, par3, -1); 238 this.tryHarvestBlock(par1, par2, par3); 239 } 240 else if (!this.receivedFinishDiggingPacket) 241 { 242 this.isDestroyingBlock = false; 243 this.receivedFinishDiggingPacket = true; 244 this.posX = par1; 245 this.posY = par2; 246 this.posZ = par3; 247 this.field_73093_n = this.initialDamage; 248 } 249 } 250 } 251 } 252 253 /** 254 * note: this ignores the pars passed in and continues to destroy the onClickedBlock 255 */ 256 public void cancelDestroyingBlock(int par1, int par2, int par3) 257 { 258 this.isDestroyingBlock = false; 259 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ, -1); 260 } 261 262 /** 263 * Removes a block and triggers the appropriate events 264 */ 265 private boolean removeBlock(int par1, int par2, int par3) 266 { 267 Block block = Block.blocksList[this.theWorld.getBlockId(par1, par2, par3)]; 268 int l = this.theWorld.getBlockMetadata(par1, par2, par3); 269 270 if (block != null) 271 { 272 block.onBlockHarvested(this.theWorld, par1, par2, par3, l, this.thisPlayerMP); 273 } 274 275 boolean flag = (block != null && block.removeBlockByPlayer(theWorld, thisPlayerMP, par1, par2, par3)); 276 277 if (block != null && flag) 278 { 279 block.onBlockDestroyedByPlayer(this.theWorld, par1, par2, par3, l); 280 } 281 282 return flag; 283 } 284 285 /** 286 * Attempts to harvest a block at the given coordinate 287 */ 288 public boolean tryHarvestBlock(int par1, int par2, int par3) 289 { 290 if (this.gameType.isAdventure() && !this.thisPlayerMP.canCurrentToolHarvestBlock(par1, par2, par3)) 291 { 292 return false; 293 } 294 else 295 { 296 ItemStack stack = thisPlayerMP.getCurrentEquippedItem(); 297 if (stack != null && stack.getItem().onBlockStartBreak(stack, par1, par2, par3, thisPlayerMP)) 298 { 299 return false; 300 } 301 int l = this.theWorld.getBlockId(par1, par2, par3); 302 int i1 = this.theWorld.getBlockMetadata(par1, par2, par3); 303 this.theWorld.playAuxSFXAtEntity(this.thisPlayerMP, 2001, par1, par2, par3, l + (this.theWorld.getBlockMetadata(par1, par2, par3) << 12)); 304 boolean flag = false; 305 306 if (this.isCreative()) 307 { 308 flag = this.removeBlock(par1, par2, par3); 309 this.thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, this.theWorld)); 310 } 311 else 312 { 313 ItemStack itemstack = this.thisPlayerMP.getCurrentEquippedItem(); 314 boolean flag1 = false; 315 Block block = Block.blocksList[l]; 316 if (block != null) 317 { 318 flag1 = block.canHarvestBlock(thisPlayerMP, i1); 319 } 320 321 if (itemstack != null) 322 { 323 itemstack.onBlockDestroyed(this.theWorld, l, par1, par2, par3, this.thisPlayerMP); 324 325 if (itemstack.stackSize == 0) 326 { 327 this.thisPlayerMP.destroyCurrentEquippedItem(); 328 } 329 } 330 331 flag = this.removeBlock(par1, par2, par3); 332 if (flag && flag1) 333 { 334 Block.blocksList[l].harvestBlock(this.theWorld, this.thisPlayerMP, par1, par2, par3, i1); 335 } 336 } 337 338 return flag; 339 } 340 } 341 342 /** 343 * Attempts to right-click use an item by the given EntityPlayer in the given World 344 */ 345 public boolean tryUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack) 346 { 347 int i = par3ItemStack.stackSize; 348 int j = par3ItemStack.getItemDamage(); 349 ItemStack itemstack1 = par3ItemStack.useItemRightClick(par2World, par1EntityPlayer); 350 351 if (itemstack1 == par3ItemStack && (itemstack1 == null || itemstack1.stackSize == i && itemstack1.getMaxItemUseDuration() <= 0 && itemstack1.getItemDamage() == j)) 352 { 353 return false; 354 } 355 else 356 { 357 par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = itemstack1; 358 359 if (this.isCreative()) 360 { 361 itemstack1.stackSize = i; 362 363 if (itemstack1.isItemStackDamageable()) 364 { 365 itemstack1.setItemDamage(j); 366 } 367 } 368 369 if (itemstack1.stackSize == 0) 370 { 371 par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = null; 372 MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(thisPlayerMP, itemstack1)); 373 } 374 375 if (!par1EntityPlayer.isUsingItem()) 376 { 377 ((EntityPlayerMP)par1EntityPlayer).sendContainerToPlayer(par1EntityPlayer.inventoryContainer); 378 } 379 380 return true; 381 } 382 } 383 384 /** 385 * Activate the clicked on block, otherwise use the held item. Args: player, world, itemStack, x, y, z, side, 386 * xOffset, yOffset, zOffset 387 */ 388 public boolean activateBlockOrUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack, int par4, int par5, int par6, int par7, float par8, float par9, float par10) 389 { 390 PlayerInteractEvent event = ForgeEventFactory.onPlayerInteract(par1EntityPlayer, Action.RIGHT_CLICK_BLOCK, par4, par5, par6, par7); 391 if (event.isCanceled()) 392 { 393 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld)); 394 return false; 395 } 396 397 Item item = (par3ItemStack != null ? par3ItemStack.getItem() : null); 398 if (item != null && item.onItemUseFirst(par3ItemStack, par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10)) 399 { 400 if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack); 401 return true; 402 } 403 404 int i1 = par2World.getBlockId(par4, par5, par6); 405 Block block = Block.blocksList[i1]; 406 boolean result = false; 407 408 if (block != null && (!par1EntityPlayer.isSneaking() || ( par1EntityPlayer.getHeldItem() == null || par1EntityPlayer.getHeldItem().getItem().shouldPassSneakingClickToBlock(par2World, par4, par5, par6)))) 409 { 410 if (event.useBlock != Event.Result.DENY) 411 { 412 result = block.onBlockActivated(par2World, par4, par5, par6, par1EntityPlayer, par7, par8, par9, par10); 413 } 414 else 415 { 416 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld)); 417 result = event.useItem != Event.Result.ALLOW; 418 } 419 } 420 421 if (par3ItemStack != null && !result && event.useItem != Event.Result.DENY) 422 { 423 int meta = par3ItemStack.getItemDamage(); 424 int size = par3ItemStack.stackSize; 425 result = par3ItemStack.tryPlaceItemIntoWorld(par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10); 426 if (isCreative()) 427 { 428 par3ItemStack.setItemDamage(meta); 429 par3ItemStack.stackSize = size; 430 } 431 if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack); 432 } 433 434 /* Re-enable if this causes bukkit incompatibility, or re-write client side to only send a single packet per right click. 435 if (par3ItemStack != null && ((!result && event.useItem != Event.Result.DENY) || event.useItem == Event.Result.ALLOW)) 436 { 437 this.tryUseItem(thisPlayerMP, par2World, par3ItemStack); 438 }*/ 439 return result; 440 } 441 442 /** 443 * Sets the world instance. 444 */ 445 public void setWorld(WorldServer par1WorldServer) 446 { 447 this.theWorld = par1WorldServer; 448 } 449 450 public double getBlockReachDistance() 451 { 452 return blockReachDistance; 453 } 454 public void setBlockReachDistance(double distance) 455 { 456 blockReachDistance = distance; 457 } 458}