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 j = entity.chunkCoordX; 2169 k = entity.chunkCoordZ; 2170 2171 if (entity.addedToChunk && this.chunkExists(j, k)) 2172 { 2173 this.getChunkFromChunkCoords(j, k).removeEntity(entity); 2174 } 2175 2176 this.loadedEntityList.remove(i--); 2177 this.releaseEntitySkin(entity); 2178 } 2179 2180 this.theProfiler.endSection(); 2181 } 2182 2183 this.theProfiler.endStartSection("tileEntities"); 2184 this.scanningTileEntities = true; 2185 Iterator iterator = this.loadedTileEntityList.iterator(); 2186 2187 while (iterator.hasNext()) 2188 { 2189 TileEntity tileentity = (TileEntity)iterator.next(); 2190 2191 if (!tileentity.isInvalid() && tileentity.func_70309_m() && this.blockExists(tileentity.xCoord, tileentity.yCoord, tileentity.zCoord)) 2192 { 2193 try 2194 { 2195 tileentity.updateEntity(); 2196 } 2197 catch (Throwable throwable2) 2198 { 2199 crashreport = CrashReport.makeCrashReport(throwable2, "Ticking tile entity"); 2200 crashreportcategory = crashreport.makeCategory("Tile entity being ticked"); 2201 tileentity.func_85027_a(crashreportcategory); 2202 if (ForgeDummyContainer.removeErroringTileEntities) 2203 { 2204 FMLLog.severe(crashreport.getCompleteReport()); 2205 tileentity.invalidate(); 2206 setBlockToAir(tileentity.xCoord, tileentity.yCoord, tileentity.zCoord); 2207 } 2208 else 2209 { 2210 throw new ReportedException(crashreport); 2211 } 2212 } 2213 } 2214 2215 if (tileentity.isInvalid()) 2216 { 2217 iterator.remove(); 2218 2219 if (this.chunkExists(tileentity.xCoord >> 4, tileentity.zCoord >> 4)) 2220 { 2221 Chunk chunk = this.getChunkFromChunkCoords(tileentity.xCoord >> 4, tileentity.zCoord >> 4); 2222 2223 if (chunk != null) 2224 { 2225 chunk.cleanChunkBlockTileEntity(tileentity.xCoord & 15, tileentity.yCoord, tileentity.zCoord & 15); 2226 } 2227 } 2228 } 2229 } 2230 2231 2232 if (!this.entityRemoval.isEmpty()) 2233 { 2234 for (Object tile : entityRemoval) 2235 { 2236 ((TileEntity)tile).onChunkUnload(); 2237 } 2238 this.loadedTileEntityList.removeAll(this.entityRemoval); 2239 this.entityRemoval.clear(); 2240 } 2241 2242 this.scanningTileEntities = false; 2243 2244 this.theProfiler.endStartSection("pendingTileEntities"); 2245 2246 if (!this.addedTileEntityList.isEmpty()) 2247 { 2248 for (int l = 0; l < this.addedTileEntityList.size(); ++l) 2249 { 2250 TileEntity tileentity1 = (TileEntity)this.addedTileEntityList.get(l); 2251 2252 if (!tileentity1.isInvalid()) 2253 { 2254 if (!this.loadedTileEntityList.contains(tileentity1)) 2255 { 2256 this.loadedTileEntityList.add(tileentity1); 2257 } 2258 } 2259 else 2260 { 2261 if (this.chunkExists(tileentity1.xCoord >> 4, tileentity1.zCoord >> 4)) 2262 { 2263 Chunk chunk1 = this.getChunkFromChunkCoords(tileentity1.xCoord >> 4, tileentity1.zCoord >> 4); 2264 2265 if (chunk1 != null) 2266 { 2267 chunk1.cleanChunkBlockTileEntity(tileentity1.xCoord & 15, tileentity1.yCoord, tileentity1.zCoord & 15); 2268 } 2269 } 2270 } 2271 } 2272 2273 this.addedTileEntityList.clear(); 2274 } 2275 2276 this.theProfiler.endSection(); 2277 this.theProfiler.endSection(); 2278 } 2279 2280 public void addTileEntity(Collection par1Collection) 2281 { 2282 List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList; 2283 for(Object entity : par1Collection) 2284 { 2285 if(((TileEntity)entity).canUpdate()) 2286 { 2287 dest.add(entity); 2288 } 2289 } 2290 } 2291 2292 /** 2293 * Will update the entity in the world if the chunk the entity is in is currently loaded. Args: entity 2294 */ 2295 public void updateEntity(Entity par1Entity) 2296 { 2297 this.updateEntityWithOptionalForce(par1Entity, true); 2298 } 2299 2300 /** 2301 * Will update the entity in the world if the chunk the entity is in is currently loaded or its forced to update. 2302 * Args: entity, forceUpdate 2303 */ 2304 public void updateEntityWithOptionalForce(Entity par1Entity, boolean par2) 2305 { 2306 int i = MathHelper.floor_double(par1Entity.posX); 2307 int j = MathHelper.floor_double(par1Entity.posZ); 2308 2309 boolean isForced = getPersistentChunks().containsKey(new ChunkCoordIntPair(i >> 4, j >> 4)); 2310 byte b0 = isForced ? (byte)0 : 32; 2311 boolean canUpdate = !par2 || this.checkChunksExist(i - b0, 0, j - b0, i + b0, 0, j + b0); 2312 if (!canUpdate) 2313 { 2314 EntityEvent.CanUpdate event = new EntityEvent.CanUpdate(par1Entity); 2315 MinecraftForge.EVENT_BUS.post(event); 2316 canUpdate = event.canUpdate; 2317 } 2318 if (canUpdate) 2319 { 2320 par1Entity.lastTickPosX = par1Entity.posX; 2321 par1Entity.lastTickPosY = par1Entity.posY; 2322 par1Entity.lastTickPosZ = par1Entity.posZ; 2323 par1Entity.prevRotationYaw = par1Entity.rotationYaw; 2324 par1Entity.prevRotationPitch = par1Entity.rotationPitch; 2325 2326 if (par2 && par1Entity.addedToChunk) 2327 { 2328 if (par1Entity.ridingEntity != null) 2329 { 2330 par1Entity.updateRidden(); 2331 } 2332 else 2333 { 2334 ++par1Entity.ticksExisted; 2335 par1Entity.onUpdate(); 2336 } 2337 } 2338 2339 this.theProfiler.startSection("chunkCheck"); 2340 2341 if (Double.isNaN(par1Entity.posX) || Double.isInfinite(par1Entity.posX)) 2342 { 2343 par1Entity.posX = par1Entity.lastTickPosX; 2344 } 2345 2346 if (Double.isNaN(par1Entity.posY) || Double.isInfinite(par1Entity.posY)) 2347 { 2348 par1Entity.posY = par1Entity.lastTickPosY; 2349 } 2350 2351 if (Double.isNaN(par1Entity.posZ) || Double.isInfinite(par1Entity.posZ)) 2352 { 2353 par1Entity.posZ = par1Entity.lastTickPosZ; 2354 } 2355 2356 if (Double.isNaN((double)par1Entity.rotationPitch) || Double.isInfinite((double)par1Entity.rotationPitch)) 2357 { 2358 par1Entity.rotationPitch = par1Entity.prevRotationPitch; 2359 } 2360 2361 if (Double.isNaN((double)par1Entity.rotationYaw) || Double.isInfinite((double)par1Entity.rotationYaw)) 2362 { 2363 par1Entity.rotationYaw = par1Entity.prevRotationYaw; 2364 } 2365 2366 int k = MathHelper.floor_double(par1Entity.posX / 16.0D); 2367 int l = MathHelper.floor_double(par1Entity.posY / 16.0D); 2368 int i1 = MathHelper.floor_double(par1Entity.posZ / 16.0D); 2369 2370 if (!par1Entity.addedToChunk || par1Entity.chunkCoordX != k || par1Entity.chunkCoordY != l || par1Entity.chunkCoordZ != i1) 2371 { 2372 if (par1Entity.addedToChunk && this.chunkExists(par1Entity.chunkCoordX, par1Entity.chunkCoordZ)) 2373 { 2374 this.getChunkFromChunkCoords(par1Entity.chunkCoordX, par1Entity.chunkCoordZ).removeEntityAtIndex(par1Entity, par1Entity.chunkCoordY); 2375 } 2376 2377 if (this.chunkExists(k, i1)) 2378 { 2379 par1Entity.addedToChunk = true; 2380 this.getChunkFromChunkCoords(k, i1).addEntity(par1Entity); 2381 } 2382 else 2383 { 2384 par1Entity.addedToChunk = false; 2385 } 2386 } 2387 2388 this.theProfiler.endSection(); 2389 2390 if (par2 && par1Entity.addedToChunk && par1Entity.riddenByEntity != null) 2391 { 2392 if (!par1Entity.riddenByEntity.isDead && par1Entity.riddenByEntity.ridingEntity == par1Entity) 2393 { 2394 this.updateEntity(par1Entity.riddenByEntity); 2395 } 2396 else 2397 { 2398 par1Entity.riddenByEntity.ridingEntity = null; 2399 par1Entity.riddenByEntity = null; 2400 } 2401 } 2402 } 2403 } 2404 2405 /** 2406 * Returns true if there are no solid, live entities in the specified AxisAlignedBB 2407 */ 2408 public boolean checkIfAABBIsClear(AxisAlignedBB par1AxisAlignedBB) 2409 { 2410 return this.checkIfAABBIsClearExcludingEntity(par1AxisAlignedBB, (Entity)null); 2411 } 2412 2413 /** 2414 * Returns true if there are no solid, live entities in the specified AxisAlignedBB, excluding the given entity 2415 */ 2416 public boolean checkIfAABBIsClearExcludingEntity(AxisAlignedBB par1AxisAlignedBB, Entity par2Entity) 2417 { 2418 List list = this.getEntitiesWithinAABBExcludingEntity((Entity)null, par1AxisAlignedBB); 2419 2420 for (int i = 0; i < list.size(); ++i) 2421 { 2422 Entity entity1 = (Entity)list.get(i); 2423 2424 if (!entity1.isDead && entity1.preventEntitySpawning && entity1 != par2Entity) 2425 { 2426 return false; 2427 } 2428 } 2429 2430 return true; 2431 } 2432 2433 /** 2434 * Returns true if there are any blocks in the region constrained by an AxisAlignedBB 2435 */ 2436 public boolean isAABBNonEmpty(AxisAlignedBB par1AxisAlignedBB) 2437 { 2438 int i = MathHelper.floor_double(par1AxisAlignedBB.minX); 2439 int j = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D); 2440 int k = MathHelper.floor_double(par1AxisAlignedBB.minY); 2441 int l = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D); 2442 int i1 = MathHelper.floor_double(par1AxisAlignedBB.minZ); 2443 int j1 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D); 2444 2445 if (par1AxisAlignedBB.minX < 0.0D) 2446 { 2447 --i; 2448 } 2449 2450 if (par1AxisAlignedBB.minY < 0.0D) 2451 { 2452 --k; 2453 } 2454 2455 if (par1AxisAlignedBB.minZ < 0.0D) 2456 { 2457 --i1; 2458 } 2459 2460 for (int k1 = i; k1 < j; ++k1) 2461 { 2462 for (int l1 = k; l1 < l; ++l1) 2463 { 2464 for (int i2 = i1; i2 < j1; ++i2) 2465 { 2466 Block block = Block.blocksList[this.getBlockId(k1, l1, i2)]; 2467 2468 if (block != null) 2469 { 2470 return true; 2471 } 2472 } 2473 } 2474 } 2475 2476 return false; 2477 } 2478 2479 /** 2480 * Returns if any of the blocks within the aabb are liquids. Args: aabb 2481 */ 2482 public boolean isAnyLiquid(AxisAlignedBB par1AxisAlignedBB) 2483 { 2484 int i = MathHelper.floor_double(par1AxisAlignedBB.minX); 2485 int j = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D); 2486 int k = MathHelper.floor_double(par1AxisAlignedBB.minY); 2487 int l = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D); 2488 int i1 = MathHelper.floor_double(par1AxisAlignedBB.minZ); 2489 int j1 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D); 2490 2491 if (par1AxisAlignedBB.minX < 0.0D) 2492 { 2493 --i; 2494 } 2495 2496 if (par1AxisAlignedBB.minY < 0.0D) 2497 { 2498 --k; 2499 } 2500 2501 if (par1AxisAlignedBB.minZ < 0.0D) 2502 { 2503 --i1; 2504 } 2505 2506 for (int k1 = i; k1 < j; ++k1) 2507 { 2508 for (int l1 = k; l1 < l; ++l1) 2509 { 2510 for (int i2 = i1; i2 < j1; ++i2) 2511 { 2512 Block block = Block.blocksList[this.getBlockId(k1, l1, i2)]; 2513 2514 if (block != null && block.blockMaterial.isLiquid()) 2515 { 2516 return true; 2517 } 2518 } 2519 } 2520 } 2521 2522 return false; 2523 } 2524 2525 /** 2526 * Returns whether or not the given bounding box is on fire or not 2527 */ 2528 public boolean isBoundingBoxBurning(AxisAlignedBB par1AxisAlignedBB) 2529 { 2530 int i = MathHelper.floor_double(par1AxisAlignedBB.minX); 2531 int j = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D); 2532 int k = MathHelper.floor_double(par1AxisAlignedBB.minY); 2533 int l = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D); 2534 int i1 = MathHelper.floor_double(par1AxisAlignedBB.minZ); 2535 int j1 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D); 2536 2537 if (this.checkChunksExist(i, k, i1, j, l, j1)) 2538 { 2539 for (int k1 = i; k1 < j; ++k1) 2540 { 2541 for (int l1 = k; l1 < l; ++l1) 2542 { 2543 for (int i2 = i1; i2 < j1; ++i2) 2544 { 2545 int j2 = this.getBlockId(k1, l1, i2); 2546 2547 if (j2 == Block.fire.blockID || j2 == Block.lavaMoving.blockID || j2 == Block.lavaStill.blockID) 2548 { 2549 return true; 2550 } 2551 else 2552 { 2553 Block block = Block.blocksList[j2]; 2554 if (block != null && block.isBlockBurning(this, k1, l1, i2)) 2555 { 2556 return true; 2557 } 2558 } 2559 } 2560 } 2561 } 2562 } 2563 2564 return false; 2565 } 2566 2567 /** 2568 * handles the acceleration of an object whilst in water. Not sure if it is used elsewhere. 2569 */ 2570 public boolean handleMaterialAcceleration(AxisAlignedBB par1AxisAlignedBB, Material par2Material, Entity par3Entity) 2571 { 2572 int i = MathHelper.floor_double(par1AxisAlignedBB.minX); 2573 int j = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D); 2574 int k = MathHelper.floor_double(par1AxisAlignedBB.minY); 2575 int l = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D); 2576 int i1 = MathHelper.floor_double(par1AxisAlignedBB.minZ); 2577 int j1 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D); 2578 2579 if (!this.checkChunksExist(i, k, i1, j, l, j1)) 2580 { 2581 return false; 2582 } 2583 else 2584 { 2585 boolean flag = false; 2586 Vec3 vec3 = this.getWorldVec3Pool().getVecFromPool(0.0D, 0.0D, 0.0D); 2587 2588 for (int k1 = i; k1 < j; ++k1) 2589 { 2590 for (int l1 = k; l1 < l; ++l1) 2591 { 2592 for (int i2 = i1; i2 < j1; ++i2) 2593 { 2594 Block block = Block.blocksList[this.getBlockId(k1, l1, i2)]; 2595 2596 if (block != null && block.blockMaterial == par2Material) 2597 { 2598 double d0 = (double)((float)(l1 + 1) - BlockFluid.getFluidHeightPercent(this.getBlockMetadata(k1, l1, i2))); 2599 2600 if ((double)l >= d0) 2601 { 2602 flag = true; 2603 block.velocityToAddToEntity(this, k1, l1, i2, par3Entity, vec3); 2604 } 2605 } 2606 } 2607 } 2608 } 2609 2610 if (vec3.lengthVector() > 0.0D && par3Entity.func_96092_aw()) 2611 { 2612 vec3 = vec3.normalize(); 2613 double d1 = 0.014D; 2614 par3Entity.motionX += vec3.xCoord * d1; 2615 par3Entity.motionY += vec3.yCoord * d1; 2616 par3Entity.motionZ += vec3.zCoord * d1; 2617 } 2618 2619 return flag; 2620 } 2621 } 2622 2623 /** 2624 * Returns true if the given bounding box contains the given material 2625 */ 2626 public boolean isMaterialInBB(AxisAlignedBB par1AxisAlignedBB, Material par2Material) 2627 { 2628 int i = MathHelper.floor_double(par1AxisAlignedBB.minX); 2629 int j = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D); 2630 int k = MathHelper.floor_double(par1AxisAlignedBB.minY); 2631 int l = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D); 2632 int i1 = MathHelper.floor_double(par1AxisAlignedBB.minZ); 2633 int j1 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D); 2634 2635 for (int k1 = i; k1 < j; ++k1) 2636 { 2637 for (int l1 = k; l1 < l; ++l1) 2638 { 2639 for (int i2 = i1; i2 < j1; ++i2) 2640 { 2641 Block block = Block.blocksList[this.getBlockId(k1, l1, i2)]; 2642 2643 if (block != null && block.blockMaterial == par2Material) 2644 { 2645 return true; 2646 } 2647 } 2648 } 2649 } 2650 2651 return false; 2652 } 2653 2654 /** 2655 * checks if the given AABB is in the material given. Used while swimming. 2656 */ 2657 public boolean isAABBInMaterial(AxisAlignedBB par1AxisAlignedBB, Material par2Material) 2658 { 2659 int i = MathHelper.floor_double(par1AxisAlignedBB.minX); 2660 int j = MathHelper.floor_double(par1AxisAlignedBB.maxX + 1.0D); 2661 int k = MathHelper.floor_double(par1AxisAlignedBB.minY); 2662 int l = MathHelper.floor_double(par1AxisAlignedBB.maxY + 1.0D); 2663 int i1 = MathHelper.floor_double(par1AxisAlignedBB.minZ); 2664 int j1 = MathHelper.floor_double(par1AxisAlignedBB.maxZ + 1.0D); 2665 2666 for (int k1 = i; k1 < j; ++k1) 2667 { 2668 for (int l1 = k; l1 < l; ++l1) 2669 { 2670 for (int i2 = i1; i2 < j1; ++i2) 2671 { 2672 Block block = Block.blocksList[this.getBlockId(k1, l1, i2)]; 2673 2674 if (block != null && block.blockMaterial == par2Material) 2675 { 2676 int j2 = this.getBlockMetadata(k1, l1, i2); 2677 double d0 = (double)(l1 + 1); 2678 2679 if (j2 < 8) 2680 { 2681 d0 = (double)(l1 + 1) - (double)j2 / 8.0D; 2682 } 2683 2684 if (d0 >= par1AxisAlignedBB.minY) 2685 { 2686 return true; 2687 } 2688 } 2689 } 2690 } 2691 } 2692 2693 return false; 2694 } 2695 2696 /** 2697 * Creates an explosion. Args: entity, x, y, z, strength 2698 */ 2699 public Explosion createExplosion(Entity par1Entity, double par2, double par4, double par6, float par8, boolean par9) 2700 { 2701 return this.newExplosion(par1Entity, par2, par4, par6, par8, false, par9); 2702 } 2703 2704 /** 2705 * returns a new explosion. Does initiation (at time of writing Explosion is not finished) 2706 */ 2707 public Explosion newExplosion(Entity par1Entity, double par2, double par4, double par6, float par8, boolean par9, boolean par10) 2708 { 2709 Explosion explosion = new Explosion(this, par1Entity, par2, par4, par6, par8); 2710 explosion.isFlaming = par9; 2711 explosion.isSmoking = par10; 2712 explosion.doExplosionA(); 2713 explosion.doExplosionB(true); 2714 return explosion; 2715 } 2716 2717 /** 2718 * Gets the percentage of real blocks within within a bounding box, along a specified vector. 2719 */ 2720 public float getBlockDensity(Vec3 par1Vec3, AxisAlignedBB par2AxisAlignedBB) 2721 { 2722 double d0 = 1.0D / ((par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * 2.0D + 1.0D); 2723 double d1 = 1.0D / ((par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * 2.0D + 1.0D); 2724 double d2 = 1.0D / ((par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * 2.0D + 1.0D); 2725 int i = 0; 2726 int j = 0; 2727 2728 for (float f = 0.0F; f <= 1.0F; f = (float)((double)f + d0)) 2729 { 2730 for (float f1 = 0.0F; f1 <= 1.0F; f1 = (float)((double)f1 + d1)) 2731 { 2732 for (float f2 = 0.0F; f2 <= 1.0F; f2 = (float)((double)f2 + d2)) 2733 { 2734 double d3 = par2AxisAlignedBB.minX + (par2AxisAlignedBB.maxX - par2AxisAlignedBB.minX) * (double)f; 2735 double d4 = par2AxisAlignedBB.minY + (par2AxisAlignedBB.maxY - par2AxisAlignedBB.minY) * (double)f1; 2736 double d5 = par2AxisAlignedBB.minZ + (par2AxisAlignedBB.maxZ - par2AxisAlignedBB.minZ) * (double)f2; 2737 2738 if (this.rayTraceBlocks(this.getWorldVec3Pool().getVecFromPool(d3, d4, d5), par1Vec3) == null) 2739 { 2740 ++i; 2741 } 2742 2743 ++j; 2744 } 2745 } 2746 } 2747 2748 return (float)i / (float)j; 2749 } 2750 2751 /** 2752 * If the block in the given direction of the given coordinate is fire, extinguish it. Args: Player, X,Y,Z, 2753 * blockDirection 2754 */ 2755 public boolean extinguishFire(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5) 2756 { 2757 if (par5 == 0) 2758 { 2759 --par3; 2760 } 2761 2762 if (par5 == 1) 2763 { 2764 ++par3; 2765 } 2766 2767 if (par5 == 2) 2768 { 2769 --par4; 2770 } 2771 2772 if (par5 == 3) 2773 { 2774 ++par4; 2775 } 2776 2777 if (par5 == 4) 2778 { 2779 --par2; 2780 } 2781 2782 if (par5 == 5) 2783 { 2784 ++par2; 2785 } 2786 2787 if (this.getBlockId(par2, par3, par4) == Block.fire.blockID) 2788 { 2789 this.playAuxSFXAtEntity(par1EntityPlayer, 1004, par2, par3, par4, 0); 2790 this.setBlockToAir(par2, par3, par4); 2791 return true; 2792 } 2793 else 2794 { 2795 return false; 2796 } 2797 } 2798 2799 @SideOnly(Side.CLIENT) 2800 2801 /** 2802 * This string is 'All: (number of loaded entities)' Viewable by press ing F3 2803 */ 2804 public String getDebugLoadedEntities() 2805 { 2806 return "All: " + this.loadedEntityList.size(); 2807 } 2808 2809 @SideOnly(Side.CLIENT) 2810 2811 /** 2812 * Returns the name of the current chunk provider, by calling chunkprovider.makeString() 2813 */ 2814 public String getProviderName() 2815 { 2816 return this.chunkProvider.makeString(); 2817 } 2818 2819 /** 2820 * Returns the TileEntity associated with a given block in X,Y,Z coordinates, or null if no TileEntity exists 2821 */ 2822 public TileEntity getBlockTileEntity(int par1, int par2, int par3) 2823 { 2824 if (par2 >= 0 && par2 < 256) 2825 { 2826 TileEntity tileentity = null; 2827 int l; 2828 TileEntity tileentity1; 2829 2830 if (this.scanningTileEntities) 2831 { 2832 for (l = 0; l < this.addedTileEntityList.size(); ++l) 2833 { 2834 tileentity1 = (TileEntity)this.addedTileEntityList.get(l); 2835 2836 if (!tileentity1.isInvalid() && tileentity1.xCoord == par1 && tileentity1.yCoord == par2 && tileentity1.zCoord == par3) 2837 { 2838 tileentity = tileentity1; 2839 break; 2840 } 2841 } 2842 } 2843 2844 if (tileentity == null) 2845 { 2846 Chunk chunk = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4); 2847 2848 if (chunk != null) 2849 { 2850 tileentity = chunk.getChunkBlockTileEntity(par1 & 15, par2, par3 & 15); 2851 } 2852 } 2853 2854 if (tileentity == null) 2855 { 2856 for (l = 0; l < this.addedTileEntityList.size(); ++l) 2857 { 2858 tileentity1 = (TileEntity)this.addedTileEntityList.get(l); 2859 2860 if (!tileentity1.isInvalid() && tileentity1.xCoord == par1 && tileentity1.yCoord == par2 && tileentity1.zCoord == par3) 2861 { 2862 tileentity = tileentity1; 2863 break; 2864 } 2865 } 2866 } 2867 2868 return tileentity; 2869 } 2870 else 2871 { 2872 return null; 2873 } 2874 } 2875 2876 /** 2877 * Sets the TileEntity for a given block in X, Y, Z coordinates 2878 */ 2879 public void setBlockTileEntity(int par1, int par2, int par3, TileEntity par4TileEntity) 2880 { 2881 if (par4TileEntity == null || par4TileEntity.isInvalid()) 2882 { 2883 return; 2884 } 2885 2886 if (par4TileEntity.canUpdate()) 2887 { 2888 if (scanningTileEntities) 2889 { 2890 Iterator iterator = addedTileEntityList.iterator(); 2891 while (iterator.hasNext()) 2892 { 2893 TileEntity tileentity1 = (TileEntity)iterator.next(); 2894 2895 if (tileentity1.xCoord == par1 && tileentity1.yCoord == par2 && tileentity1.zCoord == par3) 2896 { 2897 tileentity1.invalidate(); 2898 iterator.remove(); 2899 } 2900 } 2901 addedTileEntityList.add(par4TileEntity); 2902 } 2903 else 2904 { 2905 loadedTileEntityList.add(par4TileEntity); 2906 } 2907 } 2908 2909 Chunk chunk = this.getChunkFromChunkCoords(par1 >> 4, par3 >> 4); 2910 if (chunk != null) 2911 { 2912 chunk.setChunkBlockTileEntity(par1 & 15, par2, par3 & 15, par4TileEntity); 2913 } 2914 } 2915 2916 /** 2917 * Removes the TileEntity for a given block in X,Y,Z coordinates 2918 */ 2919 public void removeBlockTileEntity(int par1, int par2, int par3) 2920 { 2921 Chunk chunk = getChunkFromChunkCoords(par1 >> 4, par3 >> 4); 2922 if (chunk != null) 2923 { 2924 chunk.removeChunkBlockTileEntity(par1 & 15, par2, par3 & 15); 2925 } 2926 } 2927 2928 /** 2929 * adds tile entity to despawn list (renamed from markEntityForDespawn) 2930 */ 2931 public void markTileEntityForDespawn(TileEntity par1TileEntity) 2932 { 2933 this.entityRemoval.add(par1TileEntity); 2934 } 2935 2936 /** 2937 * Returns true if the block at the specified coordinates is an opaque cube. Args: x, y, z 2938 */ 2939 public boolean isBlockOpaqueCube(int par1, int par2, int par3) 2940 { 2941 Block block = Block.blocksList[this.getBlockId(par1, par2, par3)]; 2942 return block == null ? false : block.isOpaqueCube(); 2943 } 2944 2945 /** 2946 * Indicate if a material is a normal solid opaque cube. 2947 */ 2948 public boolean isBlockNormalCube(int par1, int par2, int par3) 2949 { 2950 Block block = Block.blocksList[getBlockId(par1, par2, par3)]; 2951 return block != null && block.isBlockNormalCube(this, par1, par2, par3); 2952 } 2953 2954 public boolean func_85174_u(int par1, int par2, int par3) 2955 { 2956 int l = this.getBlockId(par1, par2, par3); 2957 2958 if (l != 0 && Block.blocksList[l] != null) 2959 { 2960 AxisAlignedBB axisalignedbb = Block.blocksList[l].getCollisionBoundingBoxFromPool(this, par1, par2, par3); 2961 return axisalignedbb != null && axisalignedbb.getAverageEdgeLength() >= 1.0D; 2962 } 2963 else 2964 { 2965 return false; 2966 } 2967 } 2968 2969 /** 2970 * Returns true if the block at the given coordinate has a solid (buildable) top surface. 2971 */ 2972 public boolean doesBlockHaveSolidTopSurface(int par1, int par2, int par3) 2973 { 2974 return isBlockSolidOnSide(par1, par2, par3, ForgeDirection.UP); 2975 } 2976 2977 @Deprecated //DO NOT USE THIS!!! USE doesBlockHaveSolidTopSurface 2978 public boolean func_102026_a(Block par1Block, int par2) 2979 { 2980 // -.- Mojang PLEASE make this location sensitive, you have no reason not to. 2981 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))))); 2982 } 2983 2984 /** 2985 * Checks if the block is a solid, normal cube. If the chunk does not exist, or is not loaded, it returns the 2986 * boolean parameter. 2987 */ 2988 public boolean isBlockNormalCubeDefault(int par1, int par2, int par3, boolean par4) 2989 { 2990 if (par1 >= -30000000 && par3 >= -30000000 && par1 < 30000000 && par3 < 30000000) 2991 { 2992 Chunk chunk = this.chunkProvider.provideChunk(par1 >> 4, par3 >> 4); 2993 2994 if (chunk != null && !chunk.isEmpty()) 2995 { 2996 Block block = Block.blocksList[this.getBlockId(par1, par2, par3)]; 2997 return block == null ? false : isBlockNormalCube(par1, par2, par3); 2998 } 2999 else 3000 { 3001 return par4; 3002 } 3003 } 3004 else 3005 { 3006 return par4; 3007 } 3008 } 3009 3010 /** 3011 * Called on construction of the World class to setup the initial skylight values 3012 */ 3013 public void calculateInitialSkylight() 3014 { 3015 int i = this.calculateSkylightSubtracted(1.0F); 3016 3017 if (i != this.skylightSubtracted) 3018 { 3019 this.skylightSubtracted = i; 3020 } 3021 } 3022 3023 /** 3024 * Set which types of mobs are allowed to spawn (peaceful vs hostile). 3025 */ 3026 public void setAllowedSpawnTypes(boolean par1, boolean par2) 3027 { 3028 provider.setAllowedSpawnTypes(par1, par2); 3029 } 3030 3031 /** 3032 * Runs a single tick for the world 3033 */ 3034 public void tick() 3035 { 3036 this.updateWeather(); 3037 } 3038 3039 /** 3040 * Called from World constructor to set rainingStrength and thunderingStrength 3041 */ 3042 private void calculateInitialWeather() 3043 { 3044 provider.calculateInitialWeather(); 3045 } 3046 3047 public void calculateInitialWeatherBody() 3048 { 3049 if (this.worldInfo.isRaining()) 3050 { 3051 this.rainingStrength = 1.0F; 3052 3053 if (this.worldInfo.isThundering()) 3054 { 3055 this.thunderingStrength = 1.0F; 3056 } 3057 } 3058 } 3059 3060 /** 3061 * Updates all weather states. 3062 */ 3063 protected void updateWeather() 3064 { 3065 provider.updateWeather(); 3066 } 3067 3068 public void updateWeatherBody() 3069 { 3070 if (!this.provider.hasNoSky) 3071 { 3072 int i = this.worldInfo.getThunderTime(); 3073 3074 if (i <= 0) 3075 { 3076 if (this.worldInfo.isThundering()) 3077 { 3078 this.worldInfo.setThunderTime(this.rand.nextInt(12000) + 3600); 3079 } 3080 else 3081 { 3082 this.worldInfo.setThunderTime(this.rand.nextInt(168000) + 12000); 3083 } 3084 } 3085 else 3086 { 3087 --i; 3088 this.worldInfo.setThunderTime(i); 3089 3090 if (i <= 0) 3091 { 3092 this.worldInfo.setThundering(!this.worldInfo.isThundering()); 3093 } 3094 } 3095 3096 int j = this.worldInfo.getRainTime(); 3097 3098 if (j <= 0) 3099 { 3100 if (this.worldInfo.isRaining()) 3101 { 3102 this.worldInfo.setRainTime(this.rand.nextInt(12000) + 12000); 3103 } 3104 else 3105 { 3106 this.worldInfo.setRainTime(this.rand.nextInt(168000) + 12000); 3107 } 3108 } 3109 else 3110 { 3111 --j; 3112 this.worldInfo.setRainTime(j); 3113 3114 if (j <= 0) 3115 { 3116 this.worldInfo.setRaining(!this.worldInfo.isRaining()); 3117 } 3118 } 3119 3120 this.prevRainingStrength = this.rainingStrength; 3121 3122 if (this.worldInfo.isRaining()) 3123 { 3124 this.rainingStrength = (float)((double)this.rainingStrength + 0.01D); 3125 } 3126 else 3127 { 3128 this.rainingStrength = (float)((double)this.rainingStrength - 0.01D); 3129 } 3130 3131 if (this.rainingStrength < 0.0F) 3132 { 3133 this.rainingStrength = 0.0F; 3134 } 3135 3136 if (this.rainingStrength > 1.0F) 3137 { 3138 this.rainingStrength = 1.0F; 3139 } 3140 3141 this.prevThunderingStrength = this.thunderingStrength; 3142 3143 if (this.worldInfo.isThundering()) 3144 { 3145 this.thunderingStrength = (float)((double)this.thunderingStrength + 0.01D); 3146 } 3147 else 3148 { 3149 this.thunderingStrength = (float)((double)this.thunderingStrength - 0.01D); 3150 } 3151 3152 if (this.thunderingStrength < 0.0F) 3153 { 3154 this.thunderingStrength = 0.0F; 3155 } 3156 3157 if (this.thunderingStrength > 1.0F) 3158 { 3159 this.thunderingStrength = 1.0F; 3160 } 3161 } 3162 } 3163 3164 public void toggleRain() 3165 { 3166 provider.toggleRain(); 3167 } 3168 3169 protected void setActivePlayerChunksAndCheckLight() 3170 { 3171 this.activeChunkSet.clear(); 3172 this.activeChunkSet.addAll(getPersistentChunks().keySet()); 3173 3174 this.theProfiler.startSection("buildList"); 3175 int i; 3176 EntityPlayer entityplayer; 3177 int j; 3178 int k; 3179 3180 for (i = 0; i < this.playerEntities.size(); ++i) 3181 { 3182 entityplayer = (EntityPlayer)this.playerEntities.get(i); 3183 j = MathHelper.floor_double(entityplayer.posX / 16.0D); 3184 k = MathHelper.floor_double(entityplayer.posZ / 16.0D); 3185 byte b0 = 7; 3186 3187 for (int l = -b0; l <= b0; ++l) 3188 { 3189 for (int i1 = -b0; i1 <= b0; ++i1) 3190 { 3191 this.activeChunkSet.add(new ChunkCoordIntPair(l + j, i1 + k)); 3192 } 3193 } 3194 } 3195 3196 this.theProfiler.endSection(); 3197 3198 if (this.ambientTickCountdown > 0) 3199 { 3200 --this.ambientTickCountdown; 3201 } 3202 3203 this.theProfiler.startSection("playerCheckLight"); 3204 3205 if (!this.playerEntities.isEmpty()) 3206 { 3207 i = this.rand.nextInt(this.playerEntities.size()); 3208 entityplayer = (EntityPlayer)this.playerEntities.get(i); 3209 j = MathHelper.floor_double(entityplayer.posX) + this.rand.nextInt(11) - 5; 3210 k = MathHelper.floor_double(entityplayer.posY) + this.rand.nextInt(11) - 5; 3211 int j1 = MathHelper.floor_double(entityplayer.posZ) + this.rand.nextInt(11) - 5; 3212 this.updateAllLightTypes(j, k, j1); 3213 } 3214 3215 this.theProfiler.endSection(); 3216 } 3217 3218 protected void moodSoundAndLightCheck(int par1, int par2, Chunk par3Chunk) 3219 { 3220 this.theProfiler.endStartSection("moodSound"); 3221 3222 if (this.ambientTickCountdown == 0 && !this.isRemote) 3223 { 3224 this.updateLCG = this.updateLCG * 3 + 1013904223; 3225 int k = this.updateLCG >> 2; 3226 int l = k & 15; 3227 int i1 = k >> 8 & 15; 3228 int j1 = k >> 16 & 127; 3229 int k1 = par3Chunk.getBlockID(l, j1, i1); 3230 l += par1; 3231 i1 += par2; 3232 3233 if (k1 == 0 && this.getFullBlockLightValue(l, j1, i1) <= this.rand.nextInt(8) && this.getSavedLightValue(EnumSkyBlock.Sky, l, j1, i1) <= 0) 3234 { 3235 EntityPlayer entityplayer = this.getClosestPlayer((double)l + 0.5D, (double)j1 + 0.5D, (double)i1 + 0.5D, 8.0D); 3236 3237 if (entityplayer != null && entityplayer.getDistanceSq((double)l + 0.5D, (double)j1 + 0.5D, (double)i1 + 0.5D) > 4.0D) 3238 { 3239 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); 3240 this.ambientTickCountdown = this.rand.nextInt(12000) + 6000; 3241 } 3242 } 3243 } 3244 3245 this.theProfiler.endStartSection("checkLight"); 3246 par3Chunk.enqueueRelightChecks(); 3247 } 3248 3249 /** 3250 * plays random cave ambient sounds and runs updateTick on random blocks within each chunk in the vacinity of a 3251 * player 3252 */ 3253 protected void tickBlocksAndAmbiance() 3254 { 3255 this.setActivePlayerChunksAndCheckLight(); 3256 } 3257 3258 /** 3259 * checks to see if a given block is both water and is cold enough to freeze 3260 */ 3261 public boolean isBlockFreezable(int par1, int par2, int par3) 3262 { 3263 return this.canBlockFreeze(par1, par2, par3, false); 3264 } 3265 3266 /** 3267 * checks to see if a given block is both water and has at least one immediately adjacent non-water block 3268 */ 3269 public boolean isBlockFreezableNaturally(int par1, int par2, int par3) 3270 { 3271 return this.canBlockFreeze(par1, par2, par3, true); 3272 } 3273 3274 /** 3275 * checks to see if a given block is both water, and cold enough to freeze - if the par4 boolean is set, this will 3276 * only return true if there is a non-water block immediately adjacent to the specified block 3277 */ 3278 public boolean canBlockFreeze(int par1, int par2, int par3, boolean par4) 3279 { 3280 return provider.canBlockFreeze(par1, par2, par3, par4); 3281 } 3282 3283 public boolean canBlockFreezeBody(int par1, int par2, int par3, boolean par4) 3284 { 3285 BiomeGenBase biomegenbase = this.getBiomeGenForCoords(par1, par3); 3286 float f = biomegenbase.getFloatTemperature(); 3287 3288 if (f > 0.15F) 3289 { 3290 return false; 3291 } 3292 else 3293 { 3294 if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10) 3295 { 3296 int l = this.getBlockId(par1, par2, par3); 3297 3298 if ((l == Block.waterStill.blockID || l == Block.waterMoving.blockID) && this.getBlockMetadata(par1, par2, par3) == 0) 3299 { 3300 if (!par4) 3301 { 3302 return true; 3303 } 3304 3305 boolean flag1 = true; 3306 3307 if (flag1 && this.getBlockMaterial(par1 - 1, par2, par3) != Material.water) 3308 { 3309 flag1 = false; 3310 } 3311 3312 if (flag1 && this.getBlockMaterial(par1 + 1, par2, par3) != Material.water) 3313 { 3314 flag1 = false; 3315 } 3316 3317 if (flag1 && this.getBlockMaterial(par1, par2, par3 - 1) != Material.water) 3318 { 3319 flag1 = false; 3320 } 3321 3322 if (flag1 && this.getBlockMaterial(par1, par2, par3 + 1) != Material.water) 3323 { 3324 flag1 = false; 3325 } 3326 3327 if (!flag1) 3328 { 3329 return true; 3330 } 3331 } 3332 } 3333 3334 return false; 3335 } 3336 } 3337 3338 /** 3339 * Tests whether or not snow can be placed at a given location 3340 */ 3341 public boolean canSnowAt(int par1, int par2, int par3) 3342 { 3343 return provider.canSnowAt(par1, par2, par3); 3344 } 3345 3346 public boolean canSnowAtBody(int par1, int par2, int par3) 3347 { 3348 BiomeGenBase biomegenbase = this.getBiomeGenForCoords(par1, par3); 3349 float f = biomegenbase.getFloatTemperature(); 3350 3351 if (f > 0.15F) 3352 { 3353 return false; 3354 } 3355 else 3356 { 3357 if (par2 >= 0 && par2 < 256 && this.getSavedLightValue(EnumSkyBlock.Block, par1, par2, par3) < 10) 3358 { 3359 int l = this.getBlockId(par1, par2 - 1, par3); 3360 int i1 = this.getBlockId(par1, par2, par3); 3361 3362 if (i1 == 0 && Block.snow.canPlaceBlockAt(this, par1, par2, par3) && l != 0 && l != Block.ice.blockID && Block.blocksList[l].blockMaterial.blocksMovement()) 3363 { 3364 return true; 3365 } 3366 } 3367 3368 return false; 3369 } 3370 } 3371 3372 public void updateAllLightTypes(int par1, int par2, int par3) 3373 { 3374 if (!this.provider.hasNoSky) 3375 { 3376 this.updateLightByType(EnumSkyBlock.Sky, par1, par2, par3); 3377 } 3378 3379 this.updateLightByType(EnumSkyBlock.Block, par1, par2, par3); 3380 } 3381 3382 private int func_98179_a(int par1, int par2, int par3, EnumSkyBlock par4EnumSkyBlock) 3383 { 3384 if (par4EnumSkyBlock == EnumSkyBlock.Sky && this.canBlockSeeTheSky(par1, par2, par3)) 3385 { 3386 return 15; 3387 } 3388 else 3389 { 3390 int l = this.getBlockId(par1, par2, par3); 3391 Block block = Block.blocksList[l]; 3392 int blockLight = (block == null ? 0 : block.getLightValue(this, par1, par2, par3)); 3393 int i1 = par4EnumSkyBlock == EnumSkyBlock.Sky ? 0 : blockLight; 3394 int j1 = (block == null ? 0 : block.getLightOpacity(this, par1, par2, par3)); 3395 3396 if (j1 >= 15 && blockLight > 0) 3397 { 3398 j1 = 1; 3399 } 3400 3401 if (j1 < 1) 3402 { 3403 j1 = 1; 3404 } 3405 3406 if (j1 >= 15) 3407 { 3408 return 0; 3409 } 3410 else if (i1 >= 14) 3411 { 3412 return i1; 3413 } 3414 else 3415 { 3416 for (int k1 = 0; k1 < 6; ++k1) 3417 { 3418 int l1 = par1 + Facing.offsetsXForSide[k1]; 3419 int i2 = par2 + Facing.offsetsYForSide[k1]; 3420 int j2 = par3 + Facing.offsetsZForSide[k1]; 3421 int k2 = this.getSavedLightValue(par4EnumSkyBlock, l1, i2, j2) - j1; 3422 3423 if (k2 > i1) 3424 { 3425 i1 = k2; 3426 } 3427 3428 if (i1 >= 14) 3429 { 3430 return i1; 3431 } 3432 } 3433 3434 return i1; 3435 } 3436 } 3437 } 3438 3439 public void updateLightByType(EnumSkyBlock par1EnumSkyBlock, int par2, int par3, int par4) 3440 { 3441 if (this.doChunksNearChunkExist(par2, par3, par4, 17)) 3442 { 3443 int l = 0; 3444 int i1 = 0; 3445 this.theProfiler.startSection("getBrightness"); 3446 int j1 = this.getSavedLightValue(par1EnumSkyBlock, par2, par3, par4); 3447 int k1 = this.func_98179_a(par2, par3, par4, par1EnumSkyBlock); 3448 int l1; 3449 int i2; 3450 int j2; 3451 int k2; 3452 int l2; 3453 int i3; 3454 int j3; 3455 int k3; 3456 int l3; 3457 3458 if (k1 > j1) 3459 { 3460 this.lightUpdateBlockList[i1++] = 133152; 3461 } 3462 else if (k1 < j1) 3463 { 3464 this.lightUpdateBlockList[i1++] = 133152 | j1 << 18; 3465 3466 while (l < i1) 3467 { 3468 l1 = this.lightUpdateBlockList[l++]; 3469 i2 = (l1 & 63) - 32 + par2; 3470 j2 = (l1 >> 6 & 63) - 32 + par3; 3471 k2 = (l1 >> 12 & 63) - 32 + par4; 3472 l2 = l1 >> 18 & 15; 3473 i3 = this.getSavedLightValue(par1EnumSkyBlock, i2, j2, k2); 3474 3475 if (i3 == l2) 3476 { 3477 this.setLightValue(par1EnumSkyBlock, i2, j2, k2, 0); 3478 3479 if (l2 > 0) 3480 { 3481 j3 = MathHelper.abs_int(i2 - par2); 3482 l3 = MathHelper.abs_int(j2 - par3); 3483 k3 = MathHelper.abs_int(k2 - par4); 3484 3485 if (j3 + l3 + k3 < 17) 3486 { 3487 for (int i4 = 0; i4 < 6; ++i4) 3488 { 3489 int j4 = i2 + Facing.offsetsXForSide[i4]; 3490 int k4 = j2 + Facing.offsetsYForSide[i4]; 3491 int l4 = k2 + Facing.offsetsZForSide[i4]; 3492 Block block = Block.blocksList[getBlockId(j4, k4, l4)]; 3493 int blockOpacity = (block == null ? 0 : block.getLightOpacity(this, j4, k4, l4)); 3494 int i5 = Math.max(1, blockOpacity); 3495 i3 = this.getSavedLightValue(par1EnumSkyBlock, j4, k4, l4); 3496 3497 if (i3 == l2 - i5 && i1 < this.lightUpdateBlockList.length) 3498 { 3499 this.lightUpdateBlockList[i1++] = j4 - par2 + 32 | k4 - par3 + 32 << 6 | l4 - par4 + 32 << 12 | l2 - i5 << 18; 3500 } 3501 } 3502 } 3503 } 3504 } 3505 } 3506 3507 l = 0; 3508 } 3509 3510 this.theProfiler.endSection(); 3511 this.theProfiler.startSection("checkedPosition < toCheckCount"); 3512 3513 while (l < i1) 3514 { 3515 l1 = this.lightUpdateBlockList[l++]; 3516 i2 = (l1 & 63) - 32 + par2; 3517 j2 = (l1 >> 6 & 63) - 32 + par3; 3518 k2 = (l1 >> 12 & 63) - 32 + par4; 3519 l2 = this.getSavedLightValue(par1EnumSkyBlock, i2, j2, k2); 3520 i3 = this.func_98179_a(i2, j2, k2, par1EnumSkyBlock); 3521 3522 if (i3 != l2) 3523 { 3524 this.setLightValue(par1EnumSkyBlock, i2, j2, k2, i3); 3525 3526 if (i3 > l2) 3527 { 3528 j3 = Math.abs(i2 - par2); 3529 l3 = Math.abs(j2 - par3); 3530 k3 = Math.abs(k2 - par4); 3531 boolean flag = i1 < this.lightUpdateBlockList.length - 6; 3532 3533 if (j3 + l3 + k3 < 17 && flag) 3534 { 3535 if (this.getSavedLightValue(par1EnumSkyBlock, i2 - 1, j2, k2) < i3) 3536 { 3537 this.lightUpdateBlockList[i1++] = i2 - 1 - par2 + 32 + (j2 - par3 + 32 << 6) + (k2 - par4 + 32 << 12); 3538 } 3539 3540 if (this.getSavedLightValue(par1EnumSkyBlock, i2 + 1, j2, k2) < i3) 3541 { 3542 this.lightUpdateBlockList[i1++] = i2 + 1 - par2 + 32 + (j2 - par3 + 32 << 6) + (k2 - par4 + 32 << 12); 3543 } 3544 3545 if (this.getSavedLightValue(par1EnumSkyBlock, i2, j2 - 1, k2) < i3) 3546 { 3547 this.lightUpdateBlockList[i1++] = i2 - par2 + 32 + (j2 - 1 - par3 + 32 << 6) + (k2 - par4 + 32 << 12); 3548 } 3549 3550 if (this.getSavedLightValue(par1EnumSkyBlock, i2, j2 + 1, k2) < i3) 3551 { 3552 this.lightUpdateBlockList[i1++] = i2 - par2 + 32 + (j2 + 1 - par3 + 32 << 6) + (k2 - par4 + 32 << 12); 3553 } 3554 3555 if (this.getSavedLightValue(par1EnumSkyBlock, i2, j2, k2 - 1) < i3) 3556 { 3557 this.lightUpdateBlockList[i1++] = i2 - par2 + 32 + (j2 - par3 + 32 << 6) + (k2 - 1 - par4 + 32 << 12); 3558 } 3559 3560 if (this.getSavedLightValue(par1EnumSkyBlock, i2, j2, k2 + 1) < i3) 3561 { 3562 this.lightUpdateBlockList[i1++] = i2 - par2 + 32 + (j2 - par3 + 32 << 6) + (k2 + 1 - par4 + 32 << 12); 3563 } 3564 } 3565 } 3566 } 3567 } 3568 3569 this.theProfiler.endSection(); 3570 } 3571 } 3572 3573 /** 3574 * Runs through the list of updates to run and ticks them 3575 */ 3576 public boolean tickUpdates(boolean par1) 3577 { 3578 return false; 3579 } 3580 3581 public List getPendingBlockUpdates(Chunk par1Chunk, boolean par2) 3582 { 3583 return null; 3584 } 3585 3586 /** 3587 * Will get all entities within the specified AABB excluding the one passed into it. Args: entityToExclude, aabb 3588 */ 3589 public List getEntitiesWithinAABBExcludingEntity(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB) 3590 { 3591 return this.func_94576_a(par1Entity, par2AxisAlignedBB, (IEntitySelector)null); 3592 } 3593 3594 public List func_94576_a(Entity par1Entity, AxisAlignedBB par2AxisAlignedBB, IEntitySelector par3IEntitySelector) 3595 { 3596 ArrayList arraylist = new ArrayList(); 3597 int i = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D); 3598 int j = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D); 3599 int k = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D); 3600 int l = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D); 3601 3602 for (int i1 = i; i1 <= j; ++i1) 3603 { 3604 for (int j1 = k; j1 <= l; ++j1) 3605 { 3606 if (this.chunkExists(i1, j1)) 3607 { 3608 this.getChunkFromChunkCoords(i1, j1).getEntitiesWithinAABBForEntity(par1Entity, par2AxisAlignedBB, arraylist, par3IEntitySelector); 3609 } 3610 } 3611 } 3612 3613 return arraylist; 3614 } 3615 3616 /** 3617 * Returns all entities of the specified class type which intersect with the AABB. Args: entityClass, aabb 3618 */ 3619 public List getEntitiesWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB) 3620 { 3621 return this.selectEntitiesWithinAABB(par1Class, par2AxisAlignedBB, (IEntitySelector)null); 3622 } 3623 3624 public List selectEntitiesWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, IEntitySelector par3IEntitySelector) 3625 { 3626 int i = MathHelper.floor_double((par2AxisAlignedBB.minX - MAX_ENTITY_RADIUS) / 16.0D); 3627 int j = MathHelper.floor_double((par2AxisAlignedBB.maxX + MAX_ENTITY_RADIUS) / 16.0D); 3628 int k = MathHelper.floor_double((par2AxisAlignedBB.minZ - MAX_ENTITY_RADIUS) / 16.0D); 3629 int l = MathHelper.floor_double((par2AxisAlignedBB.maxZ + MAX_ENTITY_RADIUS) / 16.0D); 3630 ArrayList arraylist = new ArrayList(); 3631 3632 for (int i1 = i; i1 <= j; ++i1) 3633 { 3634 for (int j1 = k; j1 <= l; ++j1) 3635 { 3636 if (this.chunkExists(i1, j1)) 3637 { 3638 this.getChunkFromChunkCoords(i1, j1).getEntitiesOfTypeWithinAAAB(par1Class, par2AxisAlignedBB, arraylist, par3IEntitySelector); 3639 } 3640 } 3641 } 3642 3643 return arraylist; 3644 } 3645 3646 public Entity findNearestEntityWithinAABB(Class par1Class, AxisAlignedBB par2AxisAlignedBB, Entity par3Entity) 3647 { 3648 List list = this.getEntitiesWithinAABB(par1Class, par2AxisAlignedBB); 3649 Entity entity1 = null; 3650 double d0 = Double.MAX_VALUE; 3651 3652 for (int i = 0; i < list.size(); ++i) 3653 { 3654 Entity entity2 = (Entity)list.get(i); 3655 3656 if (entity2 != par3Entity) 3657 { 3658 double d1 = par3Entity.getDistanceSqToEntity(entity2); 3659 3660 if (d1 <= d0) 3661 { 3662 entity1 = entity2; 3663 d0 = d1; 3664 } 3665 } 3666 } 3667 3668 return entity1; 3669 } 3670 3671 /** 3672 * Returns the Entity with the given ID, or null if it doesn't exist in this World. 3673 */ 3674 public abstract Entity getEntityByID(int i); 3675 3676 @SideOnly(Side.CLIENT) 3677 3678 /** 3679 * Accessor for world Loaded Entity List 3680 */ 3681 public List getLoadedEntityList() 3682 { 3683 return this.loadedEntityList; 3684 } 3685 3686 /** 3687 * marks the chunk that contains this tilentity as modified and then calls worldAccesses.doNothingWithTileEntity 3688 */ 3689 public void updateTileEntityChunkAndDoNothing(int par1, int par2, int par3, TileEntity par4TileEntity) 3690 { 3691 if (this.blockExists(par1, par2, par3)) 3692 { 3693 this.getChunkFromBlockCoords(par1, par3).setChunkModified(); 3694 } 3695 } 3696 3697 /** 3698 * Counts how many entities of an entity class exist in the world. Args: entityClass 3699 */ 3700 public int countEntities(Class par1Class) 3701 { 3702 int i = 0; 3703 3704 for (int j = 0; j < this.loadedEntityList.size(); ++j) 3705 { 3706 Entity entity = (Entity)this.loadedEntityList.get(j); 3707 3708 if (par1Class.isAssignableFrom(entity.getClass())) 3709 { 3710 ++i; 3711 } 3712 } 3713 3714 return i; 3715 } 3716 3717 /** 3718 * adds entities to the loaded entities list, and loads thier skins. 3719 */ 3720 public void addLoadedEntities(List par1List) 3721 { 3722 for (int i = 0; i < par1List.size(); ++i) 3723 { 3724 Entity entity = (Entity)par1List.get(i); 3725 if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(entity, this))) 3726 { 3727 loadedEntityList.add(entity); 3728 this.obtainEntitySkin(entity); 3729 } 3730 } 3731 } 3732 3733 /** 3734 * Adds a list of entities to be unloaded on the next pass of World.updateEntities() 3735 */ 3736 public void unloadEntities(List par1List) 3737 { 3738 this.unloadedEntityList.addAll(par1List); 3739 } 3740 3741 /** 3742 * Returns true if the given Entity can be placed on the given side of the given block position. 3743 */ 3744 public boolean canPlaceEntityOnSide(int par1, int par2, int par3, int par4, boolean par5, int par6, Entity par7Entity, ItemStack par8ItemStack) 3745 { 3746 int j1 = this.getBlockId(par2, par3, par4); 3747 Block block = Block.blocksList[j1]; 3748 Block block1 = Block.blocksList[par1]; 3749 AxisAlignedBB axisalignedbb = block1.getCollisionBoundingBoxFromPool(this, par2, par3, par4); 3750 3751 if (par5) 3752 { 3753 axisalignedbb = null; 3754 } 3755 3756 if (axisalignedbb != null && !this.checkIfAABBIsClearExcludingEntity(axisalignedbb, par7Entity)) 3757 { 3758 return false; 3759 } 3760 else 3761 { 3762 if (block != null && (block == Block.waterMoving || block == Block.waterStill || block == Block.lavaMoving || block == Block.lavaStill || block == Block.fire || block.blockMaterial.isReplaceable())) 3763 { 3764 block = null; 3765 } 3766 3767 if (block != null && block.isBlockReplaceable(this, par2, par3, par4)) 3768 { 3769 block = null; 3770 } 3771 3772 return block != null && block.blockMaterial == Material.circuits && block1 == Block.anvil ? true : par1 > 0 && block == null && block1.canPlaceBlockOnSide(this, par2, par3, par4, par6, par8ItemStack); 3773 } 3774 } 3775 3776 public PathEntity getPathEntityToEntity(Entity par1Entity, Entity par2Entity, float par3, boolean par4, boolean par5, boolean par6, boolean par7) 3777 { 3778 this.theProfiler.startSection("pathfind"); 3779 int i = MathHelper.floor_double(par1Entity.posX); 3780 int j = MathHelper.floor_double(par1Entity.posY + 1.0D); 3781 int k = MathHelper.floor_double(par1Entity.posZ); 3782 int l = (int)(par3 + 16.0F); 3783 int i1 = i - l; 3784 int j1 = j - l; 3785 int k1 = k - l; 3786 int l1 = i + l; 3787 int i2 = j + l; 3788 int j2 = k + l; 3789 ChunkCache chunkcache = new ChunkCache(this, i1, j1, k1, l1, i2, j2, 0); 3790 PathEntity pathentity = (new PathFinder(chunkcache, par4, par5, par6, par7)).createEntityPathTo(par1Entity, par2Entity, par3); 3791 this.theProfiler.endSection(); 3792 return pathentity; 3793 } 3794 3795 public PathEntity getEntityPathToXYZ(Entity par1Entity, int par2, int par3, int par4, float par5, boolean par6, boolean par7, boolean par8, boolean par9) 3796 { 3797 this.theProfiler.startSection("pathfind"); 3798 int l = MathHelper.floor_double(par1Entity.posX); 3799 int i1 = MathHelper.floor_double(par1Entity.posY); 3800 int j1 = MathHelper.floor_double(par1Entity.posZ); 3801 int k1 = (int)(par5 + 8.0F); 3802 int l1 = l - k1; 3803 int i2 = i1 - k1; 3804 int j2 = j1 - k1; 3805 int k2 = l + k1; 3806 int l2 = i1 + k1; 3807 int i3 = j1 + k1; 3808 ChunkCache chunkcache = new ChunkCache(this, l1, i2, j2, k2, l2, i3, 0); 3809 PathEntity pathentity = (new PathFinder(chunkcache, par6, par7, par8, par9)).createEntityPathTo(par1Entity, par2, par3, par4, par5); 3810 this.theProfiler.endSection(); 3811 return pathentity; 3812 } 3813 3814 /** 3815 * Is this block powering in the specified direction Args: x, y, z, direction 3816 */ 3817 public int isBlockProvidingPowerTo(int par1, int par2, int par3, int par4) 3818 { 3819 int i1 = this.getBlockId(par1, par2, par3); 3820 return i1 == 0 ? 0 : Block.blocksList[i1].isProvidingStrongPower(this, par1, par2, par3, par4); 3821 } 3822 3823 /** 3824 * Returns the highest redstone signal strength powering the given block. Args: X, Y, Z. 3825 */ 3826 public int getBlockPowerInput(int par1, int par2, int par3) 3827 { 3828 byte b0 = 0; 3829 int l = Math.max(b0, this.isBlockProvidingPowerTo(par1, par2 - 1, par3, 0)); 3830 3831 if (l >= 15) 3832 { 3833 return l; 3834 } 3835 else 3836 { 3837 l = Math.max(l, this.isBlockProvidingPowerTo(par1, par2 + 1, par3, 1)); 3838 3839 if (l >= 15) 3840 { 3841 return l; 3842 } 3843 else 3844 { 3845 l = Math.max(l, this.isBlockProvidingPowerTo(par1, par2, par3 - 1, 2)); 3846 3847 if (l >= 15) 3848 { 3849 return l; 3850 } 3851 else 3852 { 3853 l = Math.max(l, this.isBlockProvidingPowerTo(par1, par2, par3 + 1, 3)); 3854 3855 if (l >= 15) 3856 { 3857 return l; 3858 } 3859 else 3860 { 3861 l = Math.max(l, this.isBlockProvidingPowerTo(par1 - 1, par2, par3, 4)); 3862 3863 if (l >= 15) 3864 { 3865 return l; 3866 } 3867 else 3868 { 3869 l = Math.max(l, this.isBlockProvidingPowerTo(par1 + 1, par2, par3, 5)); 3870 return l >= 15 ? l : l; 3871 } 3872 } 3873 } 3874 } 3875 } 3876 } 3877 3878 /** 3879 * Returns the indirect signal strength being outputted by the given block in the *opposite* of the given direction. 3880 * Args: X, Y, Z, direction 3881 */ 3882 public boolean getIndirectPowerOutput(int par1, int par2, int par3, int par4) 3883 { 3884 return this.getIndirectPowerLevelTo(par1, par2, par3, par4) > 0; 3885 } 3886 3887 /** 3888 * Gets the power level from a certain block face. Args: x, y, z, direction 3889 */ 3890 public int getIndirectPowerLevelTo(int par1, int par2, int par3, int par4) 3891 { 3892 if (this.isBlockNormalCube(par1, par2, par3)) 3893 { 3894 return this.getBlockPowerInput(par1, par2, par3); 3895 } 3896 else 3897 { 3898 int i1 = this.getBlockId(par1, par2, par3); 3899 return i1 == 0 ? 0 : Block.blocksList[i1].isProvidingWeakPower(this, par1, par2, par3, par4); 3900 } 3901 } 3902 3903 /** 3904 * Used to see if one of the blocks next to you or your block is getting power from a neighboring block. Used by 3905 * items like TNT or Doors so they don't have redstone going straight into them. Args: x, y, z 3906 */ 3907 public boolean isBlockIndirectlyGettingPowered(int par1, int par2, int par3) 3908 { 3909 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)))); 3910 } 3911 3912 public int getStrongestIndirectPower(int par1, int par2, int par3) 3913 { 3914 int l = 0; 3915 3916 for (int i1 = 0; i1 < 6; ++i1) 3917 { 3918 int j1 = this.getIndirectPowerLevelTo(par1 + Facing.offsetsXForSide[i1], par2 + Facing.offsetsYForSide[i1], par3 + Facing.offsetsZForSide[i1], i1); 3919 3920 if (j1 >= 15) 3921 { 3922 return 15; 3923 } 3924 3925 if (j1 > l) 3926 { 3927 l = j1; 3928 } 3929 } 3930 3931 return l; 3932 } 3933 3934 /** 3935 * Gets the closest player to the entity within the specified distance (if distance is less than 0 then ignored). 3936 * Args: entity, dist 3937 */ 3938 public EntityPlayer getClosestPlayerToEntity(Entity par1Entity, double par2) 3939 { 3940 return this.getClosestPlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2); 3941 } 3942 3943 /** 3944 * Gets the closest player to the point within the specified distance (distance can be set to less than 0 to not 3945 * limit the distance). Args: x, y, z, dist 3946 */ 3947 public EntityPlayer getClosestPlayer(double par1, double par3, double par5, double par7) 3948 { 3949 double d4 = -1.0D; 3950 EntityPlayer entityplayer = null; 3951 3952 for (int i = 0; i < this.playerEntities.size(); ++i) 3953 { 3954 EntityPlayer entityplayer1 = (EntityPlayer)this.playerEntities.get(i); 3955 double d5 = entityplayer1.getDistanceSq(par1, par3, par5); 3956 3957 if ((par7 < 0.0D || d5 < par7 * par7) && (d4 == -1.0D || d5 < d4)) 3958 { 3959 d4 = d5; 3960 entityplayer = entityplayer1; 3961 } 3962 } 3963 3964 return entityplayer; 3965 } 3966 3967 /** 3968 * Returns the closest vulnerable player to this entity within the given radius, or null if none is found 3969 */ 3970 public EntityPlayer getClosestVulnerablePlayerToEntity(Entity par1Entity, double par2) 3971 { 3972 return this.getClosestVulnerablePlayer(par1Entity.posX, par1Entity.posY, par1Entity.posZ, par2); 3973 } 3974 3975 /** 3976 * Returns the closest vulnerable player within the given radius, or null if none is found. 3977 */ 3978 public EntityPlayer getClosestVulnerablePlayer(double par1, double par3, double par5, double par7) 3979 { 3980 double d4 = -1.0D; 3981 EntityPlayer entityplayer = null; 3982 3983 for (int i = 0; i < this.playerEntities.size(); ++i) 3984 { 3985 EntityPlayer entityplayer1 = (EntityPlayer)this.playerEntities.get(i); 3986 3987 if (!entityplayer1.capabilities.disableDamage && entityplayer1.isEntityAlive()) 3988 { 3989 double d5 = entityplayer1.getDistanceSq(par1, par3, par5); 3990 double d6 = par7; 3991 3992 if (entityplayer1.isSneaking()) 3993 { 3994 d6 = par7 * 0.800000011920929D; 3995 } 3996 3997 if (entityplayer1.getHasActivePotion()) 3998 { 3999 float f = entityplayer1.func_82243_bO(); 4000 4001 if (f < 0.1F) 4002 { 4003 f = 0.1F; 4004 } 4005 4006 d6 *= (double)(0.7F * f); 4007 } 4008 4009 if ((par7 < 0.0D || d5 < d6 * d6) && (d4 == -1.0D || d5 < d4)) 4010 { 4011 d4 = d5; 4012 entityplayer = entityplayer1; 4013 } 4014 } 4015 } 4016 4017 return entityplayer; 4018 } 4019 4020 /** 4021 * Find a player by name in this world. 4022 */ 4023 public EntityPlayer getPlayerEntityByName(String par1Str) 4024 { 4025 for (int i = 0; i < this.playerEntities.size(); ++i) 4026 { 4027 if (par1Str.equals(((EntityPlayer)this.playerEntities.get(i)).username)) 4028 { 4029 return (EntityPlayer)this.playerEntities.get(i); 4030 } 4031 } 4032 4033 return null; 4034 } 4035 4036 @SideOnly(Side.CLIENT) 4037 4038 /** 4039 * If on MP, sends a quitting packet. 4040 */ 4041 public void sendQuittingDisconnectingPacket() {} 4042 4043 /** 4044 * Checks whether the session lock file was modified by another process 4045 */ 4046 public void checkSessionLock() throws MinecraftException 4047 { 4048 this.saveHandler.checkSessionLock(); 4049 } 4050 4051 @SideOnly(Side.CLIENT) 4052 public void func_82738_a(long par1) 4053 { 4054 this.worldInfo.incrementTotalWorldTime(par1); 4055 } 4056 4057 /** 4058 * Retrieve the world seed from level.dat 4059 */ 4060 public long getSeed() 4061 { 4062 return provider.getSeed(); 4063 } 4064 4065 public long getTotalWorldTime() 4066 { 4067 return this.worldInfo.getWorldTotalTime(); 4068 } 4069 4070 public long getWorldTime() 4071 { 4072 return provider.getWorldTime(); 4073 } 4074 4075 /** 4076 * Sets the world time. 4077 */ 4078 public void setWorldTime(long par1) 4079 { 4080 provider.setWorldTime(par1); 4081 } 4082 4083 /** 4084 * Returns the coordinates of the spawn point 4085 */ 4086 public ChunkCoordinates getSpawnPoint() 4087 { 4088 return provider.getSpawnPoint(); 4089 } 4090 4091 @SideOnly(Side.CLIENT) 4092 public void setSpawnLocation(int par1, int par2, int par3) 4093 { 4094 provider.setSpawnPoint(par1, par2, par3); 4095 } 4096 4097 @SideOnly(Side.CLIENT) 4098 4099 /** 4100 * spwans an entity and loads surrounding chunks 4101 */ 4102 public void joinEntityInSurroundings(Entity par1Entity) 4103 { 4104 int i = MathHelper.floor_double(par1Entity.posX / 16.0D); 4105 int j = MathHelper.floor_double(par1Entity.posZ / 16.0D); 4106 byte b0 = 2; 4107 4108 for (int k = i - b0; k <= i + b0; ++k) 4109 { 4110 for (int l = j - b0; l <= j + b0; ++l) 4111 { 4112 this.getChunkFromChunkCoords(k, l); 4113 } 4114 } 4115 4116 if (!this.loadedEntityList.contains(par1Entity)) 4117 { 4118 if (!MinecraftForge.EVENT_BUS.post(new EntityJoinWorldEvent(par1Entity, this))) 4119 { 4120 loadedEntityList.add(par1Entity); 4121 } 4122 } 4123 } 4124 4125 /** 4126 * Called when checking if a certain block can be mined or not. The 'spawn safe zone' check is located here. 4127 */ 4128 public boolean canMineBlock(EntityPlayer par1EntityPlayer, int par2, int par3, int par4) 4129 { 4130 return provider.canMineBlock(par1EntityPlayer, par2, par3, par4); 4131 } 4132 4133 public boolean canMineBlockBody(EntityPlayer par1EntityPlayer, int par2, int par3, int par4) 4134 { 4135 return true; 4136 } 4137 4138 /** 4139 * sends a Packet 38 (Entity Status) to all tracked players of that entity 4140 */ 4141 public void setEntityState(Entity par1Entity, byte par2) {} 4142 4143 /** 4144 * gets the IChunkProvider this world uses. 4145 */ 4146 public IChunkProvider getChunkProvider() 4147 { 4148 return this.chunkProvider; 4149 } 4150 4151 /** 4152 * Adds a block event with the given Args to the blockEventCache. During the next tick(), the block specified will 4153 * have its onBlockEvent handler called with the given parameters. Args: X,Y,Z, BlockID, EventID, EventParameter 4154 */ 4155 public void addBlockEvent(int par1, int par2, int par3, int par4, int par5, int par6) 4156 { 4157 if (par4 > 0) 4158 { 4159 Block.blocksList[par4].onBlockEventReceived(this, par1, par2, par3, par5, par6); 4160 } 4161 } 4162 4163 /** 4164 * Returns this world's current save handler 4165 */ 4166 public ISaveHandler getSaveHandler() 4167 { 4168 return this.saveHandler; 4169 } 4170 4171 /** 4172 * Gets the World's WorldInfo instance 4173 */ 4174 public WorldInfo getWorldInfo() 4175 { 4176 return this.worldInfo; 4177 } 4178 4179 /** 4180 * Gets the GameRules instance. 4181 */ 4182 public GameRules getGameRules() 4183 { 4184 return this.worldInfo.getGameRulesInstance(); 4185 } 4186 4187 /** 4188 * Updates the flag that indicates whether or not all players in the world are sleeping. 4189 */ 4190 public void updateAllPlayersSleepingFlag() {} 4191 4192 public float getWeightedThunderStrength(float par1) 4193 { 4194 return (this.prevThunderingStrength + (this.thunderingStrength - this.prevThunderingStrength) * par1) * this.getRainStrength(par1); 4195 } 4196 4197 /** 4198 * Not sure about this actually. Reverting this one myself. 4199 */ 4200 public float getRainStrength(float par1) 4201 { 4202 return this.prevRainingStrength + (this.rainingStrength - this.prevRainingStrength) * par1; 4203 } 4204 4205 @SideOnly(Side.CLIENT) 4206 public void setRainStrength(float par1) 4207 { 4208 this.prevRainingStrength = par1; 4209 this.rainingStrength = par1; 4210 } 4211 4212 /** 4213 * Returns true if the current thunder strength (weighted with the rain strength) is greater than 0.9 4214 */ 4215 public boolean isThundering() 4216 { 4217 return (double)this.getWeightedThunderStrength(1.0F) > 0.9D; 4218 } 4219 4220 /** 4221 * Returns true if the current rain strength is greater than 0.2 4222 */ 4223 public boolean isRaining() 4224 { 4225 return (double)this.getRainStrength(1.0F) > 0.2D; 4226 } 4227 4228 public boolean canLightningStrikeAt(int par1, int par2, int par3) 4229 { 4230 if (!this.isRaining()) 4231 { 4232 return false; 4233 } 4234 else if (!this.canBlockSeeTheSky(par1, par2, par3)) 4235 { 4236 return false; 4237 } 4238 else if (this.getPrecipitationHeight(par1, par3) > par2) 4239 { 4240 return false; 4241 } 4242 else 4243 { 4244 BiomeGenBase biomegenbase = this.getBiomeGenForCoords(par1, par3); 4245 return biomegenbase.getEnableSnow() ? false : biomegenbase.canSpawnLightningBolt(); 4246 } 4247 } 4248 4249 /** 4250 * Checks to see if the biome rainfall values for a given x,y,z coordinate set are extremely high 4251 */ 4252 public boolean isBlockHighHumidity(int par1, int par2, int par3) 4253 { 4254 return provider.isBlockHighHumidity(par1, par2, par3); 4255 } 4256 4257 /** 4258 * Assigns the given String id to the given MapDataBase using the MapStorage, removing any existing ones of the same 4259 * id. 4260 */ 4261 public void setItemData(String par1Str, WorldSavedData par2WorldSavedData) 4262 { 4263 this.mapStorage.setData(par1Str, par2WorldSavedData); 4264 } 4265 4266 /** 4267 * Loads an existing MapDataBase corresponding to the given String id from disk using the MapStorage, instantiating 4268 * the given Class, or returns null if none such file exists. args: Class to instantiate, String dataid 4269 */ 4270 public WorldSavedData loadItemData(Class par1Class, String par2Str) 4271 { 4272 return this.mapStorage.loadData(par1Class, par2Str); 4273 } 4274 4275 /** 4276 * Returns an unique new data id from the MapStorage for the given prefix and saves the idCounts map to the 4277 * 'idcounts' file. 4278 */ 4279 public int getUniqueDataId(String par1Str) 4280 { 4281 return this.mapStorage.getUniqueDataId(par1Str); 4282 } 4283 4284 public void func_82739_e(int par1, int par2, int par3, int par4, int par5) 4285 { 4286 for (int j1 = 0; j1 < this.worldAccesses.size(); ++j1) 4287 { 4288 ((IWorldAccess)this.worldAccesses.get(j1)).broadcastSound(par1, par2, par3, par4, par5); 4289 } 4290 } 4291 4292 /** 4293 * See description for playAuxSFX. 4294 */ 4295 public void playAuxSFX(int par1, int par2, int par3, int par4, int par5) 4296 { 4297 this.playAuxSFXAtEntity((EntityPlayer)null, par1, par2, par3, par4, par5); 4298 } 4299 4300 /** 4301 * See description for playAuxSFX. 4302 */ 4303 public void playAuxSFXAtEntity(EntityPlayer par1EntityPlayer, int par2, int par3, int par4, int par5, int par6) 4304 { 4305 try 4306 { 4307 for (int j1 = 0; j1 < this.worldAccesses.size(); ++j1) 4308 { 4309 ((IWorldAccess)this.worldAccesses.get(j1)).playAuxSFX(par1EntityPlayer, par2, par3, par4, par5, par6); 4310 } 4311 } 4312 catch (Throwable throwable) 4313 { 4314 CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Playing level event"); 4315 CrashReportCategory crashreportcategory = crashreport.makeCategory("Level event being played"); 4316 crashreportcategory.addCrashSection("Block coordinates", CrashReportCategory.func_85071_a(par3, par4, par5)); 4317 crashreportcategory.addCrashSection("Event source", par1EntityPlayer); 4318 crashreportcategory.addCrashSection("Event type", Integer.valueOf(par2)); 4319 crashreportcategory.addCrashSection("Event data", Integer.valueOf(par6)); 4320 throw new ReportedException(crashreport); 4321 } 4322 } 4323 4324 /** 4325 * Returns current world height. 4326 */ 4327 public int getHeight() 4328 { 4329 return provider.getHeight(); 4330 } 4331 4332 /** 4333 * Returns current world height. 4334 */ 4335 public int getActualHeight() 4336 { 4337 return provider.getActualHeight(); 4338 } 4339 4340 public IUpdatePlayerListBox func_82735_a(EntityMinecart par1EntityMinecart) 4341 { 4342 return null; 4343 } 4344 4345 /** 4346 * puts the World Random seed to a specific state dependant on the inputs 4347 */ 4348 public Random setRandomSeed(int par1, int par2, int par3) 4349 { 4350 long l = (long)par1 * 341873128712L + (long)par2 * 132897987541L + this.getWorldInfo().getSeed() + (long)par3; 4351 this.rand.setSeed(l); 4352 return this.rand; 4353 } 4354 4355 /** 4356 * Returns the location of the closest structure of the specified type. If not found returns null. 4357 */ 4358 public ChunkPosition findClosestStructure(String par1Str, int par2, int par3, int par4) 4359 { 4360 return this.getChunkProvider().findClosestStructure(this, par1Str, par2, par3, par4); 4361 } 4362 4363 @SideOnly(Side.CLIENT) 4364 4365 /** 4366 * set by !chunk.getAreLevelsEmpty 4367 */ 4368 public boolean extendedLevelsInChunkCache() 4369 { 4370 return false; 4371 } 4372 4373 @SideOnly(Side.CLIENT) 4374 4375 /** 4376 * Returns horizon height for use in rendering the sky. 4377 */ 4378 public double getHorizon() 4379 { 4380 return provider.getHorizon(); 4381 } 4382 4383 /** 4384 * Adds some basic stats of the world to the given crash report. 4385 */ 4386 public CrashReportCategory addWorldInfoToCrashReport(CrashReport par1CrashReport) 4387 { 4388 CrashReportCategory crashreportcategory = par1CrashReport.makeCategoryDepth("Affected level", 1); 4389 crashreportcategory.addCrashSection("Level name", this.worldInfo == null ? "????" : this.worldInfo.getWorldName()); 4390 crashreportcategory.addCrashSectionCallable("All players", new CallableLvl2(this)); 4391 crashreportcategory.addCrashSectionCallable("Chunk stats", new CallableLvl3(this)); 4392 4393 try 4394 { 4395 this.worldInfo.addToCrashReport(crashreportcategory); 4396 } 4397 catch (Throwable throwable) 4398 { 4399 crashreportcategory.addCrashSectionThrowable("Level Data Unobtainable", throwable); 4400 } 4401 4402 return crashreportcategory; 4403 } 4404 4405 /** 4406 * Starts (or continues) destroying a block with given ID at the given coordinates for the given partially destroyed 4407 * value 4408 */ 4409 public void destroyBlockInWorldPartially(int par1, int par2, int par3, int par4, int par5) 4410 { 4411 for (int j1 = 0; j1 < this.worldAccesses.size(); ++j1) 4412 { 4413 IWorldAccess iworldaccess = (IWorldAccess)this.worldAccesses.get(j1); 4414 iworldaccess.destroyBlockPartially(par1, par2, par3, par4, par5); 4415 } 4416 } 4417 4418 /** 4419 * Return the Vec3Pool object for this world. 4420 */ 4421 public Vec3Pool getWorldVec3Pool() 4422 { 4423 return this.vecPool; 4424 } 4425 4426 /** 4427 * returns a calendar object containing the current date 4428 */ 4429 public Calendar getCurrentDate() 4430 { 4431 if (this.getTotalWorldTime() % 600L == 0L) 4432 { 4433 this.theCalendar.setTimeInMillis(System.currentTimeMillis()); 4434 } 4435 4436 return this.theCalendar; 4437 } 4438 4439 @SideOnly(Side.CLIENT) 4440 public void func_92088_a(double par1, double par3, double par5, double par7, double par9, double par11, NBTTagCompound par13NBTTagCompound) {} 4441 4442 public Scoreboard getScoreboard() 4443 { 4444 return this.worldScoreboard; 4445 } 4446 4447 public void func_96440_m(int par1, int par2, int par3, int par4) 4448 { 4449 for (int i1 = 0; i1 < 4; ++i1) 4450 { 4451 int j1 = par1 + Direction.offsetX[i1]; 4452 int k1 = par3 + Direction.offsetZ[i1]; 4453 int l1 = this.getBlockId(j1, par2, k1); 4454 4455 if (l1 != 0) 4456 { 4457 Block block = Block.blocksList[l1]; 4458 4459 if (Block.redstoneComparatorIdle.func_94487_f(l1)) 4460 { 4461 block.onNeighborBlockChange(this, j1, par2, k1, par4); 4462 } 4463 else if (Block.isNormalCube(l1)) 4464 { 4465 j1 += Direction.offsetX[i1]; 4466 k1 += Direction.offsetZ[i1]; 4467 l1 = this.getBlockId(j1, par2, k1); 4468 block = Block.blocksList[l1]; 4469 4470 if (Block.redstoneComparatorIdle.func_94487_f(l1)) 4471 { 4472 block.onNeighborBlockChange(this, j1, par2, k1, par4); 4473 } 4474 } 4475 } 4476 } 4477 } 4478 4479 public ILogAgent getWorldLogAgent() 4480 { 4481 return this.field_98181_L; 4482 } 4483 4484 /** 4485 * Adds a single TileEntity to the world. 4486 * @param entity The TileEntity to be added. 4487 */ 4488 public void addTileEntity(TileEntity entity) 4489 { 4490 List dest = scanningTileEntities ? addedTileEntityList : loadedTileEntityList; 4491 if(entity.canUpdate()) 4492 { 4493 dest.add(entity); 4494 } 4495 } 4496 4497 /** 4498 * Determine if the given block is considered solid on the 4499 * specified side. Used by placement logic. 4500 * 4501 * @param x Block X Position 4502 * @param y Block Y Position 4503 * @param z Block Z Position 4504 * @param side The Side in question 4505 * @return True if the side is solid 4506 */ 4507 public boolean isBlockSolidOnSide(int x, int y, int z, ForgeDirection side) 4508 { 4509 return isBlockSolidOnSide(x, y, z, side, false); 4510 } 4511 4512 /** 4513 * Determine if the given block is considered solid on the 4514 * specified side. Used by placement logic. 4515 * 4516 * @param x Block X Position 4517 * @param y Block Y Position 4518 * @param z Block Z Position 4519 * @param side The Side in question 4520 * @param _default The defult to return if the block doesn't exist. 4521 * @return True if the side is solid 4522 */ 4523 public boolean isBlockSolidOnSide(int x, int y, int z, ForgeDirection side, boolean _default) 4524 { 4525 if (x < -30000000 || z < -30000000 || x >= 30000000 || z >= 30000000) 4526 { 4527 return _default; 4528 } 4529 4530 Chunk chunk = this.chunkProvider.provideChunk(x >> 4, z >> 4); 4531 if (chunk == null || chunk.isEmpty()) 4532 { 4533 return _default; 4534 } 4535 4536 Block block = Block.blocksList[getBlockId(x, y, z)]; 4537 if(block == null) 4538 { 4539 return false; 4540 } 4541 4542 return block.isBlockSolidOnSide(this, x, y, z, side); 4543 } 4544 4545 /** 4546 * Get the persistent chunks for this world 4547 * 4548 * @return 4549 */ 4550 public ImmutableSetMultimap<ChunkCoordIntPair, Ticket> getPersistentChunks() 4551 { 4552 return ForgeChunkManager.getPersistentChunksFor(this); 4553 } 4554 4555 /** 4556 * Readded as it was removed, very useful helper function 4557 * 4558 * @param x X position 4559 * @param y Y Position 4560 * @param z Z Position 4561 * @return The blocks light opacity 4562 */ 4563 public int getBlockLightOpacity(int x, int y, int z) 4564 { 4565 if (x < -30000000 || z < -30000000 || x >= 30000000 || z >= 30000000) 4566 { 4567 return 0; 4568 } 4569 4570 if (y < 0 || y >= 256) 4571 { 4572 return 0; 4573 } 4574 4575 return getChunkFromChunkCoords(x >> 4, z >> 4).getBlockLightOpacity(x & 15, y, z & 15); 4576 } 4577 4578 /** 4579 * Returns a count of entities that classify themselves as the specified creature type. 4580 */ 4581 public int countEntities(EnumCreatureType type, boolean forSpawnCount) 4582 { 4583 int count = 0; 4584 for (int x = 0; x < loadedEntityList.size(); x++) 4585 { 4586 if (((Entity)loadedEntityList.get(x)).isCreatureType(type, forSpawnCount)) 4587 { 4588 count++; 4589 } 4590 } 4591 return count; 4592 } 4593}