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 }
325 }
326
327 var6 = this.removeBlock(par1, par2, par3);
328 if (var6 && var8)
329 {
330 Block.blocksList[var4].harvestBlock(this.theWorld, this.thisPlayerMP, par1, par2, par3, var5);
331 }
332 }
333
334 return var6;
335 }
336 }
337
338 /**
339 * Attempts to right-click use an item by the given EntityPlayer in the given World
340 */
341 public boolean tryUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack)
342 {
343 int var4 = par3ItemStack.stackSize;
344 int var5 = par3ItemStack.getItemDamage();
345 ItemStack var6 = par3ItemStack.useItemRightClick(par2World, par1EntityPlayer);
346
347 if (var6 == par3ItemStack && (var6 == null || var6.stackSize == var4 && var6.getMaxItemUseDuration() <= 0 && var6.getItemDamage() == var5))
348 {
349 return false;
350 }
351 else
352 {
353 par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = var6;
354
355 if (this.isCreative())
356 {
357 var6.stackSize = var4;
358
359 if (var6.isItemStackDamageable())
360 {
361 var6.setItemDamage(var5);
362 }
363 }
364
365 if (var6.stackSize == 0)
366 {
367 par1EntityPlayer.inventory.mainInventory[par1EntityPlayer.inventory.currentItem] = null;
368 MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(thisPlayerMP, var6));
369 }
370
371 if (!par1EntityPlayer.isUsingItem())
372 {
373 ((EntityPlayerMP)par1EntityPlayer).sendContainerToPlayer(par1EntityPlayer.inventoryContainer);
374 }
375
376 return true;
377 }
378 }
379
380 /**
381 * Activate the clicked on block, otherwise use the held item. Args: player, world, itemStack, x, y, z, side,
382 * xOffset, yOffset, zOffset
383 */
384 public boolean activateBlockOrUseItem(EntityPlayer par1EntityPlayer, World par2World, ItemStack par3ItemStack, int par4, int par5, int par6, int par7, float par8, float par9, float par10)
385 {
386 PlayerInteractEvent event = ForgeEventFactory.onPlayerInteract(par1EntityPlayer, Action.RIGHT_CLICK_BLOCK, par4, par5, par6, par7);
387 if (event.isCanceled())
388 {
389 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld));
390 return false;
391 }
392
393 Item item = (par3ItemStack != null ? par3ItemStack.getItem() : null);
394 if (item != null && item.onItemUseFirst(par3ItemStack, par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10))
395 {
396 if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack);
397 return true;
398 }
399
400 int var11 = par2World.getBlockId(par4, par5, par6);
401 Block block = Block.blocksList[var11];
402 boolean result = false;
403
404 if (block != null)
405 {
406 if (event.useBlock != Event.Result.DENY)
407 {
408 result = block.onBlockActivated(par2World, par4, par5, par6, par1EntityPlayer, par7, par8, par9, par10);
409 }
410 else
411 {
412 thisPlayerMP.playerNetServerHandler.sendPacketToPlayer(new Packet53BlockChange(par4, par5, par6, theWorld));
413 result = event.useItem != Event.Result.ALLOW;
414 }
415 }
416
417 if (par3ItemStack != null && !result)
418 {
419 int meta = par3ItemStack.getItemDamage();
420 int size = par3ItemStack.stackSize;
421 result = par3ItemStack.tryPlaceItemIntoWorld(par1EntityPlayer, par2World, par4, par5, par6, par7, par8, par9, par10);
422 if (isCreative())
423 {
424 par3ItemStack.setItemDamage(meta);
425 par3ItemStack.stackSize = size;
426 }
427 if (par3ItemStack.stackSize <= 0) ForgeEventFactory.onPlayerDestroyItem(thisPlayerMP, par3ItemStack);
428 }
429
430 /* Re-enable if this causes bukkit incompatibility, or re-write client side to only send a single packet per right click.
431 if (par3ItemStack != null && ((!result && event.useItem != Event.Result.DENY) || event.useItem == Event.Result.ALLOW))
432 {
433 this.tryUseItem(thisPlayerMP, par2World, par3ItemStack);
434 }*/
435 return result;
436 }
437
438 /**
439 * Sets the world instance.
440 */
441 public void setWorld(WorldServer par1WorldServer)
442 {
443 this.theWorld = par1WorldServer;
444 }
445
446 public double getBlockReachDistance()
447 {
448 return blockReachDistance;
449 }
450 public void setBlockReachDistance(double distance)
451 {
452 blockReachDistance = distance;
453 }
454 }