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