001 package net.minecraft.item; 002 003 import net.minecraft.block.Block; 004 import net.minecraft.entity.player.EntityPlayer; 005 import net.minecraft.entity.player.EntityPlayerMP; 006 import net.minecraft.network.packet.Packet53BlockChange; 007 import net.minecraft.world.EnumGameType; 008 import net.minecraft.world.World; 009 import net.minecraft.world.WorldServer; 010 011 import net.minecraftforge.common.ForgeHooks; 012 import net.minecraftforge.common.MinecraftForge; 013 import net.minecraftforge.event.Event; 014 import net.minecraftforge.event.ForgeEventFactory; 015 import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent; 016 import net.minecraftforge.event.entity.player.PlayerInteractEvent; 017 import net.minecraftforge.event.entity.player.PlayerInteractEvent.Action; 018 019 public 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 var1; 094 float var4; 095 int var5; 096 097 if (this.receivedFinishDiggingPacket) 098 { 099 var1 = this.curblockDamage - this.field_73093_n; 100 int var2 = this.theWorld.getBlockId(this.posX, this.posY, this.posZ); 101 102 if (var2 == 0) 103 { 104 this.receivedFinishDiggingPacket = false; 105 } 106 else 107 { 108 Block var3 = Block.blocksList[var2]; 109 var4 = var3.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, this.posX, this.posY, this.posZ) * (float)(var1 + 1); 110 var5 = (int)(var4 * 10.0F); 111 112 if (var5 != this.durabilityRemainingOnBlock) 113 { 114 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.posX, this.posY, this.posZ, var5); 115 this.durabilityRemainingOnBlock = var5; 116 } 117 118 if (var4 >= 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 var1 = this.theWorld.getBlockId(this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ); 128 Block var6 = Block.blocksList[var1]; 129 130 if (var6 == 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 var7 = this.curblockDamage - this.initialDamage; 139 var4 = var6.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ) * (float)(var7 + 1); 140 var5 = (int)(var4 * 10.0F); 141 142 if (var5 != this.durabilityRemainingOnBlock) 143 { 144 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ, var5); 145 this.durabilityRemainingOnBlock = var5; 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 var5 = 1.0F; 177 int var6 = this.theWorld.getBlockId(par1, par2, par3); 178 Block block = Block.blocksList[var6]; 179 180 if (block != null) 181 { 182 if (event.useBlock != Event.Result.DENY) 183 { 184 block.onBlockClicked(theWorld, par1, par2, par3, thisPlayerMP); 185 theWorld.extinguishFire(thisPlayerMP, par1, par2, par3, par4); 186 } 187 else 188 { 189 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, theWorld)); 190 } 191 var5 = block.getPlayerRelativeBlockHardness(thisPlayerMP, thisPlayerMP.worldObj, par1, par2, par3); 192 } 193 194 if (event.useItem == Event.Result.DENY) 195 { 196 if (var5 >= 1.0f) 197 { 198 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, theWorld)); 199 } 200 return; 201 } 202 203 if (var6 > 0 && var5 >= 1.0F) 204 { 205 this.tryHarvestBlock(par1, par2, par3); 206 } 207 else 208 { 209 this.isDestroyingBlock = true; 210 this.partiallyDestroyedBlockX = par1; 211 this.partiallyDestroyedBlockY = par2; 212 this.partiallyDestroyedBlockZ = par3; 213 int var7 = (int)(var5 * 10.0F); 214 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, par1, par2, par3, var7); 215 this.durabilityRemainingOnBlock = var7; 216 } 217 } 218 } 219 } 220 221 public void uncheckedTryHarvestBlock(int par1, int par2, int par3) 222 { 223 if (par1 == this.partiallyDestroyedBlockX && par2 == this.partiallyDestroyedBlockY && par3 == this.partiallyDestroyedBlockZ) 224 { 225 int var4 = this.curblockDamage - this.initialDamage; 226 int var5 = this.theWorld.getBlockId(par1, par2, par3); 227 228 if (var5 != 0) 229 { 230 Block var6 = Block.blocksList[var5]; 231 float var7 = var6.getPlayerRelativeBlockHardness(this.thisPlayerMP, this.thisPlayerMP.worldObj, par1, par2, par3) * (float)(var4 + 1); 232 233 if (var7 >= 0.7F) 234 { 235 this.isDestroyingBlock = false; 236 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, par1, par2, par3, -1); 237 this.tryHarvestBlock(par1, par2, par3); 238 } 239 else if (!this.receivedFinishDiggingPacket) 240 { 241 this.isDestroyingBlock = false; 242 this.receivedFinishDiggingPacket = true; 243 this.posX = par1; 244 this.posY = par2; 245 this.posZ = par3; 246 this.field_73093_n = this.initialDamage; 247 } 248 } 249 } 250 } 251 252 /** 253 * note: this ignores the pars passed in and continues to destroy the onClickedBlock 254 */ 255 public void cancelDestroyingBlock(int par1, int par2, int par3) 256 { 257 this.isDestroyingBlock = false; 258 this.theWorld.destroyBlockInWorldPartially(this.thisPlayerMP.entityId, this.partiallyDestroyedBlockX, this.partiallyDestroyedBlockY, this.partiallyDestroyedBlockZ, -1); 259 } 260 261 /** 262 * Removes a block and triggers the appropriate events 263 */ 264 private boolean removeBlock(int par1, int par2, int par3) 265 { 266 Block var4 = Block.blocksList[this.theWorld.getBlockId(par1, par2, par3)]; 267 int var5 = this.theWorld.getBlockMetadata(par1, par2, par3); 268 269 if (var4 != null) 270 { 271 var4.onBlockHarvested(this.theWorld, par1, par2, par3, var5, this.thisPlayerMP); 272 } 273 274 boolean var6 = (var4 != null && var4.removeBlockByPlayer(theWorld, thisPlayerMP, par1, par2, par3)); 275 276 if (var4 != null && var6) 277 { 278 var4.onBlockDestroyedByPlayer(this.theWorld, par1, par2, par3, var5); 279 } 280 281 return var6; 282 } 283 284 /** 285 * Attempts to harvest a block at the given coordinate 286 */ 287 public boolean tryHarvestBlock(int par1, int par2, int par3) 288 { 289 if (this.gameType.isAdventure() && !this.thisPlayerMP.canCurrentToolHarvestBlock(par1, par2, par3)) 290 { 291 return false; 292 } 293 else 294 { 295 ItemStack stack = thisPlayerMP.getCurrentEquippedItem(); 296 if (stack != null && stack.getItem().onBlockStartBreak(stack, par1, par2, par3, thisPlayerMP)) 297 { 298 return false; 299 } 300 int var4 = this.theWorld.getBlockId(par1, par2, par3); 301 int var5 = this.theWorld.getBlockMetadata(par1, par2, par3); 302 this.theWorld.playAuxSFXAtEntity(this.thisPlayerMP, 2001, par1, par2, par3, var4 + (this.theWorld.getBlockMetadata(par1, par2, par3) << 12)); 303 boolean var6 = false; 304 305 if (this.isCreative()) 306 { 307 var6 = this.removeBlock(par1, par2, par3); 308 this.thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par1, par2, par3, this.theWorld)); 309 } 310 else 311 { 312 ItemStack var7 = this.thisPlayerMP.getCurrentEquippedItem(); 313 boolean var8 = false; 314 Block block = Block.blocksList[var4]; 315 if (block != null) 316 { 317 var8 = block.canHarvestBlock(thisPlayerMP, var5); 318 } 319 320 if (var7 != null) 321 { 322 var7.onBlockDestroyed(this.theWorld, var4, par1, par2, par3, this.thisPlayerMP); 323 324 if (var7.stackSize == 0) 325 { 326 this.thisPlayerMP.destroyCurrentEquippedItem(); 327 } 328 } 329 330 var6 = this.removeBlock(par1, par2, par3); 331 if (var6 && var8) 332 { 333 Block.blocksList[var4].harvestBlock(this.theWorld, this.thisPlayerMP, par1, par2, par3, var5); 334 } 335 } 336 337 return var6; 338 } 339 } 340 341 /** 342 * Attempts to right-click use an item by the given EntityPlayer in the given World 343 */ 344 public boolean tryUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack) 345 { 346 int var4 = par3ItemStack.stackSize; 347 int var5 = par3ItemStack.getItemDamage(); 348 ItemStack var6 = par3ItemStack.useItemRightClick(par2World, par1EntityPlayer); 349 350 if (var6 == par3ItemStack && (var6 == null || var6.stackSize == var4 && var6.getMaxItemUseDuration() <= 0 && var6.getItemDamage() == var5)) 351 { 352 return false; 353 } 354 else 355 { 356 par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = var6; 357 358 if (this.isCreative()) 359 { 360 var6.stackSize = var4; 361 362 if (var6.isItemStackDamageable()) 363 { 364 var6.setItemDamage(var5); 365 } 366 } 367 368 if (var6.stackSize == 0) 369 { 370 par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = null; 371 MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(thisPlayerMP, var6)); 372 } 373 374 if (!par1EntityPlayer.isUsingItem()) 375 { 376 ((EntityPlayerMP)par1EntityPlayer).sendContainerToPlayer(par1EntityPlayer.inventoryContainer); 377 } 378 379 return true; 380 } 381 } 382 383 /** 384 * Activate the clicked on block, otherwise use the held item. Args: player, world, itemStack, x, y, z, side, 385 * xOffset, yOffset, zOffset 386 */ 387 public boolean activateBlockOrUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack, int par4, int par5, int par6, int par7, float par8, float par9, float par10) 388 { 389 PlayerInteractEvent event = ForgeEventFactory.onPlayerInteract(par1EntityPlayer, Action.RIGHT_CLICK_BLOCK, par4, par5, par6, par7); 390 if (event.isCanceled()) 391 { 392 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld)); 393 return false; 394 } 395 396 Item item = (par3ItemStack != null ? par3ItemStack.getItem() : null); 397 if (item != null && item.onItemUseFirst(par3ItemStack, par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10)) 398 { 399 if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack); 400 return true; 401 } 402 403 int var11 = par2World.getBlockId(par4, par5, par6); 404 Block block = Block.blocksList[var11]; 405 boolean result = false; 406 407 if (block != null && (!par1EntityPlayer.isSneaking() || ( par1EntityPlayer.getHeldItem() == null || par1EntityPlayer.getHeldItem().getItem().shouldPassSneakingClickToBlock(par2World, par4, par5, par6)))) 408 { 409 if (event.useBlock != Event.Result.DENY) 410 { 411 result = block.onBlockActivated(par2World, par4, par5, par6, par1EntityPlayer, par7, par8, par9, par10); 412 } 413 else 414 { 415 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld)); 416 result = event.useItem != Event.Result.ALLOW; 417 } 418 } 419 420 if (par3ItemStack != null && !result && event.useItem != Event.Result.DENY) 421 { 422 int meta = par3ItemStack.getItemDamage(); 423 int size = par3ItemStack.stackSize; 424 result = par3ItemStack.tryPlaceItemIntoWorld(par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10); 425 if (isCreative()) 426 { 427 par3ItemStack.setItemDamage(meta); 428 par3ItemStack.stackSize = size; 429 } 430 if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack); 431 } 432 433 /* Re-enable if this causes bukkit incompatibility, or re-write client side to only send a single packet per right click. 434 if (par3ItemStack != null && ((!result && event.useItem != Event.Result.DENY) || event.useItem == Event.Result.ALLOW)) 435 { 436 this.tryUseItem(thisPlayerMP, par2World, par3ItemStack); 437 }*/ 438 return result; 439 } 440 441 /** 442 * Sets the world instance. 443 */ 444 public void setWorld(WorldServer par1WorldServer) 445 { 446 this.theWorld = par1WorldServer; 447 } 448 449 public double getBlockReachDistance() 450 { 451 return blockReachDistance; 452 } 453 public void setBlockReachDistance(double distance) 454 { 455 blockReachDistance = distance; 456 } 457 }