183 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
			
		
		
	
	
			183 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			Java
		
	
	
	
	
	
| package net.minecraft.world.level.lighting;
 | |
| 
 | |
| import net.minecraft.core.BlockPos;
 | |
| import net.minecraft.core.Direction;
 | |
| import net.minecraft.core.SectionPos;
 | |
| import net.minecraft.util.BitStorage;
 | |
| import net.minecraft.util.Mth;
 | |
| import net.minecraft.util.SimpleBitStorage;
 | |
| import net.minecraft.world.level.BlockGetter;
 | |
| import net.minecraft.world.level.LevelHeightAccessor;
 | |
| import net.minecraft.world.level.block.Blocks;
 | |
| import net.minecraft.world.level.block.state.BlockState;
 | |
| import net.minecraft.world.level.chunk.ChunkAccess;
 | |
| import net.minecraft.world.level.chunk.LevelChunkSection;
 | |
| import net.minecraft.world.phys.shapes.Shapes;
 | |
| import net.minecraft.world.phys.shapes.VoxelShape;
 | |
| 
 | |
| public class ChunkSkyLightSources {
 | |
| 	private static final int SIZE = 16;
 | |
| 	public static final int NEGATIVE_INFINITY = Integer.MIN_VALUE;
 | |
| 	private final int minY;
 | |
| 	private final BitStorage heightmap;
 | |
| 	private final BlockPos.MutableBlockPos mutablePos1 = new BlockPos.MutableBlockPos();
 | |
| 	private final BlockPos.MutableBlockPos mutablePos2 = new BlockPos.MutableBlockPos();
 | |
| 
 | |
| 	public ChunkSkyLightSources(LevelHeightAccessor level) {
 | |
| 		this.minY = level.getMinY() - 1;
 | |
| 		int i = level.getMaxY() + 1;
 | |
| 		int j = Mth.ceillog2(i - this.minY + 1);
 | |
| 		this.heightmap = new SimpleBitStorage(j, 256);
 | |
| 	}
 | |
| 
 | |
| 	public void fillFrom(ChunkAccess chunk) {
 | |
| 		int i = chunk.getHighestFilledSectionIndex();
 | |
| 		if (i == -1) {
 | |
| 			this.fill(this.minY);
 | |
| 		} else {
 | |
| 			for (int j = 0; j < 16; j++) {
 | |
| 				for (int k = 0; k < 16; k++) {
 | |
| 					int l = Math.max(this.findLowestSourceY(chunk, i, k, j), this.minY);
 | |
| 					this.set(index(k, j), l);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private int findLowestSourceY(ChunkAccess chunk, int sectionIndex, int x, int z) {
 | |
| 		int i = SectionPos.sectionToBlockCoord(chunk.getSectionYFromSectionIndex(sectionIndex) + 1);
 | |
| 		BlockPos.MutableBlockPos mutableBlockPos = this.mutablePos1.set(x, i, z);
 | |
| 		BlockPos.MutableBlockPos mutableBlockPos2 = this.mutablePos2.setWithOffset(mutableBlockPos, Direction.DOWN);
 | |
| 		BlockState blockState = Blocks.AIR.defaultBlockState();
 | |
| 
 | |
| 		for (int j = sectionIndex; j >= 0; j--) {
 | |
| 			LevelChunkSection levelChunkSection = chunk.getSection(j);
 | |
| 			if (levelChunkSection.hasOnlyAir()) {
 | |
| 				blockState = Blocks.AIR.defaultBlockState();
 | |
| 				int k = chunk.getSectionYFromSectionIndex(j);
 | |
| 				mutableBlockPos.setY(SectionPos.sectionToBlockCoord(k));
 | |
| 				mutableBlockPos2.setY(mutableBlockPos.getY() - 1);
 | |
| 			} else {
 | |
| 				for (int k = 15; k >= 0; k--) {
 | |
| 					BlockState blockState2 = levelChunkSection.getBlockState(x, k, z);
 | |
| 					if (isEdgeOccluded(blockState, blockState2)) {
 | |
| 						return mutableBlockPos.getY();
 | |
| 					}
 | |
| 
 | |
| 					blockState = blockState2;
 | |
| 					mutableBlockPos.set(mutableBlockPos2);
 | |
| 					mutableBlockPos2.move(Direction.DOWN);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return this.minY;
 | |
| 	}
 | |
| 
 | |
| 	public boolean update(BlockGetter level, int x, int y, int z) {
 | |
| 		int i = y + 1;
 | |
| 		int j = index(x, z);
 | |
| 		int k = this.get(j);
 | |
| 		if (i < k) {
 | |
| 			return false;
 | |
| 		} else {
 | |
| 			BlockPos blockPos = this.mutablePos1.set(x, y + 1, z);
 | |
| 			BlockState blockState = level.getBlockState(blockPos);
 | |
| 			BlockPos blockPos2 = this.mutablePos2.set(x, y, z);
 | |
| 			BlockState blockState2 = level.getBlockState(blockPos2);
 | |
| 			if (this.updateEdge(level, j, k, blockPos, blockState, blockPos2, blockState2)) {
 | |
| 				return true;
 | |
| 			} else {
 | |
| 				BlockPos blockPos3 = this.mutablePos1.set(x, y - 1, z);
 | |
| 				BlockState blockState3 = level.getBlockState(blockPos3);
 | |
| 				return this.updateEdge(level, j, k, blockPos2, blockState2, blockPos3, blockState3);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private boolean updateEdge(BlockGetter level, int index, int minY, BlockPos pos1, BlockState state1, BlockPos pos2, BlockState state2) {
 | |
| 		int i = pos1.getY();
 | |
| 		if (isEdgeOccluded(state1, state2)) {
 | |
| 			if (i > minY) {
 | |
| 				this.set(index, i);
 | |
| 				return true;
 | |
| 			}
 | |
| 		} else if (i == minY) {
 | |
| 			this.set(index, this.findLowestSourceBelow(level, pos2, state2));
 | |
| 			return true;
 | |
| 		}
 | |
| 
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	private int findLowestSourceBelow(BlockGetter level, BlockPos pos, BlockState state) {
 | |
| 		BlockPos.MutableBlockPos mutableBlockPos = this.mutablePos1.set(pos);
 | |
| 		BlockPos.MutableBlockPos mutableBlockPos2 = this.mutablePos2.setWithOffset(pos, Direction.DOWN);
 | |
| 		BlockState blockState = state;
 | |
| 
 | |
| 		while (mutableBlockPos2.getY() >= this.minY) {
 | |
| 			BlockState blockState2 = level.getBlockState(mutableBlockPos2);
 | |
| 			if (isEdgeOccluded(blockState, blockState2)) {
 | |
| 				return mutableBlockPos.getY();
 | |
| 			}
 | |
| 
 | |
| 			blockState = blockState2;
 | |
| 			mutableBlockPos.set(mutableBlockPos2);
 | |
| 			mutableBlockPos2.move(Direction.DOWN);
 | |
| 		}
 | |
| 
 | |
| 		return this.minY;
 | |
| 	}
 | |
| 
 | |
| 	private static boolean isEdgeOccluded(BlockState state1, BlockState state2) {
 | |
| 		if (state2.getLightBlock() != 0) {
 | |
| 			return true;
 | |
| 		} else {
 | |
| 			VoxelShape voxelShape = LightEngine.getOcclusionShape(state1, Direction.DOWN);
 | |
| 			VoxelShape voxelShape2 = LightEngine.getOcclusionShape(state2, Direction.UP);
 | |
| 			return Shapes.faceShapeOccludes(voxelShape, voxelShape2);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	public int getLowestSourceY(int x, int z) {
 | |
| 		int i = this.get(index(x, z));
 | |
| 		return this.extendSourcesBelowWorld(i);
 | |
| 	}
 | |
| 
 | |
| 	public int getHighestLowestSourceY() {
 | |
| 		int i = Integer.MIN_VALUE;
 | |
| 
 | |
| 		for (int j = 0; j < this.heightmap.getSize(); j++) {
 | |
| 			int k = this.heightmap.get(j);
 | |
| 			if (k > i) {
 | |
| 				i = k;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return this.extendSourcesBelowWorld(i + this.minY);
 | |
| 	}
 | |
| 
 | |
| 	private void fill(int value) {
 | |
| 		int i = value - this.minY;
 | |
| 
 | |
| 		for (int j = 0; j < this.heightmap.getSize(); j++) {
 | |
| 			this.heightmap.set(j, i);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	private void set(int index, int value) {
 | |
| 		this.heightmap.set(index, value - this.minY);
 | |
| 	}
 | |
| 
 | |
| 	private int get(int index) {
 | |
| 		return this.heightmap.get(index) + this.minY;
 | |
| 	}
 | |
| 
 | |
| 	private int extendSourcesBelowWorld(int y) {
 | |
| 		return y == this.minY ? Integer.MIN_VALUE : y;
 | |
| 	}
 | |
| 
 | |
| 	private static int index(int x, int z) {
 | |
| 		return x + z * 16;
 | |
| 	}
 | |
| }
 |