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