diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java index 93c19c4af..106aaba75 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -181,7 +181,7 @@ public class LodNodeBufferBuilder LodQuadTreeNode lod = lodDim.getLodFromCoordinates(new ChunkPos(chunkX, chunkZ), LodQuadTreeNode.CHUNK_LEVEL); - if (lod == null || lod.getComplexity() == DistanceGenerationMode.NONE) + if (lod == null || lod.complexity == DistanceGenerationMode.NONE) { // generate a new chunk if no chunk currently exists // and we aren't waiting on any other chunks to generate diff --git a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java b/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java index c06253254..d7968af09 100644 --- a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java +++ b/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java @@ -18,6 +18,7 @@ package com.seibel.lod.enums; /** + * NONE
* BIOME_ONLY
* BIOME_ONLY_SIMULATE_HEIGHT
* SURFACE
@@ -27,13 +28,14 @@ package com.seibel.lod.enums; * In order of fastest to slowest. * * @author James Seibel - * @version 6-27-2021 + * @author Leonardo Amato + * @version 8-7-2021 */ public enum DistanceGenerationMode { - /** No generation has be used*/ + /** Don't generate anything */ NONE(0), - + /** Only generate the biomes and use biome * grass/foliage color, water color, or ice color * to generate the color. @@ -67,17 +69,13 @@ public enum DistanceGenerationMode * are adding the mod to a pre-existing world. * Singlethreaded - Slow (15-50 ms, with spikes up to 200 ms) */ SERVER(5); - + + + /** The higher the number the more complete the generation is. */ public final int complexity; - - DistanceGenerationMode(int complexity) { + + DistanceGenerationMode(int complexity) + { this.complexity = complexity; } - - - /* - public int compareTo(DistanceGenerationMode other){ - return Integer.compare(complexity, other.complexity); - ) - */ } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/LodQuadTree.java index 15050d904..7d83ca71e 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -347,7 +347,7 @@ public class LodQuadTree // this detail level's node if (!getOnlyLeaf && !(getOnlyDirty && !lodNode.isDirty()) - && complexityMask.contains(lodNode.getComplexity())) + && complexityMask.contains(lodNode.complexity)) { nodeList.add(lodNode); } @@ -370,7 +370,7 @@ public class LodQuadTree { // This tree has no children - if (!(getOnlyDirty && !lodNode.isDirty()) && (complexityMask.contains(lodNode.getComplexity()))) + if (!(getOnlyDirty && !lodNode.isDirty()) && (complexityMask.contains(lodNode.complexity))) { nodeList.add(lodNode); } @@ -395,10 +395,10 @@ public class LodQuadTree int z = playerPos.getZ(); List distances = new ArrayList<>(); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getStartX(), 2) + Math.pow(z - lodNode.getStartZ(), 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getStartX(), 2) + Math.pow(z - lodNode.getEndZ(), 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getEndX(), 2) + Math.pow(z - lodNode.getStartZ(), 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getEndX(), 2) + Math.pow(z - lodNode.getEndZ(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.startX, 2) + Math.pow(z - lodNode.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.startX, 2) + Math.pow(z - lodNode.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.endX, 2) + Math.pow(z - lodNode.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.endX, 2) + Math.pow(z - lodNode.endZ, 2))); int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); @@ -412,7 +412,7 @@ public class LodQuadTree { // we have either reached the right detail level or this tree isn't full - if (!lodNode.isVoidNode() && complexityMask.contains(lodNode.getComplexity())) + if (!lodNode.isVoidNode() && complexityMask.contains(lodNode.complexity)) { // this node isn't void and has the complexity level we are looking for nodeList.add(lodNode); @@ -449,10 +449,10 @@ public class LodQuadTree int z = playerPos.getZ(); List distances = new ArrayList<>(); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getStartX(), 2) + Math.pow(z - lodNode.getStartZ(), 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getStartX(), 2) + Math.pow(z - lodNode.getEndZ(), 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getEndX(), 2) + Math.pow(z - lodNode.getStartZ(), 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getEndX(), 2) + Math.pow(z - lodNode.getEndZ(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.startX, 2) + Math.pow(z - lodNode.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.startX, 2) + Math.pow(z - lodNode.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.endX, 2) + Math.pow(z - lodNode.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.endX, 2) + Math.pow(z - lodNode.endZ, 2))); int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); @@ -465,7 +465,7 @@ public class LodQuadTree // TODO shouldn't tagetLevel be != lodNode.detailLevel? if(!hasChildren() || targetLevel == lodNode.detailLevel) { - if (this.lodNode.getComplexity().compareTo(complexityToGenerate) <= 0 ) + if (this.lodNode.complexity.compareTo(complexityToGenerate) <= 0 ) { nodeList.add(new AbstractMap.SimpleEntry(this.lodNode, min)); } @@ -522,10 +522,10 @@ public class LodQuadTree */ public boolean isCoordinateInQuadTree(BlockPos pos) { - return (lodNode.getStartX() * lodNode.width <= pos.getX() && - lodNode.getStartZ() * lodNode.width <= pos.getZ() && - lodNode.getEndX() * lodNode.width >= pos.getX() && - lodNode.getEndZ() * lodNode.width >= pos.getZ()); + return (lodNode.startX * lodNode.width <= pos.getX() && + lodNode.startZ * lodNode.width <= pos.getZ() && + lodNode.endX * lodNode.width >= pos.getX() && + lodNode.endZ * lodNode.width >= pos.getZ()); } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java index 637869ea4..6d69a895b 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java @@ -27,12 +27,20 @@ import com.seibel.lod.handlers.LodQuadTreeDimensionFileHandler; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.gen.Heightmap; +/** + * This object contains position + * and color data for an LOD object. + * + * @author Leonardo Amato + * @author James Seibel + * @version 8-7-2021 + */ public class LodQuadTreeNode { /** This is what separates each piece of data in the toData method */ - private static final char DATA_DELIMITER = LodQuadTreeDimensionFileHandler.DATA_DELIMITER; + private static final char DATA_DELIMITER = LodQuadTreeDimensionFileHandler.DATA_DELIMITER; - /** alpha used when drawing chunks in debug mode */ + /** alpha used when drawing chunks in debug mode */ private static final int DEBUG_ALPHA = 255; // 0 - 255 @SuppressWarnings("unused") private static final Color DEBUG_BLACK = new Color(0, 0, 0, DEBUG_ALPHA); @@ -44,389 +52,356 @@ public class LodQuadTreeNode /** If we ever have to use a heightmap for any reason, use this one. */ public static final Heightmap.Type DEFAULT_HEIGHTMAP = Heightmap.Type.WORLD_SURFACE_WG; - + /** If this is set to true then toData will return * the empty string */ public boolean dontSave = false; - - - - /** this is how many pieces of data are exported when toData is called */ - public static final int NUMBER_OF_DELIMITERS = 10; - - - //Complexity indicate how the block was built. This is important because we could use - public DistanceGenerationMode complexity; - - //level height goes from 0 to 9 with 0 the deepest (block size) and 9 the highest (region size) - public final byte detailLevel; - public static final byte REGION_LEVEL = 9; //at level 9 we reach the dimension of a single region - public static final byte CHUNK_LEVEL = 4; //at level 4 we reach the dimension of a single chunk - public static final byte BLOCK_LEVEL = 0; //at level 0 we reach the dimension of a single block - - //indicate the width in block of this node (goes from 1 to 512) - public final short width; - public static final short REGION_WIDTH = 512; //at level 9 we reach the dimension of a single region - public static final short CHUNK_WIDTH = 16; //at level 4 we reach the dimension of a single chunk - public static final short BLOCK_WIDTH = 1; //at level 0 we reach the dimension of a single block - - //this 2 values indicate the position of the LOD in the relative Level - //this will be useful in the generation process - public final int posX; - public final int posZ; - - //these 4 value indicate the corner of the LOD block - //they can be named SW, SE, NW, NE as the cardinal direction. - //the start values should always be smaller than the end values. - //All this value could be calculated from level, posx and posz - //so they could be removed and replaced with just a getter - public final int startX; - public final int startZ; - public final int endX; - public final int endZ; - //these 2 value indicate the center of the LodNode in real coordinate. This - //can be used to calculate the distance from the player - public final int centerX; - public final int centerZ; - - public LodDataPoint lodDataPoint; - - //void node is used - public boolean voidNode; - //if dirty is true, then this node have unsaved changes - public boolean dirty; - - - /**TODO There should be a check for the level. Level must be positive, i could use runtime exception or simple if*/ - /**TODO There should be a good way to create node that must not be saved - * For example loading a 64 region wide dimension that is fully generated is too much memory heavy. - * There should be a way to create Node that are approximated and at region level, so you could load those - * for far region, and then when you get closer you load the actual region from the file or you generate it. - * */ - - - /** - * Creates and empty LodDataPoint - * This LodDataPoint only contains the position data - * @param detailLevel of the node - * @param posX position x in the level - * @param posZ position z in the level - */ - public LodQuadTreeNode(ChunkPos pos) - { - this(CHUNK_LEVEL, pos.x, pos.z); - } - - /** - * Creates and empty LodDataPoint - * This LodDataPoint only contains the position data - * @param detailLevel of the node - * @param posX position x in the level - * @param posZ position z in the level - */ - public LodQuadTreeNode(byte detailLevel, int posX, int posZ) - { - this.detailLevel = detailLevel; - - this.posX = posX; - this.posZ = posZ; - - width = (short) Math.pow(2, detailLevel); - - startX = posX * width; - startZ = posZ * width; - endX = startX + width - 1; - endZ = startZ + width - 1; - - centerX = startX + width/2; - centerZ = startZ + width/2; - - lodDataPoint = new LodDataPoint(); - - complexity = DistanceGenerationMode.NONE; - - dirty = true; - voidNode = true; - dontSave = true; - } - - /** - * Constructor for a LodNodeData - * @param level - * @param posX - * @param posZ - * @param height - * @param depth - * @param color - * @param complexity - */ - public LodQuadTreeNode(byte level, int posX, int posZ, short height, short depth , Color color, DistanceGenerationMode complexity) - { - this(level, posX, posZ, new LodDataPoint(height,depth,color), complexity); - } - - /** - * Constructor for a LodNodeData - * @param level - * @param posX - * @param posZ - * @param height - * @param depth - * @param color - * @param complexity - */ - public LodQuadTreeNode(byte level, int posX, int posZ, int height , int depth , Color color, DistanceGenerationMode complexity) - { - this(level, posX, posZ, new LodDataPoint(height,depth,color), complexity); - } - - /** - * Constructor for a LodNodeData - * @param detailLevel level of this - * @param posX - * @param posZ - * @param lodDataPoint - * @param complexity - */ - public LodQuadTreeNode(byte detailLevel, int posX, int posZ, LodDataPoint lodDataPoint, DistanceGenerationMode complexity) - { - this.detailLevel = detailLevel; - - this.posX = posX; - this.posZ = posZ; - - width = (short) Math.pow(2, detailLevel); - - startX = posX * width; - startZ = posZ * width; - - endX = startX + width - 1; - endZ = startZ + width - 1; - centerX = startX + width/2; - centerZ = startZ + width/2; - - this.lodDataPoint = lodDataPoint; - this.complexity = complexity; - - dirty = true; - voidNode = false; - dontSave = false; - } - - public LodQuadTreeNode(String data) - { - int index = 0; - int lastIndex = 0; - - index = data.indexOf(DATA_DELIMITER, 0); - this.detailLevel = (byte) Integer.parseInt(data.substring(0,index)); - - lastIndex = index; - index = data.indexOf(DATA_DELIMITER, lastIndex+1); - this.posX = Integer.parseInt(data.substring(lastIndex+1,index)); - - lastIndex = index; - index = data.indexOf(DATA_DELIMITER, lastIndex+1); - this.posZ = Integer.parseInt(data.substring(lastIndex+1,index)); - - lastIndex = index; - index = data.indexOf(DATA_DELIMITER, lastIndex+1); - this.complexity = DistanceGenerationMode.valueOf(data.substring(lastIndex+1,index)); - - lastIndex = index; - index = data.indexOf(DATA_DELIMITER, lastIndex+1); - short height = (short) Integer.parseInt(data.substring(lastIndex+1,index)); - - lastIndex = index; - index = data.indexOf(DATA_DELIMITER, lastIndex+1); - short depth = (short) Integer.parseInt(data.substring(lastIndex+1,index)); - - lastIndex = index; - index = data.indexOf(DATA_DELIMITER, lastIndex+1); - int r = Integer.parseInt(data.substring(lastIndex+1,index)); - lastIndex = index; - index = data.indexOf(DATA_DELIMITER, lastIndex+1); - int g = Integer.parseInt(data.substring(lastIndex+1,index)); - lastIndex = index; - index = data.indexOf(DATA_DELIMITER, lastIndex+1); - int b = Integer.parseInt(data.substring(lastIndex+1,index)); - lastIndex = index; - index = data.indexOf(DATA_DELIMITER, lastIndex+1); - int a = Integer.parseInt(data.substring(lastIndex+1,index)); - Color color = new Color(r,g,b,a); - lodDataPoint = new LodDataPoint(height,depth,color); - - int val = Integer.parseInt(data.substring(lastIndex+1,index)); - this.voidNode = (val == 1); - - - width = (short) Math.pow(2, detailLevel); - - startX = posX * width; - startZ = posZ * width; - endX = startX + width - 1; - endZ = startZ + width - 1; - - centerX = startX + width/2; - centerZ = startZ + width/2; - - dirty = false; - dontSave = false; - } - - public void update(LodQuadTreeNode lodQuadTreeNode){ - this.lodDataPoint = lodQuadTreeNode.lodDataPoint; - this.complexity = lodQuadTreeNode.complexity; - this.voidNode = lodQuadTreeNode.voidNode; - dirty = true; - dontSave = false; - } - - public LodDataPoint getLodDataPoint(){ - return lodDataPoint; - } - - public void combineData(List dataList) - { - if(dataList.isEmpty()) - { - lodDataPoint = new LodDataPoint(); - } - else - { - short height = (short) dataList.stream().mapToInt(x -> (int) x.getLodDataPoint().height).min().getAsInt(); - short depth = (short) dataList.stream().mapToInt(x -> (int) x.getLodDataPoint().depth).max().getAsInt(); - int red = dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getRed()).sum()/dataList.size(); - int green = dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getGreen()).sum()/dataList.size(); - int blue = dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getBlue()).sum()/dataList.size(); - Color color = new Color(red,green,blue); - lodDataPoint = new LodDataPoint(height,depth,color); - - //the new complexity equal to the lowest complexity of the list - DistanceGenerationMode minComplexity = DistanceGenerationMode.SERVER; - for(LodQuadTreeNode node: dataList) - { - if (minComplexity.compareTo(node.complexity) > 0) - { - minComplexity = node.complexity; - } - } - - complexity = minComplexity; - - voidNode = dataList.stream().filter(x -> !x.voidNode).count() == 0; - } - - dirty = true; - dontSave = false; - } - - - @Override - public int hashCode(){ - return Objects.hash(this.complexity, this.detailLevel, this.posX, this.posZ, this.lodDataPoint, this.voidNode); - } - - public int compareComplexity(LodQuadTreeNode other){ - return this.complexity.compareTo(other.complexity); - } - - - public boolean equals(LodQuadTreeNode other){ - return (this.complexity == other.complexity - && this.detailLevel == other.detailLevel - && this.posX == other.posX - && this.posZ == other.posZ - && this.lodDataPoint.equals(other.lodDataPoint) - && this.complexity == other.complexity - && this.voidNode == other.voidNode); - } - - - /** - * Outputs all data in a csv format - */ - public String toData() - { - if (dontSave) - return ""; - - String s = Integer.toString(detailLevel) + DATA_DELIMITER - + Integer.toString(posX) + DATA_DELIMITER - + Integer.toString(posZ) + DATA_DELIMITER - + complexity.toString() + DATA_DELIMITER - + Integer.toString((lodDataPoint.height)) + DATA_DELIMITER - + Integer.toString((lodDataPoint.depth)) + DATA_DELIMITER - + Integer.toString(lodDataPoint.color.getRed()) + DATA_DELIMITER - + Integer.toString(lodDataPoint.color.getGreen()) + DATA_DELIMITER - + Integer.toString(lodDataPoint.color.getBlue()) + DATA_DELIMITER - + Integer.toString(lodDataPoint.color.getAlpha()) + DATA_DELIMITER; - int val = voidNode ? 1 : 0; - s += Integer.toString(val) + DATA_DELIMITER; - return s; - } - - - - @Override + + + + /** this is how many pieces of data are exported when toData is called */ + public static final int NUMBER_OF_DELIMITERS = 10; + + + //Complexity indicate how the block was built. This is important because we could use + public DistanceGenerationMode complexity; + + /** Indicates how complicated this node is.
+ * Goes from 0 to 9, 0 being the deepest (block size) and 9 being the highest (region size) */ + public final byte detailLevel; + /** 512 blocks wide */ + public static final byte REGION_LEVEL = 9; + /** 16 blocks wide */ + public static final byte CHUNK_LEVEL = 4; + /** 1 block wide */ + public static final byte BLOCK_LEVEL = 0; + + /** Indicates the width in blocks of this node.
+ * Goes from 1 to 512 */ + public final short width; + /** detail level 9 */ + public static final short REGION_WIDTH = 512; + /** detail level 4 */ + public static final short CHUNK_WIDTH = 16; + /** detail level 0 */ + public static final short BLOCK_WIDTH = 1; + + //this 2 values indicate the position of the LOD in the relative Level + //this will be useful in the generation process + public final int posX; + public final int posZ; + + //these 4 value indicate the corner of the LOD block + //they can be named SW, SE, NW, NE as the cardinal direction. + //the start values should always be smaller than the end values. + //All this value could be calculated from level, posx and posz + //so they could be removed and replaced with just a getter + public final int startX; + public final int startZ; + public final int endX; + public final int endZ; + //these 2 value indicate the center of the LodNode in real coordinate. This + //can be used to calculate the distance from the player + public final int centerX; + public final int centerZ; + + public LodDataPoint lodDataPoint; + + //void node is used + public boolean voidNode; + //if dirty is true, then this node have unsaved changes + public boolean dirty; + + + /**TODO There should be a check for the level. Level must be positive, i could use runtime exception or simple if*/ + /**TODO There should be a good way to create node that must not be saved + * For example loading a 64 region wide dimension that is fully generated is too much memory heavy. + * There should be a way to create Node that are approximated and at region level, so you could load those + * for far region, and then when you get closer you load the actual region from the file or you generate it. + * */ + + + /** + * Creates and empty LodDataPoint + * This LodDataPoint only contains the position data + * @param detailLevel of the node + * @param posX position x in the level + * @param posZ position z in the level + */ + public LodQuadTreeNode(ChunkPos pos) + { + this(CHUNK_LEVEL, pos.x, pos.z); + } + + /** + * Creates and empty LodDataPoint + * This LodDataPoint only contains the position data + * @param detailLevel of the node + * @param posX position x in the level + * @param posZ position z in the level + */ + public LodQuadTreeNode(byte detailLevel, int posX, int posZ) + { + this.detailLevel = detailLevel; + + this.posX = posX; + this.posZ = posZ; + + width = (short) Math.pow(2, detailLevel); + + startX = posX * width; + startZ = posZ * width; + endX = startX + width - 1; + endZ = startZ + width - 1; + + centerX = startX + width/2; + centerZ = startZ + width/2; + + lodDataPoint = new LodDataPoint(); + + complexity = DistanceGenerationMode.NONE; + + dirty = true; + voidNode = true; + dontSave = true; + } + + /** + * Constructor for a LodNodeData + * @param level + * @param posX + * @param posZ + * @param height + * @param depth + * @param color + * @param complexity + */ + public LodQuadTreeNode(byte level, int posX, int posZ, short height, short depth , Color color, DistanceGenerationMode complexity) + { + this(level, posX, posZ, new LodDataPoint(height,depth,color), complexity); + } + + /** + * Constructor for a LodNodeData + * @param level + * @param posX + * @param posZ + * @param height + * @param depth + * @param color + * @param complexity + */ + public LodQuadTreeNode(byte level, int posX, int posZ, int height, int depth, Color color, DistanceGenerationMode complexity) + { + this(level, posX, posZ, new LodDataPoint(height,depth,color), complexity); + } + + /** + * Constructor for a LodNodeData + * @param detailLevel level of this + * @param posX + * @param posZ + * @param lodDataPoint + * @param complexity + */ + public LodQuadTreeNode(byte detailLevel, int posX, int posZ, LodDataPoint lodDataPoint, DistanceGenerationMode complexity) + { + this.detailLevel = detailLevel; + + this.posX = posX; + this.posZ = posZ; + + width = (short) Math.pow(2, detailLevel); + + startX = posX * width; + startZ = posZ * width; + + endX = startX + width - 1; + endZ = startZ + width - 1; + centerX = startX + width/2; + centerZ = startZ + width/2; + + this.lodDataPoint = lodDataPoint; + this.complexity = complexity; + + dirty = true; + voidNode = false; + dontSave = false; + } + + public LodQuadTreeNode(String data) + { + int index = 0; + int lastIndex = 0; + + index = data.indexOf(DATA_DELIMITER, 0); + this.detailLevel = (byte) Integer.parseInt(data.substring(0,index)); + + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + this.posX = Integer.parseInt(data.substring(lastIndex+1,index)); + + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + this.posZ = Integer.parseInt(data.substring(lastIndex+1,index)); + + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + this.complexity = DistanceGenerationMode.valueOf(data.substring(lastIndex+1,index)); + + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + short height = (short) Integer.parseInt(data.substring(lastIndex+1,index)); + + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + short depth = (short) Integer.parseInt(data.substring(lastIndex+1,index)); + + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + int r = Integer.parseInt(data.substring(lastIndex+1,index)); + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + int g = Integer.parseInt(data.substring(lastIndex+1,index)); + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + int b = Integer.parseInt(data.substring(lastIndex+1,index)); + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + int a = Integer.parseInt(data.substring(lastIndex+1,index)); + Color color = new Color(r,g,b,a); + lodDataPoint = new LodDataPoint(height,depth,color); + + int val = Integer.parseInt(data.substring(lastIndex+1,index)); + this.voidNode = (val == 1); + + + width = (short) Math.pow(2, detailLevel); + + startX = posX * width; + startZ = posZ * width; + endX = startX + width - 1; + endZ = startZ + width - 1; + + centerX = startX + width/2; + centerZ = startZ + width/2; + + dirty = false; + dontSave = false; + } + + public void update(LodQuadTreeNode lodQuadTreeNode) + { + this.lodDataPoint = lodQuadTreeNode.lodDataPoint; + this.complexity = lodQuadTreeNode.complexity; + this.voidNode = lodQuadTreeNode.voidNode; + dirty = true; + dontSave = false; + } + + public LodDataPoint getLodDataPoint() + { + return lodDataPoint; + } + + public void combineData(List dataList) + { + if(dataList.isEmpty()) + { + lodDataPoint = new LodDataPoint(); + } + else + { + short height = (short) dataList.stream().mapToInt(x -> (int) x.getLodDataPoint().height).min().getAsInt(); + short depth = (short) dataList.stream().mapToInt(x -> (int) x.getLodDataPoint().depth).max().getAsInt(); + int red = dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getRed()).sum()/dataList.size(); + int green = dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getGreen()).sum()/dataList.size(); + int blue = dataList.stream().mapToInt(x -> x.getLodDataPoint().color.getBlue()).sum()/dataList.size(); + Color color = new Color(red,green,blue); + lodDataPoint = new LodDataPoint(height,depth,color); + + //the new complexity equal to the lowest complexity of the list + DistanceGenerationMode minComplexity = DistanceGenerationMode.SERVER; + for(LodQuadTreeNode node: dataList) + { + if (minComplexity.compareTo(node.complexity) > 0) + { + minComplexity = node.complexity; + } + } + + complexity = minComplexity; + + voidNode = dataList.stream().filter(x -> !x.voidNode).count() == 0; + } + + dirty = true; + dontSave = false; + } + + + @Override + public int hashCode() + { + return Objects.hash(this.complexity, this.detailLevel, this.posX, this.posZ, this.lodDataPoint, this.voidNode); + } + + public int compareComplexity(LodQuadTreeNode other) + { + return this.complexity.compareTo(other.complexity); + } + + + public boolean equals(LodQuadTreeNode other) + { + return (this.complexity == other.complexity + && this.detailLevel == other.detailLevel + && this.posX == other.posX + && this.posZ == other.posZ + && this.lodDataPoint.equals(other.lodDataPoint) + && this.complexity == other.complexity + && this.voidNode == other.voidNode); + } + + + public boolean isVoidNode() + { + return voidNode; + } + + public boolean isDirty() + { + return dirty; + } + + + /** + * Outputs all data in a csv format + */ + public String toData() + { + if (dontSave) + return ""; + + String s = Integer.toString(detailLevel) + DATA_DELIMITER + + Integer.toString(posX) + DATA_DELIMITER + + Integer.toString(posZ) + DATA_DELIMITER + + complexity.toString() + DATA_DELIMITER + + Integer.toString((lodDataPoint.height)) + DATA_DELIMITER + + Integer.toString((lodDataPoint.depth)) + DATA_DELIMITER + + Integer.toString(lodDataPoint.color.getRed()) + DATA_DELIMITER + + Integer.toString(lodDataPoint.color.getGreen()) + DATA_DELIMITER + + Integer.toString(lodDataPoint.color.getBlue()) + DATA_DELIMITER + + Integer.toString(lodDataPoint.color.getAlpha()) + DATA_DELIMITER + + Integer.toString(voidNode ? 1 : 0) + DATA_DELIMITER; + return s; + } + + @Override public String toString() - { - return this.toData(); - } - - - // These getters should be used - - public byte getDetailLevel() { - return detailLevel; - } - - public DistanceGenerationMode getComplexity() { - return complexity; - } - - public short getWidth() { - return width; - } - - public int getPosX() { - return posX; - } - - public int getPosZ() { - return posZ; - } - - public int getStartX() { - return startX; - } - - public int getStartZ() { - return startZ; - } - - public int getEndX() { - return endX; - } - - public int getEndZ() { - return endZ; - } - - public int getCenterX() { - return centerX; - } - - public int getCenterZ() { - return centerZ; - } - - public boolean isVoidNode() { - return voidNode; - } - - public boolean isDirty() { - return dirty; - } + { + return this.toData(); + } + }