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