001 package net.minecraft.src;
002
003 import cpw.mods.fml.common.Side;
004 import cpw.mods.fml.common.asm.SideOnly;
005 import java.util.ArrayList;
006 import java.util.Collection;
007 import java.util.HashSet;
008 import java.util.Iterator;
009 import java.util.List;
010 import java.util.Random;
011 import java.util.Set;
012
013 import com.google.common.collect.SetMultimap;
014
015 import net.minecraftforge.common.ForgeChunkManager;
016 import net.minecraftforge.common.ForgeChunkManager.Ticket;
017 import net.minecraftforge.common.ForgeHooks;
018 import net.minecraftforge.common.MinecraftForge;
019 import net.minecraftforge.common.ForgeDirection;
020 import net.minecraftforge.event.entity.EntityEvent;
021 import net.minecraftforge.event.entity.EntityJoinWorldEvent;
022 import net.minecraftforge.event.world.WorldEvent;
023 import net.minecraftforge.event.entity.PlaySoundAtEntityEvent;
024
025 public abstract class World implements IBlockAccess
026 {
027 /**
028 * Used in the getEntitiesWithinAABB functions to expand the search area for entities.
029 * Modders should change this variable to a higher value if it is less then the radius
030 * of one of there entities.
031 */
032 public static double MAX_ENTITY_RADIUS = 2.0D;
033
034 /**
035 * boolean; if true updates scheduled by scheduleBlockUpdate happen immediately
036 */
037 public boolean scheduledUpdatesAreImmediate = false;
038
039 /** A list of all Entities in all currently-loaded chunks */
040 public List loadedEntityList = new ArrayList();
041 protected List unloadedEntityList = new ArrayList();
042
043 /** A list of all TileEntities in all currently-loaded chunks */
044 public List loadedTileEntityList = new ArrayList();
045 private List addedTileEntityList = new ArrayList();
046
047 /** Entities marked for removal. */
048 private List entityRemoval = new ArrayList();
049
050 /** Array list of players in the world. */
051 public List playerEntities = new ArrayList();
052
053 /** a list of all the lightning entities */
054 public List weatherEffects = new ArrayList();
055 private long cloudColour = 16777215L;
056
057 /** How much light is subtracted from full daylight */
058 public int skylightSubtracted = 0;
059
060 /**
061 * Contains the current Linear Congruential Generator seed for block updates. Used with an A value of 3 and a C
062 * value of 0x3c6ef35f, producing a highly planar series of values ill-suited for choosing random blocks in a
063 * 16x128x16 field.
064 */
065 protected int updateLCG = (new Random()).nextInt();
066
067 /**
068 * magic number used to generate fast random numbers for 3d distribution within a chunk
069 */
070 protected final int DIST_HASH_MAGIC = 1013904223;
071 protected float prevRainingStrength;
072 protected float rainingStrength;
073 protected float prevThunderingStrength;
074 protected float thunderingStrength;
075
076 /**
077 * Set to 2 whenever a lightning bolt is generated in SSP. Decrements if > 0 in updateWeather(). Value appears to be
078 * unused.
079 */
080 protected int lastLightningBolt = 0;
081
082 /**
083 * If > 0, the sky and skylight colors are illuminated by a lightning flash
084 */
085 public int lightningFlash = 0;
086
087 /** true while the world is editing blocks */
088 public boolean editingBlocks = false;
089
090 /** Option > Difficulty setting (0 - 3) */
091 public int difficultySetting;
092
093 /** RNG for World. */
094 public Random rand = new Random();
095
096 /** The WorldProvider instance that World uses. */
097 public final WorldProvider provider;
098 protected List worldAccesses = new ArrayList();
099
100 /** Handles chunk operations and caching */
101 protected IChunkProvider chunkProvider;
102 protected final ISaveHandler saveHandler;
103
104 /**
105 * holds information about a world (size on disk, time, spawn point, seed, ...)
106 */
107 protected WorldInfo worldInfo;
108
109 /** Boolean that is set to true when trying to find a spawn point */
110 public boolean findingSpawnPoint;
111 public MapStorage mapStorage;
112 public final VillageCollection villageCollectionObj = new VillageCollection(this);
113 protected final VillageSiege villageSiegeObj = new VillageSiege(this);
114 public final Profiler theProfiler;
115 private ArrayList collidingBoundingBoxes = new ArrayList();
116 private boolean scanningTileEntities;
117
118 /** indicates if enemies are spawned or not */
119 protected boolean spawnHostileMobs = true;
120
121 /** A flag indicating whether we should spawn peaceful mobs. */
122 protected boolean spawnPeacefulMobs = true;
123
124 /** Positions to update */
125 protected Set activeChunkSet = new HashSet();
126
127 /** number of ticks until the next random ambients play */
128 private int ambientTickCountdown;
129
130 /**
131 * is a temporary list of blocks and light values used when updating light levels. Holds up to 32x32x32 blocks (the
132 * maximum influence of a light source.) Every element is a packed bit value: 0000000000LLLLzzzzzzyyyyyyxxxxxx. The
133 * 4-bit L is a light level used when darkening blocks. 6-bit numbers x, y and z represent the block's offset from
134 * the original block, plus 32 (i.e. value of 31 would mean a -1 offset
135 */
136 int[] lightUpdateBlockList;
137
138 /**
139 * entities within AxisAlignedBB excluding one, set and returned in getEntitiesWithinAABBExcludingEntity(Entity
140 * var1, AxisAlignedBB var2)
141 */
142 private List entitiesWithinAABBExcludingEntity;
143
144 /**
145 * This is set to true when you are a client connected to a multiplayer world, false otherwise. As of Minecraft 1.3
146 * and the integrated server, this will always return true.
147 */
148 public boolean isRemote;
149
150 /**
151 * Gets the biome for a given set of x/z coordinates
152 */
153 public BiomeGenBase getBiomeGenForCoords(int par1, int par2)
154 {
155 return provider.getBiomeGenForCoords(par1, par2);
156 }
157
158 public BiomeGenBase getBiomeGenForCoordsBody(int par1, int par2)
159 {
160 if (this.blockExists(par1, 0, par2))
161 {
162 Chunk var3 = this.getChunkFromBlockCoords(par1, par2);
163
164 if (var3 != null)
165 {
166 return var3.getBiomeGenForWorldCoords(par1 & 15, par2 & 15, this.provider.worldChunkMgr);
167 }
168 }
169
170 return this.provider.worldChunkMgr.getBiomeGenAt(par1, par2);
171 }
172
173 public WorldChunkManager getWorldChunkManager()
174 {
175 return this.provider.worldChunkMgr;
176 }
177
178 @SideOnly(Side.CLIENT)
179 public World(ISaveHandler par1ISaveHandler, String par2Str, WorldProvider par3WorldProvider, WorldSettings par4WorldSettings, Profiler par5Profiler)
180 {
181 this.ambientTickCountdown = this.rand.nextInt(12000);
182 this.lightUpdateBlockList = new int[32768];
183 this.entitiesWithinAABBExcludingEntity = new ArrayList();
184 this.isRemote = false;
185 this.saveHandler = par1ISaveHandler;
186 this.theProfiler = par5Profiler;
187 this.worldInfo = new WorldInfo(par4WorldSettings, par2Str);
188 this.provider = par3WorldProvider;
189 }
190 // Broken up so that the WorldClient gets the chance to set the mapstorage object before the dimension initializes
191 @SideOnly(Side.CLIENT)
192 protected void finishSetup() {
193 this.provider.registerWorld(this);
194 this.chunkProvider = this.createChunkProvider();
195 this.calculateInitialSkylight();
196 this.calculateInitialWeather();
197 }
198
199 public World(ISaveHandler par1ISaveHandler, String par2Str, WorldSettings par3WorldSettings, WorldProvider par4WorldProvider, Profiler par5Profiler)
200 {
201 this.ambientTickCountdown = this.rand.nextInt(12000);
202 this.lightUpdateBlockList = new int[32768];
203 this.entitiesWithinAABBExcludingEntity = new ArrayList();
204 this.isRemote = false;
205 this.saveHandler = par1ISaveHandler;
206 this.theProfiler = par5Profiler;
207 this.mapStorage = getMapStorage(par1ISaveHandler);
208 this.worldInfo = par1ISaveHandler.loadWorldInfo();
209
210 if (par4WorldProvider != null)
211 {
212 this.provider = par4WorldProvider;
213 }
214 else if (this.worldInfo != null && this.worldInfo.getDimension() != 0)
215 {
216 this.provider = WorldProvider.getProviderForDimension(this.worldInfo.getDimension());
217 }
218 else
219 {
220 this.provider = WorldProvider.getProviderForDimension(0);
221 }
222
223 if (this.worldInfo == null)
224 {
225 this.worldInfo = new WorldInfo(par3WorldSettings, par2Str);
226 }
227 else
228 {
229 this.worldInfo.setWorldName(par2Str);
230 }
231
232 this.provider.registerWorld(this);
233 this.chunkProvider = this.createChunkProvider();
234
235 if (!this.worldInfo.isInitialized())
236 {
237 this.initialize(par3WorldSettings);
238 this.worldInfo.setServerInitialized(true);
239 }
240
241 this.calculateInitialSkylight();
242 this.calculateInitialWeather();
243 }
244
245 private static MapStorage s_mapStorage;
246 private static ISaveHandler s_savehandler;
247 //Provides a solution for different worlds getting different copies of the same data, potentially rewriting the data or causing race conditions/stale data
248 //Buildcraft has suffered from the issue this fixes. If you load the same data from two different worlds they can get two different copies of the same object, thus the last saved gets final say.
249 private MapStorage getMapStorage(ISaveHandler savehandler)
250 {
251 if (s_savehandler != savehandler || s_mapStorage == null) {
252 s_mapStorage = new MapStorage(savehandler);
253 s_savehandler = savehandler;
254 }
255 return s_mapStorage;
256 }
257
258 /**
259 * Creates the chunk provider for this world. Called in the constructor. Retrieves provider from worldProvider?
260 */
261 protected abstract IChunkProvider createChunkProvider();
262
263 protected void initialize(WorldSettings par1WorldSettings)
264 {
265 this.worldInfo.setServerInitialized(true);
266 }
267
268 @SideOnly(Side.CLIENT)
269
270 /**
271 * Sets a new spawn location by finding an uncovered block at a random (x,z) location in the chunk.
272 */
273 public void setSpawnLocation()
274 {
275 this.setSpawnLocation(8, 64, 8);
276 }
277
278 /**
279 * Returns the block ID of the first block at this (x,z) location with air above it, searching from sea level
280 * upwards.
281 */
282 public int getFirstUncoveredBlock(int par1, int par2)
283 {
284 int var3;
285
286 for (var3 = 63; !this.isAirBlock(par1, var3 + 1, par2); ++var3)
287 {
288 ;
289 }
290
291 return this.getBlockId(par1, var3, par2);
292 }
293
294 /**
295 * Returns the block ID at coords x,y,z
296 */
297 public int getBlockId(int par1, int par2, int par3)
298 {
299 return par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000 ? (par2 < 0 ? 0 : (par2 >= 256 ? 0 : this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).getBlockID(par1 & 15, par2, par3 & 15))) : 0;
300 }
301
302 public int getBlockLightOpacity(int par1, int par2, int par3)
303 {
304 return par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000 ? (par2 < 0 ? 0 : (par2 >= 256 ? 0 : this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).getBlockLightOpacity(par1 & 15, par2, par3 & 15))) : 0;
305 }
306
307 /**
308 * Returns true if the block at the specified coordinates is empty
309 */
310 public boolean isAirBlock(int par1, int par2, int par3)
311 {
312 int id = getBlockId(par1, par2, par3);
313 return id == 0 || Block.blocksList[id] == null || Block.blocksList[id].isAirBlock(this, par1, par2, par3);
314 }
315
316 /**
317 * Checks if a block at a given position should have a tile entity.
318 */
319 public boolean blockHasTileEntity(int par1, int par2, int par3)
320 {
321 int var4 = this.getBlockId(par1, par2, par3);
322 int meta = this.getBlockMetadata(par1, par2, par3);
323 return Block.blocksList[var4] != null && Block.blocksList[var4].hasTileEntity(meta);
324 }
325
326 /**
327 * Returns whether a block exists at world coordinates x, y, z
328 */
329 public boolean blockExists(int par1, int par2, int par3)
330 {
331 return par2 >= 0 && par2 < 256 ? this.chunkExists(par1 >> 4, par3 >> 4) : false;
332 }
333
334 /**
335 * Checks if any of the chunks within distance (argument 4) blocks of the given block exist
336 */
337 public boolean doChunksNearChunkExist(int par1, int par2, int par3, int par4)
338 {
339 return this.checkChunksExist(par1 - par4, par2 - par4, par3 - par4, par1 + par4, par2 + par4, par3 + par4);
340 }
341
342 /**
343 * Checks between a min and max all the chunks inbetween actually exist. Args: minX, minY, minZ, maxX, maxY, maxZ
344 */
345 public boolean checkChunksExist(int par1, int par2, int par3, int par4, int par5, int par6)
346 {
347 if (par5 >= 0 && par2 < 256)
348 {
349 par1 >>= 4;
350 par3 >>= 4;
351 par4 >>= 4;
352 par6 >>= 4;
353
354 for (int var7 = par1; var7 <= par4; ++var7)
355 {
356 for (int var8 = par3; var8 <= par6; ++var8)
357 {
358 if (!this.chunkExists(var7, var8))
359 {
360 return false;
361 }
362 }
363 }
364
365 return true;
366 }
367 else
368 {
369 return false;
370 }
371 }
372
373 /**
374 * Returns whether a chunk exists at chunk coordinates x, y
375 */
376 protected boolean chunkExists(int par1, int par2)
377 {
378 return this.chunkProvider.chunkExists(par1, par2);
379 }
380
381 /**
382 * Returns a chunk looked up by block coordinates. Args: x, z
383 */
384 public Chunk getChunkFromBlockCoords(int par1, int par2)
385 {
386 return this.getChunkFromChunkCoords(par1 >> 4, par2 >> 4);
387 }
388
389 /**
390 * Returns back a chunk looked up by chunk coordinates Args: x, y
391 */
392 public Chunk getChunkFromChunkCoords(int par1, int par2)
393 {
394 return this.chunkProvider.provideChunk(par1, par2);
395 }
396
397 /**
398 * Sets the block ID and metadata of a block in global coordinates
399 */
400 public boolean setBlockAndMetadata(int par1, int par2, int par3, int par4, int par5)
401 {
402 return this.setBlockAndMetadataWithUpdate(par1, par2, par3, par4, par5, true);
403 }
404
405 /**
406 * Sets the block ID and metadata of a block, optionally marking it as needing update. Args: X,Y,Z, blockID,
407 * metadata, needsUpdate
408 */
409 public boolean setBlockAndMetadataWithUpdate(int par1, int par2, int par3, int par4, int par5, boolean par6)
410 {
411 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
412 {
413 if (par2 < 0)
414 {
415 return false;
416 }
417 else if (par2 >= 256)
418 {
419 return false;
420 }
421 else
422 {
423 Chunk var7 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
424 boolean var8 = var7.setBlockIDWithMetadata(par1 & 15, par2, par3 & 15, par4, par5);
425 this.theProfiler.startSection("checkLight");
426 this.updateAllLightTypes(par1, par2, par3);
427 this.theProfiler.endSection();
428
429 if (par6 && var8 && (this.isRemote || var7.deferRender))
430 {
431 this.markBlockNeedsUpdate(par1, par2, par3);
432 }
433
434 return var8;
435 }
436 }
437 else
438 {
439 return false;
440 }
441 }
442
443 /**
444 * Sets the block to the specified blockID at the block coordinates Args x, y, z, blockID
445 */
446 public boolean setBlock(int par1, int par2, int par3, int par4)
447 {
448 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
449 {
450 if (par2 < 0)
451 {
452 return false;
453 }
454 else if (par2 >= 256)
455 {
456 return false;
457 }
458 else
459 {
460 Chunk var5 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
461 boolean var6 = var5.setBlockID(par1 & 15, par2, par3 & 15, par4);
462 this.theProfiler.startSection("checkLight");
463 this.updateAllLightTypes(par1, par2, par3);
464 this.theProfiler.endSection();
465
466 if (var6 && (this.isRemote || var5.deferRender))
467 {
468 this.markBlockNeedsUpdate(par1, par2, par3);
469 }
470
471 return var6;
472 }
473 }
474 else
475 {
476 return false;
477 }
478 }
479
480 /**
481 * Returns the block's material.
482 */
483 public Material getBlockMaterial(int par1, int par2, int par3)
484 {
485 int var4 = this.getBlockId(par1, par2, par3);
486 return var4 == 0 ? Material.air : Block.blocksList[var4].blockMaterial;
487 }
488
489 /**
490 * Returns the block metadata at coords x,y,z
491 */
492 public int getBlockMetadata(int par1, int par2, int par3)
493 {
494 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
495 {
496 if (par2 < 0)
497 {
498 return 0;
499 }
500 else if (par2 >= 256)
501 {
502 return 0;
503 }
504 else
505 {
506 Chunk var4 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
507 par1 &= 15;
508 par3 &= 15;
509 return var4.getBlockMetadata(par1, par2, par3);
510 }
511 }
512 else
513 {
514 return 0;
515 }
516 }
517
518 /**
519 * Sets the blocks metadata and if set will then notify blocks that this block changed. Args: x, y, z, metadata
520 */
521 public void setBlockMetadataWithNotify(int par1, int par2, int par3, int par4)
522 {
523 if (this.setBlockMetadata(par1, par2, par3, par4))
524 {
525 this.notifyBlockChange(par1, par2, par3, this.getBlockId(par1, par2, par3));
526 }
527 }
528
529 /**
530 * Set the metadata of a block in global coordinates
531 */
532 public boolean setBlockMetadata(int par1, int par2, int par3, int par4)
533 {
534 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
535 {
536 if (par2 < 0)
537 {
538 return false;
539 }
540 else if (par2 >= 256)
541 {
542 return false;
543 }
544 else
545 {
546 Chunk var5 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
547 int var6 = par1 & 15;
548 int var7 = par3 & 15;
549 boolean var8 = var5.setBlockMetadata(var6, par2, var7, par4);
550
551 if (var8 && (this.isRemote || var5.deferRender && Block.requiresSelfNotify[var5.getBlockID(var6, par2, var7) & 4095]))
552 {
553 this.markBlockNeedsUpdate(par1, par2, par3);
554 }
555
556 return var8;
557 }
558 }
559 else
560 {
561 return false;
562 }
563 }
564
565 /**
566 * Sets a block and notifies relevant systems with the block change Args: x, y, z, blockID
567 */
568 public boolean setBlockWithNotify(int par1, int par2, int par3, int par4)
569 {
570 if (this.setBlock(par1, par2, par3, par4))
571 {
572 this.notifyBlockChange(par1, par2, par3, par4);
573 return true;
574 }
575 else
576 {
577 return false;
578 }
579 }
580
581 /**
582 * Sets the block ID and metadata, then notifies neighboring blocks of the change Params: x, y, z, BlockID, Metadata
583 */
584 public boolean setBlockAndMetadataWithNotify(int par1, int par2, int par3, int par4, int par5)
585 {
586 if (this.setBlockAndMetadata(par1, par2, par3, par4, par5))
587 {
588 this.notifyBlockChange(par1, par2, par3, par4);
589 return true;
590 }
591 else
592 {
593 return false;
594 }
595 }
596
597 /**
598 * Marks the block as needing an update with the renderer. Args: x, y, z
599 */
600 public void markBlockNeedsUpdate(int par1, int par2, int par3)
601 {
602 Iterator var4 = this.worldAccesses.iterator();
603
604 while (var4.hasNext())
605 {
606 IWorldAccess var5 = (IWorldAccess)var4.next();
607 var5.markBlockNeedsUpdate(par1, par2, par3);
608 }
609 }
610
611 /**
612 * The block type change and need to notify other systems Args: x, y, z, blockID
613 */
614 public void notifyBlockChange(int par1, int par2, int par3, int par4)
615 {
616 this.notifyBlocksOfNeighborChange(par1, par2, par3, par4);
617 }
618
619 /**
620 * marks a vertical line of blocks as dirty
621 */
622 public void markBlocksDirtyVertical(int par1, int par2, int par3, int par4)
623 {
624 int var5;
625
626 if (par3 > par4)
627 {
628 var5 = par4;
629 par4 = par3;
630 par3 = var5;
631 }
632
633 if (!this.provider.hasNoSky)
634 {
635 for (var5 = par3; var5 <= par4; ++var5)
636 {
637 this.updateLightByType(EnumSkyBlock.Sky, par1, var5, par2);
638 }
639 }
640
641 this.markBlocksDirty(par1, par3, par2, par1, par4, par2);
642 }
643
644 /**
645 * calls the 'MarkBlockAsNeedsUpdate' in all block accesses in this world
646 */
647 public void markBlockAsNeedsUpdate(int par1, int par2, int par3)
648 {
649 Iterator var4 = this.worldAccesses.iterator();
650
651 while (var4.hasNext())
652 {
653 IWorldAccess var5 = (IWorldAccess)var4.next();
654 var5.markBlockRangeNeedsUpdate(par1, par2, par3, par1, par2, par3);
655 }
656 }
657
658 public void markBlocksDirty(int par1, int par2, int par3, int par4, int par5, int par6)
659 {
660 Iterator var7 = this.worldAccesses.iterator();
661
662 while (var7.hasNext())
663 {
664 IWorldAccess var8 = (IWorldAccess)var7.next();
665 var8.markBlockRangeNeedsUpdate(par1, par2, par3, par4, par5, par6);
666 }
667 }
668
669 /**
670 * Notifies neighboring blocks that this specified block changed Args: x, y, z, blockID
671 */
672 public void notifyBlocksOfNeighborChange(int par1, int par2, int par3, int par4)
673 {
674 this.notifyBlockOfNeighborChange(par1 - 1, par2, par3, par4);
675 this.notifyBlockOfNeighborChange(par1 + 1, par2, par3, par4);
676 this.notifyBlockOfNeighborChange(par1, par2 - 1, par3, par4);
677 this.notifyBlockOfNeighborChange(par1, par2 + 1, par3, par4);
678 this.notifyBlockOfNeighborChange(par1, par2, par3 - 1, par4);
679 this.notifyBlockOfNeighborChange(par1, par2, par3 + 1, par4);
680 }
681
682 /**
683 * Notifies a block that one of its neighbor change to the specified type Args: x, y, z, blockID
684 */
685 private void notifyBlockOfNeighborChange(int par1, int par2, int par3, int par4)
686 {
687 if (!this.editingBlocks && !this.isRemote)
688 {
689 Block var5 = Block.blocksList[this.getBlockId(par1, par2, par3)];
690
691 if (var5 != null)
692 {
693 var5.onNeighborBlockChange(this, par1, par2, par3, par4);
694 }
695 }
696 }
697
698 /**
699 * Checks if the specified block is able to see the sky
700 */
701 public boolean canBlockSeeTheSky(int par1, int par2, int par3)
702 {
703 return this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).canBlockSeeTheSky(par1 & 15, par2, par3 & 15);
704 }
705
706 /**
707 * Does the same as getBlockLightValue_do but without checking if its not a normal block
708 */
709 public int getFullBlockLightValue(int par1, int par2, int par3)
710 {
711 if (par2 < 0)
712 {
713 return 0;
714 }
715 else
716 {
717 if (par2 >= 256)
718 {
719 par2 = 255;
720 }
721
722 return this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4).getBlockLightValue(par1 & 15, par2, par3 & 15, 0);
723 }
724 }
725
726 /**
727 * Gets the light value of a block location
728 */
729 public int getBlockLightValue(int par1, int par2, int par3)
730 {
731 return this.getBlockLightValue_do(par1, par2, par3, true);
732 }
733
734 /**
735 * Gets the light value of a block location. This is the actual function that gets the value and has a bool flag
736 * that indicates if its a half step block to get the maximum light value of a direct neighboring block (left,
737 * right, forward, back, and up)
738 */
739 public int getBlockLightValue_do(int par1, int par2, int par3, boolean par4)
740 {
741 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
742 {
743 if (par4)
744 {
745 int var5 = this.getBlockId(par1, par2, par3);
746
747 if (var5 == Block.stoneSingleSlab.blockID || var5 == Block.woodSingleSlab.blockID || var5 == Block.tilledField.blockID || var5 == Block.stairCompactCobblestone.blockID || var5 == Block.stairCompactPlanks.blockID)
748 {
749 int var6 = this.getBlockLightValue_do(par1, par2 + 1, par3, false);
750 int var7 = this.getBlockLightValue_do(par1 + 1, par2, par3, false);
751 int var8 = this.getBlockLightValue_do(par1 - 1, par2, par3, false);
752 int var9 = this.getBlockLightValue_do(par1, par2, par3 + 1, false);
753 int var10 = this.getBlockLightValue_do(par1, par2, par3 - 1, false);
754
755 if (var7 > var6)
756 {
757 var6 = var7;
758 }
759
760 if (var8 > var6)
761 {
762 var6 = var8;
763 }
764
765 if (var9 > var6)
766 {
767 var6 = var9;
768 }
769
770 if (var10 > var6)
771 {
772 var6 = var10;
773 }
774
775 return var6;
776 }
777 }
778
779 if (par2 < 0)
780 {
781 return 0;
782 }
783 else
784 {
785 if (par2 >= 256)
786 {
787 par2 = 255;
788 }
789
790 Chunk var11 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
791 par1 &= 15;
792 par3 &= 15;
793 return var11.getBlockLightValue(par1, par2, par3, this.skylightSubtracted);
794 }
795 }
796 else
797 {
798 return 15;
799 }
800 }
801
802 /**
803 * Returns the y coordinate with a block in it at this x, z coordinate
804 */
805 public int getHeightValue(int par1, int par2)
806 {
807 if (par1 >= -30000000 && par2 >= -30000000 && par1 < 30000000 && par2 < 30000000)
808 {
809 if (!this.chunkExists(par1 >> 4, par2 >> 4))
810 {
811 return 0;
812 }
813 else
814 {
815 Chunk var3 = this.getChunkFromChunkCoords(par1 >> 4, par2 >> 4);
816 return var3.getHeightValue(par1 & 15, par2 & 15);
817 }
818 }
819 else
820 {
821 return 0;
822 }
823 }
824
825 @SideOnly(Side.CLIENT)
826
827 /**
828 * Brightness for SkyBlock.Sky is clear white and (through color computing it is assumed) DEPENDENT ON DAYTIME.
829 * Brightness for SkyBlock.Block is yellowish and independent.
830 */
831 public int getSkyBlockTypeBrightness(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
832 {
833 if (this.provider.hasNoSky && par1EnumSkyBlock == EnumSkyBlock.Sky)
834 {
835 return 0;
836 }
837 else
838 {
839 if (par3 < 0)
840 {
841 par3 = 0;
842 }
843
844 if (par3 >= 256)
845 {
846 return par1EnumSkyBlock.defaultLightValue;
847 }
848 else if (par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 < 30000000)
849 {
850 int var5 = par2 >> 4;
851 int var6 = par4 >> 4;
852
853 if (!this.chunkExists(var5, var6))
854 {
855 return par1EnumSkyBlock.defaultLightValue;
856 }
857 else if (Block.useNeighborBrightness[this.getBlockId(par2, par3, par4)])
858 {
859 int var12 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3 + 1, par4);
860 int var8 = this.getSavedLightValue(par1EnumSkyBlock, par2 + 1, par3, par4);
861 int var9 = this.getSavedLightValue(par1EnumSkyBlock, par2 - 1, par3, par4);
862 int var10 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4 + 1);
863 int var11 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4 - 1);
864
865 if (var8 > var12)
866 {
867 var12 = var8;
868 }
869
870 if (var9 > var12)
871 {
872 var12 = var9;
873 }
874
875 if (var10 > var12)
876 {
877 var12 = var10;
878 }
879
880 if (var11 > var12)
881 {
882 var12 = var11;
883 }
884
885 return var12;
886 }
887 else
888 {
889 Chunk var7 = this.getChunkFromChunkCoords(var5, var6);
890 return var7.getSavedLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15);
891 }
892 }
893 else
894 {
895 return par1EnumSkyBlock.defaultLightValue;
896 }
897 }
898 }
899
900 /**
901 * Returns saved light value without taking into account the time of day. Either looks in the sky light map or
902 * block light map based on the enumSkyBlock arg.
903 */
904 public int getSavedLightValue(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
905 {
906 if (par3 < 0)
907 {
908 par3 = 0;
909 }
910
911 if (par3 >= 256)
912 {
913 par3 = 255;
914 }
915
916 if (par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 < 30000000)
917 {
918 int var5 = par2 >> 4;
919 int var6 = par4 >> 4;
920
921 if (!this.chunkExists(var5, var6))
922 {
923 return par1EnumSkyBlock.defaultLightValue;
924 }
925 else
926 {
927 Chunk var7 = this.getChunkFromChunkCoords(var5, var6);
928 return var7.getSavedLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15);
929 }
930 }
931 else
932 {
933 return par1EnumSkyBlock.defaultLightValue;
934 }
935 }
936
937 /**
938 * Sets the light value either into the sky map or block map depending on if enumSkyBlock is set to sky or block.
939 * Args: enumSkyBlock, x, y, z, lightValue
940 */
941 public void setLightValue(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4, int par5)
942 {
943 if (par2 >= -30000000 && par4 >= -30000000 && par2 < 30000000 && par4 < 30000000)
944 {
945 if (par3 >= 0)
946 {
947 if (par3 < 256)
948 {
949 if (this.chunkExists(par2 >> 4, par4 >> 4))
950 {
951 Chunk var6 = this.getChunkFromChunkCoords(par2 >> 4, par4 >> 4);
952 var6.setLightValue(par1EnumSkyBlock, par2 & 15, par3, par4 & 15, par5);
953 Iterator var7 = this.worldAccesses.iterator();
954
955 while (var7.hasNext())
956 {
957 IWorldAccess var8 = (IWorldAccess)var7.next();
958 var8.markBlockNeedsUpdate2(par2, par3, par4);
959 }
960 }
961 }
962 }
963 }
964 }
965
966 /**
967 * all WorldAcceses mark this block as dirty
968 */
969 public void markBlockNeedsUpdateForAll(int par1, int par2, int par3)
970 {
971 Iterator var4 = this.worldAccesses.iterator();
972
973 while (var4.hasNext())
974 {
975 IWorldAccess var5 = (IWorldAccess)var4.next();
976 var5.markBlockNeedsUpdate2(par1, par2, par3);
977 }
978 }
979
980 @SideOnly(Side.CLIENT)
981
982 /**
983 * Any Light rendered on a 1.8 Block goes through here
984 */
985 public int getLightBrightnessForSkyBlocks(int par1, int par2, int par3, int par4)
986 {
987 int var5 = this.getSkyBlockTypeBrightness(EnumSkyBlock.Sky, par1, par2, par3);
988 int var6 = this.getSkyBlockTypeBrightness(EnumSkyBlock.Block, par1, par2, par3);
989
990 if (var6 < par4)
991 {
992 var6 = par4;
993 }
994
995 return var5 << 20 | var6 << 4;
996 }
997
998 @SideOnly(Side.CLIENT)
999 public float getBrightness(int par1, int par2, int par3, int par4)
1000 {
1001 int var5 = this.getBlockLightValue(par1, par2, par3);
1002
1003 if (var5 < par4)
1004 {
1005 var5 = par4;
1006 }
1007
1008 return this.provider.lightBrightnessTable[var5];
1009 }
1010
1011 /**
1012 * Returns how bright the block is shown as which is the block's light value looked up in a lookup table (light
1013 * values aren't linear for brightness). Args: x, y, z
1014 */
1015 public float getLightBrightness(int par1, int par2, int par3)
1016 {
1017 return this.provider.lightBrightnessTable[this.getBlockLightValue(par1, par2, par3)];
1018 }
1019
1020 /**
1021 * Checks whether its daytime by seeing if the light subtracted from the skylight is less than 4
1022 */
1023 public boolean isDaytime()
1024 {
1025 return provider.isDaytime();
1026 }
1027
1028 /**
1029 * ray traces all blocks, including non-collideable ones
1030 */
1031 public MovingObjectPosition rayTraceBlocks(Vec3 par1Vec3, Vec3 par2Vec3)
1032 {
1033 return this.rayTraceBlocks_do_do(par1Vec3, par2Vec3, false, false);
1034 }
1035
1036 public MovingObjectPosition rayTraceBlocks_do(Vec3 par1Vec3, Vec3 par2Vec3, boolean par3)
1037 {
1038 return this.rayTraceBlocks_do_do(par1Vec3, par2Vec3, par3, false);
1039 }
1040
1041 public MovingObjectPosition rayTraceBlocks_do_do(Vec3 par1Vec3, Vec3 par2Vec3, boolean par3, boolean par4)
1042 {
1043 if (!Double.isNaN(par1Vec3.xCoord) && !Double.isNaN(par1Vec3.yCoord) && !Double.isNaN(par1Vec3.zCoord))
1044 {
1045 if (!Double.isNaN(par2Vec3.xCoord) && !Double.isNaN(par2Vec3.yCoord) && !Double.isNaN(par2Vec3.zCoord))
1046 {
1047 int var5 = MathHelper.floor_double(par2Vec3.xCoord);
1048 int var6 = MathHelper.floor_double(par2Vec3.yCoord);
1049 int var7 = MathHelper.floor_double(par2Vec3.zCoord);
1050 int var8 = MathHelper.floor_double(par1Vec3.xCoord);
1051 int var9 = MathHelper.floor_double(par1Vec3.yCoord);
1052 int var10 = MathHelper.floor_double(par1Vec3.zCoord);
1053 int var11 = this.getBlockId(var8, var9, var10);
1054 int var12 = this.getBlockMetadata(var8, var9, var10);
1055 Block var13 = Block.blocksList[var11];
1056
1057 if (var13 != null && (!par4 || var13 == null || var13.getCollisionBoundingBoxFromPool(this, var8, var9, var10) != null) && var11 > 0 && var13.canCollideCheck(var12, par3))
1058 {
1059 MovingObjectPosition var14 = var13.collisionRayTrace(this, var8, var9, var10, par1Vec3, par2Vec3);
1060
1061 if (var14 != null)
1062 {
1063 return var14;
1064 }
1065 }
1066
1067 var11 = 200;
1068
1069 while (var11-- >= 0)
1070 {
1071 if (Double.isNaN(par1Vec3.xCoord) || Double.isNaN(par1Vec3.yCoord) || Double.isNaN(par1Vec3.zCoord))
1072 {
1073 return null;
1074 }
1075
1076 if (var8 == var5 && var9 == var6 && var10 == var7)
1077 {
1078 return null;
1079 }
1080
1081 boolean var39 = true;
1082 boolean var40 = true;
1083 boolean var41 = true;
1084 double var15 = 999.0D;
1085 double var17 = 999.0D;
1086 double var19 = 999.0D;
1087
1088 if (var5 > var8)
1089 {
1090 var15 = (double)var8 + 1.0D;
1091 }
1092 else if (var5 < var8)
1093 {
1094 var15 = (double)var8 + 0.0D;
1095 }
1096 else
1097 {
1098 var39 = false;
1099 }
1100
1101 if (var6 > var9)
1102 {
1103 var17 = (double)var9 + 1.0D;
1104 }
1105 else if (var6 < var9)
1106 {
1107 var17 = (double)var9 + 0.0D;
1108 }
1109 else
1110 {
1111 var40 = false;
1112 }
1113
1114 if (var7 > var10)
1115 {
1116 var19 = (double)var10 + 1.0D;
1117 }
1118 else if (var7 < var10)
1119 {
1120 var19 = (double)var10 + 0.0D;
1121 }
1122 else
1123 {
1124 var41 = false;
1125 }
1126
1127 double var21 = 999.0D;
1128 double var23 = 999.0D;
1129 double var25 = 999.0D;
1130 double var27 = par2Vec3.xCoord - par1Vec3.xCoord;
1131 double var29 = par2Vec3.yCoord - par1Vec3.yCoord;
1132 double var31 = par2Vec3.zCoord - par1Vec3.zCoord;
1133
1134 if (var39)
1135 {
1136 var21 = (var15 - par1Vec3.xCoord) / var27;
1137 }
1138
1139 if (var40)
1140 {
1141 var23 = (var17 - par1Vec3.yCoord) / var29;
1142 }
1143
1144 if (var41)
1145 {
1146 var25 = (var19 - par1Vec3.zCoord) / var31;
1147 }
1148
1149 boolean var33 = false;
1150 byte var42;
1151
1152 if (var21 < var23 && var21 < var25)
1153 {
1154 if (var5 > var8)
1155 {
1156 var42 = 4;
1157 }
1158 else
1159 {
1160 var42 = 5;
1161 }
1162
1163 par1Vec3.xCoord = var15;
1164 par1Vec3.yCoord += var29 * var21;
1165 par1Vec3.zCoord += var31 * var21;
1166 }
1167 else if (var23 < var25)
1168 {
1169 if (var6 > var9)
1170 {
1171 var42 = 0;
1172 }
1173 else
1174 {
1175 var42 = 1;
1176 }
1177
1178 par1Vec3.xCoord += var27 * var23;
1179 par1Vec3.yCoord = var17;
1180 par1Vec3.zCoord += var31 * var23;
1181 }
1182 else
1183 {
1184 if (var7 > var10)
1185 {
1186 var42 = 2;
1187 }
1188 else
1189 {
1190 var42 = 3;
1191 }
1192
1193 par1Vec3.xCoord += var27 * var25;
1194 par1Vec3.yCoord += var29 * var25;
1195 par1Vec3.zCoord = var19;
1196 }
1197
1198 Vec3 var34 = Vec3.getVec3Pool().getVecFromPool(par1Vec3.xCoord, par1Vec3.yCoord, par1Vec3.zCoord);
1199 var8 = (int)(var34.xCoord = (double)MathHelper.floor_double(par1Vec3.xCoord));
1200
1201 if (var42 == 5)
1202 {
1203 --var8;
1204 ++var34.xCoord;
1205 }
1206
1207 var9 = (int)(var34.yCoord = (double)MathHelper.floor_double(par1Vec3.yCoord));
1208
1209 if (var42 == 1)
1210 {
1211 --var9;
1212 ++var34.yCoord;
1213 }
1214
1215 var10 = (int)(var34.zCoord = (double)MathHelper.floor_double(par1Vec3.zCoord));
1216
1217 if (var42 == 3)
1218 {
1219 --var10;
1220 ++var34.zCoord;
1221 }
1222
1223 int var35 = this.getBlockId(var8, var9, var10);
1224 int var36 = this.getBlockMetadata(var8, var9, var10);
1225 Block var37 = Block.blocksList[var35];
1226
1227 if ((!par4 || var37 == null || var37.getCollisionBoundingBoxFromPool(this, var8, var9, var10) != null) && var35 > 0 && var37.canCollideCheck(var36, par3))
1228 {
1229 MovingObjectPosition var38 = var37.collisionRayTrace(this, var8, var9, var10, par1Vec3, par2Vec3);
1230
1231 if (var38 != null)
1232 {
1233 return var38;
1234 }
1235 }
1236 }
1237
1238 return null;
1239 }
1240 else
1241 {
1242 return null;
1243 }
1244 }
1245 else
1246 {
1247 return null;
1248 }
1249 }
1250
1251 /**
1252 * Plays a sound at the entity's position. Args: entity, sound, volume (relative to 1.0), and frequency (or pitch,
1253 * also relative to 1.0).
1254 */
1255 public void playSoundAtEntity(Entity par1Entity, String par2Str, float par3, float par4)
1256 {
1257 PlaySoundAtEntityEvent event = new PlaySoundAtEntityEvent(par1Entity, par2Str, par3, par4);
1258 if (MinecraftForge.EVENT_BUS.post(event))
1259 {
1260 return;
1261 }
1262 par2Str = event.name;
1263 if (par1Entity != null && par2Str != null)
1264 {
1265 Iterator var5 = this.worldAccesses.iterator();
1266
1267 while (var5.hasNext())
1268 {
1269 IWorldAccess var6 = (IWorldAccess)var5.next();
1270 var6.playSound(par2Str, par1Entity.posX, par1Entity.posY - (double)par1Entity.yOffset, par1Entity.posZ, par3, par4);
1271 }
1272 }
1273 }
1274
1275 /**
1276 * Play a sound effect. Many many parameters for this function. Not sure what they do, but a classic call is :
1277 * (double)i + 0.5D, (double)j + 0.5D, (double)k + 0.5D, 'random.door_open', 1.0F, world.rand.nextFloat() * 0.1F +
1278 * 0.9F with i,j,k position of the block.
1279 */
1280 public void playSoundEffect(double par1, double par3, double par5, String par7Str, float par8, float par9)
1281 {
1282 if (par7Str != null)
1283 {
1284 Iterator var10 = this.worldAccesses.iterator();
1285
1286 while (var10.hasNext())
1287 {
1288 IWorldAccess var11 = (IWorldAccess)var10.next();
1289 var11.playSound(par7Str, par1, par3, par5, par8, par9);
1290 }
1291 }
1292 }
1293
1294 /**
1295 * Plays a record at the specified coordinates of the specified name. Args: recordName, x, y, z
1296 */
1297 public void playRecord(String par1Str, int par2, int par3, int par4)
1298 {
1299 Iterator var5 = this.worldAccesses.iterator();
1300
1301 while (var5.hasNext())
1302 {
1303 IWorldAccess var6 = (IWorldAccess)var5.next();
1304 var6.playRecord(par1Str, par2, par3, par4);
1305 }
1306 }
1307
1308 /**
1309 * Spawns a particle. Args particleName, x, y, z, velX, velY, velZ
1310 */
1311 public void spawnParticle(String par1Str, double par2, double par4, double par6, double par8, double par10, double par12)
1312 {
1313 Iterator var14 = this.worldAccesses.iterator();
1314
1315 while (var14.hasNext())
1316 {
1317 IWorldAccess var15 = (IWorldAccess)var14.next();
1318 var15.spawnParticle(par1Str, par2, par4, par6, par8, par10, par12);
1319 }
1320 }
1321
1322 @SideOnly(Side.CLIENT)
1323
1324 /**
1325 * par8 is loudness, all pars passed to minecraftInstance.sndManager.playSound
1326 */
1327 public void playSound(double par1, double par3, double par5, String par7Str, float par8, float par9) {}
1328
1329 /**
1330 * adds a lightning bolt to the list of lightning bolts in this world.
1331 */
1332 public boolean addWeatherEffect(Entity par1Entity)
1333 {
1334 this.weatherEffects.add(par1Entity);
1335 return true;
1336 }
1337
1338 /**
1339 * Called to place all entities as part of a world
1340 */
1341 public boolean spawnEntityInWorld(Entity par1Entity)
1342 {
1343 int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D);
1344 int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
1345 boolean var4 = false;
1346
1347 if (par1Entity instanceof EntityPlayer)
1348 {
1349 var4 = true;
1350 }
1351
1352 if (!var4 && !this.chunkExists(var2, var3))
1353 {
1354 return false;
1355 }
1356 else
1357 {
1358 if (par1Entity instanceof EntityPlayer)
1359 {
1360 EntityPlayer var5 = (EntityPlayer)par1Entity;
1361 this.playerEntities.add(var5);
1362 this.updateAllPlayersSleepingFlag();
1363 }
1364
1365 if (!var4 && MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(par1Entity, this)))
1366 {
1367 return false;
1368 }
1369
1370 this.getChunkFromChunkCoords(var2, var3).addEntity(par1Entity);
1371 this.loadedEntityList.add(par1Entity);
1372 this.obtainEntitySkin(par1Entity);
1373 return true;
1374 }
1375 }
1376
1377 /**
1378 * Start the skin for this entity downloading, if necessary, and increment its reference counter
1379 */
1380 protected void obtainEntitySkin(Entity par1Entity)
1381 {
1382 Iterator var2 = this.worldAccesses.iterator();
1383
1384 while (var2.hasNext())
1385 {
1386 IWorldAccess var3 = (IWorldAccess)var2.next();
1387 var3.obtainEntitySkin(par1Entity);
1388 }
1389 }
1390
1391 /**
1392 * Decrement the reference counter for this entity's skin image data
1393 */
1394 protected void releaseEntitySkin(Entity par1Entity)
1395 {
1396 Iterator var2 = this.worldAccesses.iterator();
1397
1398 while (var2.hasNext())
1399 {
1400 IWorldAccess var3 = (IWorldAccess)var2.next();
1401 var3.releaseEntitySkin(par1Entity);
1402 }
1403 }
1404
1405 /**
1406 * Dismounts the entity (and anything riding the entity), sets the dead flag, and removes the player entity from the
1407 * player entity list. Called by the playerLoggedOut function.
1408 */
1409 public void setEntityDead(Entity par1Entity)
1410 {
1411 if (par1Entity.riddenByEntity != null)
1412 {
1413 par1Entity.riddenByEntity.mountEntity((Entity)null);
1414 }
1415
1416 if (par1Entity.ridingEntity != null)
1417 {
1418 par1Entity.mountEntity((Entity)null);
1419 }
1420
1421 par1Entity.setDead();
1422
1423 if (par1Entity instanceof EntityPlayer)
1424 {
1425 this.playerEntities.remove(par1Entity);
1426 this.updateAllPlayersSleepingFlag();
1427 }
1428 }
1429
1430 /**
1431 * remove dat player from dem servers
1432 */
1433 public void removeEntity(Entity par1Entity)
1434 {
1435 par1Entity.setDead();
1436
1437 if (par1Entity instanceof EntityPlayer)
1438 {
1439 this.playerEntities.remove(par1Entity);
1440 this.updateAllPlayersSleepingFlag();
1441 }
1442
1443 int var2 = par1Entity.chunkCoordX;
1444 int var3 = par1Entity.chunkCoordZ;
1445
1446 if (par1Entity.addedToChunk && this.chunkExists(var2, var3))
1447 {
1448 this.getChunkFromChunkCoords(var2, var3).removeEntity(par1Entity);
1449 }
1450
1451 this.loadedEntityList.remove(par1Entity);
1452 this.releaseEntitySkin(par1Entity);
1453 }
1454
1455 /**
1456 * Adds a IWorldAccess to the list of worldAccesses
1457 */
1458 public void addWorldAccess(IWorldAccess par1IWorldAccess)
1459 {
1460 this.worldAccesses.add(par1IWorldAccess);
1461 }
1462
1463 /**
1464 * Returns a list of bounding boxes that collide with aabb excluding the passed in entity's collision. Args: entity,
1465 * aabb
1466 */
1467 public List getCollidingBoundingBoxes(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB)
1468 {
1469 this.collidingBoundingBoxes.clear();
1470 int var3 = MathHelper.floor_double(par2AxisAlignedBB.minX);
1471 int var4 = MathHelper.floor_double(par2AxisAlignedBB.maxX + 1.0D);
1472 int var5 = MathHelper.floor_double(par2AxisAlignedBB.minY);
1473 int var6 = MathHelper.floor_double(par2AxisAlignedBB.maxY + 1.0D);
1474 int var7 = MathHelper.floor_double(par2AxisAlignedBB.minZ);
1475 int var8 = MathHelper.floor_double(par2AxisAlignedBB.maxZ + 1.0D);
1476
1477 for (int var9 = var3; var9 < var4; ++var9)
1478 {
1479 for (int var10 = var7; var10 < var8; ++var10)
1480 {
1481 if (this.blockExists(var9, 64, var10))
1482 {
1483 for (int var11 = var5 - 1; var11 < var6; ++var11)
1484 {
1485 Block var12 = Block.blocksList[this.getBlockId(var9, var11, var10)];
1486
1487 if (var12 != null)
1488 {
1489 var12.addCollidingBlockToList(this, var9, var11, var10, par2AxisAlignedBB, this.collidingBoundingBoxes, par1Entity);
1490 }
1491 }
1492 }
1493 }
1494 }
1495
1496 double var15 = 0.25D;
1497 List var17 = this.getEntitiesWithinAABBExcludingEntity(par1Entity, par2AxisAlignedBB.expand(var15, var15, var15));
1498 Iterator var16 = var17.iterator();
1499
1500 while (var16.hasNext())
1501 {
1502 Entity var13 = (Entity)var16.next();
1503 AxisAlignedBB var14 = var13.getBoundingBox();
1504
1505 if (var14 != null && var14.intersectsWith(par2AxisAlignedBB))
1506 {
1507 this.collidingBoundingBoxes.add(var14);
1508 }
1509
1510 var14 = par1Entity.getCollisionBox(var13);
1511
1512 if (var14 != null && var14.intersectsWith(par2AxisAlignedBB))
1513 {
1514 this.collidingBoundingBoxes.add(var14);
1515 }
1516 }
1517
1518 return this.collidingBoundingBoxes;
1519 }
1520
1521 /**
1522 * calculates and returns a list of colliding bounding boxes within a given AABB
1523 */
1524 public List getAllCollidingBoundingBoxes(AxisAlignedBB par1AxisAlignedBB)
1525 {
1526 this.collidingBoundingBoxes.clear();
1527 int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
1528 int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
1529 int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
1530 int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
1531 int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
1532 int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
1533
1534 for (int var8 = var2; var8 < var3; ++var8)
1535 {
1536 for (int var9 = var6; var9 < var7; ++var9)
1537 {
1538 if (this.blockExists(var8, 64, var9))
1539 {
1540 for (int var10 = var4 - 1; var10 < var5; ++var10)
1541 {
1542 Block var11 = Block.blocksList[this.getBlockId(var8, var10, var9)];
1543
1544 if (var11 != null)
1545 {
1546 var11.addCollidingBlockToList(this, var8, var10, var9, par1AxisAlignedBB, this.collidingBoundingBoxes, (Entity)null);
1547 }
1548 }
1549 }
1550 }
1551 }
1552
1553 return this.collidingBoundingBoxes;
1554 }
1555
1556 /**
1557 * Returns the amount of skylight subtracted for the current time
1558 */
1559 public int calculateSkylightSubtracted(float par1)
1560 {
1561 float var2 = this.getCelestialAngle(par1);
1562 float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.5F);
1563
1564 if (var3 < 0.0F)
1565 {
1566 var3 = 0.0F;
1567 }
1568
1569 if (var3 > 1.0F)
1570 {
1571 var3 = 1.0F;
1572 }
1573
1574 var3 = 1.0F - var3;
1575 var3 = (float)((double)var3 * (1.0D - (double)(this.getRainStrength(par1) * 5.0F) / 16.0D));
1576 var3 = (float)((double)var3 * (1.0D - (double)(this.getWeightedThunderStrength(par1) * 5.0F) / 16.0D));
1577 var3 = 1.0F - var3;
1578 return (int)(var3 * 11.0F);
1579 }
1580
1581 @SideOnly(Side.CLIENT)
1582
1583 /**
1584 * Removes a worldAccess from the worldAccesses object
1585 */
1586 public void removeWorldAccess(IWorldAccess par1IWorldAccess)
1587 {
1588 this.worldAccesses.remove(par1IWorldAccess);
1589 }
1590
1591 @SideOnly(Side.CLIENT)
1592 public float func_72971_b(float par1)
1593 {
1594 float var2 = this.getCelestialAngle(par1);
1595 float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.2F);
1596
1597 if (var3 < 0.0F)
1598 {
1599 var3 = 0.0F;
1600 }
1601
1602 if (var3 > 1.0F)
1603 {
1604 var3 = 1.0F;
1605 }
1606
1607 var3 = 1.0F - var3;
1608 var3 = (float)((double)var3 * (1.0D - (double)(this.getRainStrength(par1) * 5.0F) / 16.0D));
1609 var3 = (float)((double)var3 * (1.0D - (double)(this.getWeightedThunderStrength(par1) * 5.0F) / 16.0D));
1610 return var3 * 0.8F + 0.2F;
1611 }
1612
1613 @SideOnly(Side.CLIENT)
1614
1615 /**
1616 * Calculates the color for the skybox
1617 */
1618 public Vec3 getSkyColor(Entity par1Entity, float par2)
1619 {
1620 return provider.getSkyColor(par1Entity, par2);
1621 }
1622
1623 @SideOnly(Side.CLIENT)
1624 public Vec3 getSkyColorBody(Entity par1Entity, float par2)
1625 {
1626 float var3 = this.getCelestialAngle(par2);
1627 float var4 = MathHelper.cos(var3 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
1628
1629 if (var4 < 0.0F)
1630 {
1631 var4 = 0.0F;
1632 }
1633
1634 if (var4 > 1.0F)
1635 {
1636 var4 = 1.0F;
1637 }
1638
1639 int var5 = MathHelper.floor_double(par1Entity.posX);
1640 int var6 = MathHelper.floor_double(par1Entity.posZ);
1641 BiomeGenBase var7 = this.getBiomeGenForCoords(var5, var6);
1642 float var8 = var7.getFloatTemperature();
1643 int var9 = var7.getSkyColorByTemp(var8);
1644 float var10 = (float)(var9 >> 16 & 255) / 255.0F;
1645 float var11 = (float)(var9 >> 8 & 255) / 255.0F;
1646 float var12 = (float)(var9 & 255) / 255.0F;
1647 var10 *= var4;
1648 var11 *= var4;
1649 var12 *= var4;
1650 float var13 = this.getRainStrength(par2);
1651 float var14;
1652 float var15;
1653
1654 if (var13 > 0.0F)
1655 {
1656 var14 = (var10 * 0.3F + var11 * 0.59F + var12 * 0.11F) * 0.6F;
1657 var15 = 1.0F - var13 * 0.75F;
1658 var10 = var10 * var15 + var14 * (1.0F - var15);
1659 var11 = var11 * var15 + var14 * (1.0F - var15);
1660 var12 = var12 * var15 + var14 * (1.0F - var15);
1661 }
1662
1663 var14 = this.getWeightedThunderStrength(par2);
1664
1665 if (var14 > 0.0F)
1666 {
1667 var15 = (var10 * 0.3F + var11 * 0.59F + var12 * 0.11F) * 0.2F;
1668 float var16 = 1.0F - var14 * 0.75F;
1669 var10 = var10 * var16 + var15 * (1.0F - var16);
1670 var11 = var11 * var16 + var15 * (1.0F - var16);
1671 var12 = var12 * var16 + var15 * (1.0F - var16);
1672 }
1673
1674 if (this.lightningFlash > 0)
1675 {
1676 var15 = (float)this.lightningFlash - par2;
1677
1678 if (var15 > 1.0F)
1679 {
1680 var15 = 1.0F;
1681 }
1682
1683 var15 *= 0.45F;
1684 var10 = var10 * (1.0F - var15) + 0.8F * var15;
1685 var11 = var11 * (1.0F - var15) + 0.8F * var15;
1686 var12 = var12 * (1.0F - var15) + 1.0F * var15;
1687 }
1688
1689 return Vec3.getVec3Pool().getVecFromPool((double)var10, (double)var11, (double)var12);
1690 }
1691
1692 /**
1693 * calls calculateCelestialAngle
1694 */
1695 public float getCelestialAngle(float par1)
1696 {
1697 return this.provider.calculateCelestialAngle(this.worldInfo.getWorldTime(), par1);
1698 }
1699
1700 @SideOnly(Side.CLIENT)
1701 public int getMoonPhase(float par1)
1702 {
1703 return this.provider.getMoonPhase(this.worldInfo.getWorldTime(), par1);
1704 }
1705
1706 @SideOnly(Side.CLIENT)
1707
1708 /**
1709 * Return getCelestialAngle()*2*PI
1710 */
1711 public float getCelestialAngleRadians(float par1)
1712 {
1713 float var2 = this.getCelestialAngle(par1);
1714 return var2 * (float)Math.PI * 2.0F;
1715 }
1716
1717 @SideOnly(Side.CLIENT)
1718 public Vec3 drawClouds(float par1)
1719 {
1720 return provider.drawClouds(par1);
1721 }
1722
1723 @SideOnly(Side.CLIENT)
1724 public Vec3 drawCloudsBody(float par1)
1725 {
1726 float var2 = this.getCelestialAngle(par1);
1727 float var3 = MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.5F;
1728
1729 if (var3 < 0.0F)
1730 {
1731 var3 = 0.0F;
1732 }
1733
1734 if (var3 > 1.0F)
1735 {
1736 var3 = 1.0F;
1737 }
1738
1739 float var4 = (float)(this.cloudColour >> 16 & 255L) / 255.0F;
1740 float var5 = (float)(this.cloudColour >> 8 & 255L) / 255.0F;
1741 float var6 = (float)(this.cloudColour & 255L) / 255.0F;
1742 float var7 = this.getRainStrength(par1);
1743 float var8;
1744 float var9;
1745
1746 if (var7 > 0.0F)
1747 {
1748 var8 = (var4 * 0.3F + var5 * 0.59F + var6 * 0.11F) * 0.6F;
1749 var9 = 1.0F - var7 * 0.95F;
1750 var4 = var4 * var9 + var8 * (1.0F - var9);
1751 var5 = var5 * var9 + var8 * (1.0F - var9);
1752 var6 = var6 * var9 + var8 * (1.0F - var9);
1753 }
1754
1755 var4 *= var3 * 0.9F + 0.1F;
1756 var5 *= var3 * 0.9F + 0.1F;
1757 var6 *= var3 * 0.85F + 0.15F;
1758 var8 = this.getWeightedThunderStrength(par1);
1759
1760 if (var8 > 0.0F)
1761 {
1762 var9 = (var4 * 0.3F + var5 * 0.59F + var6 * 0.11F) * 0.2F;
1763 float var10 = 1.0F - var8 * 0.95F;
1764 var4 = var4 * var10 + var9 * (1.0F - var10);
1765 var5 = var5 * var10 + var9 * (1.0F - var10);
1766 var6 = var6 * var10 + var9 * (1.0F - var10);
1767 }
1768
1769 return Vec3.getVec3Pool().getVecFromPool((double)var4, (double)var5, (double)var6);
1770 }
1771
1772 @SideOnly(Side.CLIENT)
1773
1774 /**
1775 * Returns vector(ish) with R/G/B for fog
1776 */
1777 public Vec3 getFogColor(float par1)
1778 {
1779 float var2 = this.getCelestialAngle(par1);
1780 return this.provider.getFogColor(var2, par1);
1781 }
1782
1783 /**
1784 * Gets the height to which rain/snow will fall. Calculates it if not already stored.
1785 */
1786 public int getPrecipitationHeight(int par1, int par2)
1787 {
1788 return this.getChunkFromBlockCoords(par1, par2).getPrecipitationHeight(par1 & 15, par2 & 15);
1789 }
1790
1791 /**
1792 * Finds the highest block on the x, z coordinate that is solid and returns its y coord. Args x, z
1793 */
1794 public int getTopSolidOrLiquidBlock(int par1, int par2)
1795 {
1796 Chunk var3 = this.getChunkFromBlockCoords(par1, par2);
1797 int var4 = var3.getTopFilledSegment() + 15;
1798 par1 &= 15;
1799
1800 for (par2 &= 15; var4 > 0; --var4)
1801 {
1802 int var5 = var3.getBlockID(par1, var4, par2);
1803
1804 if (var5 != 0 && Block.blocksList[var5].blockMaterial.blocksMovement() && Block.blocksList[var5].blockMaterial != Material.leaves && !Block.blocksList[var5].isBlockFoliage(this, par1, var4, par2))
1805 {
1806 return var4 + 1;
1807 }
1808 }
1809
1810 return -1;
1811 }
1812
1813 @SideOnly(Side.CLIENT)
1814
1815 /**
1816 * How bright are stars in the sky
1817 */
1818 public float getStarBrightness(float par1)
1819 {
1820 return provider.getStarBrightness(par1);
1821 }
1822
1823 @SideOnly(Side.CLIENT)
1824 public float getStarBrightnessBody(float par1)
1825 {
1826 float var2 = this.getCelestialAngle(par1);
1827 float var3 = 1.0F - (MathHelper.cos(var2 * (float)Math.PI * 2.0F) * 2.0F + 0.25F);
1828
1829 if (var3 < 0.0F)
1830 {
1831 var3 = 0.0F;
1832 }
1833
1834 if (var3 > 1.0F)
1835 {
1836 var3 = 1.0F;
1837 }
1838
1839 return var3 * var3 * 0.5F;
1840 }
1841
1842 /**
1843 * Schedules a tick to a block with a delay (Most commonly the tick rate)
1844 */
1845 public void scheduleBlockUpdate(int par1, int par2, int par3, int par4, int par5) {}
1846
1847 /**
1848 * Schedules a block update from the saved information in a chunk. Called when the chunk is loaded.
1849 */
1850 public void scheduleBlockUpdateFromLoad(int par1, int par2, int par3, int par4, int par5) {}
1851
1852 /**
1853 * Updates (and cleans up) entities and tile entities
1854 */
1855 public void updateEntities()
1856 {
1857 this.theProfiler.startSection("entities");
1858 this.theProfiler.startSection("global");
1859 int var1;
1860 Entity var2;
1861
1862 for (var1 = 0; var1 < this.weatherEffects.size(); ++var1)
1863 {
1864 var2 = (Entity)this.weatherEffects.get(var1);
1865 var2.onUpdate();
1866
1867 if (var2.isDead)
1868 {
1869 this.weatherEffects.remove(var1--);
1870 }
1871 }
1872
1873 this.theProfiler.endStartSection("remove");
1874 this.loadedEntityList.removeAll(this.unloadedEntityList);
1875 Iterator var5 = this.unloadedEntityList.iterator();
1876 int var3;
1877 int var4;
1878
1879 while (var5.hasNext())
1880 {
1881 var2 = (Entity)var5.next();
1882 var3 = var2.chunkCoordX;
1883 var4 = var2.chunkCoordZ;
1884
1885 if (var2.addedToChunk && this.chunkExists(var3, var4))
1886 {
1887 this.getChunkFromChunkCoords(var3, var4).removeEntity(var2);
1888 }
1889 }
1890
1891 var5 = this.unloadedEntityList.iterator();
1892
1893 while (var5.hasNext())
1894 {
1895 var2 = (Entity)var5.next();
1896 this.releaseEntitySkin(var2);
1897 }
1898
1899 this.unloadedEntityList.clear();
1900 this.theProfiler.endStartSection("regular");
1901
1902 for (var1 = 0; var1 < this.loadedEntityList.size(); ++var1)
1903 {
1904 var2 = (Entity)this.loadedEntityList.get(var1);
1905
1906 if (var2.ridingEntity != null)
1907 {
1908 if (!var2.ridingEntity.isDead && var2.ridingEntity.riddenByEntity == var2)
1909 {
1910 continue;
1911 }
1912
1913 var2.ridingEntity.riddenByEntity = null;
1914 var2.ridingEntity = null;
1915 }
1916
1917 this.theProfiler.startSection("tick");
1918
1919 if (!var2.isDead)
1920 {
1921 this.updateEntity(var2);
1922 }
1923
1924 this.theProfiler.endSection();
1925 this.theProfiler.startSection("remove");
1926
1927 if (var2.isDead)
1928 {
1929 var3 = var2.chunkCoordX;
1930 var4 = var2.chunkCoordZ;
1931
1932 if (var2.addedToChunk && this.chunkExists(var3, var4))
1933 {
1934 this.getChunkFromChunkCoords(var3, var4).removeEntity(var2);
1935 }
1936
1937 this.loadedEntityList.remove(var1--);
1938 this.releaseEntitySkin(var2);
1939 }
1940
1941 this.theProfiler.endSection();
1942 }
1943
1944 this.theProfiler.endStartSection("tileEntities");
1945 this.scanningTileEntities = true;
1946 var5 = this.loadedTileEntityList.iterator();
1947
1948 while (var5.hasNext())
1949 {
1950 TileEntity var6 = (TileEntity)var5.next();
1951
1952 if (!var6.isInvalid() && var6.func_70309_m() && this.blockExists(var6.xCoord, var6.yCoord, var6.zCoord))
1953 {
1954 var6.updateEntity();
1955 }
1956
1957 if (var6.isInvalid())
1958 {
1959 var5.remove();
1960
1961 if (this.chunkExists(var6.xCoord >> 4, var6.zCoord >> 4))
1962 {
1963 Chunk var8 = this.getChunkFromChunkCoords(var6.xCoord >> 4, var6.zCoord >> 4);
1964
1965 if (var8 != null)
1966 {
1967 var8.cleanChunkBlockTileEntity(var6.xCoord & 15, var6.yCoord, var6.zCoord & 15);
1968 }
1969 }
1970 }
1971 }
1972
1973 this.scanningTileEntities = false;
1974
1975 if (!this.entityRemoval.isEmpty())
1976 {
1977 for (Object tile : entityRemoval)
1978 {
1979 ((TileEntity)tile).onChunkUnload();
1980 }
1981 this.loadedTileEntityList.removeAll(this.entityRemoval);
1982 this.entityRemoval.clear();
1983 }
1984
1985 this.theProfiler.endStartSection("pendingTileEntities");
1986
1987 if (!this.addedTileEntityList.isEmpty())
1988 {
1989 Iterator var7 = this.addedTileEntityList.iterator();
1990
1991 while (var7.hasNext())
1992 {
1993 TileEntity var9 = (TileEntity)var7.next();
1994
1995 if (!var9.isInvalid())
1996 {
1997 if (!this.loadedTileEntityList.contains(var9))
1998 {
1999 this.loadedTileEntityList.add(var9);
2000 }
2001 }
2002 else
2003 {
2004 if (this.chunkExists(var9.xCoord >> 4, var9.zCoord >> 4))
2005 {
2006 Chunk var10 = this.getChunkFromChunkCoords(var9.xCoord >> 4, var9.zCoord >> 4);
2007
2008 if (var10 != null)
2009 {
2010 var10.setChunkBlockTileEntity(var9.xCoord & 15, var9.yCoord, var9.zCoord & 15, var9);
2011 }
2012 }
2013 }
2014 }
2015
2016 this.addedTileEntityList.clear();
2017 }
2018
2019 this.theProfiler.endSection();
2020 this.theProfiler.endSection();
2021 }
2022
2023 public void addTileEntity(Collection par1Collection)
2024 {
2025 List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
2026 for(Object entity : par1Collection)
2027 {
2028 if(((TileEntity)entity).canUpdate())
2029 {
2030 dest.add(entity);
2031 }
2032 }
2033 }
2034
2035 /**
2036 * Will update the entity in the world if the chunk the entity is in is currently loaded. Args: entity
2037 */
2038 public void updateEntity(Entity par1Entity)
2039 {
2040 this.updateEntityWithOptionalForce(par1Entity, true);
2041 }
2042
2043 /**
2044 * Will update the entity in the world if the chunk the entity is in is currently loaded or its forced to update.
2045 * Args: entity, forceUpdate
2046 */
2047 public void updateEntityWithOptionalForce(Entity par1Entity, boolean par2)
2048 {
2049 int var3 = MathHelper.floor_double(par1Entity.posX);
2050 int var4 = MathHelper.floor_double(par1Entity.posZ);
2051
2052 boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(var3 >> 4, var4 >> 4));
2053 byte var5 = isForced ? (byte)0 : 32;
2054 boolean canUpdate = !par2 || this.checkChunksExist(var3 - var5, 0, var4 - var5, var3 + var5, 0, var4 + var5);
2055 if (!canUpdate)
2056 {
2057 EntityEvent.CanUpdate event = new EntityEvent.CanUpdate(par1Entity);
2058 MinecraftForge.EVENT_BUS.post(event);
2059 canUpdate = event.canUpdate;
2060 }
2061 if (canUpdate)
2062 {
2063 par1Entity.lastTickPosX = par1Entity.posX;
2064 par1Entity.lastTickPosY = par1Entity.posY;
2065 par1Entity.lastTickPosZ = par1Entity.posZ;
2066 par1Entity.prevRotationYaw = par1Entity.rotationYaw;
2067 par1Entity.prevRotationPitch = par1Entity.rotationPitch;
2068
2069 if (par2 && par1Entity.addedToChunk)
2070 {
2071 if (par1Entity.ridingEntity != null)
2072 {
2073 par1Entity.updateRidden();
2074 }
2075 else
2076 {
2077 par1Entity.onUpdate();
2078 }
2079 }
2080
2081 this.theProfiler.startSection("chunkCheck");
2082
2083 if (Double.isNaN(par1Entity.posX) || Double.isInfinite(par1Entity.posX))
2084 {
2085 par1Entity.posX = par1Entity.lastTickPosX;
2086 }
2087
2088 if (Double.isNaN(par1Entity.posY) || Double.isInfinite(par1Entity.posY))
2089 {
2090 par1Entity.posY = par1Entity.lastTickPosY;
2091 }
2092
2093 if (Double.isNaN(par1Entity.posZ) || Double.isInfinite(par1Entity.posZ))
2094 {
2095 par1Entity.posZ = par1Entity.lastTickPosZ;
2096 }
2097
2098 if (Double.isNaN((double)par1Entity.rotationPitch) || Double.isInfinite((double)par1Entity.rotationPitch))
2099 {
2100 par1Entity.rotationPitch = par1Entity.prevRotationPitch;
2101 }
2102
2103 if (Double.isNaN((double)par1Entity.rotationYaw) || Double.isInfinite((double)par1Entity.rotationYaw))
2104 {
2105 par1Entity.rotationYaw = par1Entity.prevRotationYaw;
2106 }
2107
2108 int var6 = MathHelper.floor_double(par1Entity.posX / 16.0D);
2109 int var7 = MathHelper.floor_double(par1Entity.posY / 16.0D);
2110 int var8 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
2111
2112 if (!par1Entity.addedToChunk || par1Entity.chunkCoordX != var6 || par1Entity.chunkCoordY != var7 || par1Entity.chunkCoordZ != var8)
2113 {
2114 if (par1Entity.addedToChunk && this.chunkExists(par1Entity.chunkCoordX, par1Entity.chunkCoordZ))
2115 {
2116 this.getChunkFromChunkCoords(par1Entity.chunkCoordX, par1Entity.chunkCoordZ).removeEntityAtIndex(par1Entity, par1Entity.chunkCoordY);
2117 }
2118
2119 if (this.chunkExists(var6, var8))
2120 {
2121 par1Entity.addedToChunk = true;
2122 this.getChunkFromChunkCoords(var6, var8).addEntity(par1Entity);
2123 }
2124 else
2125 {
2126 par1Entity.addedToChunk = false;
2127 }
2128 }
2129
2130 this.theProfiler.endSection();
2131
2132 if (par2 && par1Entity.addedToChunk && par1Entity.riddenByEntity != null)
2133 {
2134 if (!par1Entity.riddenByEntity.isDead && par1Entity.riddenByEntity.ridingEntity == par1Entity)
2135 {
2136 this.updateEntity(par1Entity.riddenByEntity);
2137 }
2138 else
2139 {
2140 par1Entity.riddenByEntity.ridingEntity = null;
2141 par1Entity.riddenByEntity = null;
2142 }
2143 }
2144 }
2145 }
2146
2147 /**
2148 * Returns true if there are no solid, live entities in the specified AxisAlignedBB
2149 */
2150 public boolean checkIfAABBIsClear(AxisAlignedBB par1AxisAlignedBB)
2151 {
2152 return this.checkIfAABBIsClearExcludingEntity(par1AxisAlignedBB, (Entity)null);
2153 }
2154
2155 /**
2156 * Returns true if there are no solid, live entities in the specified AxisAlignedBB, excluding the given entity
2157 */
2158 public boolean checkIfAABBIsClearExcludingEntity(AxisAlignedBB par1AxisAlignedBB, Entity par2Entity)
2159 {
2160 List var3 = this.getEntitiesWithinAABBExcludingEntity((Entity)null, par1AxisAlignedBB);
2161 Iterator var4 = var3.iterator();
2162 Entity var5;
2163
2164 do
2165 {
2166 if (!var4.hasNext())
2167 {
2168 return true;
2169 }
2170
2171 var5 = (Entity)var4.next();
2172 }
2173 while (var5.isDead || !var5.preventEntitySpawning || var5 == par2Entity);
2174
2175 return false;
2176 }
2177
2178 /**
2179 * Returns true if there are any blocks in the region constrained by an AxisAlignedBB
2180 */
2181 public boolean isAABBNonEmpty(AxisAlignedBB par1AxisAlignedBB)
2182 {
2183 int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2184 int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2185 int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2186 int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2187 int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2188 int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2189
2190 if (par1AxisAlignedBB.minX < 0.0D)
2191 {
2192 --var2;
2193 }
2194
2195 if (par1AxisAlignedBB.minY < 0.0D)
2196 {
2197 --var4;
2198 }
2199
2200 if (par1AxisAlignedBB.minZ < 0.0D)
2201 {
2202 --var6;
2203 }
2204
2205 for (int var8 = var2; var8 < var3; ++var8)
2206 {
2207 for (int var9 = var4; var9 < var5; ++var9)
2208 {
2209 for (int var10 = var6; var10 < var7; ++var10)
2210 {
2211 Block var11 = Block.blocksList[this.getBlockId(var8, var9, var10)];
2212
2213 if (var11 != null)
2214 {
2215 return true;
2216 }
2217 }
2218 }
2219 }
2220
2221 return false;
2222 }
2223
2224 /**
2225 * Returns if any of the blocks within the aabb are liquids. Args: aabb
2226 */
2227 public boolean isAnyLiquid(AxisAlignedBB par1AxisAlignedBB)
2228 {
2229 int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2230 int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2231 int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2232 int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2233 int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2234 int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2235
2236 if (par1AxisAlignedBB.minX < 0.0D)
2237 {
2238 --var2;
2239 }
2240
2241 if (par1AxisAlignedBB.minY < 0.0D)
2242 {
2243 --var4;
2244 }
2245
2246 if (par1AxisAlignedBB.minZ < 0.0D)
2247 {
2248 --var6;
2249 }
2250
2251 for (int var8 = var2; var8 < var3; ++var8)
2252 {
2253 for (int var9 = var4; var9 < var5; ++var9)
2254 {
2255 for (int var10 = var6; var10 < var7; ++var10)
2256 {
2257 Block var11 = Block.blocksList[this.getBlockId(var8, var9, var10)];
2258
2259 if (var11 != null && var11.blockMaterial.isLiquid())
2260 {
2261 return true;
2262 }
2263 }
2264 }
2265 }
2266
2267 return false;
2268 }
2269
2270 /**
2271 * Returns whether or not the given bounding box is on fire or not
2272 */
2273 public boolean isBoundingBoxBurning(AxisAlignedBB par1AxisAlignedBB)
2274 {
2275 int var2 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2276 int var3 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2277 int var4 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2278 int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2279 int var6 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2280 int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2281
2282 if (this.checkChunksExist(var2, var4, var6, var3, var5, var7))
2283 {
2284 for (int var8 = var2; var8 < var3; ++var8)
2285 {
2286 for (int var9 = var4; var9 < var5; ++var9)
2287 {
2288 for (int var10 = var6; var10 < var7; ++var10)
2289 {
2290 int var11 = this.getBlockId(var8, var9, var10);
2291
2292 if (var11 == Block.fire.blockID || var11 == Block.lavaMoving.blockID || var11 == Block.lavaStill.blockID)
2293 {
2294 return true;
2295 }
2296 else
2297 {
2298 Block block = Block.blocksList[var11];
2299 if (block != null && block.isBlockBurning(this, var8, var9, var10))
2300 {
2301 return true;
2302 }
2303 }
2304 }
2305 }
2306 }
2307 }
2308
2309 return false;
2310 }
2311
2312 /**
2313 * handles the acceleration of an object whilst in water. Not sure if it is used elsewhere.
2314 */
2315 public boolean handleMaterialAcceleration(AxisAlignedBB par1AxisAlignedBB, Material par2Material, Entity par3Entity)
2316 {
2317 int var4 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2318 int var5 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2319 int var6 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2320 int var7 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2321 int var8 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2322 int var9 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2323
2324 if (!this.checkChunksExist(var4, var6, var8, var5, var7, var9))
2325 {
2326 return false;
2327 }
2328 else
2329 {
2330 boolean var10 = false;
2331 Vec3 var11 = Vec3.getVec3Pool().getVecFromPool(0.0D, 0.0D, 0.0D);
2332
2333 for (int var12 = var4; var12 < var5; ++var12)
2334 {
2335 for (int var13 = var6; var13 < var7; ++var13)
2336 {
2337 for (int var14 = var8; var14 < var9; ++var14)
2338 {
2339 Block var15 = Block.blocksList[this.getBlockId(var12, var13, var14)];
2340
2341 if (var15 != null && var15.blockMaterial == par2Material)
2342 {
2343 double var16 = (double)((float)(var13 + 1) - BlockFluid.getFluidHeightPercent(this.getBlockMetadata(var12, var13, var14)));
2344
2345 if ((double)var7 >= var16)
2346 {
2347 var10 = true;
2348 var15.velocityToAddToEntity(this, var12, var13, var14, par3Entity, var11);
2349 }
2350 }
2351 }
2352 }
2353 }
2354
2355 if (var11.lengthVector() > 0.0D)
2356 {
2357 var11 = var11.normalize();
2358 double var18 = 0.014D;
2359 par3Entity.motionX += var11.xCoord * var18;
2360 par3Entity.motionY += var11.yCoord * var18;
2361 par3Entity.motionZ += var11.zCoord * var18;
2362 }
2363
2364 return var10;
2365 }
2366 }
2367
2368 /**
2369 * Returns true if the given bounding box contains the given material
2370 */
2371 public boolean isMaterialInBB(AxisAlignedBB par1AxisAlignedBB, Material par2Material)
2372 {
2373 int var3 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2374 int var4 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2375 int var5 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2376 int var6 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2377 int var7 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2378 int var8 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2379
2380 for (int var9 = var3; var9 < var4; ++var9)
2381 {
2382 for (int var10 = var5; var10 < var6; ++var10)
2383 {
2384 for (int var11 = var7; var11 < var8; ++var11)
2385 {
2386 Block var12 = Block.blocksList[this.getBlockId(var9, var10, var11)];
2387
2388 if (var12 != null && var12.blockMaterial == par2Material)
2389 {
2390 return true;
2391 }
2392 }
2393 }
2394 }
2395
2396 return false;
2397 }
2398
2399 /**
2400 * checks if the given AABB is in the material given. Used while swimming.
2401 */
2402 public boolean isAABBInMaterial(AxisAlignedBB par1AxisAlignedBB, Material par2Material)
2403 {
2404 int var3 = MathHelper.floor_double(par1AxisAlignedBB.minX);
2405 int var4 = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D);
2406 int var5 = MathHelper.floor_double(par1AxisAlignedBB.minY);
2407 int var6 = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D);
2408 int var7 = MathHelper.floor_double(par1AxisAlignedBB.minZ);
2409 int var8 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D);
2410
2411 for (int var9 = var3; var9 < var4; ++var9)
2412 {
2413 for (int var10 = var5; var10 < var6; ++var10)
2414 {
2415 for (int var11 = var7; var11 < var8; ++var11)
2416 {
2417 Block var12 = Block.blocksList[this.getBlockId(var9, var10, var11)];
2418
2419 if (var12 != null && var12.blockMaterial == par2Material)
2420 {
2421 int var13 = this.getBlockMetadata(var9, var10, var11);
2422 double var14 = (double)(var10 + 1);
2423
2424 if (var13 < 8)
2425 {
2426 var14 = (double)(var10 + 1) - (double)var13 / 8.0D;
2427 }
2428
2429 if (var14 >= par1AxisAlignedBB.minY)
2430 {
2431 return true;
2432 }
2433 }
2434 }
2435 }
2436 }
2437
2438 return false;
2439 }
2440
2441 /**
2442 * Creates an explosion. Args: entity, x, y, z, strength
2443 */
2444 public Explosion createExplosion(Entity par1Entity, double par2, double par4, double par6, float par8)
2445 {
2446 return this.newExplosion(par1Entity, par2, par4, par6, par8, false);
2447 }
2448
2449 /**
2450 * returns a new explosion. Does initiation (at time of writing Explosion is not finished)
2451 */
2452 public Explosion newExplosion(Entity par1Entity, double par2, double par4, double par6, float par8, boolean par9)
2453 {
2454 Explosion var10 = new Explosion(this, par1Entity, par2, par4, par6, par8);
2455 var10.isFlaming = par9;
2456 var10.doExplosionA();
2457 var10.doExplosionB(true);
2458 return var10;
2459 }
2460
2461 /**
2462 * Gets the percentage of real blocks within within a bounding box, along a specified vector.
2463 */
2464 public float getBlockDensity(Vec3 par1Vec3, AxisAlignedBB par2AxisAlignedBB)
2465 {
2466 double var3 = 1.0D / ((par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * 2.0D + 1.0D);
2467 double var5 = 1.0D / ((par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * 2.0D + 1.0D);
2468 double var7 = 1.0D / ((par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * 2.0D + 1.0D);
2469 int var9 = 0;
2470 int var10 = 0;
2471
2472 for (float var11 = 0.0F; var11 <= 1.0F; var11 = (float)((double)var11 + var3))
2473 {
2474 for (float var12 = 0.0F; var12 <= 1.0F; var12 = (float)((double)var12 + var5))
2475 {
2476 for (float var13 = 0.0F; var13 <= 1.0F; var13 = (float)((double)var13 + var7))
2477 {
2478 double var14 = par2AxisAlignedBB.minX + (par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * (double)var11;
2479 double var16 = par2AxisAlignedBB.minY + (par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * (double)var12;
2480 double var18 = par2AxisAlignedBB.minZ + (par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * (double)var13;
2481
2482 if (this.rayTraceBlocks(Vec3.getVec3Pool().getVecFromPool(var14, var16, var18), par1Vec3) == null)
2483 {
2484 ++var9;
2485 }
2486
2487 ++var10;
2488 }
2489 }
2490 }
2491
2492 return (float)var9 / (float)var10;
2493 }
2494
2495 /**
2496 * If the block in the given direction of the given coordinate is fire, extinguish it. Args: Player, X,Y,Z,
2497 * blockDirection
2498 */
2499 public boolean extinguishFire(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5)
2500 {
2501 if (par5 == 0)
2502 {
2503 --par3;
2504 }
2505
2506 if (par5 == 1)
2507 {
2508 ++par3;
2509 }
2510
2511 if (par5 == 2)
2512 {
2513 --par4;
2514 }
2515
2516 if (par5 == 3)
2517 {
2518 ++par4;
2519 }
2520
2521 if (par5 == 4)
2522 {
2523 --par2;
2524 }
2525
2526 if (par5 == 5)
2527 {
2528 ++par2;
2529 }
2530
2531 if (this.getBlockId(par2, par3, par4) == Block.fire.blockID)
2532 {
2533 this.playAuxSFXAtEntity(par1EntityPlayer, 1004, par2, par3, par4, 0);
2534 this.setBlockWithNotify(par2, par3, par4, 0);
2535 return true;
2536 }
2537 else
2538 {
2539 return false;
2540 }
2541 }
2542
2543 @SideOnly(Side.CLIENT)
2544
2545 /**
2546 * This string is 'All: (number of loaded entities)' Viewable by press ing F3
2547 */
2548 public String getDebugLoadedEntities()
2549 {
2550 return "All: " + this.loadedEntityList.size();
2551 }
2552
2553 @SideOnly(Side.CLIENT)
2554
2555 /**
2556 * Returns the name of the current chunk provider, by calling chunkprovider.makeString()
2557 */
2558 public String getProviderName()
2559 {
2560 return this.chunkProvider.makeString();
2561 }
2562
2563 /**
2564 * Returns the TileEntity associated with a given block in X,Y,Z coordinates, or null if no TileEntity exists
2565 */
2566 public TileEntity getBlockTileEntity(int par1, int par2, int par3)
2567 {
2568 if (par2 >= 256)
2569 {
2570 return null;
2571 }
2572 else
2573 {
2574 Chunk var4 = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2575
2576 if (var4 == null)
2577 {
2578 return null;
2579 }
2580 else
2581 {
2582 TileEntity var5 = var4.getChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
2583
2584 if (var5 == null)
2585 {
2586 Iterator var6 = this.addedTileEntityList.iterator();
2587
2588 while (var6.hasNext())
2589 {
2590 TileEntity var7 = (TileEntity)var6.next();
2591
2592 if (!var7.isInvalid() && var7.xCoord == par1 && var7.yCoord == par2 && var7.zCoord == par3)
2593 {
2594 var5 = var7;
2595 break;
2596 }
2597 }
2598 }
2599
2600 return var5;
2601 }
2602 }
2603 }
2604
2605 /**
2606 * Sets the TileEntity for a given block in X, Y, Z coordinates
2607 */
2608 public void setBlockTileEntity(int par1, int par2, int par3, TileEntity par4TileEntity)
2609 {
2610 if (par4TileEntity == null || par4TileEntity.isInvalid())
2611 {
2612 return;
2613 }
2614
2615 if (par4TileEntity.canUpdate())
2616 {
2617 List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
2618 dest.add(par4TileEntity);
2619 }
2620
2621 Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2622 if (chunk != null)
2623 {
2624 chunk.setChunkBlockTileEntity(par1 & 15, par2, par3 & 15, par4TileEntity);
2625 }
2626 }
2627
2628 /**
2629 * Removes the TileEntity for a given block in X,Y,Z coordinates
2630 */
2631 public void removeBlockTileEntity(int par1, int par2, int par3)
2632 {
2633 Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4);
2634 if (chunk != null)
2635 {
2636 chunk.removeChunkBlockTileEntity(par1 & 15, par2, par3 & 15);
2637 }
2638 }
2639
2640 /**
2641 * adds tile entity to despawn list (renamed from markEntityForDespawn)
2642 */
2643 public void markTileEntityForDespawn(TileEntity par1TileEntity)
2644 {
2645 this.entityRemoval.add(par1TileEntity);
2646 }
2647
2648 /**
2649 * Returns true if the block at the specified coordinates is an opaque cube. Args: x, y, z
2650 */
2651 public boolean isBlockOpaqueCube(int par1, int par2, int par3)
2652 {
2653 Block var4 = Block.blocksList[this.getBlockId(par1, par2, par3)];
2654 return var4 == null ? false : var4.isOpaqueCube();
2655 }
2656
2657 /**
2658 * Indicate if a material is a normal solid opaque cube.
2659 */
2660 public boolean isBlockNormalCube(int par1, int par2, int par3)
2661 {
2662 Block block = Block.blocksList[getBlockId(par1, par2, par3)];
2663 return block != null && block.isBlockNormalCube(this, par1, par2, par3);
2664 }
2665
2666 /**
2667 * Returns true if the block at the given coordinate has a solid (buildable) top surface.
2668 */
2669 public boolean doesBlockHaveSolidTopSurface(int par1, int par2, int par3)
2670 {
2671 return isBlockSolidOnSide(par1, par2, par3, ForgeDirection.UP);
2672 }
2673
2674 /**
2675 * Checks if the block is a solid, normal cube. If the chunk does not exist, or is not loaded, it returns the
2676 * boolean parameter.
2677 */
2678 public boolean isBlockNormalCubeDefault(int par1, int par2, int par3, boolean par4)
2679 {
2680 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000)
2681 {
2682 Chunk var5 = this.chunkProvider.provideChunk(par1 >> 4, par3 >> 4);
2683
2684 if (var5 != null && !var5.isEmpty())
2685 {
2686 Block var6 = Block.blocksList[this.getBlockId(par1, par2, par3)];
2687 return var6 == null ? false : isBlockNormalCube(par1, par2, par3);
2688 }
2689 else
2690 {
2691 return par4;
2692 }
2693 }
2694 else
2695 {
2696 return par4;
2697 }
2698 }
2699
2700 /**
2701 * Called on construction of the World class to setup the initial skylight values
2702 */
2703 public void calculateInitialSkylight()
2704 {
2705 int var1 = this.calculateSkylightSubtracted(1.0F);
2706
2707 if (var1 != this.skylightSubtracted)
2708 {
2709 this.skylightSubtracted = var1;
2710 }
2711 }
2712
2713 /**
2714 * Set which types of mobs are allowed to spawn (peaceful vs hostile).
2715 */
2716 public void setAllowedSpawnTypes(boolean par1, boolean par2)
2717 {
2718 provider.setAllowedSpawnTypes(par1, par2);
2719 }
2720
2721 /**
2722 * Runs a single tick for the world
2723 */
2724 public void tick()
2725 {
2726 this.updateWeather();
2727 }
2728
2729 /**
2730 * Called from World constructor to set rainingStrength and thunderingStrength
2731 */
2732 private void calculateInitialWeather()
2733 {
2734 provider.calculateInitialWeather();
2735 }
2736
2737 public void calculateInitialWeatherBody()
2738 {
2739 if (this.worldInfo.isRaining())
2740 {
2741 this.rainingStrength = 1.0F;
2742
2743 if (this.worldInfo.isThundering())
2744 {
2745 this.thunderingStrength = 1.0F;
2746 }
2747 }
2748 }
2749
2750 /**
2751 * Updates all weather states.
2752 */
2753 protected void updateWeather()
2754 {
2755 provider.updateWeather();
2756 }
2757
2758 public void updateWeatherBody()
2759 {
2760 if (!this.provider.hasNoSky)
2761 {
2762 if (this.lastLightningBolt > 0)
2763 {
2764 --this.lastLightningBolt;
2765 }
2766
2767 int var1 = this.worldInfo.getThunderTime();
2768
2769 if (var1 <= 0)
2770 {
2771 if (this.worldInfo.isThundering())
2772 {
2773 this.worldInfo.setThunderTime(this.rand.nextInt(12000) + 3600);
2774 }
2775 else
2776 {
2777 this.worldInfo.setThunderTime(this.rand.nextInt(168000) + 12000);
2778 }
2779 }
2780 else
2781 {
2782 --var1;
2783 this.worldInfo.setThunderTime(var1);
2784
2785 if (var1 <= 0)
2786 {
2787 this.worldInfo.setThundering(!this.worldInfo.isThundering());
2788 }
2789 }
2790
2791 int var2 = this.worldInfo.getRainTime();
2792
2793 if (var2 <= 0)
2794 {
2795 if (this.worldInfo.isRaining())
2796 {
2797 this.worldInfo.setRainTime(this.rand.nextInt(12000) + 12000);
2798 }
2799 else
2800 {
2801 this.worldInfo.setRainTime(this.rand.nextInt(168000) + 12000);
2802 }
2803 }
2804 else
2805 {
2806 --var2;
2807 this.worldInfo.setRainTime(var2);
2808
2809 if (var2 <= 0)
2810 {
2811 this.worldInfo.setRaining(!this.worldInfo.isRaining());
2812 }
2813 }
2814
2815 this.prevRainingStrength = this.rainingStrength;
2816
2817 if (this.worldInfo.isRaining())
2818 {
2819 this.rainingStrength = (float)((double)this.rainingStrength + 0.01D);
2820 }
2821 else
2822 {
2823 this.rainingStrength = (float)((double)this.rainingStrength - 0.01D);
2824 }
2825
2826 if (this.rainingStrength < 0.0F)
2827 {
2828 this.rainingStrength = 0.0F;
2829 }
2830
2831 if (this.rainingStrength > 1.0F)
2832 {
2833 this.rainingStrength = 1.0F;
2834 }
2835
2836 this.prevThunderingStrength = this.thunderingStrength;
2837
2838 if (this.worldInfo.isThundering())
2839 {
2840 this.thunderingStrength = (float)((double)this.thunderingStrength + 0.01D);
2841 }
2842 else
2843 {
2844 this.thunderingStrength = (float)((double)this.thunderingStrength - 0.01D);
2845 }
2846
2847 if (this.thunderingStrength < 0.0F)
2848 {
2849 this.thunderingStrength = 0.0F;
2850 }
2851
2852 if (this.thunderingStrength > 1.0F)
2853 {
2854 this.thunderingStrength = 1.0F;
2855 }
2856 }
2857 }
2858
2859 public void toggleRain()
2860 {
2861 provider.toggleRain();
2862 }
2863
2864 protected void setActivePlayerChunksAndCheckLight()
2865 {
2866 this.activeChunkSet.clear();
2867 this.activeChunkSet.addAll(getPersistentChunks().keySet());
2868
2869 this.theProfiler.startSection("buildList");
2870 int var1;
2871 EntityPlayer var2;
2872 int var3;
2873 int var4;
2874
2875 for (var1 = 0; var1 < this.playerEntities.size(); ++var1)
2876 {
2877 var2 = (EntityPlayer)this.playerEntities.get(var1);
2878 var3 = MathHelper.floor_double(var2.posX / 16.0D);
2879 var4 = MathHelper.floor_double(var2.posZ / 16.0D);
2880 byte var5 = 7;
2881
2882 for (int var6 = -var5; var6 <= var5; ++var6)
2883 {
2884 for (int var7 = -var5; var7 <= var5; ++var7)
2885 {
2886 this.activeChunkSet.add(new ChunkCoordIntPair(var6 + var3, var7 + var4));
2887 }
2888 }
2889 }
2890
2891 this.theProfiler.endSection();
2892
2893 if (this.ambientTickCountdown > 0)
2894 {
2895 --this.ambientTickCountdown;
2896 }
2897
2898 this.theProfiler.startSection("playerCheckLight");
2899
2900 if (!this.playerEntities.isEmpty())
2901 {
2902 var1 = this.rand.nextInt(this.playerEntities.size());
2903 var2 = (EntityPlayer)this.playerEntities.get(var1);
2904 var3 = MathHelper.floor_double(var2.posX) + this.rand.nextInt(11) - 5;
2905 var4 = MathHelper.floor_double(var2.posY) + this.rand.nextInt(11) - 5;
2906 int var8 = MathHelper.floor_double(var2.posZ) + this.rand.nextInt(11) - 5;
2907 this.updateAllLightTypes(var3, var4, var8);
2908 }
2909
2910 this.theProfiler.endSection();
2911 }
2912
2913 protected void moodSoundAndLightCheck(int par1, int par2, Chunk par3Chunk)
2914 {
2915 this.theProfiler.endStartSection("moodSound");
2916
2917 if (this.ambientTickCountdown == 0)
2918 {
2919 this.updateLCG = this.updateLCG * 3 + 1013904223;
2920 int var4 = this.updateLCG >> 2;
2921 int var5 = var4 & 15;
2922 int var6 = var4 >> 8 & 15;
2923 int var7 = var4 >> 16 & 127;
2924 int var8 = par3Chunk.getBlockID(var5, var7, var6);
2925 var5 += par1;
2926 var6 += par2;
2927
2928 if (var8 == 0 && this.getFullBlockLightValue(var5, var7, var6) <= this.rand.nextInt(8) && this.getSavedLightValue(EnumSkyBlock.Sky, var5, var7, var6) <= 0)
2929 {
2930 EntityPlayer var9 = this.getClosestPlayer((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D, 8.0D);
2931
2932 if (var9 != null && var9.getDistanceSq((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D) > 4.0D)
2933 {
2934 this.playSoundEffect((double)var5 + 0.5D, (double)var7 + 0.5D, (double)var6 + 0.5D, "ambient.cave.cave", 0.7F, 0.8F + this.rand.nextFloat() * 0.2F);
2935 this.ambientTickCountdown = this.rand.nextInt(12000) + 6000;
2936 }
2937 }
2938 }
2939
2940 this.theProfiler.endStartSection("checkLight");
2941 par3Chunk.enqueueRelightChecks();
2942 }
2943
2944 /**
2945 * plays random cave ambient sounds and runs updateTick on random blocks within each chunk in the vacinity of a
2946 * player
2947 */
2948 protected void tickBlocksAndAmbiance()
2949 {
2950 this.setActivePlayerChunksAndCheckLight();
2951 }
2952
2953 /**
2954 * checks to see if a given block is both water and is cold enough to freeze
2955 */
2956 public boolean isBlockFreezable(int par1, int par2, int par3)
2957 {
2958 return this.canBlockFreeze(par1, par2, par3, false);
2959 }
2960
2961 /**
2962 * checks to see if a given block is both water and has at least one immediately adjacent non-water block
2963 */
2964 public boolean isBlockFreezableNaturally(int par1, int par2, int par3)
2965 {
2966 return this.canBlockFreeze(par1, par2, par3, true);
2967 }
2968
2969 /**
2970 * checks to see if a given block is both water, and cold enough to freeze - if the par4 boolean is set, this will
2971 * only return true if there is a non-water block immediately adjacent to the specified block
2972 */
2973 public boolean canBlockFreeze(int par1, int par2, int par3, boolean par4)
2974 {
2975 return provider.canBlockFreeze(par1, par2, par3, par4);
2976 }
2977
2978 public boolean canBlockFreezeBody(int par1, int par2, int par3, boolean par4)
2979 {
2980 BiomeGenBase var5 = this.getBiomeGenForCoords(par1, par3);
2981 float var6 = var5.getFloatTemperature();
2982
2983 if (var6 > 0.15F)
2984 {
2985 return false;
2986 }
2987 else
2988 {
2989 if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10)
2990 {
2991 int var7 = this.getBlockId(par1, par2, par3);
2992
2993 if ((var7 == Block.waterStill.blockID || var7 == Block.waterMoving.blockID) && this.getBlockMetadata(par1, par2, par3) == 0)
2994 {
2995 if (!par4)
2996 {
2997 return true;
2998 }
2999
3000 boolean var8 = true;
3001
3002 if (var8 && this.getBlockMaterial(par1 - 1, par2, par3) != Material.water)
3003 {
3004 var8 = false;
3005 }
3006
3007 if (var8 && this.getBlockMaterial(par1 + 1, par2, par3) != Material.water)
3008 {
3009 var8 = false;
3010 }
3011
3012 if (var8 && this.getBlockMaterial(par1, par2, par3 - 1) != Material.water)
3013 {
3014 var8 = false;
3015 }
3016
3017 if (var8 && this.getBlockMaterial(par1, par2, par3 + 1) != Material.water)
3018 {
3019 var8 = false;
3020 }
3021
3022 if (!var8)
3023 {
3024 return true;
3025 }
3026 }
3027 }
3028
3029 return false;
3030 }
3031 }
3032
3033 /**
3034 * Tests whether or not snow can be placed at a given location
3035 */
3036 public boolean canSnowAt(int par1, int par2, int par3)
3037 {
3038 return provider.canSnowAt(par1, par2, par3);
3039 }
3040
3041 public boolean canSnowAtBody(int par1, int par2, int par3)
3042 {
3043 BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
3044 float var5 = var4.getFloatTemperature();
3045
3046 if (var5 > 0.15F)
3047 {
3048 return false;
3049 }
3050 else
3051 {
3052 if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10)
3053 {
3054 int var6 = this.getBlockId(par1, par2 - 1, par3);
3055 int var7 = this.getBlockId(par1, par2, par3);
3056
3057 if (var7 == 0 && Block.snow.canPlaceBlockAt(this, par1, par2, par3) && var6 != 0 && var6 != Block.ice.blockID && Block.blocksList[var6].blockMaterial.blocksMovement())
3058 {
3059 return true;
3060 }
3061 }
3062
3063 return false;
3064 }
3065 }
3066
3067 public void updateAllLightTypes(int par1, int par2, int par3)
3068 {
3069 if (!this.provider.hasNoSky)
3070 {
3071 this.updateLightByType(EnumSkyBlock.Sky, par1, par2, par3);
3072 }
3073
3074 this.updateLightByType(EnumSkyBlock.Block, par1, par2, par3);
3075 }
3076
3077 private int computeSkyLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
3078 {
3079 int var7 = 0;
3080
3081 if (this.canBlockSeeTheSky(par2, par3, par4))
3082 {
3083 var7 = 15;
3084 }
3085 else
3086 {
3087 if (par6 == 0)
3088 {
3089 par6 = 1;
3090 }
3091
3092 int var8 = this.getSavedLightValue(EnumSkyBlock.Sky, par2 - 1, par3, par4) - par6;
3093 int var9 = this.getSavedLightValue(EnumSkyBlock.Sky, par2 + 1, par3, par4) - par6;
3094 int var10 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3 - 1, par4) - par6;
3095 int var11 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3 + 1, par4) - par6;
3096 int var12 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3, par4 - 1) - par6;
3097 int var13 = this.getSavedLightValue(EnumSkyBlock.Sky, par2, par3, par4 + 1) - par6;
3098
3099 if (var8 > var7)
3100 {
3101 var7 = var8;
3102 }
3103
3104 if (var9 > var7)
3105 {
3106 var7 = var9;
3107 }
3108
3109 if (var10 > var7)
3110 {
3111 var7 = var10;
3112 }
3113
3114 if (var11 > var7)
3115 {
3116 var7 = var11;
3117 }
3118
3119 if (var12 > var7)
3120 {
3121 var7 = var12;
3122 }
3123
3124 if (var13 > var7)
3125 {
3126 var7 = var13;
3127 }
3128 }
3129
3130 return var7;
3131 }
3132
3133 private int computeBlockLightValue(int par1, int par2, int par3, int par4, int par5, int par6)
3134 {
3135 int var7 = (par5 == 0 || Block.blocksList[par5] == null ? 0 : Block.blocksList[par5].getLightValue(this, par2, par3, par4));
3136 int var8 = this.getSavedLightValue(EnumSkyBlock.Block, par2 - 1, par3, par4) - par6;
3137 int var9 = this.getSavedLightValue(EnumSkyBlock.Block, par2 + 1, par3, par4) - par6;
3138 int var10 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 - 1, par4) - par6;
3139 int var11 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3 + 1, par4) - par6;
3140 int var12 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3, par4 - 1) - par6;
3141 int var13 = this.getSavedLightValue(EnumSkyBlock.Block, par2, par3, par4 + 1) - par6;
3142
3143 if (var8 > var7)
3144 {
3145 var7 = var8;
3146 }
3147
3148 if (var9 > var7)
3149 {
3150 var7 = var9;
3151 }
3152
3153 if (var10 > var7)
3154 {
3155 var7 = var10;
3156 }
3157
3158 if (var11 > var7)
3159 {
3160 var7 = var11;
3161 }
3162
3163 if (var12 > var7)
3164 {
3165 var7 = var12;
3166 }
3167
3168 if (var13 > var7)
3169 {
3170 var7 = var13;
3171 }
3172
3173 return var7;
3174 }
3175
3176 public void updateLightByType(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4)
3177 {
3178 if (this.doChunksNearChunkExist(par2, par3, par4, 17))
3179 {
3180 int var5 = 0;
3181 int var6 = 0;
3182 this.theProfiler.startSection("getBrightness");
3183 int var7 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4);
3184 boolean var8 = false;
3185 int var9 = this.getBlockId(par2, par3, par4);
3186 int var10 = this.getBlockLightOpacity(par2, par3, par4);
3187
3188 if (var10 == 0)
3189 {
3190 var10 = 1;
3191 }
3192
3193 boolean var11 = false;
3194 int var24;
3195
3196 if (par1EnumSkyBlock == EnumSkyBlock.Sky)
3197 {
3198 var24 = this.computeSkyLightValue(var7, par2, par3, par4, var9, var10);
3199 }
3200 else
3201 {
3202 var24 = this.computeBlockLightValue(var7, par2, par3, par4, var9, var10);
3203 }
3204
3205 int var12;
3206 int var13;
3207 int var14;
3208 int var15;
3209 int var17;
3210 int var16;
3211 int var19;
3212 int var18;
3213
3214 if (var24 > var7)
3215 {
3216 this.lightUpdateBlockList[var6++] = 133152;
3217 }
3218 else if (var24 < var7)
3219 {
3220 if (par1EnumSkyBlock != EnumSkyBlock.Block)
3221 {
3222 ;
3223 }
3224
3225 this.lightUpdateBlockList[var6++] = 133152 + (var7 << 18);
3226
3227 while (var5 < var6)
3228 {
3229 var9 = this.lightUpdateBlockList[var5++];
3230 var10 = (var9 & 63) - 32 + par2;
3231 var24 = (var9 >> 6 & 63) - 32 + par3;
3232 var12 = (var9 >> 12 & 63) - 32 + par4;
3233 var13 = var9 >> 18 & 15;
3234 var14 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12);
3235
3236 if (var14 == var13)
3237 {
3238 this.setLightValue(par1EnumSkyBlock, var10, var24, var12, 0);
3239
3240 if (var13 > 0)
3241 {
3242 var15 = var10 - par2;
3243 var16 = var24 - par3;
3244 var17 = var12 - par4;
3245
3246 if (var15 < 0)
3247 {
3248 var15 = -var15;
3249 }
3250
3251 if (var16 < 0)
3252 {
3253 var16 = -var16;
3254 }
3255
3256 if (var17 < 0)
3257 {
3258 var17 = -var17;
3259 }
3260
3261 if (var15 + var16 + var17 < 17)
3262 {
3263 for (var18 = 0; var18 < 6; ++var18)
3264 {
3265 var19 = var18 % 2 * 2 - 1;
3266 int var20 = var10 + var18 / 2 % 3 / 2 * var19;
3267 int var21 = var24 + (var18 / 2 + 1) % 3 / 2 * var19;
3268 int var22 = var12 + (var18 / 2 + 2) % 3 / 2 * var19;
3269 var14 = this.getSavedLightValue(par1EnumSkyBlock, var20, var21, var22);
3270 int var23 = this.getBlockLightOpacity(var20, var21, var22);
3271
3272 if (var23 == 0)
3273 {
3274 var23 = 1;
3275 }
3276
3277 if (var14 == var13 - var23 && var6 < this.lightUpdateBlockList.length)
3278 {
3279 this.lightUpdateBlockList[var6++] = var20 - par2 + 32 + (var21 - par3 + 32 << 6) + (var22 - par4 + 32 << 12) + (var13 - var23 << 18);
3280 }
3281 }
3282 }
3283 }
3284 }
3285 }
3286
3287 var5 = 0;
3288 }
3289
3290 this.theProfiler.endSection();
3291 this.theProfiler.startSection("tcp < tcc");
3292
3293 while (var5 < var6)
3294 {
3295 var9 = this.lightUpdateBlockList[var5++];
3296 var10 = (var9 & 63) - 32 + par2;
3297 var24 = (var9 >> 6 & 63) - 32 + par3;
3298 var12 = (var9 >> 12 & 63) - 32 + par4;
3299 var13 = this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12);
3300 var14 = this.getBlockId(var10, var24, var12);
3301 var15 = this.getBlockLightOpacity(var10, var24, var12);
3302
3303 if (var15 == 0)
3304 {
3305 var15 = 1;
3306 }
3307
3308 boolean var25 = false;
3309
3310 if (par1EnumSkyBlock == EnumSkyBlock.Sky)
3311 {
3312 var16 = this.computeSkyLightValue(var13, var10, var24, var12, var14, var15);
3313 }
3314 else
3315 {
3316 var16 = this.computeBlockLightValue(var13, var10, var24, var12, var14, var15);
3317 }
3318
3319 if (var16 != var13)
3320 {
3321 this.setLightValue(par1EnumSkyBlock, var10, var24, var12, var16);
3322
3323 if (var16 > var13)
3324 {
3325 var17 = var10 - par2;
3326 var18 = var24 - par3;
3327 var19 = var12 - par4;
3328
3329 if (var17 < 0)
3330 {
3331 var17 = -var17;
3332 }
3333
3334 if (var18 < 0)
3335 {
3336 var18 = -var18;
3337 }
3338
3339 if (var19 < 0)
3340 {
3341 var19 = -var19;
3342 }
3343
3344 if (var17 + var18 + var19 < 17 && var6 < this.lightUpdateBlockList.length - 6)
3345 {
3346 if (this.getSavedLightValue(par1EnumSkyBlock, var10 - 1, var24, var12) < var16)
3347 {
3348 this.lightUpdateBlockList[var6++] = var10 - 1 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3349 }
3350
3351 if (this.getSavedLightValue(par1EnumSkyBlock, var10 + 1, var24, var12) < var16)
3352 {
3353 this.lightUpdateBlockList[var6++] = var10 + 1 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3354 }
3355
3356 if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24 - 1, var12) < var16)
3357 {
3358 this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - 1 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3359 }
3360
3361 if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24 + 1, var12) < var16)
3362 {
3363 this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 + 1 - par3 + 32 << 6) + (var12 - par4 + 32 << 12);
3364 }
3365
3366 if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12 - 1) < var16)
3367 {
3368 this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 - 1 - par4 + 32 << 12);
3369 }
3370
3371 if (this.getSavedLightValue(par1EnumSkyBlock, var10, var24, var12 + 1) < var16)
3372 {
3373 this.lightUpdateBlockList[var6++] = var10 - par2 + 32 + (var24 - par3 + 32 << 6) + (var12 + 1 - par4 + 32 << 12);
3374 }
3375 }
3376 }
3377 }
3378 }
3379
3380 this.theProfiler.endSection();
3381 }
3382 }
3383
3384 /**
3385 * Runs through the list of updates to run and ticks them
3386 */
3387 public boolean tickUpdates(boolean par1)
3388 {
3389 return false;
3390 }
3391
3392 public List getPendingBlockUpdates(Chunk par1Chunk, boolean par2)
3393 {
3394 return null;
3395 }
3396
3397 /**
3398 * Will get all entities within the specified AABB excluding the one passed into it. Args: entityToExclude, aabb
3399 */
3400 public List getEntitiesWithinAABBExcludingEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB)
3401 {
3402 this.entitiesWithinAABBExcludingEntity.clear();
3403 int var3 = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D);
3404 int var4 = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D);
3405 int var5 = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D);
3406 int var6 = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
3407
3408 for (int var7 = var3; var7 <= var4; ++var7)
3409 {
3410 for (int var8 = var5; var8 <= var6; ++var8)
3411 {
3412 if (this.chunkExists(var7, var8))
3413 {
3414 this.getChunkFromChunkCoords(var7, var8).getEntitiesWithinAABBForEntity(par1Entity, par2AxisAlignedBB, this.entitiesWithinAABBExcludingEntity);
3415 }
3416 }
3417 }
3418
3419 return this.entitiesWithinAABBExcludingEntity;
3420 }
3421
3422 /**
3423 * Returns all entities of the specified class type which intersect with the AABB. Args: entityClass, aabb
3424 */
3425 public List getEntitiesWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB)
3426 {
3427 int var3 = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D);
3428 int var4 = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D);
3429 int var5 = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D);
3430 int var6 = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D);
3431 ArrayList var7 = new ArrayList();
3432
3433 for (int var8 = var3; var8 <= var4; ++var8)
3434 {
3435 for (int var9 = var5; var9 <= var6; ++var9)
3436 {
3437 if (this.chunkExists(var8, var9))
3438 {
3439 this.getChunkFromChunkCoords(var8, var9).getEntitiesOfTypeWithinAAAB(par1Class, par2AxisAlignedBB, var7);
3440 }
3441 }
3442 }
3443
3444 return var7;
3445 }
3446
3447 public Entity findNearestEntityWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, Entity par3Entity)
3448 {
3449 List var4 = this.getEntitiesWithinAABB(par1Class, par2AxisAlignedBB);
3450 Entity var5 = null;
3451 double var6 = Double.MAX_VALUE;
3452 Iterator var8 = var4.iterator();
3453
3454 while (var8.hasNext())
3455 {
3456 Entity var9 = (Entity)var8.next();
3457
3458 if (var9 != par3Entity)
3459 {
3460 double var10 = par3Entity.getDistanceSqToEntity(var9);
3461
3462 if (var10 <= var6)
3463 {
3464 var5 = var9;
3465 var6 = var10;
3466 }
3467 }
3468 }
3469
3470 return var5;
3471 }
3472
3473 @SideOnly(Side.CLIENT)
3474
3475 /**
3476 * Accessor for world Loaded Entity List
3477 */
3478 public List getLoadedEntityList()
3479 {
3480 return this.loadedEntityList;
3481 }
3482
3483 /**
3484 * marks the chunk that contains this tilentity as modified and then calls worldAccesses.doNothingWithTileEntity
3485 */
3486 public void updateTileEntityChunkAndDoNothing(int par1, int par2, int par3, TileEntity par4TileEntity)
3487 {
3488 if (this.blockExists(par1, par2, par3))
3489 {
3490 this.getChunkFromBlockCoords(par1, par3).setChunkModified();
3491 }
3492 }
3493
3494 /**
3495 * Counts how many entities of an entity class exist in the world. Args: entityClass
3496 */
3497 public int countEntities(Class par1Class)
3498 {
3499 int var2 = 0;
3500
3501 for (int var3 = 0; var3 < this.loadedEntityList.size(); ++var3)
3502 {
3503 Entity var4 = (Entity)this.loadedEntityList.get(var3);
3504
3505 if (par1Class.isAssignableFrom(var4.getClass()))
3506 {
3507 ++var2;
3508 }
3509 }
3510
3511 return var2;
3512 }
3513
3514 /**
3515 * adds entities to the loaded entities list, and loads thier skins.
3516 */
3517 public void addLoadedEntities(List par1List)
3518 {
3519 for (int var2 = 0; var2 < par1List.size(); ++var2)
3520 {
3521 Entity entity = (Entity)par1List.get(var2);
3522 if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(entity, this)))
3523 {
3524 loadedEntityList.add(entity);
3525 this.obtainEntitySkin(entity);
3526 }
3527 }
3528 }
3529
3530 /**
3531 * Adds a list of entities to be unloaded on the next pass of World.updateEntities()
3532 */
3533 public void unloadEntities(List par1List)
3534 {
3535 this.unloadedEntityList.addAll(par1List);
3536 }
3537
3538 /**
3539 * Returns true if the given Entity can be placed on the given side of the given block position.
3540 */
3541 public boolean canPlaceEntityOnSide(int par1, int par2, int par3, int par4, boolean par5, int par6, Entity par7Entity)
3542 {
3543 int var8 = this.getBlockId(par2, par3, par4);
3544 Block var9 = Block.blocksList[var8];
3545 Block var10 = Block.blocksList[par1];
3546 AxisAlignedBB var11 = var10.getCollisionBoundingBoxFromPool(this, par2, par3, par4);
3547
3548 if (par5)
3549 {
3550 var11 = null;
3551 }
3552
3553 if (var11 != null && !this.checkIfAABBIsClearExcludingEntity(var11, par7Entity))
3554 {
3555 return false;
3556 }
3557 else
3558 {
3559 if (var9 != null && (var9 == Block.waterMoving || var9 == Block.waterStill || var9 == Block.lavaMoving || var9 == Block.lavaStill || var9 == Block.fire || var9.blockMaterial.isGroundCover()))
3560 {
3561 var9 = null;
3562 }
3563 if (var9 != null && var9.isBlockReplaceable(this, par2, par3, par4))
3564 {
3565 var9 = null;
3566 }
3567 return par1 > 0 && var9 == null && var10.canPlaceBlockOnSide(this, par2, par3, par4, par6);
3568 }
3569 }
3570
3571 public PathEntity getPathEntityToEntity(Entity par1Entity, Entity par2Entity, float par3, boolean par4, boolean par5, boolean par6, boolean par7)
3572 {
3573 this.theProfiler.startSection("pathfind");
3574 int var8 = MathHelper.floor_double(par1Entity.posX);
3575 int var9 = MathHelper.floor_double(par1Entity.posY + 1.0D);
3576 int var10 = MathHelper.floor_double(par1Entity.posZ);
3577 int var11 = (int)(par3 + 16.0F);
3578 int var12 = var8 - var11;
3579 int var13 = var9 - var11;
3580 int var14 = var10 - var11;
3581 int var15 = var8 + var11;
3582 int var16 = var9 + var11;
3583 int var17 = var10 + var11;
3584 ChunkCache var18 = new ChunkCache(this, var12, var13, var14, var15, var16, var17);
3585 PathEntity var19 = (new PathFinder(var18, par4, par5, par6, par7)).createEntityPathTo(par1Entity, par2Entity, par3);
3586 this.theProfiler.endSection();
3587 return var19;
3588 }
3589
3590 public PathEntity getEntityPathToXYZ(Entity par1Entity, int par2, int par3, int par4, float par5, boolean par6, boolean par7, boolean par8, boolean par9)
3591 {
3592 this.theProfiler.startSection("pathfind");
3593 int var10 = MathHelper.floor_double(par1Entity.posX);
3594 int var11 = MathHelper.floor_double(par1Entity.posY);
3595 int var12 = MathHelper.floor_double(par1Entity.posZ);
3596 int var13 = (int)(par5 + 8.0F);
3597 int var14 = var10 - var13;
3598 int var15 = var11 - var13;
3599 int var16 = var12 - var13;
3600 int var17 = var10 + var13;
3601 int var18 = var11 + var13;
3602 int var19 = var12 + var13;
3603 ChunkCache var20 = new ChunkCache(this, var14, var15, var16, var17, var18, var19);
3604 PathEntity var21 = (new PathFinder(var20, par6, par7, par8, par9)).createEntityPathTo(par1Entity, par2, par3, par4, par5);
3605 this.theProfiler.endSection();
3606 return var21;
3607 }
3608
3609 /**
3610 * Is this block powering in the specified direction Args: x, y, z, direction
3611 */
3612 public boolean isBlockProvidingPowerTo(int par1, int par2, int par3, int par4)
3613 {
3614 int var5 = this.getBlockId(par1, par2, par3);
3615 return var5 == 0 ? false : Block.blocksList[var5].isIndirectlyPoweringTo(this, par1, par2, par3, par4);
3616 }
3617
3618 /**
3619 * Whether one of the neighboring blocks is putting power into this block. Args: x, y, z
3620 */
3621 public boolean isBlockGettingPowered(int par1, int par2, int par3)
3622 {
3623 return this.isBlockProvidingPowerTo(par1, par2 - 1, par3, 0) ? true : (this.isBlockProvidingPowerTo(par1, par2 + 1, par3, 1) ? true : (this.isBlockProvidingPowerTo(par1, par2, par3 - 1, 2) ? true : (this.isBlockProvidingPowerTo(par1, par2, par3 + 1, 3) ? true : (this.isBlockProvidingPowerTo(par1 - 1, par2, par3, 4) ? true : this.isBlockProvidingPowerTo(par1 + 1, par2, par3, 5)))));
3624 }
3625
3626 /**
3627 * Is a block next to you getting powered (if its an attachable block) or is it providing power directly to you.
3628 * Args: x, y, z, direction
3629 */
3630 public boolean isBlockIndirectlyProvidingPowerTo(int par1, int par2, int par3, int par4)
3631 {
3632 if (this.isBlockNormalCube(par1, par2, par3))
3633 {
3634 return this.isBlockGettingPowered(par1, par2, par3);
3635 }
3636 else
3637 {
3638 int var5 = this.getBlockId(par1, par2, par3);
3639 return var5 == 0 ? false : Block.blocksList[var5].isPoweringTo(this, par1, par2, par3, par4);
3640 }
3641 }
3642
3643 /**
3644 * Used to see if one of the blocks next to you or your block is getting power from a neighboring block. Used by
3645 * items like TNT or Doors so they don't have redstone going straight into them. Args: x, y, z
3646 */
3647 public boolean isBlockIndirectlyGettingPowered(int par1, int par2, int par3)
3648 {
3649 return this.isBlockIndirectlyProvidingPowerTo(par1, par2 - 1, par3, 0) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1, par2 + 1, par3, 1) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1, par2, par3 - 1, 2) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1, par2, par3 + 1, 3) ? true : (this.isBlockIndirectlyProvidingPowerTo(par1 - 1, par2, par3, 4) ? true : this.isBlockIndirectlyProvidingPowerTo(par1 + 1, par2, par3, 5)))));
3650 }
3651
3652 /**
3653 * Gets the closest player to the entity within the specified distance (if distance is less than 0 then ignored).
3654 * Args: entity, dist
3655 */
3656 public EntityPlayer getClosestPlayerToEntity(Entity par1Entity, double par2)
3657 {
3658 return this.getClosestPlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2);
3659 }
3660
3661 /**
3662 * Gets the closest player to the point within the specified distance (distance can be set to less than 0 to not
3663 * limit the distance). Args: x, y, z, dist
3664 */
3665 public EntityPlayer getClosestPlayer(double par1, double par3, double par5, double par7)
3666 {
3667 double var9 = -1.0D;
3668 EntityPlayer var11 = null;
3669
3670 for (int var12 = 0; var12 < this.playerEntities.size(); ++var12)
3671 {
3672 EntityPlayer var13 = (EntityPlayer)this.playerEntities.get(var12);
3673 double var14 = var13.getDistanceSq(par1, par3, par5);
3674
3675 if ((par7 < 0.0D || var14 < par7 * par7) && (var9 == -1.0D || var14 < var9))
3676 {
3677 var9 = var14;
3678 var11 = var13;
3679 }
3680 }
3681
3682 return var11;
3683 }
3684
3685 /**
3686 * Returns the closest vulnerable player to this entity within the given radius, or null if none is found
3687 */
3688 public EntityPlayer getClosestVulnerablePlayerToEntity(Entity par1Entity, double par2)
3689 {
3690 return this.getClosestVulnerablePlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2);
3691 }
3692
3693 /**
3694 * Returns the closest vulnerable player within the given radius, or null if none is found.
3695 */
3696 public EntityPlayer getClosestVulnerablePlayer(double par1, double par3, double par5, double par7)
3697 {
3698 double var9 = -1.0D;
3699 EntityPlayer var11 = null;
3700
3701 for (int var12 = 0; var12 < this.playerEntities.size(); ++var12)
3702 {
3703 EntityPlayer var13 = (EntityPlayer)this.playerEntities.get(var12);
3704
3705 if (!var13.capabilities.disableDamage)
3706 {
3707 double var14 = var13.getDistanceSq(par1, par3, par5);
3708
3709 if ((par7 < 0.0D || var14 < par7 * par7) && (var9 == -1.0D || var14 < var9))
3710 {
3711 var9 = var14;
3712 var11 = var13;
3713 }
3714 }
3715 }
3716
3717 return var11;
3718 }
3719
3720 /**
3721 * Find a player by name in this world.
3722 */
3723 public EntityPlayer getPlayerEntityByName(String par1Str)
3724 {
3725 for (int var2 = 0; var2 < this.playerEntities.size(); ++var2)
3726 {
3727 if (par1Str.equals(((EntityPlayer)this.playerEntities.get(var2)).username))
3728 {
3729 return (EntityPlayer)this.playerEntities.get(var2);
3730 }
3731 }
3732
3733 return null;
3734 }
3735
3736 @SideOnly(Side.CLIENT)
3737
3738 /**
3739 * If on MP, sends a quitting packet.
3740 */
3741 public void sendQuittingDisconnectingPacket() {}
3742
3743 /**
3744 * Checks whether the session lock file was modified by another process
3745 */
3746 public void checkSessionLock() throws MinecraftException
3747 {
3748 this.saveHandler.checkSessionLock();
3749 }
3750
3751 /**
3752 * Sets the world time.
3753 */
3754 public void setWorldTime(long par1)
3755 {
3756 provider.setWorldTime(par1);
3757 }
3758
3759 /**
3760 * Retrieve the world seed from level.dat
3761 */
3762 public long getSeed()
3763 {
3764 return provider.getSeed();
3765 }
3766
3767 public long getWorldTime()
3768 {
3769 return provider.getWorldTime();
3770 }
3771
3772 /**
3773 * Returns the coordinates of the spawn point
3774 */
3775 public ChunkCoordinates getSpawnPoint()
3776 {
3777 return provider.getSpawnPoint();
3778 }
3779
3780 @SideOnly(Side.CLIENT)
3781 public void setSpawnLocation(int par1, int par2, int par3)
3782 {
3783 provider.setSpawnPoint(par1, par2, par3);
3784 }
3785
3786 @SideOnly(Side.CLIENT)
3787
3788 /**
3789 * spwans an entity and loads surrounding chunks
3790 */
3791 public void joinEntityInSurroundings(Entity par1Entity)
3792 {
3793 int var2 = MathHelper.floor_double(par1Entity.posX / 16.0D);
3794 int var3 = MathHelper.floor_double(par1Entity.posZ / 16.0D);
3795 byte var4 = 2;
3796
3797 for (int var5 = var2 - var4; var5 <= var2 + var4; ++var5)
3798 {
3799 for (int var6 = var3 - var4; var6 <= var3 + var4; ++var6)
3800 {
3801 this.getChunkFromChunkCoords(var5, var6);
3802 }
3803 }
3804
3805 if (!this.loadedEntityList.contains(par1Entity))
3806 {
3807 if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(par1Entity, this)))
3808 {
3809 loadedEntityList.add(par1Entity);
3810 }
3811 }
3812 }
3813
3814 /**
3815 * Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here.
3816 */
3817 public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
3818 {
3819 return provider.canMineBlock(par1EntityPlayer, par2, par3, par4);
3820 }
3821
3822 public boolean canMineBlockBody(EntityPlayer par1EntityPlayer, int par2, int par3, int par4)
3823 {
3824 return true;
3825 }
3826
3827 /**
3828 * sends a Packet 38 (Entity Status) to all tracked players of that entity
3829 */
3830 public void setEntityState(Entity par1Entity, byte par2) {}
3831
3832 /**
3833 * gets the IChunkProvider this world uses.
3834 */
3835 public IChunkProvider getChunkProvider()
3836 {
3837 return this.chunkProvider;
3838 }
3839
3840 /**
3841 * Adds a block event with the given Args to the blockEventCache. During the next tick(), the block specified will
3842 * have its onBlockEvent handler called with the given parameters. Args: X,Y,Z, BlockID, EventID, EventParameter
3843 */
3844 public void addBlockEvent(int par1, int par2, int par3, int par4, int par5, int par6)
3845 {
3846 if (par4 > 0)
3847 {
3848 Block.blocksList[par4].onBlockEventReceived(this, par1, par2, par3, par5, par6);
3849 }
3850 }
3851
3852 /**
3853 * Returns this world's current save handler
3854 */
3855 public ISaveHandler getSaveHandler()
3856 {
3857 return this.saveHandler;
3858 }
3859
3860 /**
3861 * Gets the World's WorldInfo instance
3862 */
3863 public WorldInfo getWorldInfo()
3864 {
3865 return this.worldInfo;
3866 }
3867
3868 /**
3869 * Updates the flag that indicates whether or not all players in the world are sleeping.
3870 */
3871 public void updateAllPlayersSleepingFlag() {}
3872
3873 public float getWeightedThunderStrength(float par1)
3874 {
3875 return (this.prevThunderingStrength + (this.thunderingStrength - this.prevThunderingStrength) * par1) * this.getRainStrength(par1);
3876 }
3877
3878 /**
3879 * Not sure about this actually. Reverting this one myself.
3880 */
3881 public float getRainStrength(float par1)
3882 {
3883 return this.prevRainingStrength + (this.rainingStrength - this.prevRainingStrength) * par1;
3884 }
3885
3886 @SideOnly(Side.CLIENT)
3887 public void setRainStrength(float par1)
3888 {
3889 this.prevRainingStrength = par1;
3890 this.rainingStrength = par1;
3891 }
3892
3893 /**
3894 * Returns true if the current thunder strength (weighted with the rain strength) is greater than 0.9
3895 */
3896 public boolean isThundering()
3897 {
3898 return (double)this.getWeightedThunderStrength(1.0F) > 0.9D;
3899 }
3900
3901 /**
3902 * Returns true if the current rain strength is greater than 0.2
3903 */
3904 public boolean isRaining()
3905 {
3906 return (double)this.getRainStrength(1.0F) > 0.2D;
3907 }
3908
3909 public boolean canLightningStrikeAt(int par1, int par2, int par3)
3910 {
3911 if (!this.isRaining())
3912 {
3913 return false;
3914 }
3915 else if (!this.canBlockSeeTheSky(par1, par2, par3))
3916 {
3917 return false;
3918 }
3919 else if (this.getPrecipitationHeight(par1, par3) > par2)
3920 {
3921 return false;
3922 }
3923 else
3924 {
3925 BiomeGenBase var4 = this.getBiomeGenForCoords(par1, par3);
3926 return var4.getEnableSnow() ? false : var4.canSpawnLightningBolt();
3927 }
3928 }
3929
3930 /**
3931 * Checks to see if the biome rainfall values for a given x,y,z coordinate set are extremely high
3932 */
3933 public boolean isBlockHighHumidity(int par1, int par2, int par3)
3934 {
3935 return provider.isBlockHighHumidity(par1, par2, par3);
3936 }
3937
3938 /**
3939 * Assigns the given String id to the given MapDataBase using the MapStorage, removing any existing ones of the same
3940 * id.
3941 */
3942 public void setItemData(String par1Str, WorldSavedData par2WorldSavedData)
3943 {
3944 this.mapStorage.setData(par1Str, par2WorldSavedData);
3945 }
3946
3947 /**
3948 * Loads an existing MapDataBase corresponding to the given String id from disk using the MapStorage, instantiating
3949 * the given Class, or returns null if none such file exists. args: Class to instantiate, String dataid
3950 */
3951 public WorldSavedData loadItemData(Class par1Class, String par2Str)
3952 {
3953 return this.mapStorage.loadData(par1Class, par2Str);
3954 }
3955
3956 /**
3957 * Returns an unique new data id from the MapStorage for the given prefix and saves the idCounts map to the
3958 * 'idcounts' file.
3959 */
3960 public int getUniqueDataId(String par1Str)
3961 {
3962 return this.mapStorage.getUniqueDataId(par1Str);
3963 }
3964
3965 /**
3966 * See description for playAuxSFX.
3967 */
3968 public void playAuxSFX(int par1, int par2, int par3, int par4, int par5)
3969 {
3970 this.playAuxSFXAtEntity((EntityPlayer)null, par1, par2, par3, par4, par5);
3971 }
3972
3973 /**
3974 * See description for playAuxSFX.
3975 */
3976 public void playAuxSFXAtEntity(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5, int par6)
3977 {
3978 for (int var7 = 0; var7 < this.worldAccesses.size(); ++var7)
3979 {
3980 ((IWorldAccess)this.worldAccesses.get(var7)).playAuxSFX(par1EntityPlayer, par2, par3, par4, par5, par6);
3981 }
3982 }
3983
3984 /**
3985 * Returns current world height.
3986 */
3987 public int getHeight()
3988 {
3989 return provider.getHeight();
3990 }
3991
3992 /**
3993 * Returns current world height.
3994 */
3995 public int getActualHeight()
3996 {
3997 return provider.getActualHeight();
3998 }
3999
4000 /**
4001 * puts the World Random seed to a specific state dependant on the inputs
4002 */
4003 public Random setRandomSeed(int par1, int par2, int par3)
4004 {
4005 long var4 = (long)par1 * 341873128712L + (long)par2 * 132897987541L + this.getWorldInfo().getSeed() + (long)par3;
4006 this.rand.setSeed(var4);
4007 return this.rand;
4008 }
4009
4010 /**
4011 * Updates lighting. Returns true if there are more lighting updates to update
4012 */
4013 public boolean updatingLighting()
4014 {
4015 return false;
4016 }
4017
4018 /**
4019 * Returns the location of the closest structure of the specified type. If not found returns null.
4020 */
4021 public ChunkPosition findClosestStructure(String par1Str, int par2, int par3, int par4)
4022 {
4023 return this.getChunkProvider().findClosestStructure(this, par1Str, par2, par3, par4);
4024 }
4025
4026 @SideOnly(Side.CLIENT)
4027
4028 /**
4029 * set by !chunk.getAreLevelsEmpty
4030 */
4031 public boolean extendedLevelsInChunkCache()
4032 {
4033 return false;
4034 }
4035
4036 @SideOnly(Side.CLIENT)
4037
4038 /**
4039 * Returns horizon height for use in rendering the sky.
4040 */
4041 public double getHorizon()
4042 {
4043 return provider.getHorizon();
4044 }
4045
4046 /**
4047 * Adds some basic stats of the world to the given crash report.
4048 */
4049 public CrashReport addWorldInfoToCrashReport(CrashReport par1CrashReport)
4050 {
4051 par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Entities", new CallableLvl1(this));
4052 par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Players", new CallableLvl2(this));
4053 par1CrashReport.addCrashSectionCallable("World " + this.worldInfo.getWorldName() + " Chunk Stats", new CallableLvl3(this));
4054 return par1CrashReport;
4055 }
4056
4057 /**
4058 * Starts (or continues) destroying a block with given ID at the given coordinates for the given partially destroyed
4059 * value
4060 */
4061 public void destroyBlockInWorldPartially(int par1, int par2, int par3, int par4, int par5)
4062 {
4063 Iterator var6 = this.worldAccesses.iterator();
4064
4065 while (var6.hasNext())
4066 {
4067 IWorldAccess var7 = (IWorldAccess)var6.next();
4068 var7.destroyBlockPartially(par1, par2, par3, par4, par5);
4069 }
4070 }
4071
4072 /**
4073 * Adds a single TileEntity to the world.
4074 * @param entity The TileEntity to be added.
4075 */
4076 public void addTileEntity(TileEntity entity)
4077 {
4078 List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList;
4079 if(entity.canUpdate())
4080 {
4081 dest.add(entity);
4082 }
4083 }
4084
4085 /**
4086 * Determine if the given block is considered solid on the
4087 * specified side. Used by placement logic.
4088 *
4089 * @param X Block X Position
4090 * @param Y Block Y Position
4091 * @param Z Block Z Position
4092 * @param side The Side in question
4093 * @return True if the side is solid
4094 */
4095 public boolean isBlockSolidOnSide(int X, int Y, int Z, ForgeDirection side)
4096 {
4097 return isBlockSolidOnSide(X, Y, Z, side, false);
4098 }
4099
4100 /**
4101 * Determine if the given block is considered solid on the
4102 * specified side. Used by placement logic.
4103 *
4104 * @param X Block X Position
4105 * @param Y Block Y Position
4106 * @param Z Block Z Position
4107 * @param side The Side in question
4108 * @param _default The defult to return if the block doesn't exist.
4109 * @return True if the side is solid
4110 */
4111 public boolean isBlockSolidOnSide(int X, int Y, int Z, ForgeDirection side, boolean _default)
4112 {
4113 if (X < -30000000 || Z < -30000000 || X >= 30000000 || Z >= 30000000)
4114 {
4115 return _default;
4116 }
4117
4118 Chunk var5 = this.chunkProvider.provideChunk(X >> 4, Z >> 4);
4119 if (var5 == null || var5.isEmpty())
4120 {
4121 return _default;
4122 }
4123
4124 Block block = Block.blocksList[getBlockId(X, Y, Z)];
4125 if(block == null)
4126 {
4127 return false;
4128 }
4129
4130 return block.isBlockSolidOnSide(this, X, Y, Z, side);
4131 }
4132
4133 /**
4134 * Get the persistent chunks for this world
4135 *
4136 * @return
4137 */
4138 SetMultimap<ChunkCoordIntPair, Ticket> getPersistentChunks()
4139 {
4140 return ForgeChunkManager.getPersistentChunksFor(this);
4141 }
4142 }