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