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