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