Barteks2x

Untitled

Nov 7th, 2016
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 7.57 KB | None | 0 0
  1. package cubicchunks.lighting;
  2.  
  3. import com.carrotsearch.hppc.IntSet;
  4. import com.carrotsearch.hppc.cursors.IntCursor;
  5.  
  6. import net.minecraft.block.state.IBlockState;
  7. import net.minecraft.util.math.BlockPos;
  8. import net.minecraft.world.EnumSkyBlock;
  9.  
  10. import cubicchunks.util.Coords;
  11. import cubicchunks.world.ClientHeightMap;
  12. import cubicchunks.world.ICubicWorld;
  13. import cubicchunks.world.IHeightMap;
  14. import cubicchunks.world.column.Column;
  15. import cubicchunks.world.cube.Cube;
  16.  
  17. import static cubicchunks.util.Coords.blockToCube;
  18. import static cubicchunks.util.Coords.localToBlock;
  19.  
  20. //TODO: extract interfaces when it's done
  21. public class LightingManager {
  22.  
  23.     private static final int MAX_CLIENT_LIGHT_SCAN_DEPTH = 64;
  24.     private ICubicWorld world;
  25.  
  26.     public LightingManager(ICubicWorld world) {
  27.         this.world = world;
  28.     }
  29.  
  30.     public CubeLightUpdateInfo createCubeLightUpdateInfo(Cube cube) {
  31.         return new CubeLightUpdateInfo(cube);
  32.     }
  33.  
  34.     //TODO: make it private
  35.     public void columnSkylightUpdate(UpdateType type, Column column, int localX, int minY, int maxY, int localZ) {
  36.         int blockX = localToBlock(column.getX(), localX);
  37.         int blockZ = localToBlock(column.getZ(), localZ);
  38.         switch (type) {
  39.             case IMMEDIATE:
  40.                 IntSet toDiffuse = SkyLightUpdateCubeSelector.getCubesY(column, localX, localZ, minY, maxY);
  41.                 for (IntCursor cubeY : toDiffuse) {
  42.                     boolean success = updateDiffuseLight(column.getCube(cubeY.value), localX, localZ, minY, maxY);
  43.                     if (!success) {
  44.                         markCubeBlockColumnForUpdate(column.getLoadedCube(cubeY.value), blockX, blockZ);
  45.                     }
  46.                 }
  47.                 break;
  48.             case QUEUED:
  49.                 toDiffuse = SkyLightUpdateCubeSelector.getCubesY(column, localX, localZ, minY, maxY);
  50.                 for (IntCursor cubeY : toDiffuse) {
  51.                     markCubeBlockColumnForUpdate(column.getLoadedCube(cubeY.value), blockX, blockZ);
  52.                 }
  53.                 break;
  54.         }
  55.     }
  56.  
  57.     private boolean updateDiffuseLight(Cube cube, int localX, int localZ, int minY, int maxY) {
  58.         ICubicWorld world = cube.getCubicWorld();
  59.         int minCubeY = cube.getCoords().getMinBlockY();
  60.         int maxCubeY = cube.getCoords().getMaxBlockY();
  61.  
  62.         int blockX = localToBlock(cube.getX(), localX);
  63.         int blockZ = localToBlock(cube.getZ(), localZ);
  64.  
  65.         for (int blockY = minCubeY; blockY <= maxCubeY; blockY++) {
  66.             if (blockY < minY || blockY > maxY) {
  67.                 continue;
  68.             }
  69.             if (!world.checkLightFor(EnumSkyBlock.SKY, new BlockPos(blockX, blockY, blockZ))) {
  70.                 return false;
  71.             }
  72.         }
  73.         return true;
  74.     }
  75.  
  76.     public void doOnBlockSetLightUpdates(Column column, BlockPos changePos, IBlockState newBlockState, int oldOpacity) {
  77.         int newOpacity = newBlockState.getLightOpacity(column.getWorld(), changePos);
  78.         if (!needsUpdate(oldOpacity, newOpacity)) {
  79.             //nothing to update, this will frequently happen in ore generation
  80.             return;
  81.         }
  82.  
  83.         int localX = Coords.blockToLocal(changePos.getX());
  84.         int localZ = Coords.blockToLocal(changePos.getZ());
  85.  
  86.         IHeightMap heightMap = column.getHeightMapObject();
  87.  
  88.         // did the top non-transparent block change?
  89.         int oldTopY = heightMap.getTopBlockY(localX, localZ);
  90.         heightMap.onOpacityChange(localX, changePos.getY(), localZ, newOpacity);
  91.         column.setModified(true);
  92.  
  93.         int newTopY = findNewTopBlockY(heightMap, changePos, column, newOpacity, localX, localZ, oldTopY);
  94.  
  95.         int minY = Math.min(oldTopY, newTopY);
  96.         int maxY = Math.max(oldTopY, newTopY);
  97.         assert minY <= maxY;
  98.  
  99.         this.columnSkylightUpdate(UpdateType.IMMEDIATE, column, localX, minY, maxY, localZ);
  100.     }
  101.  
  102.     //TODO: make it private
  103.     public void markCubeBlockColumnForUpdate(Cube cube, int blockX, int blockZ) {
  104.         CubeLightUpdateInfo data = cube.getCubeLightUpdateInfo();
  105.         data.markBlockColumnForUpdate(Coords.blockToLocal(blockX), Coords.blockToLocal(blockZ));
  106.     }
  107.  
  108.     private int findNewTopBlockY(IHeightMap heightMap, BlockPos changePos, Column column, int newOpacity, int localX, int localZ, int oldTopY) {
  109.         if (!column.getWorld().isRemote) {
  110.             return heightMap.getTopBlockY(localX, localZ);
  111.         }
  112.         //to avoid unnecessary delay when breaking blocks client needs to figure out new height before
  113.         //server tells the client what it is
  114.         //common cases first
  115.         if (addedTopBlock(changePos, newOpacity, oldTopY)) {
  116.             //added new block, so it's correct. Server update will be ignored
  117.             return changePos.getY();
  118.         }
  119.         if (!changedTopToTransparent(changePos, newOpacity, oldTopY)) {
  120.             //if not breaking the top block - no changes
  121.             return oldTopY;
  122.         }
  123.         assert !(newOpacity == 0 && oldTopY < changePos.getY()) : "Changed transparent block into transparent!";
  124.  
  125.         //changed the top block
  126.         int newTop = oldTopY - 1;
  127.         while (column.getBlockLightOpacity(new BlockPos(localX, newTop, localZ)) == 0 && newTop > oldTopY - MAX_CLIENT_LIGHT_SCAN_DEPTH) {
  128.             newTop--;
  129.         }
  130.         //update the heightmap. If this update it not accurate - it will be corrected when server sends block update
  131.         ((ClientHeightMap) heightMap).setHeight(localX, localZ, newTop);
  132.         return newTop;
  133.     }
  134.  
  135.     private boolean changedTopToTransparent(BlockPos changePos, int newOpacity, int oldTopY) {
  136.         return newOpacity == 0 && changePos.getY() == oldTopY;
  137.     }
  138.  
  139.     private boolean addedTopBlock(BlockPos pos, int newOpacity, int oldTopY) {
  140.         return (pos.getY() > oldTopY) && newOpacity != 0;
  141.     }
  142.  
  143.     private boolean needsUpdate(int oldOpacity, int newOpacity) {
  144.         //update is needed only if opacities are different and booth are less than 15
  145.         return oldOpacity != newOpacity && (oldOpacity < 15 || newOpacity < 15);
  146.     }
  147.  
  148.     public void onHeightMapUpdate(Column column, int localX, int localZ, int oldHeight, int newHeight) {
  149.         int minCubeY = blockToCube(Math.min(oldHeight, newHeight));
  150.         int maxCubeY = blockToCube(Math.max(oldHeight, newHeight));
  151.         for(Cube cube : column.getLoadedCubes()) {
  152.             if(cube.getY() >= minCubeY && cube.getY() <= maxCubeY) {
  153.                 markCubeBlockColumnForUpdate(cube, localX, localZ);
  154.             }
  155.         }
  156.     }
  157.  
  158.     public enum UpdateType {
  159.         IMMEDIATE, QUEUED
  160.     }
  161.  
  162.     //this will be interface
  163.     public static class CubeLightUpdateInfo {
  164.         private final Cube cube;
  165.         private final boolean[] toUpdateColumns = new boolean[Cube.SIZE*Cube.SIZE];
  166.         private boolean hasUpdates;
  167.  
  168.         public CubeLightUpdateInfo(Cube cube) {
  169.             this.cube = cube;
  170.         }
  171.  
  172.         public void markBlockColumnForUpdate(int localX, int localZ) {
  173.             toUpdateColumns[index(localX, localZ)] = true;
  174.             hasUpdates = true;
  175.         }
  176.  
  177.         public void tick() {
  178.             if(!this.hasUpdates) {
  179.                 return;
  180.             }
  181.             for (int localX = 0; localX < Cube.SIZE; localX++) {
  182.                 for (int localZ = 0; localZ < Cube.SIZE; localZ++) {
  183.                     if (!toUpdateColumns[index(localX, localZ)]) {
  184.                         continue;
  185.                     }
  186.                     int height = cube.getColumn().getHeightMapObject().getTopBlockY(localX, localZ);
  187.  
  188.                     for (int localY = 0; localY < Cube.SIZE; localY++) {
  189.                         int skylight = cube.getSkylight(localX, localY, localZ);
  190.                         int blockY = localToBlock(cube.getY(), localY);
  191.                         boolean isAbove = blockY > height;
  192.                         //unlike in FirstLightProcessor - don't need to care about cubes above possibly
  193.                         //affecting this -they are updated separately
  194.                         if ((isAbove && skylight < 15) || (!isAbove && skylight == 15)) {
  195.                             int blockX = localToBlock(cube.getX(), localX);
  196.                             int blockZ = localToBlock(cube.getZ(), localZ);
  197.                             BlockPos updatePos = new BlockPos(blockX, blockY, blockZ);
  198.                             if(!cube.getCubicWorld().checkLightFor(EnumSkyBlock.SKY, updatePos)) {
  199.                                 //don't waste more time processing updates in cube at the edge
  200.                                 return;
  201.                             }
  202.                         }
  203.                     }
  204.                     toUpdateColumns[index(localX, localZ)] = false;
  205.                 }
  206.             }
  207.             this.hasUpdates = false;
  208.         }
  209.  
  210.         private int index(int x, int z) {
  211.             return x << 4 | z;
  212.         }
  213.     }
  214. }
Add Comment
Please, Sign In to add comment