From cafd4f0c47c85448f08ca63a05af4d5853a336b0 Mon Sep 17 00:00:00 2001 From: James Seibel Date: Wed, 24 Mar 2021 21:59:06 -0500 Subject: [PATCH] Move all LodChunk generation code to the LodBuilder object --- .../com/backsun/lod/builders/LodBuilder.java | 588 +++++++++++++++++- .../com/backsun/lod/objects/LodChunk.java | 587 +---------------- .../java/com/backsun/lod/util/LodUtils.java | 23 +- 3 files changed, 608 insertions(+), 590 deletions(-) diff --git a/src/main/java/com/backsun/lod/builders/LodBuilder.java b/src/main/java/com/backsun/lod/builders/LodBuilder.java index 7bcc9fe16..6e6f470fa 100644 --- a/src/main/java/com/backsun/lod/builders/LodBuilder.java +++ b/src/main/java/com/backsun/lod/builders/LodBuilder.java @@ -1,17 +1,25 @@ package com.backsun.lod.builders; +import java.awt.Color; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import com.backsun.lod.enums.ColorDirection; +import com.backsun.lod.enums.LodLocation; import com.backsun.lod.handlers.LodDimensionFileHandler; import com.backsun.lod.objects.LodChunk; import com.backsun.lod.objects.LodDimension; import com.backsun.lod.objects.LodWorld; import com.backsun.lod.util.LodUtils; +import net.minecraft.block.Blocks; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.color.BlockColors; import net.minecraft.world.DimensionType; +import net.minecraft.world.World; import net.minecraft.world.chunk.ChunkSection; import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.gen.Heightmap; import net.minecraft.world.server.ServerWorld; /** @@ -30,6 +38,20 @@ public class LodBuilder /** Default size of any LOD regions we use */ public int regionWidth = 5; + + public static final int CHUNK_DATA_WIDTH = LodChunk.WIDTH; + public static final int CHUNK_DATA_HEIGHT = LodChunk.WIDTH; + + /** + * This is how many blocks are + * required at a specific y-value + * to constitute a LOD point + */ + private final int LOD_BLOCK_REQ = 16; + // the max number of blocks per layer = 64 (8*8) + // since each layer is 1/4 the chunk + + public LodBuilder() { @@ -56,7 +78,7 @@ public class LodBuilder // given a valid chunk object // (Minecraft often gives back empty // or null chunks in this method) - if (chunk == null || !hasBlockData(chunk)) + if (chunk == null || !LodUtils.chunkHasBlockData(chunk)) return lodWorld; ServerWorld world = LodUtils.getServerWorldFromDimension(dim); @@ -69,7 +91,7 @@ public class LodBuilder { try { - LodChunk lod = new LodChunk(chunk, world); + LodChunk lod = generateLodFromChunk(chunk, world); LodDimension lodDim; @@ -106,22 +128,568 @@ public class LodBuilder + + + /** - * Return whether the given chunk - * has any data in it. + * Creates a LodChunk for a chunk in the given world.
+ * Note: The world is required to determine each block's color + * + * @throws IllegalArgumentException + * thrown if either the chunk or world is null. */ - public boolean hasBlockData(IChunk chunk) + public LodChunk generateLodFromChunk(IChunk chunk, World world) throws IllegalArgumentException { - ChunkSection[] blockStorage = chunk.getSections(); - - for(ChunkSection section : blockStorage) + if(chunk == null) { - if(section != null && !section.isEmpty()) + throw new IllegalArgumentException("generateLodFromChunk given a null chunk"); + } + if(world == null) + { + throw new IllegalArgumentException("generateLodFromChunk given a null world"); + } + + short[] top = new short[4]; + short[] bottom = new short[4]; + Color[] colors = new Color[6]; + + // generate the top and bottom points of this LOD + for(LodLocation loc : LodLocation.values()) + { + top[loc.value] = generateLodCorner(chunk, SectionGenerationMode.GENERATE_TOP, loc); + bottom[loc.value] = generateLodCorner(chunk, SectionGenerationMode.GENERATE_BOTTOM, loc); + } + + // determine the average color for each direction + for(ColorDirection dir : ColorDirection.values()) + { + colors[dir.value] = generateLodColorForDirection(chunk, world, dir); + } + + return new LodChunk(chunk.getPos(), top, bottom, colors); + } + + + + + + + //=====================// + // constructor helpers // + //=====================// + + /** GENERATE_TOP, GENERATE_BOTTOM */ + private enum SectionGenerationMode + { + GENERATE_TOP, + GENERATE_BOTTOM; + } + + /** + * Generate the height for the given LodLocation, either the top or bottom. + *

