diff --git a/src/main/java/com/backsun/lod/builders/LodBuilder.java b/src/main/java/com/backsun/lod/builders/LodBuilder.java index c1ec997b1..7bcc9fe16 100644 --- a/src/main/java/com/backsun/lod/builders/LodBuilder.java +++ b/src/main/java/com/backsun/lod/builders/LodBuilder.java @@ -10,8 +10,8 @@ import com.backsun.lod.objects.LodWorld; import com.backsun.lod.util.LodUtils; import net.minecraft.world.DimensionType; -import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkSection; +import net.minecraft.world.chunk.IChunk; import net.minecraft.world.server.ServerWorld; /** @@ -20,7 +20,7 @@ import net.minecraft.world.server.ServerWorld; * (specifically: Lod World, Dimension, Region, and Chunk objects) * * @author James Seibel - * @version 2-22-2021 + * @version 3-24-2021 */ public class LodBuilder { @@ -40,8 +40,9 @@ public class LodBuilder /** * Returns LodWorld so that it can be passed * to the LodRenderer. + * @param dimensionType */ - public LodWorld generateLodChunkAsync(Chunk chunk) + public LodWorld generateLodChunkAsync(IChunk chunk, DimensionType dim) { if (lodWorld != null) // is this chunk from the same world as the lodWorld? @@ -55,11 +56,9 @@ public class LodBuilder // given a valid chunk object // (Minecraft often gives back empty // or null chunks in this method) - if (chunk == null || !isValidChunk(chunk)) + if (chunk == null || !hasBlockData(chunk)) return lodWorld; - - DimensionType dim = chunk.getWorld().getDimensionType(); ServerWorld world = LodUtils.getServerWorldFromDimension(dim); @@ -71,6 +70,7 @@ public class LodBuilder try { LodChunk lod = new LodChunk(chunk, world); + LodDimension lodDim; if (lodWorld == null) @@ -103,11 +103,14 @@ public class LodBuilder return lodWorld; } + + + /** * Return whether the given chunk * has any data in it. */ - public boolean isValidChunk(Chunk chunk) + public boolean hasBlockData(IChunk chunk) { ChunkSection[] blockStorage = chunk.getSections(); diff --git a/src/main/java/com/backsun/lod/objects/LodChunk.java b/src/main/java/com/backsun/lod/objects/LodChunk.java index 454057a85..7d1aa1a66 100644 --- a/src/main/java/com/backsun/lod/objects/LodChunk.java +++ b/src/main/java/com/backsun/lod/objects/LodChunk.java @@ -2,23 +2,24 @@ package com.backsun.lod.objects; import java.awt.Color; -import com.backsun.lod.util.enums.ColorDirection; -import com.backsun.lod.util.enums.LodCorner; -import com.backsun.lod.util.enums.LodLocation; +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.Chunk; import net.minecraft.world.chunk.ChunkSection; +import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.gen.Heightmap; /** * This object contains position * and color data for an LOD object. * * @author James Seibel - * @version 03-19-2021 + * @version 03-24-2021 */ public class LodChunk { @@ -43,6 +44,7 @@ public class LodChunk // since each layer is 1/4 the chunk + /** The x coordinate of the chunk. */ public int x; /** The z coordinate of the chunk. */ @@ -56,7 +58,6 @@ public class LodChunk /** The average color of each 6 cardinal directions */ public Color colors[]; - /** If true that means this LodChunk is just a placeholder and * no LOD has been generated for this chunk location */ private boolean emptyPlaceholder = false; @@ -210,7 +211,7 @@ public class LodChunk * @throws IllegalArgumentException * thrown if either the chunk or world is null. */ - public LodChunk(Chunk chunk, World world) throws IllegalArgumentException + public LodChunk(IChunk chunk, World world) throws IllegalArgumentException { if(chunk == null) { @@ -249,11 +250,16 @@ 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. @@ -261,13 +267,8 @@ public class LodChunk * If invalid/null/empty chunks are given * crashes may occur. */ - public short generateLodCorner(Chunk chunk, SectionGenerationMode generationMode, LodLocation lodLoc) + public short generateLodCorner(IChunk chunk, SectionGenerationMode sectionGenMode, LodLocation lodLoc) { - // should have a length of 16 - // (each storage is 16x16x16 and the - // world height is 256) - ChunkSection[] chunkSections = chunk.getSections(); - // 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 @@ -322,17 +323,18 @@ public class LodChunk } - if(generationMode == SectionGenerationMode.GENERATE_TOP) + // 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); } - /** GENERATE_TOP, GENERATE_BOTTOM */ - private enum SectionGenerationMode - { - GENERATE_TOP, - GENERATE_BOTTOM; - } + /** * Find the lowest valid point from the bottom. @@ -340,7 +342,7 @@ public class LodChunk private short determineBottomPoint(ChunkSection[] chunkSections, int startX, int endX, int startZ, int endZ) { // search from the bottom up - for(int i = 0; i < chunkSections.length; i++) + for(int i = 0; i < CHUNK_DATA_WIDTH; i++) { for(int y = 0; y < CHUNK_DATA_HEIGHT; y++) { @@ -359,6 +361,19 @@ public class LodChunk // 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 @@ -385,6 +400,33 @@ public class LodChunk 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? @@ -433,7 +475,7 @@ public class LodChunk * Generate the color of the given ColorDirection at the given chunk * in the given world. */ - private Color generateLodColorForDirection(Chunk chunk, World world, ColorDirection colorDir) + private Color generateLodColorForDirection(IChunk chunk, World world, ColorDirection colorDir) { Minecraft mc = Minecraft.getInstance(); BlockColors bc = mc.getBlockColors(); @@ -464,13 +506,15 @@ public class LodChunk * * @throws IllegalArgumentException if given a ColorDirection other than TOP or BOTTOM */ - private Color generateLodColorVertical(Chunk chunk, ColorDirection colorDir, World world, BlockColors bc) + 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; @@ -540,6 +584,38 @@ public class LodChunk 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); + */ } /** @@ -547,7 +623,7 @@ public class LodChunk * * @throws IllegalArgumentException if given a ColorDirection other than N, S, W, E (North, South, East, West) */ - private Color generateLodColorHorizontal(Chunk chunk, ColorDirection colorDir, World world, BlockColors bc) + private Color generateLodColorHorizontal(IChunk chunk, ColorDirection colorDir, World world, BlockColors bc) { if(colorDir != ColorDirection.N && colorDir != ColorDirection.S && colorDir != ColorDirection.E && colorDir != ColorDirection.W) { @@ -674,6 +750,7 @@ public class LodChunk return new Color(red, green, blue); } + /** * Convert a BlockColors int into a Color object. */ diff --git a/src/main/java/com/backsun/lod/proxy/ClientProxy.java b/src/main/java/com/backsun/lod/proxy/ClientProxy.java index c6b5aacb3..766f9110d 100644 --- a/src/main/java/com/backsun/lod/proxy/ClientProxy.java +++ b/src/main/java/com/backsun/lod/proxy/ClientProxy.java @@ -26,7 +26,7 @@ import net.minecraftforge.eventbus.api.SubscribeEvent; * and is the starting point for most of this program. * * @author James_Seibel - * @version 03-19-2021 + * @version 03-24-2021 */ public class ClientProxy { @@ -124,7 +124,7 @@ public class ClientProxy public void chunkLoadEvent(ChunkEvent.Load event) { if (event.getChunk().getClass() == Chunk.class) - lodWorld = lodBuilder.generateLodChunkAsync((Chunk) event.getChunk()); + lodWorld = lodBuilder.generateLodChunkAsync(event.getChunk(), event.getWorld().getDimensionType()); } diff --git a/src/main/java/com/backsun/lod/proxy/SingleLodChunkGenWorker.java b/src/main/java/com/backsun/lod/proxy/SingleLodChunkGenWorker.java index 6417734f0..2db5d653d 100644 --- a/src/main/java/com/backsun/lod/proxy/SingleLodChunkGenWorker.java +++ b/src/main/java/com/backsun/lod/proxy/SingleLodChunkGenWorker.java @@ -26,7 +26,6 @@ import com.backsun.lod.renderer.LodRenderer; import com.backsun.lod.util.LodUtils; import net.minecraft.util.math.ChunkPos; -import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.ChunkStatus; import net.minecraft.world.chunk.IChunk; import net.minecraft.world.server.ServerWorld; @@ -36,7 +35,7 @@ import net.minecraftforge.common.WorldWorkerManager.IWorker; * This is used to generate a LodChunk at a given ChunkPos. * * @author James Seibel - * @version 03-19-2021 + * @version 03-24-2021 */ public class SingleLodChunkGenWorker implements IWorker { @@ -73,15 +72,20 @@ public class SingleLodChunkGenWorker implements IWorker // be added to the current LodDimension if (lodDim.regionIsInRange(pos.x / LodRegion.SIZE, pos.z / LodRegion.SIZE)) { - IChunk chunk = serverWorld.getChunk(x, z, ChunkStatus.EMPTY, true); + IChunk chunk;// = serverWorld.getChunk(x, z, ChunkStatus.EMPTY, true); - chunk = serverWorld.getChunk(x, z, ChunkStatus.FULL); + //long startTime = System.currentTimeMillis(); + chunk = serverWorld.getChunk(x, z, ChunkStatus.FEATURES); + //long endTime = System.currentTimeMillis(); + //System.out.println(endTime - startTime + "\t" + lodBuilder.hasBlockData(chunk)); - lodBuilder.generateLodChunkAsync((Chunk) chunk); + + lodBuilder.generateLodChunkAsync(chunk, serverWorld.getDimensionType()); // this is called so that the new LOD chunk is drawn // after it is generated lodRenderer.regenerateLODsNextFrame(); + // useful for debugging //if (lodDim.getLodFromCoordinates(x, z) != null) // System.out.println(x + " " + z + " Success!"); @@ -103,4 +107,31 @@ public class SingleLodChunkGenWorker implements IWorker } return true; } + + + /* + * performance/generation tests related to + * serverWorld.getChunk(x, z, ChunkStatus. *** ) + + true/false is whether they generated blocks or not + the time is how long it took to generate + + ChunkStatus.FULL 30 - 50 ms true + ChunkStatus.HEIGHTMAPS 20 - 40 ms true + ChunkStatus.BIOMES 1 - 10 ms false (no height) + ChunkStatus.CARVERS 5 - 30 ms true (no snow/trees, just grass) + ChunkStatus.EMPTY 0 - 1 ms false (empty, what did you expect? :P) + ChunkStatus.FEATURES 7 - 25 ms true + ChunkStatus.LIGHT 20 - 40 ms true + ChunkStatus.LIQUID_CARVERS 6 - 12 ms true (no snow/trees, just grass) + ChunkStatus.NOISE 4 - 15 ms true (all blocks are stone) + ChunkStatus.SPAWN 50 - 80 ms true + ChunkStatus.SURFACE 5 - 15 ms true (no snow/trees, just grass) + ChunkStatus.STRUCTURE_REFERENCES 1 - 2 ms false (no height, only generates some chunks) + + At this point I would suggest using FEATURES, as it generates snow and trees + (and any other object that is needed to make biomes distinct) + + Otherwise if snow/trees aren't necessary SURFACE is the next fastest (although not by much) + */ }