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