Skip to content

Commit

Permalink
Clean up code
Browse files Browse the repository at this point in the history
  • Loading branch information
magicus committed Nov 14, 2021
1 parent 3e44ba5 commit d68911e
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 124 deletions.
225 changes: 103 additions & 122 deletions src/main/java/ru/bulldog/justmap/map/data/fast/MapChunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,26 +13,25 @@

import ru.bulldog.justmap.map.data.Layer;
import ru.bulldog.justmap.util.BlockStateUtil;
import ru.bulldog.justmap.util.colors.ColorUtil;
import ru.bulldog.justmap.util.colors.Colors;

import static ru.bulldog.justmap.util.colors.ColorUtil.ABGRtoARGB;

public class MapChunk {
private final int relRegX;
private final int relRegZ;
private final Layer layer;
private final int level;

// Note that color data has a different layout than the scouted data
private final byte[][] colorData = new byte[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE * MapRegionLayer.BYTES_PER_PIXEL];
private final byte[][] pixelColors = new byte[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE * MapRegionLayer.BYTES_PER_PIXEL];

private final byte[][] solidY = new byte[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];
private final byte[][] transparentY = new byte[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];
private final byte[][] waterY = new byte[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];
private final byte[][] delta = new byte[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];
private final int[][] scoutedTransparentBlocks = new int[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];
private final int[][] scoutedSolidBlocks = new int[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];
private final byte[][] scoutedTransparentY = new byte[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];
private final byte[][] scoutedWaterY = new byte[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];
private final byte[][] scoutedSolidY = new byte[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];

private final int[][] solidBlock = new int[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];
private final int[][] transparentBlock = new int[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];
private final byte[][] derivedDeltaY = new byte[MapRegionLayer.CHUNK_SIZE][MapRegionLayer.CHUNK_SIZE];

public MapChunk(int relRegX, int relRegZ, Layer layer, int level) {
this.relRegX = relRegX;
Expand All @@ -41,89 +40,117 @@ public MapChunk(int relRegX, int relRegZ, Layer layer, int level) {
this.level = level;
}

private void examinePos(World world, WorldChunk worldChunk, BlockPos.Mutable thisBlockPos) {
int posX = thisBlockPos.getX();
int posZ = thisBlockPos.getZ();
private int getTopBlockYInLeveledLayer(WorldChunk worldChunk, int posX, int posZ, boolean hideWater, boolean hidePlants) {
int floor = layer.getHeight() * level;
int ceiling = layer.getHeight() * (level + 1);
int y = ceiling;
BlockPos.Mutable pos = new BlockPos.Mutable();
pos.set(posX, y, posZ);
boolean caveFound;
do {
if (y < floor) {
return -1;
}
caveFound = BlockStateUtil.isSkippedBlockState(worldChunk.getBlockState(pos), !hideWater, !hidePlants);
y--;
pos.set(posX, y, posZ);
} while (!caveFound);

boolean bottomFound;
do {
if (y < 0) {
return -1;
}
bottomFound = !BlockStateUtil.isSkippedBlockState(worldChunk.getBlockState(pos), !hideWater, !hidePlants);
y--;
pos.set(posX, y, posZ);
} while (!bottomFound);

// We overstepped by one
return y+1;
}

private void updateScoutedData(World world, WorldChunk worldChunk, BlockPos.Mutable pos) {
int xOffset = pos.getX() & 15;
int zOffset = pos.getZ() & 15;

// Get the highest non-air block
int y = worldChunk.sampleHeightmap(Heightmap.Type.WORLD_SURFACE, posX, posZ);

int solid_y = -1;
int transparent_y = -1;
int water_y = -1;
BlockState solid_block = BlockStateUtil.AIR;
BlockState transparent_block = BlockStateUtil.AIR;
while (solid_y < 0) {
thisBlockPos.setY(y);
BlockState blockState = worldChunk.getBlockState(thisBlockPos);
if (water_y < 0 &&
int y = worldChunk.sampleHeightmap(Heightmap.Type.WORLD_SURFACE, xOffset, zOffset);

int solidY = -1;
int transparentY = -1;
int waterY = -1;
BlockState solidBlock = BlockStateUtil.AIR;
BlockState transparentBlock = BlockStateUtil.AIR;
while (solidY < 0) {
pos.setY(y);
BlockState blockState = worldChunk.getBlockState(pos);
if (waterY < 0 &&
(!blockState.getFluidState().isEmpty() && blockState.getFluidState().isIn(FluidTags.WATER))) {
water_y = y;
waterY = y;
}
if (transparent_y < 0 &&
blockState.getMapColor(world, thisBlockPos) == MapColor.CLEAR) {
transparent_y = y;
transparent_block = blockState;
if (transparentY < 0 &&
blockState.getMapColor(world, pos) == MapColor.CLEAR) {
transparentY = y;
transparentBlock = blockState;
}

if (blockState.getMapColor(world, thisBlockPos) != MapColor.CLEAR
if (blockState.getMapColor(world, pos) != MapColor.CLEAR
&& blockState.getFluidState().isEmpty() && !blockState.getFluidState().isIn(FluidTags.WATER)) {
solid_y = y;
solid_block = blockState;
solidY = y;
solidBlock = blockState;
}
y--;
if (y < 0) {
// got just void
solid_y = 0;
solid_block = BlockStateUtil.AIR;
solidY = 0;
solidBlock = BlockStateUtil.AIR;
}
}

int xOffset = posX & 15;
int zOffset = posZ & 15;
solidY[xOffset][zOffset] = (byte) solid_y;
transparentY[xOffset][zOffset] = (byte) transparent_y;
waterY[xOffset][zOffset] = (byte) water_y;
scoutedSolidY[xOffset][zOffset] = (byte) solidY;
scoutedTransparentY[xOffset][zOffset] = (byte) transparentY;
scoutedWaterY[xOffset][zOffset] = (byte) waterY;

solidBlock[xOffset][zOffset] = Block.getRawIdFromState(solid_block);
transparentBlock[xOffset][zOffset] = Block.getRawIdFromState(transparent_block);
scoutedSolidBlocks[xOffset][zOffset] = Block.getRawIdFromState(solidBlock);
scoutedTransparentBlocks[xOffset][zOffset] = Block.getRawIdFromState(transparentBlock);
}

private void calculateDelta(World world, WorldChunk worldChunk, int xOffset, int zOffset) {
int solid_y = solidY[xOffset][zOffset];
private void updateDerivedData(World world, WorldChunk worldChunk, int xOffset, int zOffset) {
int solidY = scoutedSolidY[xOffset][zOffset];

// For terrain, Vanilla calculate shading according to height difference
// with north (z-1) neighbor

// FIXME: this breaks at chunk border!
int north_solid_y;
int northSolidY;
if (zOffset > 0) {
north_solid_y = solidY[xOffset][zOffset - 1];
northSolidY = scoutedSolidY[xOffset][zOffset - 1];
} else {
// FIXME: fake! use our own height
north_solid_y = solidY[xOffset][zOffset];
northSolidY = scoutedSolidY[xOffset][zOffset];
}

int my_delta = solid_y - north_solid_y;
delta[xOffset][zOffset] = (byte) my_delta;
int my_delta = solidY - northSolidY;
derivedDeltaY[xOffset][zOffset] = (byte) my_delta;
}

private int blockColorChunkFromCache(int xOffset, int zOffset) {
int solid_y = solidY[xOffset][zOffset];
int transparent_y = transparentY[xOffset][zOffset];
int water_y = waterY[xOffset][zOffset];
int y_delta = delta[xOffset][zOffset];
private int getVanillaPixelColor(int xOffset, int zOffset) {
int solidY = scoutedSolidY[xOffset][zOffset];
int transparentY = scoutedTransparentY[xOffset][zOffset];
int waterY = scoutedWaterY[xOffset][zOffset];
int deltaY = derivedDeltaY[xOffset][zOffset];

BlockState solid_block = Block.getStateFromRawId(solidBlock[xOffset][zOffset]);
BlockState transparent_block = Block.getStateFromRawId(transparentBlock[xOffset][zOffset]);
BlockState solidBlock = Block.getStateFromRawId(scoutedSolidBlocks[xOffset][zOffset]);
BlockState transparentBlock = Block.getStateFromRawId(scoutedTransparentBlocks[xOffset][zOffset]);

int shade = 0;

MapColor mapColor;

if (water_y > solid_y) {
if (waterY > solidY) {
// For water, calculate shading according to depth
int waterDepth = water_y - solid_y;
int waterDepth = waterY - solidY;
double shadeArg = waterDepth * 0.1d + (xOffset + zOffset & 1) * 0.2d;
if (shadeArg < 0.5d) {
shade = 2;
Expand All @@ -136,7 +163,7 @@ private int blockColorChunkFromCache(int xOffset, int zOffset) {
} else {
// For terrain, calculate shading according to height difference
// with neighbor
double shadeArg = y_delta * 4/5.0d + ((xOffset + zOffset & 1) - 0.5d) * 0.4d;
double shadeArg = deltaY * 4/5.0d + ((xOffset + zOffset & 1) - 0.5d) * 0.4d;
if (shadeArg > 0.6d) {
shade = 2;
} else if (shadeArg < -0.6d) {
Expand All @@ -148,7 +175,7 @@ private int blockColorChunkFromCache(int xOffset, int zOffset) {
// We're taking a bit of a chance here. In practice, the
// implementation of getMapColor() ignores its arguments, but
// that might change in the future
mapColor = solid_block.getMapColor(null, null);
mapColor = solidBlock.getMapColor(null, null);
} catch (NullPointerException e) {
mapColor = MapColor.CLEAR;
}
Expand All @@ -157,93 +184,54 @@ private int blockColorChunkFromCache(int xOffset, int zOffset) {
if (mapColor == MapColor.CLEAR) {
return Colors.BLACK;
} else {
return ABGRtoARGB(MapColor.COLORS[mapColor.id].getRenderColor(shade));
return ColorUtil.ABGRtoARGB(MapColor.COLORS[mapColor.id].getRenderColor(shade));
}
}

private int getTopBlockY(WorldChunk worldChunk, int x, int z) {
if (layer == Layer.SURFACE) {
return getTopBlockYOnSurface(worldChunk, x, z);
} else {
return getTopBlockYInLeveledLayer(worldChunk, x, z, false, true);
}
}

private int getTopBlockYOnSurface(WorldChunk worldChunk, int x, int z) {
return worldChunk.sampleHeightmap(Heightmap.Type.WORLD_SURFACE, x, z);
}

private int getTopBlockYInLeveledLayer(WorldChunk worldChunk, int posX, int posZ, boolean hideWater, boolean hidePlants) {
int floor = layer.getHeight() * level;
int ceiling = layer.getHeight() * (level + 1);
int y = ceiling;
BlockPos.Mutable pos = new BlockPos.Mutable();
pos.set(posX, y, posZ);
boolean caveFound;
do {
if (y < floor) {
return -1;
}
caveFound = BlockStateUtil.isSkippedBlockState(worldChunk.getBlockState(pos), !hideWater, !hidePlants);
y--;
pos.set(posX, y, posZ);
} while (!caveFound);

boolean bottomFound;
do {
if (y < 0) {
return -1;
}
bottomFound = !BlockStateUtil.isSkippedBlockState(worldChunk.getBlockState(pos), !hideWater, !hidePlants);
y--;
pos.set(posX, y, posZ);
} while (!bottomFound);
private void updatePixelColor(int x, int z) {
int color = getVanillaPixelColor(x, z);

// We overstepped by one
return y+1;
int xOffset = x * 4;
pixelColors[z][xOffset + 0] = (byte) 0;
pixelColors[z][xOffset + 1] = (byte) (color & 255);
pixelColors[z][xOffset + 2] = (byte) ((color >> 8) & 255);
pixelColors[z][xOffset + 3] = (byte) ((color >> 16) & 255);
}

public void updateChunk(WorldChunk worldChunk) {
public void onChunkUpdate(WorldChunk worldChunk) {
World world = FastMapManager.MANAGER.getFastWorldMapper().getWorld();
BlockPos.Mutable blockPos = new BlockPos.Mutable();

for (int x = 0; x < MapRegionLayer.CHUNK_SIZE; x++) {
blockPos.setX(worldChunk.getPos().getStartX() + x);
for (int z = 0; z < MapRegionLayer.CHUNK_SIZE; z++) {
blockPos.setZ(worldChunk.getPos().getStartZ() + z);
examinePos(world, worldChunk, blockPos);
updateScoutedData(world, worldChunk, blockPos);
}
}

for (int x = 0; x < MapRegionLayer.CHUNK_SIZE; x++) {
for (int z = 0; z < MapRegionLayer.CHUNK_SIZE; z++) {
calculateDelta(world, worldChunk, x, z);
}
}

for (int x = 0; x < MapRegionLayer.CHUNK_SIZE; x++) {
for (int z = 0; z < MapRegionLayer.CHUNK_SIZE; z++) {
int color = blockColorChunkFromCache(x, z);
setColor(x, z, color);
updateDerivedData(world, worldChunk, x, z);
updatePixelColor(x, z);
}
}
}

public void updateBlock(BlockPos blockPos) {
public void onBlockUpdate(BlockPos blockPos) {
int x = blockPos.getX() & 15;
int z = blockPos.getZ() & 15;
int relevantY = solidY[x][z];
int relevantY = scoutedSolidY[x][z];
if (blockPos.getY() >= relevantY) {
// Only look at changes to blocks that could possibly affect the map
BlockPos.Mutable pos = new BlockPos.Mutable();
pos.set(blockPos);
World world = FastMapManager.MANAGER.getFastWorldMapper().getWorld();
WorldChunk worldChunk = world.getWorldChunk(pos);
examinePos(world, worldChunk, pos);
calculateDelta(world, worldChunk, x, z);
updateScoutedData(world, worldChunk, pos);
updateDerivedData(world, worldChunk, x, z);
// FIXME: We also need to calculate delta on it's neighbor!
int color = blockColorChunkFromCache(x, z);
setColor(x, z, color);
updatePixelColor(x, z);
}
}

Expand All @@ -252,16 +240,9 @@ public void writeToTextureBuffer(ByteBuffer buffer) {
buffer.put((relRegZ * MapRegionLayer.CHUNK_SIZE + row)
* MapRegionLayer.REGION_SIZE * MapRegionLayer.BYTES_PER_PIXEL
+ (relRegX * MapRegionLayer.CHUNK_SIZE * MapRegionLayer.BYTES_PER_PIXEL),
colorData[row], 0,
pixelColors[row], 0,
MapRegionLayer.CHUNK_SIZE * MapRegionLayer.BYTES_PER_PIXEL);
}
}

private void setColor(int x, int z, int color) {
int xOffset = x * 4;
colorData[z][xOffset + 0] = (byte) 0;
colorData[z][xOffset + 1] = (byte) (color & 255);
colorData[z][xOffset + 2] = (byte) ((color >> 8) & 255);
colorData[z][xOffset + 3] = (byte) ((color >> 16) & 255);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void updateChunk(WorldChunk worldChunk) {
// FIXME: verify/assert that chunkpos is inside region?
MapChunk mapChunk = getMapChunk(worldChunk.getPos());

mapChunk.updateChunk(worldChunk);
mapChunk.onChunkUpdate(worldChunk);
mapChunk.writeToTextureBuffer(buffer);
isModified = true;
}
Expand All @@ -50,7 +50,7 @@ public void updateBlock(BlockPos pos) {
ChunkPos chunkPos = new ChunkPos(pos);
MapChunk mapChunk = getMapChunk(chunkPos);

mapChunk.updateBlock(pos);
mapChunk.onBlockUpdate(pos);
mapChunk.writeToTextureBuffer(buffer);
isModified = true;
}
Expand Down

0 comments on commit d68911e

Please sign in to comment.