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