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