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