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