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