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