Advertisement
Barteks2x

Untitled

Nov 7th, 2016
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 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. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement