1711 lines
52 KiB
Java
1711 lines
52 KiB
Java
package net.minecraft.world.chunk;
|
|
|
|
import com.google.common.base.Predicate;
|
|
import com.google.common.collect.Maps;
|
|
import java.util.Arrays;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import net.hoosiertransfer.Alfheim.IChunkLightingData;
|
|
import net.hoosiertransfer.Alfheim.ILightingEngineProvider;
|
|
import net.hoosiertransfer.Alfheim.lighting.LightUtil;
|
|
import net.hoosiertransfer.Alfheim.lighting.LightingEngine;
|
|
import net.hoosiertransfer.Alfheim.util.EnumBoundaryFacing;
|
|
import net.hoosiertransfer.Alfheim.util.WorldChunkSlice;
|
|
import net.lax1dude.eaglercraft.v1_8.EaglercraftRandom;
|
|
|
|
import java.util.concurrent.Callable;
|
|
|
|
import net.lax1dude.eaglercraft.v1_8.sp.server.EaglerMinecraftServer;
|
|
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.network.PacketBuffer;
|
|
import net.minecraft.tileentity.TileEntity;
|
|
import net.minecraft.util.AxisAlignedBB;
|
|
import net.minecraft.util.BlockPos;
|
|
import net.minecraft.util.ClassInheritanceMultiMap;
|
|
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.biome.BiomeGenBase;
|
|
import net.minecraft.world.biome.WorldChunkManager;
|
|
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
|
import net.lax1dude.eaglercraft.v1_8.log4j.LogManager;
|
|
import net.lax1dude.eaglercraft.v1_8.log4j.Logger;
|
|
import net.lax1dude.eaglercraft.v1_8.opengl.ext.deferred.DeferredStateManager;
|
|
|
|
/**
|
|
* +
|
|
* This portion of EaglercraftX contains deobfuscated Minecraft 1.8 source code.
|
|
*
|
|
* Minecraft 1.8.8 bytecode is (c) 2015 Mojang AB. "Do not distribute!"
|
|
* Mod Coder Pack v9.18 deobfuscation configs are (c) Copyright by the MCP Team
|
|
*
|
|
* EaglercraftX 1.8 patch files (c) 2022-2024 lax1dude, hoosiertransfer,
|
|
* ayunami2000. All Rights Reserved.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED.
|
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
|
|
* DIRECT,
|
|
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR
|
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
*/
|
|
public class Chunk {
|
|
private static final Logger logger = LogManager.getLogger();
|
|
private final ExtendedBlockStorage[] storageArrays;
|
|
private final byte[] blockBiomeArray;
|
|
private final int[] precipitationHeightMap;
|
|
private final boolean[] updateSkylightColumns;
|
|
private boolean isChunkLoaded;
|
|
private final World worldObj;
|
|
private final int[] heightMap;
|
|
public final int xPosition;
|
|
public final int zPosition;
|
|
private boolean isGapLightingUpdated;
|
|
private final Map<BlockPos, TileEntity> chunkTileEntityMap;
|
|
private final ClassInheritanceMultiMap<Entity>[] entityLists;
|
|
private boolean isTerrainPopulated;
|
|
private boolean isLightPopulated;
|
|
private boolean field_150815_m;
|
|
private boolean isModified;
|
|
private boolean hasEntities;
|
|
private long lastSaveTime;
|
|
private int heightMapMinimum;
|
|
private long inhabitedTime;
|
|
private int queuedLightChecks;
|
|
private List<BlockPos> tileEntityPosQueue;
|
|
|
|
public static final ExtendedBlockStorage NULL_BLOCK_STORAGE = null;
|
|
|
|
private LightingEngine alfheim$lightingEngine;
|
|
private boolean alfheim$isLightInitialized;
|
|
private short[] alfheim$neighborLightChecks;
|
|
private static final EnumSkyBlock[] ENUM_SKY_BLOCK_VALUES = EnumSkyBlock.values();
|
|
private static final EnumFacing[] ENUM_FACING_HORIZONTAL = EnumFacing.Plane.HORIZONTAL.facings();
|
|
private static final EnumFacing.AxisDirection[] ENUM_AXIS_DIRECTION_VALUES = EnumFacing.AxisDirection.values();
|
|
|
|
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.tileEntityPosQueue = new LinkedList();
|
|
this.entityLists = (ClassInheritanceMultiMap[]) (new ClassInheritanceMultiMap[16]);
|
|
this.worldObj = worldIn;
|
|
this.xPosition = x;
|
|
this.zPosition = z;
|
|
this.heightMap = new int[256];
|
|
|
|
for (int i = 0; i < this.entityLists.length; ++i) {
|
|
this.entityLists[i] = new ClassInheritanceMultiMap(Entity.class);
|
|
}
|
|
|
|
Arrays.fill(this.precipitationHeightMap, -999);
|
|
Arrays.fill(this.blockBiomeArray, (byte) -1);
|
|
|
|
alfheim$lightingEngine = worldIn.alfheim$getLightingEngine();
|
|
}
|
|
|
|
public Chunk(World worldIn, ChunkPrimer primer, int x, int z) {
|
|
this(worldIn, x, z);
|
|
short short1 = 256;
|
|
boolean flag = !worldIn.provider.getHasNoSky();
|
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
for (int j = 0; j < 16; ++j) {
|
|
for (int k = 0; k < short1; ++k) {
|
|
int l = i * short1 * 16 | j * short1 | k;
|
|
IBlockState iblockstate = primer.getBlockState(l);
|
|
if (iblockstate.getBlock().getMaterial() != Material.air) {
|
|
int i1 = k >> 4;
|
|
if (this.storageArrays[i1] == null) {
|
|
this.storageArrays[i1] = new ExtendedBlockStorage(i1 << 4, flag);
|
|
}
|
|
|
|
this.storageArrays[i1].set(i, k & 15, j, iblockstate);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Checks whether the chunk is at the X/Z location specified
|
|
*/
|
|
public boolean isAtLocation(int i, int j) {
|
|
return i == this.xPosition && j == this.zPosition;
|
|
}
|
|
|
|
public int getHeight(BlockPos pos) {
|
|
return this.getHeightValue(pos.getX() & 15, pos.getZ() & 15);
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Returns the value in the height map at this x, z coordinate
|
|
* in the chunk
|
|
*/
|
|
public int getHeightValue(int i, int j) {
|
|
return this.heightMap[j << 4 | i];
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Returns the topmost ExtendedBlockStorage instance for this
|
|
* Chunk that actually contains a block.
|
|
*/
|
|
public int getTopFilledSegment() {
|
|
for (int i = this.storageArrays.length - 1; i >= 0; --i) {
|
|
if (this.storageArrays[i] != null) {
|
|
return this.storageArrays[i].getYLocation();
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Returns the ExtendedBlockStorage array for this Chunk.
|
|
*/
|
|
public ExtendedBlockStorage[] getBlockStorageArray() {
|
|
return this.storageArrays;
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Generates the height map for a chunk from scratch
|
|
*/
|
|
protected void generateHeightMap() {
|
|
int i = this.getTopFilledSegment();
|
|
this.heightMapMinimum = Integer.MAX_VALUE;
|
|
|
|
for (int j = 0; j < 16; ++j) {
|
|
for (int k = 0; k < 16; ++k) {
|
|
this.precipitationHeightMap[j + (k << 4)] = -999;
|
|
|
|
for (int l = i + 16; l > 0; --l) {
|
|
Block block = this.getBlock0(j, l - 1, k);
|
|
if (block.getLightOpacity() != 0) {
|
|
this.heightMap[k << 4 | j] = l;
|
|
if (l < this.heightMapMinimum) {
|
|
this.heightMapMinimum = l;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.isModified = true;
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Generates the initial skylight map for the chunk upon
|
|
* generation or load.
|
|
*/
|
|
public void generateSkylightMap() {
|
|
int i = this.getTopFilledSegment();
|
|
this.heightMapMinimum = Integer.MAX_VALUE;
|
|
|
|
for (int j = 0; j < 16; ++j) {
|
|
for (int k = 0; k < 16; ++k) {
|
|
this.precipitationHeightMap[j + (k << 4)] = -999;
|
|
|
|
for (int l = i + 16; l > 0; --l) {
|
|
if (this.getBlockLightOpacity(j, l - 1, k) != 0) {
|
|
this.heightMap[k << 4 | j] = l;
|
|
if (l < this.heightMapMinimum) {
|
|
this.heightMapMinimum = l;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!this.worldObj.provider.getHasNoSky()) {
|
|
int k1 = 15;
|
|
int i1 = i + 16 - 1;
|
|
|
|
while (true) {
|
|
int j1 = this.getBlockLightOpacity(j, i1, k);
|
|
if (j1 == 0 && k1 != 15) {
|
|
j1 = 1;
|
|
}
|
|
|
|
k1 -= j1;
|
|
if (k1 > 0) {
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[i1 >> 4];
|
|
if (extendedblockstorage != null) {
|
|
extendedblockstorage.setExtSkylightValue(j, i1 & 15, k, k1);
|
|
alfheim$initSkylightForSection(storageArrays[i1 >> 4]);
|
|
// do i comment this out?
|
|
// this.worldObj.notifyLightSet(
|
|
// new BlockPos((this.xPosition << 4) + j, i1, (this.zPosition << 4) + k));
|
|
}
|
|
}
|
|
|
|
--i1;
|
|
if (i1 <= 0 || k1 <= 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!this.worldObj.isRemote) {
|
|
++EaglerMinecraftServer.counterLightUpdate;
|
|
}
|
|
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 parFlag) {
|
|
if (!worldObj.isAreaLoaded(new BlockPos((xPosition << 4) + 8, 0, (zPosition << 4) + 8), 16))
|
|
return;
|
|
|
|
final WorldChunkSlice slice = new WorldChunkSlice(worldObj.getChunkProvider(), xPosition, zPosition);
|
|
|
|
for (int x = 0; x < 16; ++x) {
|
|
for (int z = 0; z < 16; ++z) {
|
|
if (!alfheim$recheckGapsForColumn(slice, x, z))
|
|
continue;
|
|
|
|
if (parFlag)
|
|
return;
|
|
}
|
|
}
|
|
|
|
isGapLightingUpdated = false;
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* 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 z, int maxValue) {
|
|
int i = this.worldObj.getHeight(new BlockPos(x, 0, z)).getY();
|
|
if (i > maxValue) {
|
|
this.updateSkylightNeighborHeight(x, z, maxValue, i + 1);
|
|
} else if (i < maxValue) {
|
|
this.updateSkylightNeighborHeight(x, z, i, maxValue + 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 i = startY; i < endY; ++i) {
|
|
this.worldObj.checkLightFor(EnumSkyBlock.SKY, new BlockPos(x, i, 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 heightMapY = heightMap[z << 4 | x] & 255;
|
|
int newHeightMapY = Math.max(y, heightMapY);
|
|
|
|
while (newHeightMapY > 0 && getBlockLightOpacity(x, newHeightMapY - 1, z) == 0)
|
|
--newHeightMapY;
|
|
|
|
if (newHeightMapY == heightMapY)
|
|
return;
|
|
|
|
heightMap[z << 4 | x] = newHeightMapY;
|
|
|
|
if (!worldObj.provider.getHasNoSky())
|
|
alfheim$relightSkylightColumn(x, z, heightMapY, newHeightMapY);
|
|
|
|
final int heightMapY1 = heightMap[z << 4 | x];
|
|
|
|
if (heightMapY1 < heightMapMinimum)
|
|
heightMapMinimum = heightMapY1;
|
|
}
|
|
|
|
public int getBlockLightOpacity(BlockPos blockpos) {
|
|
return this.getBlock(blockpos).getLightOpacity();
|
|
}
|
|
|
|
private int getBlockLightOpacity(int x, int y, int z) {
|
|
return this.getBlock0(x, y, z).getLightOpacity();
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Returns the block corresponding to the given coordinates
|
|
* inside a chunk.
|
|
*/
|
|
private Block getBlock0(int x, int y, int z) {
|
|
Block block = Blocks.air;
|
|
if (y >= 0 && y >> 4 < this.storageArrays.length) {
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[y >> 4];
|
|
if (extendedblockstorage != null) {
|
|
try {
|
|
block = extendedblockstorage.getBlockByExtId(x, y & 15, z);
|
|
} catch (Throwable throwable) {
|
|
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block");
|
|
throw new ReportedException(crashreport);
|
|
}
|
|
}
|
|
}
|
|
|
|
return block;
|
|
}
|
|
|
|
public Block getBlock(final int x, final int y, final int z) {
|
|
try {
|
|
return this.getBlock0(x & 15, y, z & 15);
|
|
} catch (ReportedException reportedexception) {
|
|
CrashReportCategory crashreportcategory = reportedexception.getCrashReport()
|
|
.makeCategory("Block being got");
|
|
crashreportcategory.addCrashSectionCallable("Location", new Callable<String>() {
|
|
public String call() throws Exception {
|
|
return CrashReportCategory.getCoordinateInfo(
|
|
new BlockPos(Chunk.this.xPosition * 16 + x, y, Chunk.this.zPosition * 16 + z));
|
|
}
|
|
});
|
|
throw reportedexception;
|
|
}
|
|
}
|
|
|
|
public Block getBlock(final BlockPos blockpos) {
|
|
try {
|
|
return this.getBlock0(blockpos.getX() & 15, blockpos.getY(), blockpos.getZ() & 15);
|
|
} catch (ReportedException reportedexception) {
|
|
CrashReportCategory crashreportcategory = reportedexception.getCrashReport()
|
|
.makeCategory("Block being got");
|
|
crashreportcategory.addCrashSectionCallable("Location", new Callable<String>() {
|
|
public String call() throws Exception {
|
|
return CrashReportCategory.getCoordinateInfo(blockpos);
|
|
}
|
|
});
|
|
throw reportedexception;
|
|
}
|
|
}
|
|
|
|
public IBlockState getBlockState(final BlockPos pos) {
|
|
try {
|
|
if (pos.getY() >= 0 && pos.getY() >> 4 < this.storageArrays.length) {
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[pos.getY() >> 4];
|
|
if (extendedblockstorage != null) {
|
|
int j = pos.getX() & 15;
|
|
int k = pos.getY() & 15;
|
|
int i = pos.getZ() & 15;
|
|
return extendedblockstorage.get(j, k, i);
|
|
}
|
|
}
|
|
|
|
return Blocks.air.getDefaultState();
|
|
} catch (Throwable throwable) {
|
|
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block state");
|
|
CrashReportCategory crashreportcategory = crashreport.makeCategory("Block being got");
|
|
crashreportcategory.addCrashSectionCallable("Location", new Callable<String>() {
|
|
public String call() throws Exception {
|
|
return CrashReportCategory.getCoordinateInfo(pos);
|
|
}
|
|
});
|
|
throw new ReportedException(crashreport);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* only use with a regular "net.minecraft.util.BlockPos"!
|
|
*/
|
|
public IBlockState getBlockStateFaster(final BlockPos pos) {
|
|
try {
|
|
if (pos.y >= 0 && pos.y >> 4 < this.storageArrays.length) {
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[pos.getY() >> 4];
|
|
if (extendedblockstorage != null) {
|
|
int j = pos.x & 15;
|
|
int k = pos.y & 15;
|
|
int i = pos.z & 15;
|
|
return extendedblockstorage.get(j, k, i);
|
|
}
|
|
}
|
|
|
|
return Blocks.air.getDefaultState();
|
|
} catch (Throwable throwable) {
|
|
CrashReport crashreport = CrashReport.makeCrashReport(throwable, "Getting block state");
|
|
CrashReportCategory crashreportcategory = crashreport.makeCategory("Block being got");
|
|
crashreportcategory.addCrashSectionCallable("Location", new Callable<String>() {
|
|
public String call() throws Exception {
|
|
return CrashReportCategory.getCoordinateInfo(pos);
|
|
}
|
|
});
|
|
throw new ReportedException(crashreport);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Return the metadata corresponding to the given coordinates
|
|
* inside a chunk.
|
|
*/
|
|
private int getBlockMetadata(int x, int y, int z) {
|
|
if (y >> 4 >= this.storageArrays.length) {
|
|
return 0;
|
|
} else {
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[y >> 4];
|
|
return extendedblockstorage != null ? extendedblockstorage.getExtBlockMetadata(x, y & 15, z) : 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Return the metadata corresponding to the given coordinates
|
|
* inside a chunk.
|
|
*/
|
|
public int getBlockMetadata(BlockPos blockpos) {
|
|
return this.getBlockMetadata(blockpos.getX() & 15, blockpos.getY(), blockpos.getZ() & 15);
|
|
}
|
|
|
|
public IBlockState setBlockState(BlockPos pos, IBlockState state) {
|
|
int i = pos.getX() & 15;
|
|
int j = pos.getY();
|
|
int k = pos.getZ() & 15;
|
|
int l = k << 4 | i;
|
|
if (j >= this.precipitationHeightMap[l] - 1) {
|
|
this.precipitationHeightMap[l] = -999;
|
|
}
|
|
|
|
int i1 = this.heightMap[l];
|
|
IBlockState iblockstate = this.getBlockState(pos);
|
|
if (iblockstate == state) {
|
|
return null;
|
|
} else {
|
|
Block block = state.getBlock();
|
|
Block block1 = iblockstate.getBlock();
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[j >> 4];
|
|
boolean flag = false;
|
|
if (extendedblockstorage == null) {
|
|
if (block == Blocks.air) {
|
|
return null;
|
|
}
|
|
|
|
extendedblockstorage = this.storageArrays[j >> 4] = new ExtendedBlockStorage(j >> 4 << 4,
|
|
!this.worldObj.provider.getHasNoSky());
|
|
|
|
alfheim$initSkylightForSection(extendedblockstorage);
|
|
// flag = j >= i1;
|
|
}
|
|
|
|
extendedblockstorage.set(i, j & 15, k, state);
|
|
if (block1 != block) {
|
|
if (!this.worldObj.isRemote) {
|
|
block1.breakBlock(this.worldObj, pos, iblockstate);
|
|
} else if (block1 instanceof ITileEntityProvider) {
|
|
this.worldObj.removeTileEntity(pos);
|
|
}
|
|
}
|
|
|
|
if (extendedblockstorage.getBlockByExtId(i, j & 15, k) != block) {
|
|
return null;
|
|
} else {
|
|
if (flag) {
|
|
this.generateSkylightMap();
|
|
} else {
|
|
int j1 = block.getLightOpacity();
|
|
int k1 = block1.getLightOpacity();
|
|
if (j1 > 0) {
|
|
if (j >= i1) {
|
|
this.relightBlock(i, j + 1, k);
|
|
}
|
|
} else if (j == i1 - 1) {
|
|
this.relightBlock(i, j, k);
|
|
}
|
|
|
|
// if (j1 != k1 && (j1 < k1 || this.getLightFor(EnumSkyBlock.SKY, pos) > 0
|
|
// || this.getLightFor(EnumSkyBlock.BLOCK, pos) > 0)) {
|
|
// this.propagateSkylightOcclusion(i, k);
|
|
// }
|
|
}
|
|
|
|
if (block1 instanceof ITileEntityProvider) {
|
|
TileEntity tileentity = this.getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK);
|
|
if (tileentity != null) {
|
|
tileentity.updateContainingBlockInfo();
|
|
}
|
|
}
|
|
|
|
if (!this.worldObj.isRemote && block1 != block) {
|
|
block.onBlockAdded(this.worldObj, pos, state);
|
|
}
|
|
|
|
if (block instanceof ITileEntityProvider) {
|
|
TileEntity tileentity1 = this.getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK);
|
|
if (tileentity1 == null) {
|
|
tileentity1 = ((ITileEntityProvider) block).createNewTileEntity(this.worldObj,
|
|
block.getMetaFromState(state));
|
|
this.worldObj.setTileEntity(pos, tileentity1);
|
|
}
|
|
|
|
if (tileentity1 != null) {
|
|
tileentity1.updateContainingBlockInfo();
|
|
}
|
|
}
|
|
|
|
this.isModified = true;
|
|
return iblockstate;
|
|
}
|
|
}
|
|
}
|
|
|
|
public int getLightFor(EnumSkyBlock enumskyblock, BlockPos blockpos) {
|
|
alfheim$lightingEngine.processLightUpdatesForType(enumskyblock);
|
|
|
|
return alfheim$getCachedLightFor(enumskyblock, blockpos);
|
|
}
|
|
|
|
public void setLightFor(EnumSkyBlock enumskyblock, BlockPos blockpos, int i) {
|
|
int j = blockpos.getX() & 15;
|
|
int k = blockpos.getY();
|
|
int l = blockpos.getZ() & 15;
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[k >> 4];
|
|
if (extendedblockstorage == null) {
|
|
extendedblockstorage = this.storageArrays[k >> 4] = new ExtendedBlockStorage(k >> 4 << 4,
|
|
!this.worldObj.provider.getHasNoSky());
|
|
this.generateSkylightMap();
|
|
}
|
|
|
|
this.isModified = true;
|
|
if (enumskyblock == EnumSkyBlock.SKY) {
|
|
if (!this.worldObj.provider.getHasNoSky()) {
|
|
extendedblockstorage.setExtSkylightValue(j, k & 15, l, i);
|
|
}
|
|
} else if (enumskyblock == EnumSkyBlock.BLOCK) {
|
|
extendedblockstorage.setExtBlocklightValue(j, k & 15, l, i);
|
|
}
|
|
|
|
}
|
|
|
|
public int getLightSubtracted(BlockPos blockpos, int i) {
|
|
alfheim$lightingEngine.processLightUpdates();
|
|
int j = blockpos.getX() & 15;
|
|
int k = blockpos.getY();
|
|
int l = blockpos.getZ() & 15;
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[k >> 4];
|
|
if (extendedblockstorage == null) {
|
|
return !this.worldObj.provider.getHasNoSky() && i < EnumSkyBlock.SKY.defaultLightValue
|
|
? EnumSkyBlock.SKY.defaultLightValue - i
|
|
: getNoSkyLightValue();
|
|
} else {
|
|
int i1 = this.worldObj.provider.getHasNoSky() ? getNoSkyLightValue()
|
|
: extendedblockstorage.getExtSkylightValue(j, k & 15, l);
|
|
i1 = i1 - i;
|
|
int j1 = extendedblockstorage.getExtBlocklightValue(j, k & 15, l);
|
|
if (j1 > i1) {
|
|
i1 = j1;
|
|
}
|
|
|
|
return i1;
|
|
}
|
|
}
|
|
|
|
public static int getNoSkyLightValue() {
|
|
return DeferredStateManager.isDeferredRenderer() ? 5 : 0;
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Adds an entity to the chunk. Args: entity
|
|
*/
|
|
public void addEntity(Entity entity) {
|
|
this.hasEntities = true;
|
|
int i = MathHelper.floor_double(entity.posX / 16.0D);
|
|
int j = MathHelper.floor_double(entity.posZ / 16.0D);
|
|
if (i != this.xPosition || j != this.zPosition) {
|
|
logger.warn("Wrong location! (" + i + ", " + j + ") should be (" + this.xPosition + ", " + this.zPosition
|
|
+ "), " + entity, new Object[] { entity });
|
|
entity.setDead();
|
|
}
|
|
|
|
int k = MathHelper.floor_double(entity.posY / 16.0D);
|
|
if (k < 0) {
|
|
k = 0;
|
|
}
|
|
|
|
if (k >= this.entityLists.length) {
|
|
k = this.entityLists.length - 1;
|
|
}
|
|
|
|
entity.addedToChunk = true;
|
|
entity.chunkCoordX = this.xPosition;
|
|
entity.chunkCoordY = k;
|
|
entity.chunkCoordZ = this.zPosition;
|
|
this.entityLists[k].add(entity);
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* removes entity using its y chunk coordinate as its index
|
|
*/
|
|
public void removeEntity(Entity entity) {
|
|
this.removeEntityAtIndex(entity, entity.chunkCoordY);
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Removes entity at the specified index from the entity array.
|
|
*/
|
|
public void removeEntityAtIndex(Entity entity, int i) {
|
|
if (i < 0) {
|
|
i = 0;
|
|
}
|
|
|
|
if (i >= this.entityLists.length) {
|
|
i = this.entityLists.length - 1;
|
|
}
|
|
|
|
this.entityLists[i].remove(entity);
|
|
}
|
|
|
|
public boolean canSeeSky(BlockPos blockpos) {
|
|
int i = blockpos.getX() & 15;
|
|
int j = blockpos.getY();
|
|
int k = blockpos.getZ() & 15;
|
|
return j >= this.heightMap[k << 4 | i];
|
|
}
|
|
|
|
private TileEntity createNewTileEntity(BlockPos pos) {
|
|
Block block = this.getBlock(pos);
|
|
return !block.hasTileEntity() ? null
|
|
: ((ITileEntityProvider) block).createNewTileEntity(this.worldObj, this.getBlockMetadata(pos));
|
|
}
|
|
|
|
public TileEntity getTileEntity(BlockPos blockpos, Chunk.EnumCreateEntityType chunk$enumcreateentitytype) {
|
|
TileEntity tileentity = (TileEntity) this.chunkTileEntityMap.get(blockpos);
|
|
if (tileentity == null) {
|
|
if (chunk$enumcreateentitytype == Chunk.EnumCreateEntityType.IMMEDIATE) {
|
|
tileentity = this.createNewTileEntity(blockpos);
|
|
this.worldObj.setTileEntity(blockpos, tileentity);
|
|
} else if (chunk$enumcreateentitytype == Chunk.EnumCreateEntityType.QUEUED) {
|
|
this.tileEntityPosQueue.add(blockpos);
|
|
}
|
|
} else if (tileentity.isInvalid()) {
|
|
this.chunkTileEntityMap.remove(blockpos);
|
|
return null;
|
|
}
|
|
|
|
return tileentity;
|
|
}
|
|
|
|
public void addTileEntity(TileEntity tileentity) {
|
|
this.addTileEntity(tileentity.getPos(), tileentity);
|
|
if (this.isChunkLoaded) {
|
|
this.worldObj.addTileEntity(tileentity);
|
|
}
|
|
|
|
}
|
|
|
|
public void addTileEntity(BlockPos blockpos, TileEntity tileentity) {
|
|
tileentity.setWorldObj(this.worldObj);
|
|
tileentity.setPos(blockpos);
|
|
if (this.getBlock(blockpos) instanceof ITileEntityProvider) {
|
|
if (this.chunkTileEntityMap.containsKey(blockpos)) {
|
|
((TileEntity) this.chunkTileEntityMap.get(blockpos)).invalidate();
|
|
}
|
|
|
|
tileentity.validate();
|
|
this.chunkTileEntityMap.put(blockpos, tileentity);
|
|
}
|
|
}
|
|
|
|
public void removeTileEntity(BlockPos blockpos) {
|
|
if (this.isChunkLoaded) {
|
|
TileEntity tileentity = (TileEntity) this.chunkTileEntityMap.remove(blockpos);
|
|
if (tileentity != null) {
|
|
tileentity.invalidate();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Called when this Chunk is loaded by the ChunkProvider
|
|
*/
|
|
public void onChunkLoad() {
|
|
this.isChunkLoaded = true;
|
|
this.worldObj.addTileEntities(this.chunkTileEntityMap.values());
|
|
|
|
for (int i = 0; i < this.entityLists.length; ++i) {
|
|
for (Entity entity : this.entityLists[i]) {
|
|
entity.onChunkLoad();
|
|
}
|
|
|
|
this.worldObj.loadEntities(this.entityLists[i]);
|
|
}
|
|
|
|
final Chunk chunk = (Chunk) (Object) this;
|
|
|
|
for (final EnumFacing facing : EnumFacing.HORIZONTALS) {
|
|
final int xOffset = facing.getXOffset();
|
|
final int zOffset = facing.getZOffset();
|
|
|
|
final Chunk nChunk = worldObj.getChunkProvider().getLoadedChunk(chunk.xPosition + xOffset,
|
|
chunk.zPosition + zOffset);
|
|
|
|
if (nChunk == null)
|
|
continue;
|
|
|
|
for (final EnumSkyBlock lightType : ENUM_SKY_BLOCK_VALUES) {
|
|
for (final EnumFacing.AxisDirection axisDir : ENUM_AXIS_DIRECTION_VALUES) {
|
|
// Merge flags upon loading of a chunk. This ensures that all flags are always
|
|
// already on the IN boundary below
|
|
alfheim$mergeFlags(lightType, chunk, nChunk, facing, axisDir);
|
|
alfheim$mergeFlags(lightType, nChunk, chunk, facing.getOpposite(), axisDir);
|
|
|
|
// Check everything that might have been canceled due to this chunk not being
|
|
// loaded.
|
|
// Also, pass in chunks if already known
|
|
// The boundary to the neighbor chunk (both ways)
|
|
alfheim$scheduleRelightChecksForBoundary(chunk, nChunk, null, lightType, xOffset, zOffset, axisDir);
|
|
alfheim$scheduleRelightChecksForBoundary(nChunk, chunk, null, lightType, -xOffset, -zOffset,
|
|
axisDir);
|
|
// The boundary to the diagonal neighbor (since the checks in that chunk were
|
|
// aborted if this chunk wasn't loaded, see
|
|
// alfheim$scheduleRelightChecksForBoundary)
|
|
alfheim$scheduleRelightChecksForBoundary(nChunk, null, chunk, lightType,
|
|
(zOffset != 0 ? axisDir.getOffset() : 0), (xOffset != 0 ? axisDir.getOffset() : 0),
|
|
facing.getAxisDirection() == EnumFacing.AxisDirection.POSITIVE
|
|
? EnumFacing.AxisDirection.NEGATIVE
|
|
: EnumFacing.AxisDirection.POSITIVE);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Called when this Chunk is unloaded by the ChunkProvider
|
|
*/
|
|
public void onChunkUnload() {
|
|
this.isChunkLoaded = false;
|
|
|
|
for (TileEntity tileentity : this.chunkTileEntityMap.values()) {
|
|
this.worldObj.markTileEntityForRemoval(tileentity);
|
|
}
|
|
|
|
for (int i = 0; i < this.entityLists.length; ++i) {
|
|
this.worldObj.unloadEntities(this.entityLists[i]);
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Sets the isModified flag for this Chunk
|
|
*/
|
|
public void setChunkModified() {
|
|
this.isModified = true;
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Fills the given list of all entities that intersect within
|
|
* the given bounding box that aren't the passed entity.
|
|
*/
|
|
public void getEntitiesWithinAABBForEntity(Entity entity, AxisAlignedBB axisalignedbb, List<Entity> list,
|
|
Predicate<? super Entity> predicate) {
|
|
int i = MathHelper.floor_double((axisalignedbb.minY - 2.0D) / 16.0D);
|
|
int j = MathHelper.floor_double((axisalignedbb.maxY + 2.0D) / 16.0D);
|
|
i = MathHelper.clamp_int(i, 0, this.entityLists.length - 1);
|
|
j = MathHelper.clamp_int(j, 0, this.entityLists.length - 1);
|
|
|
|
for (int k = i; k <= j; ++k) {
|
|
if (!this.entityLists[k].isEmpty()) {
|
|
for (Entity entity1 : this.entityLists[k]) {
|
|
if (entity1.getEntityBoundingBox().intersectsWith(axisalignedbb) && entity1 != entity) {
|
|
if (predicate == null || predicate.apply(entity1)) {
|
|
list.add(entity1);
|
|
}
|
|
|
|
Entity[] aentity = entity1.getParts();
|
|
if (aentity != null) {
|
|
for (int l = 0; l < aentity.length; ++l) {
|
|
entity1 = aentity[l];
|
|
if (entity1 != entity && entity1.getEntityBoundingBox().intersectsWith(axisalignedbb)
|
|
&& (predicate == null || predicate.apply(entity1))) {
|
|
list.add(entity1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public <T extends Entity> void getEntitiesOfTypeWithinAAAB(Class<? extends T> oclass, AxisAlignedBB axisalignedbb,
|
|
List<T> list, Predicate<? super T> predicate) {
|
|
int i = MathHelper.floor_double((axisalignedbb.minY - 2.0D) / 16.0D);
|
|
int j = MathHelper.floor_double((axisalignedbb.maxY + 2.0D) / 16.0D);
|
|
i = MathHelper.clamp_int(i, 0, this.entityLists.length - 1);
|
|
j = MathHelper.clamp_int(j, 0, this.entityLists.length - 1);
|
|
|
|
for (int k = i; k <= j; ++k) {
|
|
for (Entity entity : this.entityLists[k].getByClass(oclass)) {
|
|
if (entity.getEntityBoundingBox().intersectsWith(axisalignedbb)
|
|
&& (predicate == null || predicate.apply((T) entity))) {
|
|
list.add((T) entity);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Returns true if this Chunk needs to be saved
|
|
*/
|
|
public boolean needsSaving(boolean flag) {
|
|
if (flag) {
|
|
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 EaglercraftRandom getRandomWithSeed(long i) {
|
|
return new EaglercraftRandom(this.worldObj.getSeed() + (long) (this.xPosition * this.xPosition * 4987142)
|
|
+ (long) (this.xPosition * 5947611) + (long) (this.zPosition * this.zPosition) * 4392871L
|
|
+ (long) (this.zPosition * 389711) ^ i);
|
|
}
|
|
|
|
public boolean isEmpty() {
|
|
return false;
|
|
}
|
|
|
|
public void populateChunk(IChunkProvider parIChunkProvider, IChunkProvider parIChunkProvider2, int parInt1,
|
|
int parInt2) {
|
|
boolean flag = parIChunkProvider.chunkExists(parInt1, parInt2 - 1);
|
|
boolean flag1 = parIChunkProvider.chunkExists(parInt1 + 1, parInt2);
|
|
boolean flag2 = parIChunkProvider.chunkExists(parInt1, parInt2 + 1);
|
|
boolean flag3 = parIChunkProvider.chunkExists(parInt1 - 1, parInt2);
|
|
boolean flag4 = parIChunkProvider.chunkExists(parInt1 - 1, parInt2 - 1);
|
|
boolean flag5 = parIChunkProvider.chunkExists(parInt1 + 1, parInt2 + 1);
|
|
boolean flag6 = parIChunkProvider.chunkExists(parInt1 - 1, parInt2 + 1);
|
|
boolean flag7 = parIChunkProvider.chunkExists(parInt1 + 1, parInt2 - 1);
|
|
if (flag1 && flag2 && flag5) {
|
|
if (!this.isTerrainPopulated) {
|
|
parIChunkProvider.populate(parIChunkProvider2, parInt1, parInt2);
|
|
} else {
|
|
parIChunkProvider.func_177460_a(parIChunkProvider2, this, parInt1, parInt2);
|
|
}
|
|
}
|
|
|
|
if (flag3 && flag2 && flag6) {
|
|
Chunk chunk = parIChunkProvider.provideChunk(parInt1 - 1, parInt2);
|
|
if (!chunk.isTerrainPopulated) {
|
|
parIChunkProvider.populate(parIChunkProvider2, parInt1 - 1, parInt2);
|
|
} else {
|
|
parIChunkProvider.func_177460_a(parIChunkProvider2, chunk, parInt1 - 1, parInt2);
|
|
}
|
|
}
|
|
|
|
if (flag && flag1 && flag7) {
|
|
Chunk chunk1 = parIChunkProvider.provideChunk(parInt1, parInt2 - 1);
|
|
if (!chunk1.isTerrainPopulated) {
|
|
parIChunkProvider.populate(parIChunkProvider2, parInt1, parInt2 - 1);
|
|
} else {
|
|
parIChunkProvider.func_177460_a(parIChunkProvider2, chunk1, parInt1, parInt2 - 1);
|
|
}
|
|
}
|
|
|
|
if (flag4 && flag && flag3) {
|
|
Chunk chunk2 = parIChunkProvider.provideChunk(parInt1 - 1, parInt2 - 1);
|
|
if (!chunk2.isTerrainPopulated) {
|
|
parIChunkProvider.populate(parIChunkProvider2, parInt1 - 1, parInt2 - 1);
|
|
} else {
|
|
parIChunkProvider.func_177460_a(parIChunkProvider2, chunk2, parInt1 - 1, parInt2 - 1);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public BlockPos getPrecipitationHeight(BlockPos pos) {
|
|
int i = pos.getX() & 15;
|
|
int j = pos.getZ() & 15;
|
|
int k = i | j << 4;
|
|
BlockPos blockpos = new BlockPos(pos.getX(), this.precipitationHeightMap[k], pos.getZ());
|
|
if (blockpos.getY() == -999) {
|
|
int l = this.getTopFilledSegment() + 15;
|
|
blockpos = new BlockPos(pos.getX(), l, pos.getZ());
|
|
int i1 = -1;
|
|
|
|
while (blockpos.getY() > 0 && i1 == -1) {
|
|
Block block = this.getBlock(blockpos);
|
|
Material material = block.getMaterial();
|
|
if (!material.blocksMovement() && !material.isLiquid()) {
|
|
blockpos = blockpos.down();
|
|
} else {
|
|
i1 = blockpos.getY() + 1;
|
|
}
|
|
}
|
|
|
|
this.precipitationHeightMap[k] = i1;
|
|
}
|
|
|
|
return new BlockPos(pos.getX(), this.precipitationHeightMap[k], pos.getZ());
|
|
}
|
|
|
|
public void func_150804_b(boolean parFlag) {
|
|
if (this.isGapLightingUpdated && !this.worldObj.provider.getHasNoSky() && !parFlag) {
|
|
this.recheckGaps(this.worldObj.isRemote);
|
|
}
|
|
|
|
this.field_150815_m = true;
|
|
if (!this.isLightPopulated && this.isTerrainPopulated) {
|
|
this.checkLight();
|
|
}
|
|
|
|
while (!this.tileEntityPosQueue.isEmpty()) {
|
|
BlockPos blockpos = (BlockPos) this.tileEntityPosQueue.remove(0);
|
|
if (this.getTileEntity(blockpos, Chunk.EnumCreateEntityType.CHECK) == null
|
|
&& this.getBlock(blockpos).hasTileEntity()) {
|
|
TileEntity tileentity = this.createNewTileEntity(blockpos);
|
|
this.worldObj.setTileEntity(blockpos, tileentity);
|
|
this.worldObj.markBlockRangeForRenderUpdate(blockpos, blockpos);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
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 i, int j) {
|
|
if (i < 0) {
|
|
i = 0;
|
|
}
|
|
|
|
if (j >= 256) {
|
|
j = 255;
|
|
}
|
|
|
|
for (int k = i; k <= j; k += 16) {
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[k >> 4];
|
|
if (extendedblockstorage != null && !extendedblockstorage.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 i = 0; i < this.storageArrays.length; ++i) {
|
|
this.storageArrays[i] = newStorageArrays[i];
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* Initialize this chunk with new binary data.
|
|
*/
|
|
public void fillChunk(PacketBuffer buf, int p_186033_2_, boolean p_186033_3_) {
|
|
boolean flag = !this.worldObj.provider.getHasNoSky();
|
|
|
|
for (int i = 0; i < this.storageArrays.length; ++i) {
|
|
ExtendedBlockStorage extendedblockstorage = this.storageArrays[i];
|
|
|
|
if ((p_186033_2_ & 1 << i) == 0) {
|
|
if (p_186033_3_ && extendedblockstorage != NULL_BLOCK_STORAGE) {
|
|
this.storageArrays[i] = NULL_BLOCK_STORAGE;
|
|
}
|
|
} else {
|
|
if (extendedblockstorage == NULL_BLOCK_STORAGE) {
|
|
extendedblockstorage = new ExtendedBlockStorage(i << 4, flag);
|
|
this.storageArrays[i] = extendedblockstorage;
|
|
}
|
|
|
|
extendedblockstorage.getData().read(buf);
|
|
buf.readBytes(extendedblockstorage.getBlocklightArray().getData());
|
|
|
|
if (flag) {
|
|
buf.readBytes(extendedblockstorage.getSkylightArray().getData());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (p_186033_3_) {
|
|
buf.readBytes(this.blockBiomeArray);
|
|
}
|
|
|
|
for (int j = 0; j < this.storageArrays.length; ++j) {
|
|
if (this.storageArrays[j] != NULL_BLOCK_STORAGE && (p_186033_2_ & 1 << j) != 0) {
|
|
this.storageArrays[j].removeInvalidBlocks();
|
|
}
|
|
}
|
|
|
|
this.isLightPopulated = true;
|
|
this.isTerrainPopulated = true;
|
|
this.generateHeightMap();
|
|
|
|
for (TileEntity tileentity : this.chunkTileEntityMap.values()) {
|
|
tileentity.updateContainingBlockInfo();
|
|
}
|
|
}
|
|
|
|
public BiomeGenBase getBiome(BlockPos pos, WorldChunkManager chunkManager) {
|
|
int i = pos.getX() & 15;
|
|
int j = pos.getZ() & 15;
|
|
int k = this.blockBiomeArray[j << 4 | i] & 255;
|
|
if (chunkManager != null && k == 255) {
|
|
BiomeGenBase biomegenbase = chunkManager.getBiomeGenerator(pos, BiomeGenBase.plains);
|
|
k = biomegenbase.biomeID;
|
|
this.blockBiomeArray[j << 4 | i] = (byte) (k & 255);
|
|
}
|
|
|
|
BiomeGenBase biomegenbase1 = BiomeGenBase.getBiome(k);
|
|
return biomegenbase1 == null ? BiomeGenBase.plains : biomegenbase1;
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* 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 i = 0; i < this.blockBiomeArray.length; ++i) {
|
|
this.blockBiomeArray[i] = biomeArray[i];
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/**
|
|
* +
|
|
* 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 blockpos = new BlockPos(this.xPosition << 4, 0, this.zPosition << 4);
|
|
|
|
for (int i = 0; i < 8; ++i) {
|
|
if (this.queuedLightChecks >= 4096) {
|
|
return;
|
|
}
|
|
|
|
int j = this.queuedLightChecks % 16;
|
|
int k = this.queuedLightChecks / 16 % 16;
|
|
int l = this.queuedLightChecks / 256;
|
|
++this.queuedLightChecks;
|
|
|
|
EnumFacing[] facings = EnumFacing._VALUES;
|
|
for (int i1 = 0; i1 < 16; ++i1) {
|
|
BlockPos blockpos1 = blockpos.add(k, (j << 4) + i1, l);
|
|
boolean flag = i1 == 0 || i1 == 15 || k == 0 || k == 15 || l == 0 || l == 15;
|
|
if (this.storageArrays[j] == null && flag || this.storageArrays[j] != null
|
|
&& this.storageArrays[j].getBlockByExtId(k, i1, l).getMaterial() == Material.air) {
|
|
for (int m = 0; m < facings.length; ++m) {
|
|
BlockPos blockpos2 = blockpos1.offset(facings[m]);
|
|
if (this.worldObj.getBlockState(blockpos2).getBlock().getLightValue() > 0) {
|
|
this.worldObj.checkLight(blockpos2);
|
|
}
|
|
}
|
|
|
|
this.worldObj.checkLight(blockpos1);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
public void checkLight() {
|
|
this.isTerrainPopulated = true;
|
|
|
|
final Chunk chunk = (Chunk) (Object) this;
|
|
|
|
if (!chunk.alfheim$isLightInitialized())
|
|
alfheim$initChunkLighting(chunk, worldObj);
|
|
|
|
for (int x = -1; x <= 1; x++) {
|
|
for (int z = -1; z <= 1; z++) {
|
|
if (x == 0 && z == 0)
|
|
continue;
|
|
|
|
final Chunk nChunk = worldObj.getChunkProvider().getLoadedChunk(chunk.xPosition + x,
|
|
chunk.zPosition + z);
|
|
|
|
if (nChunk == null || !nChunk.alfheim$isLightInitialized())
|
|
return;
|
|
}
|
|
}
|
|
|
|
chunk.setLightPopulated(true);
|
|
}
|
|
|
|
private void func_177441_y() {
|
|
for (int i = 0; i < this.updateSkylightColumns.length; ++i) {
|
|
this.updateSkylightColumns[i] = true;
|
|
}
|
|
|
|
this.recheckGaps(false);
|
|
}
|
|
|
|
private void func_180700_a(EnumFacing parEnumFacing) {
|
|
if (this.isTerrainPopulated) {
|
|
if (parEnumFacing == EnumFacing.EAST) {
|
|
for (int i = 0; i < 16; ++i) {
|
|
this.func_150811_f(15, i);
|
|
}
|
|
} else if (parEnumFacing == EnumFacing.WEST) {
|
|
for (int j = 0; j < 16; ++j) {
|
|
this.func_150811_f(0, j);
|
|
}
|
|
} else if (parEnumFacing == EnumFacing.SOUTH) {
|
|
for (int k = 0; k < 16; ++k) {
|
|
this.func_150811_f(k, 15);
|
|
}
|
|
} else if (parEnumFacing == EnumFacing.NORTH) {
|
|
for (int l = 0; l < 16; ++l) {
|
|
this.func_150811_f(l, 0);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
private boolean func_150811_f(int x, int z) {
|
|
int i = this.getTopFilledSegment();
|
|
boolean flag = false;
|
|
boolean flag1 = false;
|
|
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos((this.xPosition << 4) + x, 0,
|
|
(this.zPosition << 4) + z);
|
|
|
|
for (int j = i + 16 - 1; j > this.worldObj.func_181545_F() || j > 0 && !flag1; --j) {
|
|
blockpos$mutableblockpos.func_181079_c(blockpos$mutableblockpos.getX(), j, blockpos$mutableblockpos.getZ());
|
|
int k = this.getBlockLightOpacity(blockpos$mutableblockpos);
|
|
if (k == 255 && blockpos$mutableblockpos.getY() < this.worldObj.func_181545_F()) {
|
|
flag1 = true;
|
|
}
|
|
|
|
if (!flag && k > 0) {
|
|
flag = true;
|
|
} else if (flag && k == 0 && !this.worldObj.checkLight(blockpos$mutableblockpos)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
for (int l = blockpos$mutableblockpos.getY(); l > 0; --l) {
|
|
blockpos$mutableblockpos.func_181079_c(blockpos$mutableblockpos.getX(), l, blockpos$mutableblockpos.getZ());
|
|
if (this.getBlock(blockpos$mutableblockpos).getLightValue() > 0) {
|
|
this.worldObj.checkLight(blockpos$mutableblockpos);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public boolean isLoaded() {
|
|
return this.isChunkLoaded;
|
|
}
|
|
|
|
public void setChunkLoaded(boolean loaded) {
|
|
this.isChunkLoaded = loaded;
|
|
}
|
|
|
|
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 i = 0; i < this.heightMap.length; ++i) {
|
|
this.heightMap[i] = newHeightMap[i];
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
public Map<BlockPos, TileEntity> getTileEntityMap() {
|
|
return this.chunkTileEntityMap;
|
|
}
|
|
|
|
public ClassInheritanceMultiMap<Entity>[] 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, QUEUED, CHECK;
|
|
}
|
|
|
|
private boolean alfheim$recheckGapsForColumn(final WorldChunkSlice slice, final int x, final int z) {
|
|
final int i = x + z * 16;
|
|
|
|
if (updateSkylightColumns[i]) {
|
|
updateSkylightColumns[i] = false;
|
|
|
|
final int x1 = this.xPosition * 16 + x;
|
|
final int z1 = this.zPosition * 16 + z;
|
|
|
|
alfheim$recheckGapsSkylightNeighborHeight(slice, x1, z1, getHeightValue(x, z),
|
|
alfheim$recheckGapsGetLowestHeight(slice, x1, z1));
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private int alfheim$recheckGapsGetLowestHeight(final WorldChunkSlice slice, final int x, final int z) {
|
|
int max = Integer.MAX_VALUE;
|
|
|
|
for (final EnumFacing facing : ENUM_FACING_HORIZONTAL) {
|
|
final Chunk chunk = slice.getChunkFromWorldCoords(x + facing.getXOffset(), z + facing.getZOffset());
|
|
|
|
if (chunk != null)
|
|
max = Math.min(max, chunk.getLowestHeight());
|
|
}
|
|
|
|
return max;
|
|
}
|
|
|
|
private void alfheim$recheckGapsSkylightNeighborHeight(final WorldChunkSlice slice, final int x, final int z,
|
|
final int height, final int max) {
|
|
alfheim$checkSkylightNeighborHeight(slice, x, z, max);
|
|
|
|
for (final EnumFacing facing : ENUM_FACING_HORIZONTAL)
|
|
alfheim$checkSkylightNeighborHeight(slice, x + facing.getXOffset(), z + facing.getFrontOffsetZ(), height);
|
|
}
|
|
|
|
private void alfheim$checkSkylightNeighborHeight(final WorldChunkSlice slice, final int x, final int z,
|
|
final int maxValue) {
|
|
if (slice.getChunkFromWorldCoords(x, z) == null)
|
|
return;
|
|
|
|
final int y = slice.getChunkFromWorldCoords(x, z).getHeightValue(x & 15, z & 15);
|
|
|
|
if (y > maxValue)
|
|
alfheim$updateSkylightNeighborHeight(slice, x, z, maxValue, y + 1);
|
|
else if (y < maxValue)
|
|
alfheim$updateSkylightNeighborHeight(slice, x, z, y, maxValue + 1);
|
|
}
|
|
|
|
private void alfheim$updateSkylightNeighborHeight(final WorldChunkSlice slice, final int x, final int z,
|
|
final int startY, final int endY) {
|
|
if (endY < startY)
|
|
return;
|
|
|
|
if (!slice.isLoaded(x, z, 16))
|
|
return;
|
|
|
|
for (int y = startY; y < endY; ++y)
|
|
worldObj.checkLightFor(EnumSkyBlock.SKY, new BlockPos(x, y, z));
|
|
|
|
isModified = true;
|
|
}
|
|
|
|
private static void alfheim$mergeFlags(final EnumSkyBlock lightType, final Chunk inChunk, final Chunk outChunk,
|
|
final EnumFacing dir, final EnumFacing.AxisDirection axisDirection) {
|
|
// final IChunkLightingData outChunkLightingData = (IChunkLightingData)
|
|
// outChunk; // I REALLY NEED TO SUBMIT A BUG REPORT FOR THIS WEIRD PROBLEM
|
|
// WHERE FUNCTIONS GET DELETED IF YOU DO THIS IN TEAVM
|
|
|
|
if (outChunk.alfheim$getNeighborLightChecks() == null)
|
|
return;
|
|
|
|
inChunk.alfheim$initNeighborLightChecks();
|
|
|
|
final int inIndex = alfheim$getFlagIndex(lightType, dir, axisDirection, EnumBoundaryFacing.IN);
|
|
final int outIndex = alfheim$getFlagIndex(lightType, dir.getOpposite(), axisDirection, EnumBoundaryFacing.OUT);
|
|
|
|
inChunk.alfheim$getNeighborLightChecks()[inIndex] |= outChunk.alfheim$getNeighborLightChecks()[outIndex];
|
|
// No need to call Chunk.setModified() since checks are not deleted from
|
|
// outChunk
|
|
}
|
|
|
|
private void alfheim$scheduleRelightChecksForBoundary(final Chunk chunk, Chunk nChunk, Chunk sChunk,
|
|
final EnumSkyBlock lightType, final int xOffset, final int zOffset,
|
|
final EnumFacing.AxisDirection axisDirection) {
|
|
if (chunk.alfheim$getNeighborLightChecks() == null)
|
|
return;
|
|
|
|
final int flagIndex = alfheim$getFlagIndex(lightType, xOffset, zOffset, axisDirection, EnumBoundaryFacing.IN); // OUT
|
|
// checks
|
|
// from
|
|
// neighbor
|
|
// are
|
|
// already
|
|
// merged
|
|
|
|
final int flags = chunk.alfheim$getNeighborLightChecks()[flagIndex];
|
|
|
|
if (flags == 0)
|
|
return;
|
|
|
|
if (nChunk == null) {
|
|
nChunk = worldObj.getChunkProvider().getLoadedChunk(chunk.xPosition + xOffset, chunk.zPosition + zOffset);
|
|
|
|
if (nChunk == null)
|
|
return;
|
|
}
|
|
|
|
if (sChunk == null) {
|
|
sChunk = worldObj.getChunkProvider()
|
|
.getLoadedChunk(chunk.xPosition + (zOffset != 0 ? axisDirection.getOffset() : 0),
|
|
chunk.zPosition + (xOffset != 0 ? axisDirection.getOffset() : 0));
|
|
|
|
if (sChunk == null)
|
|
return; // Cancel, since the checks in the corner columns require the corner column of
|
|
// sChunk
|
|
}
|
|
|
|
final int reverseIndex = alfheim$getFlagIndex(lightType, -xOffset, -zOffset, axisDirection,
|
|
EnumBoundaryFacing.OUT);
|
|
|
|
chunk.alfheim$getNeighborLightChecks()[flagIndex] = 0;
|
|
|
|
if (nChunk.alfheim$getNeighborLightChecks() != null)
|
|
nChunk.alfheim$getNeighborLightChecks()[reverseIndex] = 0; // Clear only now that it's clear that the checks
|
|
// are processed
|
|
|
|
chunk.setChunkModified();
|
|
nChunk.setChunkModified();
|
|
|
|
// Get the area to check
|
|
// Start in the corner...
|
|
int xMin = chunk.xPosition << 4;
|
|
int zMin = chunk.zPosition << 4;
|
|
|
|
// Move to other side of chunk if the direction is positive
|
|
if ((xOffset | zOffset) > 0) {
|
|
xMin += 15 * xOffset;
|
|
zMin += 15 * zOffset;
|
|
}
|
|
|
|
// Shift to other half if necessary (shift perpendicular to dir)
|
|
if (axisDirection == EnumFacing.AxisDirection.POSITIVE) {
|
|
xMin += 8 * (zOffset & 1); // x & 1 is same as abs(x) for x=-1,0,1
|
|
zMin += 8 * (xOffset & 1);
|
|
}
|
|
|
|
// Get maximal values (shift perpendicular to dir)
|
|
final int xMax = xMin + 7 * (zOffset & 1);
|
|
final int zMax = zMin + 7 * (xOffset & 1);
|
|
|
|
for (int y = 0; y < 16; ++y)
|
|
if ((flags & (1 << y)) != 0)
|
|
for (int x = xMin; x <= xMax; ++x)
|
|
for (int z = zMin; z <= zMax; ++z)
|
|
alfheim$scheduleRelightChecksForColumn(lightType, x, z, y << 4, (y << 4) + 15);
|
|
}
|
|
|
|
private void alfheim$initSkylightForSection(final ExtendedBlockStorage extendedBlockStorage) {
|
|
if (worldObj.provider.getHasNoSky())
|
|
return;
|
|
|
|
for (int x = 0; x < 16; ++x) {
|
|
for (int z = 0; z < 16; ++z) {
|
|
if (((Chunk) (Object) this).getHeightValue(x, z) > extendedBlockStorage.getYLocation())
|
|
continue;
|
|
|
|
for (int y = 0; y < 16; ++y)
|
|
extendedBlockStorage.setExtSkylightValue(x, y, z, EnumSkyBlock.SKY.defaultLightValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void alfheim$scheduleRelightChecksForColumn(final EnumSkyBlock lightType, final int x, final int z,
|
|
final int yMin, final int yMax) {
|
|
final BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
|
|
|
for (int y = yMin; y <= yMax; ++y)
|
|
worldObj.checkLightFor(lightType, mutableBlockPos.setPos(x, y, z));
|
|
}
|
|
|
|
private static int alfheim$getFlagIndex(final EnumSkyBlock lightType, final int xOffset, final int zOffset,
|
|
final EnumFacing.AxisDirection axisDirection, final EnumBoundaryFacing boundaryFacing) {
|
|
return (lightType == EnumSkyBlock.BLOCK ? 0 : 16) | ((xOffset + 1) << 2) | ((zOffset + 1) << 1)
|
|
| (axisDirection.getOffset() + 1) | boundaryFacing.ordinal();
|
|
}
|
|
|
|
private static int alfheim$getFlagIndex(final EnumSkyBlock lightType, final EnumFacing facing,
|
|
final EnumFacing.AxisDirection axisDirection, final EnumBoundaryFacing boundaryFacing) {
|
|
return alfheim$getFlagIndex(lightType, facing.getXOffset(), facing.getZOffset(), axisDirection, boundaryFacing);
|
|
}
|
|
|
|
private static void alfheim$initChunkLighting(final Chunk chunk, final World world) {
|
|
final int xBase = chunk.xPosition << 4;
|
|
final int zBase = chunk.zPosition << 4;
|
|
|
|
final BlockPos.PooledMutableBlockPos mutableBlockPos = BlockPos.PooledMutableBlockPos.retain(xBase, 0, zBase);
|
|
|
|
if (world.isAreaLoaded(mutableBlockPos.add(-16, 0, -16), mutableBlockPos.add(31, 255, 31), false)) {
|
|
final ExtendedBlockStorage[] extendedBlockStorage = chunk.getBlockStorageArray();
|
|
|
|
for (int i = 0; i < extendedBlockStorage.length; ++i) {
|
|
final ExtendedBlockStorage storage = extendedBlockStorage[i];
|
|
|
|
if (storage == Chunk.NULL_BLOCK_STORAGE)
|
|
continue;
|
|
|
|
int yBase = i * 16;
|
|
|
|
for (int y = 0; y < 16; y++) {
|
|
for (int z = 0; z < 16; z++) {
|
|
for (int x = 0; x < 16; x++) {
|
|
mutableBlockPos.setPos(xBase + x, yBase + y, zBase + z);
|
|
|
|
if (LightUtil.getLightValueForState(storage.get(x, y, z), world, mutableBlockPos) > 0)
|
|
world.checkLightFor(EnumSkyBlock.BLOCK, mutableBlockPos);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!world.provider.getHasNoSky())
|
|
chunk.alfheim$setSkylightUpdatedPublic();
|
|
|
|
chunk.alfheim$setLightInitialized(true);
|
|
}
|
|
|
|
mutableBlockPos.release();
|
|
}
|
|
|
|
private void alfheim$relightSkylightColumn(final int x, final int z, final int height1, final int height2) {
|
|
final int yMin = Math.min(height1, height2);
|
|
final int yMax = Math.max(height1, height2) - 1;
|
|
|
|
final Chunk chunk = ((Chunk) (Object) this);
|
|
|
|
final ExtendedBlockStorage[] sections = chunk.getBlockStorageArray();
|
|
|
|
final int xBase = (chunk.xPosition << 4) + x;
|
|
final int zBase = (chunk.zPosition << 4) + z;
|
|
|
|
alfheim$scheduleRelightChecksForColumn(EnumSkyBlock.SKY, xBase, zBase, yMin, yMax);
|
|
|
|
if (sections[yMin >> 4] == Chunk.NULL_BLOCK_STORAGE && yMin > 0) {
|
|
worldObj.checkLightFor(EnumSkyBlock.SKY, new BlockPos(xBase, yMin - 1, zBase));
|
|
}
|
|
|
|
short emptySections = 0;
|
|
|
|
for (int sec = yMax >> 4; sec >= yMin >> 4; --sec) {
|
|
if (sections[sec] == Chunk.NULL_BLOCK_STORAGE) {
|
|
emptySections |= (short) (1 << sec);
|
|
}
|
|
}
|
|
|
|
if (emptySections != 0) {
|
|
for (final EnumFacing facing : EnumFacing.HORIZONTALS) {
|
|
final int xOffset = facing.getXOffset();
|
|
final int zOffset = facing.getZOffset();
|
|
|
|
final boolean neighborColumnExists = (((x + xOffset) | (z + zOffset)) & 16) == 0
|
|
// Checks whether the position is at the specified border (the 16 bit is set for
|
|
// both 15+1 and 0-1)
|
|
|| worldObj.getChunkProvider().getLoadedChunk(chunk.xPosition + xOffset,
|
|
chunk.zPosition + zOffset) != null;
|
|
|
|
if (neighborColumnExists) {
|
|
for (int sec = yMax >> 4; sec >= yMin >> 4; --sec) {
|
|
if ((emptySections & (1 << sec)) != 0)
|
|
alfheim$scheduleRelightChecksForColumn(EnumSkyBlock.SKY, xBase + xOffset, zBase + zOffset,
|
|
sec << 4, (sec << 4) + 15);
|
|
}
|
|
} else {
|
|
chunk.alfheim$initNeighborLightChecks();
|
|
|
|
final EnumFacing.AxisDirection axisDirection = ((facing.getAxis() == EnumFacing.Axis.X ? z : x)
|
|
& 15) < 8 ? EnumFacing.AxisDirection.NEGATIVE : EnumFacing.AxisDirection.POSITIVE;
|
|
chunk.alfheim$getNeighborLightChecks()[alfheim$getFlagIndex(EnumSkyBlock.SKY, facing, axisDirection,
|
|
EnumBoundaryFacing.OUT)] |= emptySections;
|
|
|
|
chunk.setChunkModified();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public short[] alfheim$getNeighborLightChecks() {
|
|
return alfheim$neighborLightChecks;
|
|
}
|
|
|
|
public void alfheim$setNeighborLightChecks(final short[] data) {
|
|
alfheim$neighborLightChecks = data;
|
|
}
|
|
|
|
public LightingEngine alfheim$getLightingEngine() {
|
|
return alfheim$lightingEngine;
|
|
}
|
|
|
|
public boolean alfheim$isLightInitialized() {
|
|
return alfheim$isLightInitialized;
|
|
}
|
|
|
|
public void alfheim$setLightInitialized(final boolean lightInitialized) {
|
|
alfheim$isLightInitialized = lightInitialized;
|
|
}
|
|
|
|
public void alfheim$setSkylightUpdatedPublic() {
|
|
func_177441_y();
|
|
}
|
|
|
|
public void alfheim$initNeighborLightChecks() {
|
|
if (alfheim$getNeighborLightChecks() == null)
|
|
alfheim$setNeighborLightChecks(new short[32]);
|
|
}
|
|
|
|
public byte alfheim$getCachedLightFor(final EnumSkyBlock lightType, final BlockPos blockPos) {
|
|
final int x = blockPos.getX() & 15;
|
|
final int y = blockPos.getY();
|
|
final int z = blockPos.getZ() & 15;
|
|
|
|
final ExtendedBlockStorage extendedblockstorage = storageArrays[y >> 4];
|
|
|
|
if (extendedblockstorage == Chunk.NULL_BLOCK_STORAGE)
|
|
return canSeeSky(blockPos) ? (byte) lightType.defaultLightValue : 0;
|
|
else if (lightType == EnumSkyBlock.SKY)
|
|
return !worldObj.provider.getHasNoSky() ? (byte) extendedblockstorage.getExtSkylightValue(x, y & 15, z) : 0;
|
|
else
|
|
return lightType == EnumSkyBlock.BLOCK ? (byte) extendedblockstorage.getExtBlocklightValue(x, y & 15, z)
|
|
: (byte) lightType.defaultLightValue;
|
|
}
|
|
} |