package net.minecraft.world.chunk; import com.google.common.base.Predicate; import com.google.common.collect.Maps; import com.google.common.collect.Queues; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentLinkedQueue; import net.minecraft.block.Block; import net.minecraft.block.ITileEntityProvider; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.crash.CrashReport; import net.minecraft.crash.CrashReportCategory; import net.minecraft.entity.Entity; import net.minecraft.init.Blocks; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.AxisAlignedBB; import net.minecraft.util.BlockPos; import net.minecraft.util.ClassInheratanceMultiMap; import net.minecraft.util.EnumFacing; import net.minecraft.util.MathHelper; import net.minecraft.util.ReportedException; import net.minecraft.world.ChunkCoordIntPair; import net.minecraft.world.EnumSkyBlock; import net.minecraft.world.World; import net.minecraft.world.WorldType; import net.minecraft.world.biome.BiomeGenBase; import net.minecraft.world.biome.WorldChunkManager; import net.minecraft.world.chunk.storage.ExtendedBlockStorage; import net.minecraft.world.gen.ChunkProviderDebug; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Chunk { private static final Logger logger = LogManager.getLogger(); /** * Used to store block IDs, block MSBs, Sky-light maps, Block-light maps, and metadata. Each entry corresponds to a * logical segment of 16x16x16 blocks, stacked vertically. */ private final ExtendedBlockStorage[] storageArrays; /** * Contains a 16x16 mapping on the X/Z plane of the biome ID to which each colum belongs. */ private final byte[] blockBiomeArray; /** * A map, similar to heightMap, that tracks how far down precipitation can fall. */ private final int[] precipitationHeightMap; /** Which columns need their skylightMaps updated. */ private final boolean[] updateSkylightColumns; /** Whether or not this Chunk is currently loaded into the World */ private boolean isChunkLoaded; /** Reference to the World object. */ private final World worldObj; private final int[] heightMap; /** The x coordinate of the chunk. */ public final int xPosition; /** The z coordinate of the chunk. */ public final int zPosition; private boolean isGapLightingUpdated; /** A Map of ChunkPositions to TileEntities in this chunk */ private final Map chunkTileEntityMap; /** * Array of Lists containing the entities in this Chunk. Each List represents a 16 block subchunk. */ private final ClassInheratanceMultiMap[] entityLists; /** Boolean value indicating if the terrain is populated. */ private boolean isTerrainPopulated; private boolean isLightPopulated; private boolean field_150815_m; /** * Set to true if the chunk has been modified and needs to be updated internally. */ private boolean isModified; /** * Whether this Chunk has any Entities and thus requires saving on every tick */ private boolean hasEntities; /** The time according to World.worldTime when this chunk was last saved */ private long lastSaveTime; /** Lowest value in the heightmap. */ private int heightMapMinimum; /** the cumulative number of ticks players have been in this chunk */ private long inhabitedTime; /** * Contains the current round-robin relight check index, and is implied as the relight check location as well. */ private int queuedLightChecks; private ConcurrentLinkedQueue field_177447_w; private static final String __OBFID = "CL_00000373"; public Chunk(World worldIn, int x, int z) { this.storageArrays = new ExtendedBlockStorage[16]; this.blockBiomeArray = new byte[256]; this.precipitationHeightMap = new int[256]; this.updateSkylightColumns = new boolean[256]; this.chunkTileEntityMap = Maps.newHashMap(); this.queuedLightChecks = 4096; this.field_177447_w = Queues.newConcurrentLinkedQueue(); this.entityLists = (ClassInheratanceMultiMap[])(new ClassInheratanceMultiMap[16]); this.worldObj = worldIn; this.xPosition = x; this.zPosition = z; this.heightMap = new int[256]; for (int var4 = 0; var4 < this.entityLists.length; ++var4) { this.entityLists[var4] = new ClassInheratanceMultiMap(Entity.class); } Arrays.fill(this.precipitationHeightMap, -999); Arrays.fill(this.blockBiomeArray, (byte) - 1); } public Chunk(World worldIn, ChunkPrimer primer, int x, int z) { this(worldIn, x, z); short var5 = 256; boolean var6 = !worldIn.provider.getHasNoSky(); for (int var7 = 0; var7 < 16; ++var7) { for (int var8 = 0; var8 < 16; ++var8) { for (int var9 = 0; var9 < var5; ++var9) { int var10 = var7 * var5 * 16 | var8 * var5 | var9; IBlockState var11 = primer.getBlockState(var10); if (var11.getBlock().getMaterial() != Material.air) { int var12 = var9 >> 4; if (this.storageArrays[var12] == null) { this.storageArrays[var12] = new ExtendedBlockStorage(var12 << 4, var6); } this.storageArrays[var12].set(var7, var9 & 15, var8, var11); } } } } } /** * Checks whether the chunk is at the X/Z location specified */ public boolean isAtLocation(int x, int z) { return x == this.xPosition && z == this.zPosition; } public int getHeight(BlockPos pos) { return this.getHeight(pos.getX() & 15, pos.getZ() & 15); } /** * Returns the value in the height map at this x, z coordinate in the chunk */ public int getHeight(int x, int z) { return this.heightMap[z << 4 | x]; } /** * Returns the topmost ExtendedBlockStorage instance for this Chunk that actually contains a block. */ public int getTopFilledSegment() { for (int var1 = this.storageArrays.length - 1; var1 >= 0; --var1) { if (this.storageArrays[var1] != null) { return this.storageArrays[var1].getYLocation(); } } return 0; } /** * Returns the ExtendedBlockStorage array for this Chunk. */ public ExtendedBlockStorage[] getBlockStorageArray() { return this.storageArrays; } /** * Generates the initial skylight map for the chunk upon generation or load. */ public void generateSkylightMap() { int var1 = this.getTopFilledSegment(); this.heightMapMinimum = Integer.MAX_VALUE; for (int var2 = 0; var2 < 16; ++var2) { int var3 = 0; while (var3 < 16) { this.precipitationHeightMap[var2 + (var3 << 4)] = -999; int var4 = var1 + 16; while (true) { if (var4 > 0) { if (this.getBlockLightOpacity(var2, var4 - 1, var3) == 0) { --var4; continue; } this.heightMap[var3 << 4 | var2] = var4; if (var4 < this.heightMapMinimum) { this.heightMapMinimum = var4; } } if (!this.worldObj.provider.getHasNoSky()) { var4 = 15; int var5 = var1 + 16 - 1; do { int var6 = this.getBlockLightOpacity(var2, var5, var3); if (var6 == 0 && var4 != 15) { var6 = 1; } var4 -= var6; if (var4 > 0) { ExtendedBlockStorage var7 = this.storageArrays[var5 >> 4]; if (var7 != null) { var7.setExtSkylightValue(var2, var5 & 15, var3, var4); this.worldObj.notifyLightSet(new BlockPos((this.xPosition << 4) + var2, var5, (this.zPosition << 4) + var3)); } } --var5; } while (var5 > 0 && var4 > 0); } ++var3; break; } } } this.isModified = true; } /** * Propagates a given sky-visible block's light value downward and upward to neighboring blocks as necessary. */ private void propagateSkylightOcclusion(int x, int z) { this.updateSkylightColumns[x + z * 16] = true; this.isGapLightingUpdated = true; } private void recheckGaps(boolean p_150803_1_) { this.worldObj.theProfiler.startSection("recheckGaps"); if (this.worldObj.isAreaLoaded(new BlockPos(this.xPosition * 16 + 8, 0, this.zPosition * 16 + 8), 16)) { for (int var2 = 0; var2 < 16; ++var2) { for (int var3 = 0; var3 < 16; ++var3) { if (this.updateSkylightColumns[var2 + var3 * 16]) { this.updateSkylightColumns[var2 + var3 * 16] = false; int var4 = this.getHeight(var2, var3); int var5 = this.xPosition * 16 + var2; int var6 = this.zPosition * 16 + var3; int var7 = Integer.MAX_VALUE; Iterator var8; EnumFacing var9; for (var8 = EnumFacing.Plane.HORIZONTAL.iterator(); var8.hasNext(); var7 = Math.min(var7, this.worldObj.getChunksLowestHorizon(var5 + var9.getFrontOffsetX(), var6 + var9.getFrontOffsetZ()))) { var9 = (EnumFacing)var8.next(); } this.checkSkylightNeighborHeight(var5, var6, var7); var8 = EnumFacing.Plane.HORIZONTAL.iterator(); while (var8.hasNext()) { var9 = (EnumFacing)var8.next(); this.checkSkylightNeighborHeight(var5 + var9.getFrontOffsetX(), var6 + var9.getFrontOffsetZ(), var4); } if (p_150803_1_) { this.worldObj.theProfiler.endSection(); return; } } } } this.isGapLightingUpdated = false; } this.worldObj.theProfiler.endSection(); } /** * Checks the height of a block next to a sky-visible block and schedules a lighting update as necessary. */ private void checkSkylightNeighborHeight(int x, int p_76599_2_, int z) { int var4 = this.worldObj.getHorizon(new BlockPos(x, 0, p_76599_2_)).getY(); if (var4 > z) { this.updateSkylightNeighborHeight(x, p_76599_2_, z, var4 + 1); } else if (var4 < z) { this.updateSkylightNeighborHeight(x, p_76599_2_, var4, z + 1); } } private void updateSkylightNeighborHeight(int x, int z, int startY, int endY) { if (endY > startY && this.worldObj.isAreaLoaded(new BlockPos(x, 0, z), 16)) { for (int var5 = startY; var5 < endY; ++var5) { this.worldObj.checkLightFor(EnumSkyBlock.SKY, new BlockPos(x, var5, z)); } this.isModified = true; } } /** * Initiates the recalculation of both the block-light and sky-light for a given block inside a chunk. */ private void relightBlock(int x, int y, int z) { int var4 = this.heightMap[z << 4 | x] & 255; int var5 = var4; if (y > var4) { var5 = y; } while (var5 > 0 && this.getBlockLightOpacity(x, var5 - 1, z) == 0) { --var5; } if (var5 != var4) { this.worldObj.markBlocksDirtyVertical(x + this.xPosition * 16, z + this.zPosition * 16, var5, var4); this.heightMap[z << 4 | x] = var5; int var6 = this.xPosition * 16 + x; int var7 = this.zPosition * 16 + z; int var8; int var13; if (!this.worldObj.provider.getHasNoSky()) { ExtendedBlockStorage var9; if (var5 < var4) { for (var8 = var5; var8 < var4; ++var8) { var9 = this.storageArrays[var8 >> 4]; if (var9 != null) { var9.setExtSkylightValue(x, var8 & 15, z, 15); this.worldObj.notifyLightSet(new BlockPos((this.xPosition << 4) + x, var8, (this.zPosition << 4) + z)); } } } else { for (var8 = var4; var8 < var5; ++var8) { var9 = this.storageArrays[var8 >> 4]; if (var9 != null) { var9.setExtSkylightValue(x, var8 & 15, z, 0); this.worldObj.notifyLightSet(new BlockPos((this.xPosition << 4) + x, var8, (this.zPosition << 4) + z)); } } } var8 = 15; while (var5 > 0 && var8 > 0) { --var5; var13 = this.getBlockLightOpacity(x, var5, z); if (var13 == 0) { var13 = 1; } var8 -= var13; if (var8 < 0) { var8 = 0; } ExtendedBlockStorage var10 = this.storageArrays[var5 >> 4]; if (var10 != null) { var10.setExtSkylightValue(x, var5 & 15, z, var8); } } } var8 = this.heightMap[z << 4 | x]; var13 = var4; int var14 = var8; if (var8 < var4) { var13 = var8; var14 = var4; } if (var8 < this.heightMapMinimum) { this.heightMapMinimum = var8; } if (!this.worldObj.provider.getHasNoSky()) { Iterator var11 = EnumFacing.Plane.HORIZONTAL.iterator(); while (var11.hasNext()) { EnumFacing var12 = (EnumFacing)var11.next(); this.updateSkylightNeighborHeight(var6 + var12.getFrontOffsetX(), var7 + var12.getFrontOffsetZ(), var13, var14); } this.updateSkylightNeighborHeight(var6, var7, var13, var14); } this.isModified = true; } } public int getBlockLightOpacity(BlockPos pos) { return this.getBlock(pos).getLightOpacity(); } private int getBlockLightOpacity(int p_150808_1_, int p_150808_2_, int p_150808_3_) { return this.getBlock0(p_150808_1_, p_150808_2_, p_150808_3_).getLightOpacity(); } /** * Returns the block corresponding to the given coordinates inside a chunk. */ private Block getBlock0(int x, int y, int z) { Block var4 = Blocks.air; if (y >= 0 && y >> 4 < this.storageArrays.length) { ExtendedBlockStorage var5 = this.storageArrays[y >> 4]; if (var5 != null) { try { var4 = var5.getBlockByExtId(x, y & 15, z); } catch (Throwable var8) { CrashReport var7 = CrashReport.makeCrashReport(var8, "Getting block"); throw new ReportedException(var7); } } } return var4; } public Block getBlock(final int x, final int y, final int z) { try { return this.getBlock0(x & 15, y, z & 15); } catch (ReportedException var6) { CrashReportCategory var5 = var6.getCrashReport().makeCategory("Block being got"); var5.addCrashSectionCallable("Location", new Callable() { private static final String __OBFID = "CL_00000374"; public String call() { return CrashReportCategory.getCoordinateInfo(new BlockPos(Chunk.this.xPosition * 16 + x, y, Chunk.this.zPosition * 16 + z)); } }); throw var6; } } public Block getBlock(final BlockPos pos) { try { return this.getBlock0(pos.getX() & 15, pos.getY(), pos.getZ() & 15); } catch (ReportedException var4) { CrashReportCategory var3 = var4.getCrashReport().makeCategory("Block being got"); var3.addCrashSectionCallable("Location", new Callable() { private static final String __OBFID = "CL_00002011"; public String func_177455_a() { return CrashReportCategory.getCoordinateInfo(pos); } public Object call() { return this.func_177455_a(); } }); throw var4; } } public IBlockState getBlockState(final BlockPos pos) { if (this.worldObj.getWorldType() == WorldType.DEBUG_WORLD) { IBlockState var7 = null; if (pos.getY() == 60) { var7 = Blocks.barrier.getDefaultState(); } if (pos.getY() == 70) { var7 = ChunkProviderDebug.func_177461_b(pos.getX(), pos.getZ()); } return var7 == null ? Blocks.air.getDefaultState() : var7; } else { try { if (pos.getY() >= 0 && pos.getY() >> 4 < this.storageArrays.length) { ExtendedBlockStorage var2 = this.storageArrays[pos.getY() >> 4]; if (var2 != null) { int var8 = pos.getX() & 15; int var9 = pos.getY() & 15; int var5 = pos.getZ() & 15; return var2.get(var8, var9, var5); } } return Blocks.air.getDefaultState(); } catch (Throwable var6) { CrashReport var3 = CrashReport.makeCrashReport(var6, "Getting block state"); CrashReportCategory var4 = var3.makeCategory("Block being got"); var4.addCrashSectionCallable("Location", new Callable() { private static final String __OBFID = "CL_00002010"; public String func_177448_a() { return CrashReportCategory.getCoordinateInfo(pos); } public Object call() { return this.func_177448_a(); } }); throw new ReportedException(var3); } } } /** * Return the metadata corresponding to the given coordinates inside a chunk. */ private int getBlockMetadata(int p_76628_1_, int p_76628_2_, int p_76628_3_) { if (p_76628_2_ >> 4 >= this.storageArrays.length) { return 0; } else { ExtendedBlockStorage var4 = this.storageArrays[p_76628_2_ >> 4]; return var4 != null ? var4.getExtBlockMetadata(p_76628_1_, p_76628_2_ & 15, p_76628_3_) : 0; } } public int getBlockMetadata(BlockPos pos) { return this.getBlockMetadata(pos.getX() & 15, pos.getY(), pos.getZ() & 15); } public IBlockState setBlockState(BlockPos p_177436_1_, IBlockState p_177436_2_) { int var3 = p_177436_1_.getX() & 15; int var4 = p_177436_1_.getY(); int var5 = p_177436_1_.getZ() & 15; int var6 = var5 << 4 | var3; if (var4 >= this.precipitationHeightMap[var6] - 1) { this.precipitationHeightMap[var6] = -999; } int var7 = this.heightMap[var6]; IBlockState var8 = this.getBlockState(p_177436_1_); if (var8 == p_177436_2_) { return null; } else { Block var9 = p_177436_2_.getBlock(); Block var10 = var8.getBlock(); ExtendedBlockStorage var11 = this.storageArrays[var4 >> 4]; boolean var12 = false; if (var11 == null) { if (var9 == Blocks.air) { return null; } var11 = this.storageArrays[var4 >> 4] = new ExtendedBlockStorage(var4 >> 4 << 4, !this.worldObj.provider.getHasNoSky()); var12 = var4 >= var7; } var11.set(var3, var4 & 15, var5, p_177436_2_); if (var10 != var9) { if (!this.worldObj.isRemote) { var10.breakBlock(this.worldObj, p_177436_1_, var8); } else if (var10 instanceof ITileEntityProvider) { this.worldObj.removeTileEntity(p_177436_1_); } } if (var11.getBlockByExtId(var3, var4 & 15, var5) != var9) { return null; } else { if (var12) { this.generateSkylightMap(); } else { int var13 = var9.getLightOpacity(); int var14 = var10.getLightOpacity(); if (var13 > 0) { if (var4 >= var7) { this.relightBlock(var3, var4 + 1, var5); } } else if (var4 == var7 - 1) { this.relightBlock(var3, var4, var5); } if (var13 != var14 && (var13 < var14 || this.getLightFor(EnumSkyBlock.SKY, p_177436_1_) > 0 || this.getLightFor(EnumSkyBlock.BLOCK, p_177436_1_) > 0)) { this.propagateSkylightOcclusion(var3, var5); } } TileEntity var15; if (var10 instanceof ITileEntityProvider) { var15 = this.func_177424_a(p_177436_1_, Chunk.EnumCreateEntityType.CHECK); if (var15 != null) { var15.updateContainingBlockInfo(); } } if (!this.worldObj.isRemote && var10 != var9) { var9.onBlockAdded(this.worldObj, p_177436_1_, p_177436_2_); } if (var9 instanceof ITileEntityProvider) { var15 = this.func_177424_a(p_177436_1_, Chunk.EnumCreateEntityType.CHECK); if (var15 == null) { var15 = ((ITileEntityProvider)var9).createNewTileEntity(this.worldObj, var9.getMetaFromState(p_177436_2_)); this.worldObj.setTileEntity(p_177436_1_, var15); } if (var15 != null) { var15.updateContainingBlockInfo(); } } this.isModified = true; return var8; } } } public int getLightFor(EnumSkyBlock p_177413_1_, BlockPos p_177413_2_) { int var3 = p_177413_2_.getX() & 15; int var4 = p_177413_2_.getY(); int var5 = p_177413_2_.getZ() & 15; ExtendedBlockStorage var6 = this.storageArrays[var4 >> 4]; return var6 == null ? (this.canSeeSky(p_177413_2_) ? p_177413_1_.defaultLightValue : 0) : (p_177413_1_ == EnumSkyBlock.SKY ? (this.worldObj.provider.getHasNoSky() ? 0 : var6.getExtSkylightValue(var3, var4 & 15, var5)) : (p_177413_1_ == EnumSkyBlock.BLOCK ? var6.getExtBlocklightValue(var3, var4 & 15, var5) : p_177413_1_.defaultLightValue)); } public void setLightFor(EnumSkyBlock p_177431_1_, BlockPos p_177431_2_, int p_177431_3_) { int var4 = p_177431_2_.getX() & 15; int var5 = p_177431_2_.getY(); int var6 = p_177431_2_.getZ() & 15; ExtendedBlockStorage var7 = this.storageArrays[var5 >> 4]; if (var7 == null) { var7 = this.storageArrays[var5 >> 4] = new ExtendedBlockStorage(var5 >> 4 << 4, !this.worldObj.provider.getHasNoSky()); this.generateSkylightMap(); } this.isModified = true; if (p_177431_1_ == EnumSkyBlock.SKY) { if (!this.worldObj.provider.getHasNoSky()) { var7.setExtSkylightValue(var4, var5 & 15, var6, p_177431_3_); } } else if (p_177431_1_ == EnumSkyBlock.BLOCK) { var7.setExtBlocklightValue(var4, var5 & 15, var6, p_177431_3_); } } public int setLight(BlockPos p_177443_1_, int p_177443_2_) { int var3 = p_177443_1_.getX() & 15; int var4 = p_177443_1_.getY(); int var5 = p_177443_1_.getZ() & 15; ExtendedBlockStorage var6 = this.storageArrays[var4 >> 4]; if (var6 == null) { return !this.worldObj.provider.getHasNoSky() && p_177443_2_ < EnumSkyBlock.SKY.defaultLightValue ? EnumSkyBlock.SKY.defaultLightValue - p_177443_2_ : 0; } else { int var7 = this.worldObj.provider.getHasNoSky() ? 0 : var6.getExtSkylightValue(var3, var4 & 15, var5); var7 -= p_177443_2_; int var8 = var6.getExtBlocklightValue(var3, var4 & 15, var5); if (var8 > var7) { var7 = var8; } return var7; } } /** * Adds an entity to the chunk. Args: entity */ public void addEntity(Entity entityIn) { this.hasEntities = true; int var2 = MathHelper.floor_double(entityIn.posX / 16.0D); int var3 = MathHelper.floor_double(entityIn.posZ / 16.0D); if (var2 != this.xPosition || var3 != this.zPosition) { logger.warn("Wrong location! (" + var2 + ", " + var3 + ") should be (" + this.xPosition + ", " + this.zPosition + "), " + entityIn, new Object[] {entityIn}); entityIn.setDead(); } int var4 = MathHelper.floor_double(entityIn.posY / 16.0D); if (var4 < 0) { var4 = 0; } if (var4 >= this.entityLists.length) { var4 = this.entityLists.length - 1; } entityIn.addedToChunk = true; entityIn.chunkCoordX = this.xPosition; entityIn.chunkCoordY = var4; entityIn.chunkCoordZ = this.zPosition; this.entityLists[var4].add(entityIn); } /** * removes entity using its y chunk coordinate as its index */ public void removeEntity(Entity p_76622_1_) { this.removeEntityAtIndex(p_76622_1_, p_76622_1_.chunkCoordY); } /** * Removes entity at the specified index from the entity array. */ public void removeEntityAtIndex(Entity p_76608_1_, int p_76608_2_) { if (p_76608_2_ < 0) { p_76608_2_ = 0; } if (p_76608_2_ >= this.entityLists.length) { p_76608_2_ = this.entityLists.length - 1; } this.entityLists[p_76608_2_].remove(p_76608_1_); } public boolean canSeeSky(BlockPos pos) { int var2 = pos.getX() & 15; int var3 = pos.getY(); int var4 = pos.getZ() & 15; return var3 >= this.heightMap[var4 << 4 | var2]; } private TileEntity createNewTileEntity(BlockPos pos) { Block var2 = this.getBlock(pos); return !var2.hasTileEntity() ? null : ((ITileEntityProvider)var2).createNewTileEntity(this.worldObj, this.getBlockMetadata(pos)); } public TileEntity func_177424_a(BlockPos p_177424_1_, Chunk.EnumCreateEntityType p_177424_2_) { TileEntity var3 = (TileEntity)this.chunkTileEntityMap.get(p_177424_1_); if (var3 == null) { if (p_177424_2_ == Chunk.EnumCreateEntityType.IMMEDIATE) { var3 = this.createNewTileEntity(p_177424_1_); this.worldObj.setTileEntity(p_177424_1_, var3); } else if (p_177424_2_ == Chunk.EnumCreateEntityType.QUEUED) { this.field_177447_w.add(p_177424_1_); } } else if (var3.isInvalid()) { this.chunkTileEntityMap.remove(p_177424_1_); return null; } return var3; } public void addTileEntity(TileEntity tileEntityIn) { this.addTileEntity(tileEntityIn.getPos(), tileEntityIn); if (this.isChunkLoaded) { this.worldObj.addTileEntity(tileEntityIn); } } public void addTileEntity(BlockPos pos, TileEntity tileEntityIn) { tileEntityIn.setWorldObj(this.worldObj); tileEntityIn.setPos(pos); if (this.getBlock(pos) instanceof ITileEntityProvider) { if (this.chunkTileEntityMap.containsKey(pos)) { ((TileEntity)this.chunkTileEntityMap.get(pos)).invalidate(); } tileEntityIn.validate(); this.chunkTileEntityMap.put(pos, tileEntityIn); } } public void removeTileEntity(BlockPos pos) { if (this.isChunkLoaded) { TileEntity var2 = (TileEntity)this.chunkTileEntityMap.remove(pos); if (var2 != null) { var2.invalidate(); } } } /** * Called when this Chunk is loaded by the ChunkProvider */ public void onChunkLoad() { this.isChunkLoaded = true; this.worldObj.addTileEntities(this.chunkTileEntityMap.values()); for (int var1 = 0; var1 < this.entityLists.length; ++var1) { Iterator var2 = this.entityLists[var1].iterator(); while (var2.hasNext()) { Entity var3 = (Entity)var2.next(); var3.onChunkLoad(); } this.worldObj.loadEntities(this.entityLists[var1]); } } /** * Called when this Chunk is unloaded by the ChunkProvider */ public void onChunkUnload() { this.isChunkLoaded = false; Iterator var1 = this.chunkTileEntityMap.values().iterator(); while (var1.hasNext()) { TileEntity var2 = (TileEntity)var1.next(); this.worldObj.markTileEntityForRemoval(var2); } for (int var3 = 0; var3 < this.entityLists.length; ++var3) { this.worldObj.unloadEntities(this.entityLists[var3]); } } /** * Sets the isModified flag for this Chunk */ public void setChunkModified() { this.isModified = true; } public void func_177414_a(Entity p_177414_1_, AxisAlignedBB p_177414_2_, List p_177414_3_, Predicate p_177414_4_) { int var5 = MathHelper.floor_double((p_177414_2_.minY - 2.0D) / 16.0D); int var6 = MathHelper.floor_double((p_177414_2_.maxY + 2.0D) / 16.0D); var5 = MathHelper.clamp_int(var5, 0, this.entityLists.length - 1); var6 = MathHelper.clamp_int(var6, 0, this.entityLists.length - 1); for (int var7 = var5; var7 <= var6; ++var7) { Iterator var8 = this.entityLists[var7].iterator(); while (var8.hasNext()) { Entity var9 = (Entity)var8.next(); if (var9 != p_177414_1_ && var9.getEntityBoundingBox().intersectsWith(p_177414_2_) && (p_177414_4_ == null || p_177414_4_.apply(var9))) { p_177414_3_.add(var9); Entity[] var10 = var9.getParts(); if (var10 != null) { for (int var11 = 0; var11 < var10.length; ++var11) { var9 = var10[var11]; if (var9 != p_177414_1_ && var9.getEntityBoundingBox().intersectsWith(p_177414_2_) && (p_177414_4_ == null || p_177414_4_.apply(var9))) { p_177414_3_.add(var9); } } } } } } } public void func_177430_a(Class p_177430_1_, AxisAlignedBB p_177430_2_, List p_177430_3_, Predicate p_177430_4_) { int var5 = MathHelper.floor_double((p_177430_2_.minY - 2.0D) / 16.0D); int var6 = MathHelper.floor_double((p_177430_2_.maxY + 2.0D) / 16.0D); var5 = MathHelper.clamp_int(var5, 0, this.entityLists.length - 1); var6 = MathHelper.clamp_int(var6, 0, this.entityLists.length - 1); for (int var7 = var5; var7 <= var6; ++var7) { Iterator var8 = this.entityLists[var7].func_180215_b(p_177430_1_).iterator(); while (var8.hasNext()) { Entity var9 = (Entity)var8.next(); if (var9.getEntityBoundingBox().intersectsWith(p_177430_2_) && (p_177430_4_ == null || p_177430_4_.apply(var9))) { p_177430_3_.add(var9); } } } } /** * Returns true if this Chunk needs to be saved */ public boolean needsSaving(boolean p_76601_1_) { if (p_76601_1_) { if (this.hasEntities && this.worldObj.getTotalWorldTime() != this.lastSaveTime || this.isModified) { return true; } } else if (this.hasEntities && this.worldObj.getTotalWorldTime() >= this.lastSaveTime + 600L) { return true; } return this.isModified; } public Random getRandomWithSeed(long seed) { return new Random(this.worldObj.getSeed() + (long)(this.xPosition * this.xPosition * 4987142) + (long)(this.xPosition * 5947611) + (long)(this.zPosition * this.zPosition) * 4392871L + (long)(this.zPosition * 389711) ^ seed); } public boolean isEmpty() { return false; } public void populateChunk(IChunkProvider p_76624_1_, IChunkProvider p_76624_2_, int p_76624_3_, int p_76624_4_) { boolean var5 = p_76624_1_.chunkExists(p_76624_3_, p_76624_4_ - 1); boolean var6 = p_76624_1_.chunkExists(p_76624_3_ + 1, p_76624_4_); boolean var7 = p_76624_1_.chunkExists(p_76624_3_, p_76624_4_ + 1); boolean var8 = p_76624_1_.chunkExists(p_76624_3_ - 1, p_76624_4_); boolean var9 = p_76624_1_.chunkExists(p_76624_3_ - 1, p_76624_4_ - 1); boolean var10 = p_76624_1_.chunkExists(p_76624_3_ + 1, p_76624_4_ + 1); boolean var11 = p_76624_1_.chunkExists(p_76624_3_ - 1, p_76624_4_ + 1); boolean var12 = p_76624_1_.chunkExists(p_76624_3_ + 1, p_76624_4_ - 1); if (var6 && var7 && var10) { if (!this.isTerrainPopulated) { p_76624_1_.populate(p_76624_2_, p_76624_3_, p_76624_4_); } else { p_76624_1_.func_177460_a(p_76624_2_, this, p_76624_3_, p_76624_4_); } } Chunk var13; if (var8 && var7 && var11) { var13 = p_76624_1_.provideChunk(p_76624_3_ - 1, p_76624_4_); if (!var13.isTerrainPopulated) { p_76624_1_.populate(p_76624_2_, p_76624_3_ - 1, p_76624_4_); } else { p_76624_1_.func_177460_a(p_76624_2_, var13, p_76624_3_ - 1, p_76624_4_); } } if (var5 && var6 && var12) { var13 = p_76624_1_.provideChunk(p_76624_3_, p_76624_4_ - 1); if (!var13.isTerrainPopulated) { p_76624_1_.populate(p_76624_2_, p_76624_3_, p_76624_4_ - 1); } else { p_76624_1_.func_177460_a(p_76624_2_, var13, p_76624_3_, p_76624_4_ - 1); } } if (var9 && var5 && var8) { var13 = p_76624_1_.provideChunk(p_76624_3_ - 1, p_76624_4_ - 1); if (!var13.isTerrainPopulated) { p_76624_1_.populate(p_76624_2_, p_76624_3_ - 1, p_76624_4_ - 1); } else { p_76624_1_.func_177460_a(p_76624_2_, var13, p_76624_3_ - 1, p_76624_4_ - 1); } } } public BlockPos func_177440_h(BlockPos p_177440_1_) { int var2 = p_177440_1_.getX() & 15; int var3 = p_177440_1_.getZ() & 15; int var4 = var2 | var3 << 4; BlockPos var5 = new BlockPos(p_177440_1_.getX(), this.precipitationHeightMap[var4], p_177440_1_.getZ()); if (var5.getY() == -999) { int var6 = this.getTopFilledSegment() + 15; var5 = new BlockPos(p_177440_1_.getX(), var6, p_177440_1_.getZ()); int var7 = -1; while (var5.getY() > 0 && var7 == -1) { Block var8 = this.getBlock(var5); Material var9 = var8.getMaterial(); if (!var9.blocksMovement() && !var9.isLiquid()) { var5 = var5.offsetDown(); } else { var7 = var5.getY() + 1; } } this.precipitationHeightMap[var4] = var7; } return new BlockPos(p_177440_1_.getX(), this.precipitationHeightMap[var4], p_177440_1_.getZ()); } public void func_150804_b(boolean p_150804_1_) { if (this.isGapLightingUpdated && !this.worldObj.provider.getHasNoSky() && !p_150804_1_) { this.recheckGaps(this.worldObj.isRemote); } this.field_150815_m = true; if (!this.isLightPopulated && this.isTerrainPopulated) { this.func_150809_p(); } while (!this.field_177447_w.isEmpty()) { BlockPos var2 = (BlockPos)this.field_177447_w.poll(); if (this.func_177424_a(var2, Chunk.EnumCreateEntityType.CHECK) == null && this.getBlock(var2).hasTileEntity()) { TileEntity var3 = this.createNewTileEntity(var2); this.worldObj.setTileEntity(var2, var3); this.worldObj.markBlockRangeForRenderUpdate(var2, var2); } } } public boolean isPopulated() { return this.field_150815_m && this.isTerrainPopulated && this.isLightPopulated; } /** * Gets a ChunkCoordIntPair representing the Chunk's position. */ public ChunkCoordIntPair getChunkCoordIntPair() { return new ChunkCoordIntPair(this.xPosition, this.zPosition); } /** * Returns whether the ExtendedBlockStorages containing levels (in blocks) from arg 1 to arg 2 are fully empty * (true) or not (false). */ public boolean getAreLevelsEmpty(int p_76606_1_, int p_76606_2_) { if (p_76606_1_ < 0) { p_76606_1_ = 0; } if (p_76606_2_ >= 256) { p_76606_2_ = 255; } for (int var3 = p_76606_1_; var3 <= p_76606_2_; var3 += 16) { ExtendedBlockStorage var4 = this.storageArrays[var3 >> 4]; if (var4 != null && !var4.isEmpty()) { return false; } } return true; } public void setStorageArrays(ExtendedBlockStorage[] newStorageArrays) { if (this.storageArrays.length != newStorageArrays.length) { logger.warn("Could not set level chunk sections, array length is " + newStorageArrays.length + " instead of " + this.storageArrays.length); } else { for (int var2 = 0; var2 < this.storageArrays.length; ++var2) { this.storageArrays[var2] = newStorageArrays[var2]; } } } public BiomeGenBase getBiome(BlockPos pos, WorldChunkManager chunkManager) { int var3 = pos.getX() & 15; int var4 = pos.getZ() & 15; int var5 = this.blockBiomeArray[var4 << 4 | var3] & 255; BiomeGenBase var6; if (var5 == 255) { var6 = chunkManager.func_180300_a(pos, BiomeGenBase.plains); var5 = var6.biomeID; this.blockBiomeArray[var4 << 4 | var3] = (byte)(var5 & 255); } var6 = BiomeGenBase.getBiome(var5); return var6 == null ? BiomeGenBase.plains : var6; } /** * Returns an array containing a 16x16 mapping on the X/Z of block positions in this Chunk to biome IDs. */ public byte[] getBiomeArray() { return this.blockBiomeArray; } /** * Accepts a 256-entry array that contains a 16x16 mapping on the X/Z plane of block positions in this Chunk to * biome IDs. */ public void setBiomeArray(byte[] biomeArray) { if (this.blockBiomeArray.length != biomeArray.length) { logger.warn("Could not set level chunk biomes, array length is " + biomeArray.length + " instead of " + this.blockBiomeArray.length); } else { for (int var2 = 0; var2 < this.blockBiomeArray.length; ++var2) { this.blockBiomeArray[var2] = biomeArray[var2]; } } } /** * Resets the relight check index to 0 for this Chunk. */ public void resetRelightChecks() { this.queuedLightChecks = 0; } /** * Called once-per-chunk-per-tick, and advances the round-robin relight check index by up to 8 blocks at a time. In * a worst-case scenario, can potentially take up to 25.6 seconds, calculated via (4096/8)/20, to re-check all * blocks in a chunk, which may explain lagging light updates on initial world generation. */ public void enqueueRelightChecks() { BlockPos var1 = new BlockPos(this.xPosition << 4, 0, this.zPosition << 4); for (int var2 = 0; var2 < 8; ++var2) { if (this.queuedLightChecks >= 4096) { return; } int var3 = this.queuedLightChecks % 16; int var4 = this.queuedLightChecks / 16 % 16; int var5 = this.queuedLightChecks / 256; ++this.queuedLightChecks; for (int var6 = 0; var6 < 16; ++var6) { BlockPos var7 = var1.add(var4, (var3 << 4) + var6, var5); boolean var8 = var6 == 0 || var6 == 15 || var4 == 0 || var4 == 15 || var5 == 0 || var5 == 15; if (this.storageArrays[var3] == null && var8 || this.storageArrays[var3] != null && this.storageArrays[var3].getBlockByExtId(var4, var6, var5).getMaterial() == Material.air) { EnumFacing[] var9 = EnumFacing.values(); int var10 = var9.length; for (int var11 = 0; var11 < var10; ++var11) { EnumFacing var12 = var9[var11]; BlockPos var13 = var7.offset(var12); if (this.worldObj.getBlockState(var13).getBlock().getLightValue() > 0) { this.worldObj.checkLight(var13); } } this.worldObj.checkLight(var7); } } } } public void func_150809_p() { this.isTerrainPopulated = true; this.isLightPopulated = true; BlockPos var1 = new BlockPos(this.xPosition << 4, 0, this.zPosition << 4); if (!this.worldObj.provider.getHasNoSky()) { if (this.worldObj.isAreaLoaded(var1.add(-1, 0, -1), var1.add(16, 63, 16))) { label42: for (int var2 = 0; var2 < 16; ++var2) { for (int var3 = 0; var3 < 16; ++var3) { if (!this.func_150811_f(var2, var3)) { this.isLightPopulated = false; break label42; } } } if (this.isLightPopulated) { Iterator var5 = EnumFacing.Plane.HORIZONTAL.iterator(); while (var5.hasNext()) { EnumFacing var6 = (EnumFacing)var5.next(); int var4 = var6.getAxisDirection() == EnumFacing.AxisDirection.POSITIVE ? 16 : 1; this.worldObj.getChunkFromBlockCoords(var1.offset(var6, var4)).func_180700_a(var6.getOpposite()); } this.func_177441_y(); } } else { this.isLightPopulated = false; } } } private void func_177441_y() { for (int var1 = 0; var1 < this.updateSkylightColumns.length; ++var1) { this.updateSkylightColumns[var1] = true; } this.recheckGaps(false); } private void func_180700_a(EnumFacing p_180700_1_) { if (this.isTerrainPopulated) { int var2; if (p_180700_1_ == EnumFacing.EAST) { for (var2 = 0; var2 < 16; ++var2) { this.func_150811_f(15, var2); } } else if (p_180700_1_ == EnumFacing.WEST) { for (var2 = 0; var2 < 16; ++var2) { this.func_150811_f(0, var2); } } else if (p_180700_1_ == EnumFacing.SOUTH) { for (var2 = 0; var2 < 16; ++var2) { this.func_150811_f(var2, 15); } } else if (p_180700_1_ == EnumFacing.NORTH) { for (var2 = 0; var2 < 16; ++var2) { this.func_150811_f(var2, 0); } } } } private boolean func_150811_f(int p_150811_1_, int p_150811_2_) { BlockPos var3 = new BlockPos(this.xPosition << 4, 0, this.zPosition << 4); int var4 = this.getTopFilledSegment(); boolean var5 = false; boolean var6 = false; int var7; BlockPos var8; for (var7 = var4 + 16 - 1; var7 > 63 || var7 > 0 && !var6; --var7) { var8 = var3.add(p_150811_1_, var7, p_150811_2_); int var9 = this.getBlockLightOpacity(var8); if (var9 == 255 && var7 < 63) { var6 = true; } if (!var5 && var9 > 0) { var5 = true; } else if (var5 && var9 == 0 && !this.worldObj.checkLight(var8)) { return false; } } for (; var7 > 0; --var7) { var8 = var3.add(p_150811_1_, var7, p_150811_2_); if (this.getBlock(var8).getLightValue() > 0) { this.worldObj.checkLight(var8); } } return true; } public boolean isLoaded() { return this.isChunkLoaded; } public World getWorld() { return this.worldObj; } public int[] getHeightMap() { return this.heightMap; } public void setHeightMap(int[] newHeightMap) { if (this.heightMap.length != newHeightMap.length) { logger.warn("Could not set level chunk heightmap, array length is " + newHeightMap.length + " instead of " + this.heightMap.length); } else { for (int var2 = 0; var2 < this.heightMap.length; ++var2) { this.heightMap[var2] = newHeightMap[var2]; } } } public Map getTileEntityMap() { return this.chunkTileEntityMap; } public ClassInheratanceMultiMap[] getEntityLists() { return this.entityLists; } public boolean isTerrainPopulated() { return this.isTerrainPopulated; } public void setTerrainPopulated(boolean terrainPopulated) { this.isTerrainPopulated = terrainPopulated; } public boolean isLightPopulated() { return this.isLightPopulated; } public void setLightPopulated(boolean lightPopulated) { this.isLightPopulated = lightPopulated; } public void setModified(boolean modified) { this.isModified = modified; } public void setHasEntities(boolean hasEntitiesIn) { this.hasEntities = hasEntitiesIn; } public void setLastSaveTime(long saveTime) { this.lastSaveTime = saveTime; } public int getLowestHeight() { return this.heightMapMinimum; } public long getInhabitedTime() { return this.inhabitedTime; } public void setInhabitedTime(long newInhabitedTime) { this.inhabitedTime = newInhabitedTime; } public static enum EnumCreateEntityType { IMMEDIATE("IMMEDIATE", 0), QUEUED("QUEUED", 1), CHECK("CHECK", 2); private static final Chunk.EnumCreateEntityType[] $VALUES = new Chunk.EnumCreateEntityType[]{IMMEDIATE, QUEUED, CHECK}; private static final String __OBFID = "CL_00002009"; private EnumCreateEntityType(String p_i45642_1_, int p_i45642_2_) {} } }