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 }