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