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