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