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