+ * If invalid/null/empty chunks are given + * crashes may occur. + */ + public short generateLodCorner(IChunk chunk, SectionGenerationMode sectionGenMode, LodLocation lodLoc) + { + int startX = 0; + int endX = 0; + + int startZ = 0; + int endZ = 0; + + // determine where we should look in this + // chunk + switch(lodLoc) + { + case NE: + // -N + startZ = 0; + endZ = (CHUNK_DATA_WIDTH / 2) - 1; + // +E + startX = CHUNK_DATA_WIDTH / 2; + endX = CHUNK_DATA_WIDTH - 1; + break; + + case SE: + // +S + startZ = CHUNK_DATA_WIDTH / 2; + endZ = CHUNK_DATA_WIDTH; + // +E + startX = CHUNK_DATA_WIDTH / 2; + endX = CHUNK_DATA_WIDTH; + break; + + case SW: + // +S + startZ = CHUNK_DATA_WIDTH / 2; + endZ = CHUNK_DATA_WIDTH; + // -W + startX = 0; + endX = (CHUNK_DATA_WIDTH / 2) - 1; + break; + + case NW: + // -N + startZ = 0; + endZ = CHUNK_DATA_WIDTH / 2; + // -W + startX = 0; + endX = CHUNK_DATA_WIDTH / 2; + break; + } + + + // should have a length of 16 + // (each storage is 16x16x16 and the + // world height is 256) + ChunkSection[] chunkSections = chunk.getSections(); + + + if(sectionGenMode == SectionGenerationMode.GENERATE_TOP) + return determineTopPoint(chunkSections, startX, endX, startZ, endZ); + else + return determineBottomPoint(chunkSections, startX, endX, startZ, endZ); + } + + + /** + * Find the lowest valid point from the bottom. + */ + private short determineBottomPoint(ChunkSection[] chunkSections, int startX, int endX, int startZ, int endZ) + { + // search from the bottom up + for(int i = 0; i < CHUNK_DATA_WIDTH; i++) + { + for(int y = 0; y < CHUNK_DATA_HEIGHT; y++) { - return true; + + if(isLayerValidLodPoint(chunkSections, startX, endX, startZ, endZ, i, y)) + { + // we found + // enough blocks in this + // layer to count as an + // LOD point + return (short) (y + (i * CHUNK_DATA_HEIGHT)); + } } } + // we never found a valid LOD point + return -1; + } + + /** + * Find the lowest valid point from the bottom. + */ + @SuppressWarnings("unused") + private short determineBottomPoint(Heightmap heightmap, int startX, int endX, int startZ, int endZ) + { + // the heightmap only shows how high the blocks go, it + // doesn't have any info about how low they go + return 0; + } + + + + /** + * Find the highest valid point from the Top + */ + private short determineTopPoint(ChunkSection[] chunkSections, int startX, int endX, int startZ, int endZ) + { + // search from the top down + for(int i = chunkSections.length - 1; i >= 0; i--) + { + for(int y = CHUNK_DATA_WIDTH - 1; y >= 0; y--) + { + if(isLayerValidLodPoint(chunkSections, startX, endX, startZ, endZ, i, y)) + { + // we found + // enough blocks in this + // layer to count as an + // LOD point + return (short) (y + (i * CHUNK_DATA_HEIGHT)); + } + } + } + + // we never found a valid LOD point + return -1; + } + + /** + * Find the highest valid point from the Top + */ + @SuppressWarnings("unused") + private short determineTopPoint(Heightmap heightmap, int startX, int endX, int startZ, int endZ) + { + short highest = 0; + for(int x = startX; x < endX; x++) + { + for(int z = startZ; z < endZ; z++) + { + short newHeight = (short) heightmap.getHeight(x, z); + if (newHeight > highest) + highest = newHeight; + } + } + + return highest; + } + + + + + + + + + /** + * Is the layer between the given X, Z, and dataIndex + * values a valid LOD point? + */ + private boolean isLayerValidLodPoint( + ChunkSection[] chunkSections, + int startX, int endX, + int startZ, int endZ, + int sectionIndex, int y) + { + // search through this layer + int layerBlocks = 0; + + for(int x = startX; x < endX; x++) + { + for(int z = startZ; z < endZ; z++) + { + if(chunkSections[sectionIndex] == null) + { + // this section doesn't have any blocks, + // it is not a valid section + return false; + } + else + { + if(chunkSections[sectionIndex].getBlockState(x, y, z) != null && chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.AIR) + { + // we found a valid block in + // in this layer + layerBlocks++; + + if(layerBlocks >= LOD_BLOCK_REQ) + { + return true; + } + } + } + + } // z + } // x + return false; } + + /** + * Generate the color of the given ColorDirection at the given chunk + * in the given world. + */ + private Color generateLodColorForDirection(IChunk chunk, World world, ColorDirection colorDir) + { + Minecraft mc = Minecraft.getInstance(); + BlockColors bc = mc.getBlockColors(); + + switch (colorDir) + { + case TOP: + return generateLodColorVertical(chunk, colorDir, world, bc); + case BOTTOM: + return generateLodColorVertical(chunk, colorDir, world, bc); + + case N: + return generateLodColorHorizontal(chunk, colorDir, world, bc); + case S: + return generateLodColorHorizontal(chunk, colorDir, world, bc); + + case E: + return generateLodColorHorizontal(chunk, colorDir, world, bc); + case W: + return generateLodColorHorizontal(chunk, colorDir, world, bc); + } + + return new Color(0, 0, 0, 0); + } + + /** + * Generates the color of the top or bottom of a given chunk in the given world. + * + * @throws IllegalArgumentException if given a ColorDirection other than TOP or BOTTOM + */ + private Color generateLodColorVertical(IChunk chunk, ColorDirection colorDir, World world, BlockColors bc) + { + if(colorDir != ColorDirection.TOP && colorDir != ColorDirection.BOTTOM) + { + throw new IllegalArgumentException("generateLodColorVertical only accepts the ColorDirection TOP or BOTTOM"); + } + + + + ChunkSection[] chunkSections = chunk.getSections(); + + int numbOfBlocks = 0; + int red = 0; + int green = 0; + int blue = 0; + + boolean goTopDown = (colorDir == ColorDirection.TOP); + + + // either go top down or bottom up + int dataStart = goTopDown? chunkSections.length - 1 : 0; + int dataMax = chunkSections.length; + int dataMin = 0; + int dataIncrement = goTopDown? -1 : 1; + + int topStart = goTopDown? CHUNK_DATA_HEIGHT - 1 : 0; + int topMax = CHUNK_DATA_HEIGHT; + int topMin = 0; + int topIncrement = goTopDown? -1 : 1; + + for(int x = 0; x < CHUNK_DATA_WIDTH; x++) + { + for(int z = 0; z < CHUNK_DATA_WIDTH; z++) + { + boolean foundBlock = false; + + for(int i = dataStart; !foundBlock && i >= dataMin && i < dataMax; i += dataIncrement) + { + if(!foundBlock && chunkSections[i] != null) + { + for(int y = topStart; !foundBlock && y >= topMin && y < topMax; y += topIncrement) + { + int ci; + ci = chunkSections[i].getBlockState(x, y, z).materialColor.colorValue; + + if(ci == 0) + { + // skip air or invisible blocks + continue; + } + + Color c = intToColor(ci); + + red += c.getRed(); + green += c.getGreen(); + blue += c.getBlue(); + + numbOfBlocks++; + + + // we found a valid block, skip to the + // next x and z + foundBlock = true; + } + } + } + + } + } + + if(numbOfBlocks == 0) + numbOfBlocks = 1; + + red /= numbOfBlocks; + green /= numbOfBlocks; + blue /= numbOfBlocks; + + return new Color(red, green, blue); + + /* + * unused variation that can be used with only the heightmap, + * although it just returns the foliage color, so it shouldn't + * be used normally. + + Heightmap heightmap = chunk.getHeightmap(Heightmap.Type.WORLD_SURFACE_WG); + + int numbOfBlocks = CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH; + int red = 0; + int green = 0; + int blue = 0; + + for(int x = 0; x < CHUNK_DATA_WIDTH; x++) + { + for(int z = 0; z < CHUNK_DATA_WIDTH; z++) + { + Biome biome = chunk.getBiomes().getNoiseBiome(x,z, heightmap.getHeight(x, z)); + Color c = intToColor(biome.getFoliageColor()); + + red += c.getRed(); + green += c.getGreen(); + blue += c.getBlue(); + } + } + + red /= numbOfBlocks; + green /= numbOfBlocks; + blue /= numbOfBlocks; + + return new Color(red, green, blue); + */ + } + + /** + * Generates the color of the side of a given chunk in the given world for the given ColorDirection. + * + * @throws IllegalArgumentException if given a ColorDirection other than N, S, W, E (North, South, East, West) + */ + private Color generateLodColorHorizontal(IChunk chunk, ColorDirection colorDir, World world, BlockColors bc) + { + if(colorDir != ColorDirection.N && colorDir != ColorDirection.S && colorDir != ColorDirection.E && colorDir != ColorDirection.W) + { + throw new IllegalArgumentException("generateLodColorHorizontal only accepts the ColorDirection N (North), S (South), E (East), or W (West)"); + } + + ChunkSection[] chunkSections = chunk.getSections(); + + int numbOfBlocks = 0; + int red = 0; + int green = 0; + int blue = 0; + + + // these don't change since the over direction doesn't matter + int overStart = 0; + int overIncrement = 1; + + // determine which direction is "in" + int inStart = 0; + int inIncrement = 1; + switch (colorDir) + { + case N: + inStart = 0; + inIncrement = 1; + break; + case S: + inStart = CHUNK_DATA_WIDTH - 1; + inIncrement = -1; + break; + case E: + inStart = 0; + inIncrement = 1; + break; + case W: + inStart = CHUNK_DATA_WIDTH - 1; + inIncrement = -1; + break; + default: + // we were given an invalid position, return invisible. + // this shouldn't happen and is mostly here to make the + // compiler happy + return new Color(0,0,0,0); + } + + + for (int i = 0; i < chunkSections.length; i++) + { + if (chunkSections[i] != null) + { + for (int y = 0; y < CHUNK_DATA_HEIGHT; y++) + { + boolean foundBlock = false; + + // over moves "over" the side of the chunk + // in moves "into" the chunk until it finds a block + + for (int over = overStart; !foundBlock && over >= 0 && over < CHUNK_DATA_WIDTH; over += overIncrement) + { + for (int in = inStart; !foundBlock && in >= 0 && in < CHUNK_DATA_WIDTH; in += inIncrement) + { + int x = -1; + int z = -1; + + // determine which should be X and Z + switch(colorDir) + { + case N: + x = over; + z = in; + break; + case S: + x = over; + z = in; + break; + case E: + x = in; + z = over; + break; + case W: + x = in; + z = over; + break; + default: + // this will never happen, it would have + // been caught by the switch before the loops + break; + } + + int ci; + ci = chunkSections[i].getBlockState(x, y, z).getMaterial().getColor().colorValue; + + if (ci == 0) { + // skip air or invisible blocks + continue; + } + + Color c = intToColor(ci); + + red += c.getRed(); + green += c.getGreen(); + blue += c.getBlue(); + + numbOfBlocks++; + + // we found a valid block, skip to the + // next x and z + foundBlock = true; + } + } + } + + } + } + + if(numbOfBlocks == 0) + numbOfBlocks = 1; + + red /= numbOfBlocks; + green /= numbOfBlocks; + blue /= numbOfBlocks; + + return new Color(red, green, blue); + } + + + /** + * Convert a BlockColors int into a Color object. + */ + private Color intToColor(int num) + { + int filter = 0b11111111; + + int red = (num >> 16 ) & filter; + int green = (num >> 8 ) & filter; + int blue = num & filter; + + return new Color(red, green, blue); + } + + /** + * Convert a Color into a BlockColors object. + */ + @SuppressWarnings("unused") + private int colorToInt(Color color) + { + return color.getRGB(); + } + } diff --git a/src/main/java/com/backsun/lod/objects/LodChunk.java b/src/main/java/com/backsun/lod/objects/LodChunk.java index 7d1aa1a66..3958ca7cb 100644 --- a/src/main/java/com/backsun/lod/objects/LodChunk.java +++ b/src/main/java/com/backsun/lod/objects/LodChunk.java @@ -6,13 +6,7 @@ import com.backsun.lod.enums.ColorDirection; import com.backsun.lod.enums.LodCorner; import com.backsun.lod.enums.LodLocation; -import net.minecraft.block.Blocks; -import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.color.BlockColors; -import net.minecraft.world.World; -import net.minecraft.world.chunk.ChunkSection; -import net.minecraft.world.chunk.IChunk; -import net.minecraft.world.gen.Heightmap; +import net.minecraft.util.math.ChunkPos; /** * This object contains position @@ -31,18 +25,6 @@ public class LodChunk public static final int WIDTH = 16; - private static final int CHUNK_DATA_WIDTH = WIDTH; - private static final int CHUNK_DATA_HEIGHT = WIDTH; - - /** - * This is how many blocks are - * required at a specific y-value - * to constitute a LOD point - */ - private final int LOD_BLOCK_REQ = 16; - // the max number of blocks per layer = 64 (8*8) - // since each layer is 1/4 the chunk - /** The x coordinate of the chunk. */ @@ -205,44 +187,18 @@ public class LodChunk } /** - * Creates a LodChunk for a chunk in the given world.
- * Note: The world is required to determine each block's color - * - * @throws IllegalArgumentException - * thrown if either the chunk or world is null. + * Create a LodChunk from the given values. */ - public LodChunk(IChunk chunk, World world) throws IllegalArgumentException + public LodChunk(ChunkPos pos, short[] newTop, short[] newBottom, Color[] newColors) { - if(chunk == null) - { - throw new IllegalArgumentException("LodChunk constructor given a null chunk"); - } - if(world == null) - { - throw new IllegalArgumentException("LodChunk constructor given a null world"); - } - emptyPlaceholder = false; - x = chunk.getPos().x; - z = chunk.getPos().z; + x = pos.x; + z = pos.z; - top = new short[4]; - bottom = new short[4]; - colors = new Color[6]; - - // generate the top and bottom points of this LOD - for(LodLocation loc : LodLocation.values()) - { - top[loc.value] = generateLodCorner(chunk, SectionGenerationMode.GENERATE_TOP, loc); - bottom[loc.value] = generateLodCorner(chunk, SectionGenerationMode.GENERATE_BOTTOM, loc); - } - - // determine the average color for each direction - for(ColorDirection dir : ColorDirection.values()) - { - colors[dir.value] = generateLodColorForDirection(chunk, world, dir); - } + top = newTop; + bottom = newBottom; + colors = newColors; } @@ -250,533 +206,6 @@ public class LodChunk - //=====================// - // constructor helpers // - //=====================// - - /** GENERATE_TOP, GENERATE_BOTTOM */ - private enum SectionGenerationMode - { - GENERATE_TOP, - GENERATE_BOTTOM; - } - - /** - * Generate the height for the given LodLocation, either the top or bottom. - *

- * If invalid/null/empty chunks are given - * crashes may occur. - */ - public short generateLodCorner(IChunk chunk, SectionGenerationMode sectionGenMode, LodLocation lodLoc) - { - // if this LodChunk was a empltyPlaceholder before - // it will hold some data after this method's completion, - // make sure it is handled like a normal LodChunk - emptyPlaceholder = false; - - - int startX = 0; - int endX = 0; - - int startZ = 0; - int endZ = 0; - - // determine where we should look in this - // chunk - switch(lodLoc) - { - case NE: - // -N - startZ = 0; - endZ = (CHUNK_DATA_WIDTH / 2) - 1; - // +E - startX = CHUNK_DATA_WIDTH / 2; - endX = CHUNK_DATA_WIDTH - 1; - break; - - case SE: - // +S - startZ = CHUNK_DATA_WIDTH / 2; - endZ = CHUNK_DATA_WIDTH; - // +E - startX = CHUNK_DATA_WIDTH / 2; - endX = CHUNK_DATA_WIDTH; - break; - - case SW: - // +S - startZ = CHUNK_DATA_WIDTH / 2; - endZ = CHUNK_DATA_WIDTH; - // -W - startX = 0; - endX = (CHUNK_DATA_WIDTH / 2) - 1; - break; - - case NW: - // -N - startZ = 0; - endZ = CHUNK_DATA_WIDTH / 2; - // -W - startX = 0; - endX = CHUNK_DATA_WIDTH / 2; - break; - } - - - // should have a length of 16 - // (each storage is 16x16x16 and the - // world height is 256) - ChunkSection[] chunkSections = chunk.getSections(); - - - if(sectionGenMode == SectionGenerationMode.GENERATE_TOP) - return determineTopPoint(chunkSections, startX, endX, startZ, endZ); - else - return determineBottomPoint(chunkSections, startX, endX, startZ, endZ); - } - - - /** - * Find the lowest valid point from the bottom. - */ - private short determineBottomPoint(ChunkSection[] chunkSections, int startX, int endX, int startZ, int endZ) - { - // search from the bottom up - for(int i = 0; i < CHUNK_DATA_WIDTH; i++) - { - for(int y = 0; y < CHUNK_DATA_HEIGHT; y++) - { - - if(isLayerValidLodPoint(chunkSections, startX, endX, startZ, endZ, i, y)) - { - // we found - // enough blocks in this - // layer to count as an - // LOD point - return (short) (y + (i * CHUNK_DATA_HEIGHT)); - } - } - } - - // we never found a valid LOD point - return -1; - } - - /** - * Find the lowest valid point from the bottom. - */ - @SuppressWarnings("unused") - private short determineBottomPoint(Heightmap heightmap, int startX, int endX, int startZ, int endZ) - { - // the heightmap only shows how high the blocks go, it - // doesn't have any info about how low they go - return 0; - } - - - - /** - * Find the highest valid point from the Top - */ - private short determineTopPoint(ChunkSection[] chunkSections, int startX, int endX, int startZ, int endZ) - { - // search from the top down - for(int i = chunkSections.length - 1; i >= 0; i--) - { - for(int y = CHUNK_DATA_WIDTH - 1; y >= 0; y--) - { - if(isLayerValidLodPoint(chunkSections, startX, endX, startZ, endZ, i, y)) - { - // we found - // enough blocks in this - // layer to count as an - // LOD point - return (short) (y + (i * CHUNK_DATA_HEIGHT)); - } - } - } - - // we never found a valid LOD point - return -1; - } - - /** - * Find the highest valid point from the Top - */ - @SuppressWarnings("unused") - private short determineTopPoint(Heightmap heightmap, int startX, int endX, int startZ, int endZ) - { - short highest = 0; - for(int x = startX; x < endX; x++) - { - for(int z = startZ; z < endZ; z++) - { - short newHeight = (short) heightmap.getHeight(x, z); - if (newHeight > highest) - highest = newHeight; - } - } - - return highest; - } - - - - - - - - - /** - * Is the layer between the given X, Z, and dataIndex - * values a valid LOD point? - */ - private boolean isLayerValidLodPoint( - ChunkSection[] chunkSections, - int startX, int endX, - int startZ, int endZ, - int sectionIndex, int y) - { - // search through this layer - int layerBlocks = 0; - - for(int x = startX; x < endX; x++) - { - for(int z = startZ; z < endZ; z++) - { - if(chunkSections[sectionIndex] == null) - { - // this section doesn't have any blocks, - // it is not a valid section - return false; - } - else - { - if(chunkSections[sectionIndex].getBlockState(x, y, z) != null && chunkSections[sectionIndex].getBlockState(x, y, z).getBlock() != Blocks.AIR) - { - // we found a valid block in - // in this layer - layerBlocks++; - - if(layerBlocks >= LOD_BLOCK_REQ) - { - return true; - } - } - } - - } // z - } // x - - return false; - } - - /** - * Generate the color of the given ColorDirection at the given chunk - * in the given world. - */ - private Color generateLodColorForDirection(IChunk chunk, World world, ColorDirection colorDir) - { - Minecraft mc = Minecraft.getInstance(); - BlockColors bc = mc.getBlockColors(); - - switch (colorDir) - { - case TOP: - return generateLodColorVertical(chunk, colorDir, world, bc); - case BOTTOM: - return generateLodColorVertical(chunk, colorDir, world, bc); - - case N: - return generateLodColorHorizontal(chunk, colorDir, world, bc); - case S: - return generateLodColorHorizontal(chunk, colorDir, world, bc); - - case E: - return generateLodColorHorizontal(chunk, colorDir, world, bc); - case W: - return generateLodColorHorizontal(chunk, colorDir, world, bc); - } - - return new Color(0, 0, 0, 0); - } - - /** - * Generates the color of the top or bottom of a given chunk in the given world. - * - * @throws IllegalArgumentException if given a ColorDirection other than TOP or BOTTOM - */ - private Color generateLodColorVertical(IChunk chunk, ColorDirection colorDir, World world, BlockColors bc) - { - if(colorDir != ColorDirection.TOP && colorDir != ColorDirection.BOTTOM) - { - throw new IllegalArgumentException("generateLodColorVertical only accepts the ColorDirection TOP or BOTTOM"); - } - - - - ChunkSection[] chunkSections = chunk.getSections(); - - int numbOfBlocks = 0; - int red = 0; - int green = 0; - int blue = 0; - - boolean goTopDown = (colorDir == ColorDirection.TOP); - - - // either go top down or bottom up - int dataStart = goTopDown? chunkSections.length - 1 : 0; - int dataMax = chunkSections.length; - int dataMin = 0; - int dataIncrement = goTopDown? -1 : 1; - - int topStart = goTopDown? CHUNK_DATA_HEIGHT - 1 : 0; - int topMax = CHUNK_DATA_HEIGHT; - int topMin = 0; - int topIncrement = goTopDown? -1 : 1; - - for(int x = 0; x < CHUNK_DATA_WIDTH; x++) - { - for(int z = 0; z < CHUNK_DATA_WIDTH; z++) - { - boolean foundBlock = false; - - for(int i = dataStart; !foundBlock && i >= dataMin && i < dataMax; i += dataIncrement) - { - if(!foundBlock && chunkSections[i] != null) - { - for(int y = topStart; !foundBlock && y >= topMin && y < topMax; y += topIncrement) - { - int ci; - ci = chunkSections[i].getBlockState(x, y, z).materialColor.colorValue; - - if(ci == 0) - { - // skip air or invisible blocks - continue; - } - - Color c = intToColor(ci); - - red += c.getRed(); - green += c.getGreen(); - blue += c.getBlue(); - - numbOfBlocks++; - - - // we found a valid block, skip to the - // next x and z - foundBlock = true; - } - } - } - - } - } - - if(numbOfBlocks == 0) - numbOfBlocks = 1; - - red /= numbOfBlocks; - green /= numbOfBlocks; - blue /= numbOfBlocks; - - return new Color(red, green, blue); - - /* - * unused variation that can be used with only the heightmap, - * although it just returns the foliage color, so it shouldn't - * be used normally. - - Heightmap heightmap = chunk.getHeightmap(Heightmap.Type.WORLD_SURFACE_WG); - - int numbOfBlocks = CHUNK_DATA_WIDTH * CHUNK_DATA_WIDTH; - int red = 0; - int green = 0; - int blue = 0; - - for(int x = 0; x < CHUNK_DATA_WIDTH; x++) - { - for(int z = 0; z < CHUNK_DATA_WIDTH; z++) - { - Biome biome = chunk.getBiomes().getNoiseBiome(x,z, heightmap.getHeight(x, z)); - Color c = intToColor(biome.getFoliageColor()); - - red += c.getRed(); - green += c.getGreen(); - blue += c.getBlue(); - } - } - - red /= numbOfBlocks; - green /= numbOfBlocks; - blue /= numbOfBlocks; - - return new Color(red, green, blue); - */ - } - - /** - * Generates the color of the side of a given chunk in the given world for the given ColorDirection. - * - * @throws IllegalArgumentException if given a ColorDirection other than N, S, W, E (North, South, East, West) - */ - private Color generateLodColorHorizontal(IChunk chunk, ColorDirection colorDir, World world, BlockColors bc) - { - if(colorDir != ColorDirection.N && colorDir != ColorDirection.S && colorDir != ColorDirection.E && colorDir != ColorDirection.W) - { - throw new IllegalArgumentException("generateLodColorHorizontal only accepts the ColorDirection N (North), S (South), E (East), or W (West)"); - } - - ChunkSection[] chunkSections = chunk.getSections(); - - int numbOfBlocks = 0; - int red = 0; - int green = 0; - int blue = 0; - - - // these don't change since the over direction doesn't matter - int overStart = 0; - int overIncrement = 1; - - // determine which direction is "in" - int inStart = 0; - int inIncrement = 1; - switch (colorDir) - { - case N: - inStart = 0; - inIncrement = 1; - break; - case S: - inStart = CHUNK_DATA_WIDTH - 1; - inIncrement = -1; - break; - case E: - inStart = 0; - inIncrement = 1; - break; - case W: - inStart = CHUNK_DATA_WIDTH - 1; - inIncrement = -1; - break; - default: - // we were given an invalid position, return invisible. - // this shouldn't happen and is mostly here to make the - // compiler happy - return new Color(0,0,0,0); - } - - - for (int i = 0; i < chunkSections.length; i++) - { - if (chunkSections[i] != null) - { - for (int y = 0; y < CHUNK_DATA_HEIGHT; y++) - { - boolean foundBlock = false; - - // over moves "over" the side of the chunk - // in moves "into" the chunk until it finds a block - - for (int over = overStart; !foundBlock && over >= 0 && over < CHUNK_DATA_WIDTH; over += overIncrement) - { - for (int in = inStart; !foundBlock && in >= 0 && in < CHUNK_DATA_WIDTH; in += inIncrement) - { - int x = -1; - int z = -1; - - // determine which should be X and Z - switch(colorDir) - { - case N: - x = over; - z = in; - break; - case S: - x = over; - z = in; - break; - case E: - x = in; - z = over; - break; - case W: - x = in; - z = over; - break; - default: - // this will never happen, it would have - // been caught by the switch before the loops - break; - } - - int ci; - ci = chunkSections[i].getBlockState(x, y, z).getMaterial().getColor().colorValue; - - if (ci == 0) { - // skip air or invisible blocks - continue; - } - - Color c = intToColor(ci); - - red += c.getRed(); - green += c.getGreen(); - blue += c.getBlue(); - - numbOfBlocks++; - - // we found a valid block, skip to the - // next x and z - foundBlock = true; - } - } - } - - } - } - - if(numbOfBlocks == 0) - numbOfBlocks = 1; - - red /= numbOfBlocks; - green /= numbOfBlocks; - blue /= numbOfBlocks; - - return new Color(red, green, blue); - } - - - /** - * Convert a BlockColors int into a Color object. - */ - private Color intToColor(int num) - { - int filter = 0b11111111; - - int red = (num >> 16 ) & filter; - int green = (num >> 8 ) & filter; - int blue = num & filter; - - return new Color(red, green, blue); - } - - /** - * Convert a Color into a BlockColors object. - */ - @SuppressWarnings("unused") - private int colorToInt(Color color) - { - return color.getRGB(); - } - - - - //================// // misc functions // //================// diff --git a/src/main/java/com/backsun/lod/util/LodUtils.java b/src/main/java/com/backsun/lod/util/LodUtils.java index f19455fee..c3d556add 100644 --- a/src/main/java/com/backsun/lod/util/LodUtils.java +++ b/src/main/java/com/backsun/lod/util/LodUtils.java @@ -7,13 +7,15 @@ import net.minecraft.client.Minecraft; import net.minecraft.server.integrated.IntegratedServer; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.DimensionType; +import net.minecraft.world.chunk.ChunkSection; +import net.minecraft.world.chunk.IChunk; import net.minecraft.world.server.ServerWorld; /** * This class holds methods that may be used in multiple places. * * @author James Seibel - * @version 03-19-2021 + * @version 03-24-2021 */ public class LodUtils { @@ -86,4 +88,23 @@ public class LodUtils return rPos; } + + /** + * Return whether the given chunk + * has any data in it. + */ + public static boolean chunkHasBlockData(IChunk chunk) + { + ChunkSection[] blockStorage = chunk.getSections(); + + for(ChunkSection section : blockStorage) + { + if(section != null && !section.isEmpty()) + { + return true; + } + } + + return false; + } }