From 72bcc87de7b8e5de407b646e2db7530bd46398a2 Mon Sep 17 00:00:00 2001 From: Morippi Date: Mon, 5 Jul 2021 14:46:51 +0200 Subject: [PATCH 01/46] QuadTree version, still doesn't work --- .../seibel/lod/builders/LodNodeBuilder.java | 172 +++++++ .../LodQuadTreeDimensionFileHandler.java | 324 ++++++++++++++ .../lod/objects/quadTree/LodNodeData.java | 246 +++++++++++ .../lod/objects/quadTree/LodQuadTree.java | 363 +++++++++++++++ .../quadTree/LodQuadTreeDimension.java | 418 ++++++++++++++++++ .../objects/quadTree/LodQuadTreeWorld.java | 97 ++++ .../lod/objects/quadTree/UsesExamples.java | 58 +++ 7 files changed, 1678 insertions(+) create mode 100644 src/main/java/com/seibel/lod/builders/LodNodeBuilder.java create mode 100644 src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java create mode 100644 src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java create mode 100644 src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java create mode 100644 src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java create mode 100644 src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeWorld.java create mode 100644 src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java new file mode 100644 index 000000000..5f2d00988 --- /dev/null +++ b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java @@ -0,0 +1,172 @@ +package com.seibel.lod.builders; + +import com.seibel.lod.enums.LodDetail; +import com.seibel.lod.handlers.LodConfig; +import com.seibel.lod.objects.LodChunk; +import com.seibel.lod.objects.LodDataPoint; +import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.LodWorld; +import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.objects.quadTree.LodQuadTreeWorld; +import kaptainwutax.biomeutils.source.BiomeSource; +import kaptainwutax.biomeutils.source.OverworldBiomeSource; +import kaptainwutax.mcutils.state.Dimension; +import kaptainwutax.mcutils.version.MCVersion; +import net.minecraft.util.ResourceLocation; +import net.minecraft.world.DimensionType; +import net.minecraft.world.IWorld; +import net.minecraft.world.chunk.IChunk; + +import java.awt.*; +import java.util.Iterator; +import java.util.OptionalLong; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class LodNodeBuilder { + private ExecutorService lodGenThreadPool = Executors.newSingleThreadExecutor(); + private long seed; + private DimensionType dimension; + + /** Default size of any LOD regions we use */ + public int regionWidth = 5; + + + /** fast biome calculator */ + private BiomeSource biomeSource; + //Biome biome=biomeSource.getBiome(x,y,z); // here y is always 0 no matter what you pass + + public LodNodeBuilder(){ + + } + public setApproxGenerator(long seed){ + //Dimension.OVERWORLD; + //Dimension.END; + //Dimension.NETHER; + biomeSource = BiomeSource.of(Dimension.OVERWORLD ,MCVersion.v1_16_4, seed); + } + + public void generateLodNodeAsync(List dataList){ + Thread thread = new Thread(() ->{ + for(LodNodeData data : dataList){ + + } + }); + thread.setPriority(4); + lodGenThreadPool.execute(thread); + + return; + } + + public void generateLodNodeAsync(IChunk chunk, LodWorld lodWorld, IWorld world) + { + if (lodWorld == null || !lodWorld.getIsWorldLoaded()) + return; + + // don't try to create an LOD object + // if for some reason we aren't + // given a valid chunk object + if (chunk == null) + return; + + Thread thread = new Thread(() -> + { + try + { + DimensionType dim = world.getDimensionType(); + + LodChunk lod = generateLodFromChunk(chunk, config); + + LodDimension lodDim; + + if (lodWorld.getLodDimension(dim) == null) + { + lodDim = new LodDimension(dim, lodWorld, regionWidth); + lodWorld.addLodDimension(lodDim); + } + else + { + lodDim = lodWorld.getLodDimension(dim); + } + + lodDim.addLod(lod); + } + catch(IllegalArgumentException | NullPointerException e) + { + // if the world changes while LODs are being generated + // they will throw errors as they try to access things that no longer + // exist. + } + }); + lodGenThreadPool.execute(thread); + + return; + } + + + + + + /** + * Creates a LodChunk for a chunk in the given world. + * + * @throws IllegalArgumentException + * thrown if either the chunk or world is null. + */ + public LodChunk generateLodFromChunk(IChunk chunk) throws IllegalArgumentException + { + return generateLodFromChunk(chunk, new LodBuilderConfig()); + } + + /** + * Creates a LodChunk for a chunk in the given world. + * + * @throws IllegalArgumentException + * thrown if either the chunk or world is null. + */ + public LodChunk generateLodFromChunk(IChunk chunk, LodBuilderConfig config) throws IllegalArgumentException + { + if(chunk == null) + throw new IllegalArgumentException("generateLodFromChunk given a null chunk"); + + + LodDetail detail = LodConfig.CLIENT.lodDetail.get(); + LodDataPoint[][] dataPoints = new LodDataPoint[detail.lengthCount][detail.lengthCount]; + + for(int i = 0; i < detail.lengthCount * detail.lengthCount; i++) + { + int startX = detail.startX[i]; + int startZ = detail.startZ[i]; + int endX = detail.endX[i]; + int endZ = detail.endZ[i]; + + Color color; + + color = generateLodColorForArea(chunk, config, startX, startZ, endX, endZ); + + + short height; + short depth; + + if (!config.useHeightmap) + { + height = determineHeightPointForArea(chunk.getSections(), startX, startZ, endX, endZ); + depth = determineBottomPointForArea(chunk.getSections(), startX, startZ, endX, endZ); + } + else + { + height = determineHeightPoint(chunk.getHeightmap(LodChunk.DEFAULT_HEIGHTMAP), startX, startZ, endX, endZ); + depth = 0; + } + + int x = i / detail.lengthCount; + int z = i % detail.lengthCount; + + dataPoints[x][z] = new LodDataPoint(height, depth, color); + } + + return new LodChunk(chunk.getPos(), dataPoints, detail); + } + + +} diff --git a/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java b/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java new file mode 100644 index 000000000..9ab9af696 --- /dev/null +++ b/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java @@ -0,0 +1,324 @@ +package com.seibel.lod.handlers; + +import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.objects.quadTree.LodQuadTree; +import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.proxy.ClientProxy; + +import java.io.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class LodQuadTreeDimensionFileHandler { + /** This is what separates each piece of data */ + public static final char DATA_DELIMITER = ','; + + + private LodQuadTreeDimension loadedDimension = null; + public long regionLastWriteTime[][]; + + private File dimensionDataSaveFolder; + + /** lod */ + private final String FILE_NAME_PREFIX = "lod"; + /** .txt */ + private final String FILE_EXTENSION = ".txt"; + + /** This is the file version currently accepted by this + * file handler, older versions (smaller numbers) will be deleted and overwritten, + * newer versions (larger numbers) will be ignored and won't be read. */ + public static final int LOD_SAVE_FILE_VERSION = 2; + + /** This is the string written before the file version */ + private static final String LOD_FILE_VERSION_PREFIX = "lod_save_file_version"; + + /** Allow saving asynchronously, but never try to save multiple regions + * at a time */ + private ExecutorService fileWritingThreadPool = Executors.newSingleThreadExecutor(); + + + public LodQuadTreeDimensionFileHandler(File newSaveFolder, LodQuadTreeDimension newLoadedDimension) + { + if (newSaveFolder == null) + throw new IllegalArgumentException("LodDimensionFileHandler requires a valid File location to read and write to."); + + dimensionDataSaveFolder = newSaveFolder; + + loadedDimension = newLoadedDimension; + // these two variable are used in sync with the LodDimension + regionLastWriteTime = new long[loadedDimension.getWidth()][loadedDimension.getWidth()]; + for(int i = 0; i < loadedDimension.getWidth(); i++) + for(int j = 0; j < loadedDimension.getWidth(); j++) + regionLastWriteTime[i][j] = -1; + } + + + + + + //================// + // read from file // + //================// + + + + /** + * Return the LodQuadTree region at the given coordinates. + * (null if the file doesn't exist) + */ + public LodQuadTree loadRegionFromFile(int regionX, int regionZ) + { + + String fileName = getFileNameAndPathForRegion(regionX, regionZ); + + File f = new File(fileName); + + if (!f.exists()) + { + // there wasn't a file, don't + // return anything + return null; + } + + List dataList = new ArrayList<>(); + try + { + BufferedReader br = new BufferedReader(new FileReader(f)); + String s = br.readLine(); + int fileVersion = -1; + if(s != null && !s.isEmpty()) + { + // try to get the file version + try + { + fileVersion = Integer.parseInt(s.substring(s.indexOf(' ')).trim()); + } + catch(NumberFormatException | StringIndexOutOfBoundsException e) + { + // this file doesn't have a version + // keep the version as -1 + fileVersion = -1; + } + + // check if this file can be read by this file handler + if(fileVersion < LOD_SAVE_FILE_VERSION) + { + // the file we are reading is an older version, + // close the reader and delete the file. + br.close(); + f.delete(); + ClientProxy.LOGGER.info("Outdated LOD region file for region: (" + regionX + "," + regionZ + ") version: " + fileVersion + + ", version requested: " + LOD_SAVE_FILE_VERSION + + " File was been deleted."); + + return null; + } + else if(fileVersion > LOD_SAVE_FILE_VERSION) + { + // the file we are reading is a newer version, + // close the reader and ignore the file, we don't + // want to accidently delete anything the user may want. + br.close(); + ClientProxy.LOGGER.info("Newer LOD region file for region: (" + regionX + "," + regionZ + ") version: " + fileVersion + + ", version requested: " + LOD_SAVE_FILE_VERSION + + " this region will not be written to in order to protect the newer file."); + + return null; + } + } + else + { + // there is no data in this file + br.close(); + return null; + } + + + // this file is a readable version, begin reading the file + s = br.readLine(); + + while(s != null && !s.isEmpty()) + { + try + { + dataList.add(new LodNodeData(s)); + } + catch(IllegalArgumentException e) + { + // we were unable to create this chunk + // for whatever reason. + // skip to the next chunk + ClientProxy.LOGGER.warn(e.getMessage()); + } + + s = br.readLine(); + } + br.close(); + } + catch (IOException e) + { + // the buffered reader encountered a + // problem reading the file + return null; + } + return new LodQuadTree(dataList,regionX, regionZ); + } + + + + + + + + + //==============// + // Save to File // + //==============// + + /** + * Save all dirty regions in this LodDimension to file. + */ + public void saveDirtyRegionsToFileAsync() + { + fileWritingThreadPool.execute(saveDirtyRegionsThread); + } + + private Thread saveDirtyRegionsThread = new Thread(() -> + { + for(int i = 0; i < loadedDimension.getWidth(); i++) + { + for(int j = 0; j < loadedDimension.getWidth(); j++) + { + if(loadedDimension.isRegionDirty[i][j] && loadedDimension.regions[i][j] != null) + { + saveRegionToDisk(loadedDimension.regions[i][j]); + loadedDimension.isRegionDirty[i][j] = false; + } + } + } + }); + + /** + * Save a specific region to disk.
+ * Note:
+ * 1. If a file already exists for a newer version + * the file won't be written.
+ * 2. This will save to the LodDimension that this + * handler is associated with. + */ + private void saveRegionToDisk(LodQuadTree region) + { + // convert chunk coordinates to region + // coordinates + int x = region.getLodNodeData().posX; + int z = region.getLodNodeData().posX; + + File f = new File(getFileNameAndPathForRegion(x, z)); + + try + { + // make sure the file and folder exists + if (!f.exists()) + { + // the file doesn't exist, + // create it and the folder if need be + if(!f.getParentFile().exists()) + f.getParentFile().mkdirs(); + f.createNewFile(); + } + else + { + // the file exists, make sure it + // is the correct version. + // (to make sure we don't overwrite a newer + // version file if it exists) + + BufferedReader br = new BufferedReader(new FileReader(f)); + String s = br.readLine(); + int fileVersion = LOD_SAVE_FILE_VERSION; + + if(s != null && !s.isEmpty()) + { + // try to get the file version + try + { + fileVersion = Integer.parseInt(s.substring(s.indexOf(' ')).trim()); + } + catch(NumberFormatException | StringIndexOutOfBoundsException e) + { + // this file doesn't have a correctly formated version + // just overwrite the file + } + } + br.close(); + + // check if this file can be written to by the file handler + if(fileVersion <= LOD_SAVE_FILE_VERSION) + { + // we are good to continue and overwrite the old file + } + else //if(fileVersion > LOD_SAVE_FILE_VERSION) + { + // the file we are reading is a newer version, + // don't write anything, we don't want to accidently + // delete anything the user may want. + return; + } + } + + FileWriter fw = new FileWriter(f); + + // add the version of this file + fw.write(LOD_FILE_VERSION_PREFIX + " " + LOD_SAVE_FILE_VERSION + "\n"); + + // add each LodChunk to the file + for(LodNodeData lodNodeData : Collections.unmodifiableList(region.getNodeList(false, true, true))) { + fw.write(lodNodeData.toData() + "\n"); + lodNodeData.dirty = false; + } + fw.close(); + } + catch(Exception e) + { + ClientProxy.LOGGER.error("LOD file write error: " + e.getMessage()); + } + } + + + + + + + + //================// + // helper methods // + //================// + + + /** + * Return the name of the file that should contain the + * region at the given x and z.
+ * Returns null if this object isn't ready to read and write.

+ * + * example: "lod.FULL.0.0.txt" + */ + private String getFileNameAndPathForRegion(int regionX, int regionZ) + { + try + { + // saveFolder is something like + // ".\Super Flat\DIM-1\data" + // or + // ".\Super Flat\data" + return dimensionDataSaveFolder.getCanonicalPath() + File.separatorChar + + FILE_NAME_PREFIX + regionX + "." + regionZ + FILE_EXTENSION; + } + catch(IOException e) + { + return null; + } + } +} diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java b/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java new file mode 100644 index 000000000..b354ee826 --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java @@ -0,0 +1,246 @@ +package com.seibel.lod.objects.quadTree; + +import com.seibel.lod.handlers.LodQuadTreeDimensionFileHandler; + +import java.awt.*; +import java.util.*; +import java.util.List; + +public class LodNodeData { + /** This is what separates each piece of data in the toData method */ + private static final char DATA_DELIMITER = LodQuadTreeDimensionFileHandler.DATA_DELIMITER; + + + + /** this is how many pieces of data are exported when toData is called */ + public static final int NUMBER_OF_DELIMITERS = 9; + + private static final Color INVISIBLE = new Color(0,0,0,0); + + //level height goes from 0 to 9 with 0 the deepest (block size) and 9 the highest (region size) + public final byte level; + 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 and levelWidth + //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; + + /** highest point */ + public short height; + + /** lowest point */ + public short depth; + + /** The average color for the 6 cardinal directions */ + public Color color; + + public boolean real; + public boolean voidNode; + //if dirty is true, then this node have unsaved changes + public boolean dirty; + + /** + * Creates and empty LodDataPoint + * This LodDataPoint only contains the position data + * @param level of the node + * @param posX position x in the level + * @param posZ posizion z in the level + */ + public LodNodeData(byte level, int posX, int posZ){ + this.level = level; + this.posX = posX; + this.posZ = posZ; + width = (short) Math.pow(2, level); + startX = posX * width; + startZ = posZ * width; + endX = startX + width - 1; + endZ = startZ + width - 1; + centerX = startX + width/2; + centerZ = startZ + width/2; + height = -1; + depth = -1; + color = INVISIBLE; + real = false; + dirty = true; + voidNode = true; + } + + /** + * Constructor for a LodNodeData + * @param level level of this + * @param posX + * @param posZ + * @param height + * @param depth + * @param color + * @param real + */ + public LodNodeData(byte level, int posX, int posZ, short height, short depth, Color color, boolean real){ + this.level = level; + this.posX = posX; + this.posZ = posZ; + width = (short) Math.pow(2, level); + startX = posX * width; + startZ = posZ * width; + endX = startX + width - 1; + endZ = startZ + width - 1; + centerX = startX + width/2; + centerZ = startZ + width/2; + this.height = height; + this.depth = depth; + this.color = color; + this.real = real; + dirty = true; + voidNode = false; + } + + public LodNodeData(byte level, int posX, int posZ, int height, int depth, Color color, boolean real) { + this(level, posX, posZ, (short) height,(short) depth, color, real); + } + + public LodNodeData(String data) + { + int index = 0; + int lastIndex = 0; + + index = data.indexOf(DATA_DELIMITER, 0); + this.level = (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.height = (short) Integer.parseInt(data.substring(lastIndex+1,index)); + + lastIndex = index; + index = data.indexOf(DATA_DELIMITER, lastIndex+1); + this.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)); + this.color = new Color(r,g,b,a); + + int val = Integer.parseInt(data.substring(lastIndex+1,index)); + this.real = (val == 1); + width = (short) Math.pow(2, level); + + val = Integer.parseInt(data.substring(lastIndex+1,index)); + this.voidNode = (val == 1); + startX = posX * width; + startZ = posZ * width; + endX = startX + width - 1; + endZ = startZ + width - 1; + centerX = startX + width/2; + centerZ = startZ + width/2; + dirty = false; + } + + public void update(LodNodeData lodNodeData){ + this.height = lodNodeData.height; + this.depth = lodNodeData.depth; + this.color = lodNodeData.color; + this.real = lodNodeData.real; + dirty = true; + } + + public void combineData(List dataList){ + if(dataList.isEmpty()){ + height = -1; + depth = -1; + color = INVISIBLE; + }else { + short height = (short) dataList.stream().mapToInt(x -> (int) x.height).min().getAsInt(); + short depth = (short) dataList.stream().mapToInt(x -> (int) x.depth).max().getAsInt(); + height = height; + depth = depth; + color = dataList.get(0).color; + real = dataList.stream().filter(x -> x.real).count() == 4; + voidNode = dataList.stream().filter(x -> !x.voidNode).count() == 0; + } + dirty = true; + } + + + + public int hashCode(){ + return Objects.hash(this.real, this.level, this.posX, this.posZ, this.color, this.real, this.voidNode); + } + + + public boolean equals(LodNodeData other){ + return (this.real == other.real + && this.level == other.level + && this.posX == other.posX + && this.posZ == other.posZ + && this.color.equals(other.color) + && this.real == other.real + && this.voidNode == other.voidNode); + } + + + /** + * Outputs all data in a csv format + */ + public String toData(){ + String s = Integer.toString(level) + DATA_DELIMITER + + posX + DATA_DELIMITER + + posZ + DATA_DELIMITER + + Integer.toString(height) + DATA_DELIMITER + + Integer.toString(depth) + DATA_DELIMITER + + color.getRed() + DATA_DELIMITER + + color.getGreen() + DATA_DELIMITER + + color.getBlue() + DATA_DELIMITER + + color.getAlpha() + DATA_DELIMITER; + int val = real ? 1 : 0; + s += val + DATA_DELIMITER; + val = voidNode ? 1 : 0; + s += val + DATA_DELIMITER; + return s; + } + + + + public String toString() + { + return this.toData(); + } +} diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java new file mode 100644 index 000000000..9202b1c7c --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -0,0 +1,363 @@ +package com.seibel.lod.objects.quadTree; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.List; + +/** + * This object contains all data useful to render LodBlock in a region (32x32 chunk o 512x512 block) + * for every node it contains the border of the block, the size, the position at it's level, the color, the height and the depth. + */ +public class LodQuadTree { + //notes + //The term node correspond to a LodQuadTree object + + + /* + Example on how it will be rendered (the number correspond to the level in the LodNodeData) + .___.___._______._______________. + |6|6| 7 | | | + |6|6|___| 8 | | + | 7 | 7 | | | + |___|___|_______| 9 | + | | | | + | 8 | 8 | | + | | | | + |_______|_______|_______________| + | | | + | | | + | | | + | 9 | 9 | + | | | + | | | + | | | + |_______________|_______________| + */ + //data useful to render + //if children are present then lodNodeData should be a combination of the lodData of the child. This can be + //turned off by deselecting the recursive update in all update method. + private final LodNodeData lodNodeData; + /* + .____.____. + | NW | NE | | + |____|____| Z + | SW | SE | | + |____|____| V + -----X----> + + North - negative z + South - positive z + West - negative x + east - positive x + */ + + + //level completed is true if and only if all child are not null + private boolean nodeFull; + private boolean nodeEmpty; + + //the four child based on the four diagonal cardinal direction + //the first index is for N and S and the second index is for W and S + //children should always be null for level 0. + private final LodQuadTree[][] children; + + //parent should always be null for level 9, and always not null for other levels. + private final LodQuadTree parent; + + /** + * Constructor for level 0 without LodNodeData (region level constructor) + * + * @param regionX indicate the x region position of the node + * @param regionZ indicate the z region position of the node + */ + //maybe the use of useLevelCoordinate could be changed. I could use a builder to do all this work. + public LodQuadTree(int regionX, int regionZ) { + this(null, new LodNodeData(LodNodeData.REGION_LEVEL, regionX, regionZ)); + } + + /** + * Constructor for generic level without LodNodeData + * + * @param parent parent of this node + * @param level level of this note + * @param posX position x in the level + * @param posZ position z in the level + */ + public LodQuadTree(LodQuadTree parent, byte level, int posX, int posZ) { + this(parent, new LodNodeData(level, posX, posZ)); + } + + /** + * Constructor for generic level via the LodNodeData + * + * @param lodNodeData object containing all the information of this node + */ + public LodQuadTree(LodQuadTree parent, LodNodeData lodNodeData) { + this.parent = parent; + this.lodNodeData = lodNodeData; + this.children = new LodQuadTree[2][2]; + this.nodeEmpty = true; + this.nodeFull = false; + } + + /** + * Constructor using a dataList + * + * @param dataList list of LodNodeData to put in this LodQuadTree + * @param regionX x region coordinate + * @param regionZ z region coordinate + */ + public LodQuadTree(List dataList, int regionX, int regionZ) { + this(null, new LodNodeData(LodNodeData.REGION_LEVEL, regionX, regionZ)); + this.setNodesAtLowerLevel(dataList, true); + } + + + /** + * @param dataList list of data to put in the node + * @param updateHigherLevel will update the color and height of higher level only if true + */ + public void setNodesAtLowerLevel(List dataList, boolean updateHigherLevel) { + for (LodNodeData lodNodeData : dataList) { + //this is slow, you could set update to false and use an only top down update method. + this.setNodeAtLowerLevel(lodNodeData, updateHigherLevel); + } + } + + /** + * @param newLodNodeData data to put in the node + * @param updateHigherLevel will update the color and height of higher level only if true + * @return true only if the QuadTree has been changed + */ + public boolean setNodeAtLowerLevel(LodNodeData newLodNodeData, boolean updateHigherLevel) { + //check if we try to introduce a level that is higher or equal than the current one + byte targetLevel = newLodNodeData.level; + byte currentLevel = lodNodeData.level; + if (targetLevel < currentLevel) { + int posX = newLodNodeData.posX; + int posZ = newLodNodeData.posZ; + short widthRatio = (short) (lodNodeData.width / newLodNodeData.width); + int NS = (posX / widthRatio) % lodNodeData.posX; + int WE = (posZ / widthRatio) % lodNodeData.posZ; + if (getChild(NS, WE) == null) { + setChild(NS, WE); + } + LodQuadTree child = getChild(NS, WE); + if (!newLodNodeData.real && child.isNodeReal()) { + return false; + } else { + if (targetLevel == currentLevel - 1) { + child.setLodNodeData(lodNodeData, updateHigherLevel); + return true; + } else { + return child.setNodeAtLowerLevel(lodNodeData, updateHigherLevel); + } + } + } else { + return false; + } + + } + + public LodQuadTree getChild(int NS, int WE) { + return children[NS][WE]; + } + + /** + * setChild will put a child with given data in the given position + * + * @param newLodNodeData data to put in the child + * @param NS North-South position + * @param WE West-East position + */ + public void setChild(LodNodeData newLodNodeData, int NS, int WE) { + if (newLodNodeData.level == lodNodeData.level - 1) { + children[NS][WE] = new LodQuadTree(this, lodNodeData); + } + } + + /** + * setChild will put a child with given data in the given position + * + * @param newLodNodeData data to put in the child + */ + public void setChild(LodNodeData newLodNodeData) { + if (newLodNodeData.level == lodNodeData.level - 1) { + int NS = newLodNodeData.posX % lodNodeData.posX; + int WE = newLodNodeData.posZ % lodNodeData.posZ; + children[NS][WE] = new LodQuadTree(this, lodNodeData); + } + } + + /** + * setChild will put a child in the given position + * + * @param NS North-South position + * @param WE West-East position + */ + public void setChild(int NS, int WE) { + int childX = lodNodeData.posX * 2 + WE; + int childZ = lodNodeData.posZ * 2 + NS; + children[NS][WE] = new LodQuadTree(this, (byte) (lodNodeData.level - 1), childX, childZ); + } + + /** + * Update level update the level data such as levelFull and lodNodeData. + * + * @param recursiveUpdate if recursive is true the update will rise up to the level 0 + */ + private void updateLevel(boolean recursiveUpdate) { + boolean isFull = true; + boolean isEmpty = true; + List dataList = new ArrayList<>(); + for (int NS = 0; NS <= 1; NS++) { + for (int WE = 0; WE <= 1; WE++) { + if (children[NS][WE] != null) { + dataList.add(children[NS][WE].getLodNodeData()); + isEmpty = false; + } else { + isFull = false; + } + } + } + nodeFull = isFull; + nodeEmpty = isEmpty; + lodNodeData.combineData(dataList); + if (lodNodeData.level > 0 && recursiveUpdate) { + this.parent.updateLevel(recursiveUpdate); + } + } + + /** + * method to get certain nodes from the LodQuadTree + * + * @param getOnlyReal if true it will return only real nodes + * @param getOnlyDirty if true it will return only dirty nodes + * @param getOnlyLeaf if true it will return only leaf nodes + * @return list of nodes + */ + public List getNodeList(boolean getOnlyReal, boolean getOnlyDirty, boolean getOnlyLeaf) { + List nodeList = new ArrayList<>(); + if (!isThereAnyChild()) { + if (!(getOnlyReal && !lodNodeData.dirty) + && !(getOnlyReal && !lodNodeData.real)) { + nodeList.add(lodNodeData); + } + } else { + if (!getOnlyLeaf + && !(getOnlyDirty && !lodNodeData.dirty) + && !(getOnlyReal && !lodNodeData.real)) { + nodeList.add(lodNodeData); + } + for (int NS = 0; NS <= 1; NS++) { + for (int WE = 0; WE <= 1; WE++) { + LodQuadTree child = children[NS][WE]; + if (child != null) { + nodeList.addAll(child.getNodeList(getOnlyReal, getOnlyDirty, getOnlyLeaf)); + } + } + } + } + return nodeList; + } + + /** + * method to get certain nodes from the LodQuadTree + * @return list of nodes + */ + public List getNodeToRender(int x, int z, byte targetLevel, int maxDistance, int minDistance){ + int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX,2) + Math.pow(z + lodNodeData.centerZ,2)); + List nodeList = new ArrayList<>(); + if(distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level) { + return nodeList; + } + if(targetLevel == lodNodeData.level || !isThereAnyChild()){ + if(!lodNodeData.voidNode){ + nodeList.add(lodNodeData); + return nodeList; + }else{ + return nodeList; + } + } else { + for (int NS = 0; NS <= 1; NS++) { + for (int WE = 0; WE <= 1; WE++) { + LodQuadTree child = children[NS][WE]; + if (child != null) { + nodeList.addAll(child.getNodeToRender(x,z,targetLevel,maxDistance,minDistance)); + } + } + } + } + return nodeList; + } + + /** + * method to get certain nodes from the LodQuadTree + * @return list of nodes + */ + public List> getNodeToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance){ + int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX,2) + Math.pow(z + lodNodeData.centerZ,2)); + List> nodeList = new ArrayList<>(); + if(distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level) { + return nodeList; + } + if(targetLevel == lodNodeData.level){ + return nodeList; + } else { + if(!isThereAnyChild()){ + for (int NS = 0; NS <= 1; NS++) { + for (int WE = 0; WE <= 1; WE++) { + LodQuadTree child = children[NS][WE]; + if (child != null) { + nodeList.addAll(child.getNodeToGenerate(x,z,targetLevel,maxDistance,minDistance)); + } + } + } + }else{ + nodeList.add( new AbstractMap.SimpleEntry<>(lodNodeData,distance)); + } + } + return nodeList; + } + /** + * simple getter for lodNodeData + * + * @return lodNodeData + */ + public LodNodeData getLodNodeData() { + return lodNodeData; + } + + /** + * setter for lodNodeData, to maintain a correct relationship between level this method force update on all parent + * + * @param newLodNodeData data to set + * @param updateHigherLevel if true it will update all the upper levels. + */ + public void setLodNodeData(LodNodeData newLodNodeData, boolean updateHigherLevel) { + this.lodNodeData.update(lodNodeData); + //a recursive update is necessary to change higher level + if (parent != null && updateHigherLevel) parent.updateLevel(true); + } + + public boolean isNodeFull() { + return nodeFull; + } + + public boolean isThereAnyChild() { + return nodeEmpty; + } + + public boolean isNodeReal() { + return lodNodeData.real; + } + + public boolean isRenderable() { + return (lodNodeData != null); + } +} + +/* +EXAMPLES OF USES + + */ diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java new file mode 100644 index 000000000..c864f6134 --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -0,0 +1,418 @@ +package com.seibel.lod.objects.quadTree; + +import com.seibel.lod.handlers.LodQuadTreeDimensionFileHandler; +import com.seibel.lod.objects.LodWorld; +import com.seibel.lod.objects.RegionPos; +import com.seibel.lod.util.LodUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.world.DimensionType; +import net.minecraft.world.server.ServerChunkProvider; +import net.minecraft.world.server.ServerWorld; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +public class LodQuadTreeDimension { + public final DimensionType dimension; + + private volatile int width; + private volatile int halfWidth; + public long seed; + + public volatile LodQuadTree regions[][]; + public volatile boolean isRegionDirty[][]; + + private int centerX; + private int centerZ; + + private LodQuadTreeDimensionFileHandler fileHandler; + + + public LodQuadTreeDimension(DimensionType newDimension, LodWorld lodWorld, int newMaxWidth) + { + dimension = newDimension; + width = newMaxWidth; + + try + { + Minecraft mc = Minecraft.getInstance(); + + File saveDir; + if(mc.isIntegratedServerRunning()) + { + // local world + + ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(newDimension); + seed = serverWorld.getSeed(); + // provider needs a separate variable to prevent + // the compiler from complaining + ServerChunkProvider provider = serverWorld.getChunkProvider(); + saveDir = new File(provider.getSavedData().folder.getCanonicalFile().getPath() + File.separatorChar + "lod"); + } + else + { + // connected to server + + saveDir = new File(mc.gameDir.getCanonicalFile().getPath() + + File.separatorChar + "lod server data" + File.separatorChar + LodUtil.getDimensionIDFromWorld(mc.world)); + } + + fileHandler = new LodQuadTreeDimensionFileHandler(saveDir, this); + } + catch(IOException e) + { + // the file handler wasn't able to be created + // we won't be able to read or write any files + } + + + regions = new LodQuadTree[width][width]; + isRegionDirty = new boolean[width][width]; + + // populate isRegionDirty + for(int i = 0; i < width; i++) + for(int j = 0; j < width; j++) + isRegionDirty[i][j] = false; + + centerX = 0; + centerZ = 0; + + halfWidth = (int)Math.floor(width / 2); + } + + + /** + * Move the center of this LodDimension and move all owned + * regions over by the given x and z offset. + */ + public void move(int xOffset, int zOffset) + { + // if the x or z offset is equal to or greater than + // the total size, just delete the current data + // and update the centerX and/or centerZ + if (Math.abs(xOffset) >= width || Math.abs(zOffset) >= width) + { + for(int x = 0; x < width; x++) + { + for(int z = 0; z < width; z++) + { + regions[x][z] = null; + } + } + + // update the new center + centerX += xOffset; + centerZ += zOffset; + + return; + } + + + // X + if(xOffset > 0) + { + // move everything over to the left (as the center moves to the right) + for(int x = 0; x < width; x++) + { + for(int z = 0; z < width; z++) + { + if(x + xOffset < width) + regions[x][z] = regions[x + xOffset][z]; + else + regions[x][z] = null; + } + } + } + else + { + // move everything over to the right (as the center moves to the left) + for(int x = width - 1; x >= 0; x--) + { + for(int z = 0; z < width; z++) + { + if(x + xOffset >= 0) + regions[x][z] = regions[x + xOffset][z]; + else + regions[x][z] = null; + } + } + } + + + + // Z + if(zOffset > 0) + { + // move everything up (as the center moves down) + for(int x = 0; x < width; x++) + { + for(int z = 0; z < width; z++) + { + if(z + zOffset < width) + regions[x][z] = regions[x][z + zOffset]; + else + regions[x][z] = null; + } + } + } + else + { + // move everything down (as the center moves up) + for(int x = 0; x < width; x++) + { + for(int z = width - 1; z >= 0; z--) + { + if(z + zOffset >= 0) + regions[x][z] = regions[x][z + zOffset]; + else + regions[x][z] = null; + } + } + } + + + + // update the new center + centerX += xOffset; + centerZ += zOffset; + } + + + + + + + /** + * Gets the region at the given X and Z + *
+ * Returns null if the region doesn't exist + * or is outside the loaded area. + */ + public LodQuadTree getRegion(int regionX, int regionZ) + { + int xIndex = (regionX - centerX) + halfWidth; + int zIndex = (regionZ - centerZ) + halfWidth; + + if (!regionIsInRange(regionX, regionZ)) + // out of range + return null; + + if (regions[xIndex][zIndex] == null) + { + regions[xIndex][zIndex] = getRegionFromFile(regionX, regionZ); + if (regions[xIndex][zIndex] == null) + { + regions[xIndex][zIndex] = new LodQuadTree(regionX, regionZ); + } + } + + return regions[xIndex][zIndex]; + } + + /** + * Overwrite the LodRegion at the location of newRegion with newRegion. + * @throws ArrayIndexOutOfBoundsException if newRegion is outside what can be stored in this LodDimension. + */ + public void setRegion(LodQuadTree newRegion) throws ArrayIndexOutOfBoundsException + { + int xIndex = (newRegion.getLodNodeData().posX - centerX) + halfWidth; + int zIndex = (centerZ - newRegion.getLodNodeData().posZ) + halfWidth; + + if (!regionIsInRange(newRegion.getLodNodeData().posX, newRegion.getLodNodeData().posZ)) + // out of range + throw new ArrayIndexOutOfBoundsException(); + + regions[xIndex][zIndex] = newRegion; + } + + + + + + /** + * Add the given LOD to this dimension at the coordinate + * stored in the LOD. If an LOD already exists at the given + * coordinates it will be overwritten. + */ + public void addNode(LodNodeData lodNodeData) + { + RegionPos pos = new RegionPos( + lodNodeData.posX / lodNodeData.width, + lodNodeData.posZ / lodNodeData.width + ); + + // don't continue if the region can't be saved + if (!regionIsInRange(pos.x, pos.z)) + { + return; + } + + LodQuadTree region = getRegion(pos.x, pos.z); + + if (region == null) + { + // if no region exists, create it + region = new LodQuadTree(pos.x, pos.z); + setRegion(region); + } + + region.setNodeAtLowerLevel(lodNodeData, true); + + // don't save empty place holders to disk + if (!lodNodeData.real && fileHandler != null) + { + // mark the region as dirty so it will be saved to disk + int xIndex = (pos.x - centerX) + halfWidth; + int zIndex = (pos.z - centerZ) + halfWidth; + isRegionDirty[xIndex][zIndex] = true; + fileHandler.saveDirtyRegionsToFileAsync(); + } + } + + /** + * Get the LodNodeData at the given X and Z position in the level + * in this dimension. + *
+ * Returns null if the LodChunk doesn't exist or + * is outside the loaded area. + */ + public LodNodeData getLodFromCoordinates(int posX, int posZ, byte level) + { + /*TODO */ + return null; + /* + RegionPos pos = LodUtil.convertChunkPosToRegionPos(new ChunkPos(chunkX, chunkZ)); + + LodQuadTree region = getRegion(pos.x, pos.z); + + if(region == null) + return null; + + return region.getNode(chunkX, chunkZ); + + */ + } + + /** + * method to get all the nodes that have to be rendered based on the position of the player + * @return list of nodes + */ + public List getNodeToRender(int x, int z){ + //BASIC IDEA + //Get all the node to render from every region + //combine them toghether + return null; + } + + /** + * method to get all the nodes that have to be generated based on the position of the player + * @return list of nodes + */ + public List getNodeToGenerate(int x, int z){ + //BASIC IDEA + //Get all the node to generate from every region + //combine them toghether + //sort them based on the distance to player + //this way + return null; + } + + /** + * Get the region at the given X and Z coordinates from the + * RegionFileHandler. + */ + public LodQuadTree getRegionFromFile(int regionX, int regionZ) + { + if (fileHandler != null) + return fileHandler.loadRegionFromFile(regionX, regionZ); + else + return null; + } + + + /** + * Returns whether the region at the given X and Z coordinates + * is within the loaded range. + */ + public boolean regionIsInRange(int regionX, int regionZ) + { + int xIndex = (regionX - centerX) + halfWidth; + int zIndex = (regionZ - centerZ) + halfWidth; + + return xIndex >= 0 && xIndex < width && zIndex >= 0 && zIndex < width; + } + + + + + + + + public int getCenterX() + { + return centerX; + } + + public int getCenterZ() + { + return centerZ; + } + + + /** + * Returns how many non-null LodChunks + * are stored in this LodDimension. + */ + public int getNumberOfLods() + { + int numbLods = 0; + for (LodQuadTree[] regions : regions) + { + if(regions == null) + continue; + + for (LodQuadTree region : regions) + { + if(region == null) + continue; + + numbLods= region.getNodeList(false,false,true).size(); + } + } + + return numbLods; + } + + + public int getWidth() + { + return width; + } + + public void setRegionWidth(int newWidth) + { + width = newWidth; + halfWidth = (int)Math.floor(width / 2); + + regions = new LodQuadTree[width][width]; + isRegionDirty = new boolean[width][width]; + + // populate isRegionDirty + for(int i = 0; i < width; i++) + for(int j = 0; j < width; j++) + isRegionDirty[i][j] = false; + } + + + @Override + public String toString() + { + String s = ""; + + s += "dim: " + dimension.toString() + "\t"; + s += "(" + centerX + "," + centerZ + ")"; + + return s; + } +} diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeWorld.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeWorld.java new file mode 100644 index 000000000..199d7f751 --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeWorld.java @@ -0,0 +1,97 @@ +package com.seibel.lod.objects.quadTree; + +import net.minecraft.world.DimensionType; + +import java.util.Hashtable; +import java.util.Map; + +public class LodQuadTreeWorld { + + private String worldName; + + private Map lodDimensions; + /** + * If true then the LOD world is setup and ready to use + */ + private boolean isWorldLoaded = false; + + public static final String NO_WORLD_LOADED = "No world loaded"; + + public LodQuadTreeWorld() { + worldName = NO_WORLD_LOADED; + } + + /** + * Set up the LodWorld with the given newWorldName.
+ * This should be done whenever loading a new world. + * @param newWorldName name of the world + */ + public void selectWorld(String newWorldName) { + if (newWorldName.isEmpty()) { + deselectWorld(); + return; + } + + if (worldName.equals(newWorldName)) + // don't recreate everything if we + // didn't actually change worlds + return; + + worldName = newWorldName; + lodDimensions = new Hashtable<>(); + isWorldLoaded = true; + } + + /** + * Set the worldName to "No world loaded" + * and clear the lodDimensions Map.
+ * This should be done whenever unloaded a world. + */ + public void deselectWorld() { + worldName = NO_WORLD_LOADED; + lodDimensions = null; + isWorldLoaded = false; + } + + + public void addLodDimension(LodQuadTreeDimension newStorage) { + if (lodDimensions == null) + throw new IllegalStateException("LodWorld hasn't been given a world yet."); + + lodDimensions.put(newStorage.dimension, newStorage); + } + + public LodQuadTreeDimension getLodDimension(DimensionType dimension) { + if (lodDimensions.get(dimension) == null) { + throw new IllegalStateException("LodWorld hasn't been given a world yet."); + } + return lodDimensions.get(dimension); + } + + /** + * Resizes the max width in regions that each LodDimension + * should use. + */ + public void resizeDimensionRegionWidth(int newWidth) { + if (lodDimensions == null) + throw new IllegalStateException("LodWorld hasn't been given a world yet."); + + for (DimensionType key : lodDimensions.keySet()) + lodDimensions.get(key).setRegionWidth(newWidth); + } + + + public boolean getIsWorldLoaded() { + return isWorldLoaded; + } + + public String getWorldName() { + return worldName; + } + + @Override + public String toString() { + return "World name: " + worldName; + } +} + diff --git a/src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java b/src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java new file mode 100644 index 000000000..338b27035 --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java @@ -0,0 +1,58 @@ +package com.seibel.lod.objects.quadTree; + +import com.seibel.lod.builders.LodBuilder; +import com.seibel.lod.builders.LodNodeBuilder; +import com.seibel.lod.objects.LodDimension; +import net.minecraft.client.Minecraft; +import net.minecraft.world.DimensionType; + +import java.awt.*; +import java.lang.reflect.Array; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.Map; + +public class UsesExamples { + public static void main(String[] args){ + //THIS CODE DOESN'T WORK AT THE MOMENT + /**TODO + * Complete all the new Lod objects + * Complete the getNodeToGenerate in LodQuadTreeDimension + * Complete the getNodeToRender in LodQuadTreeDimension + * Complete the node builder + * Complete the new renderer + * add everything to ClientProxy for the first test + * */ + + LodQuadTreeWorld lodWorld = new LodQuadTreeWorld(); + LodQuadTreeDimension newLodDimension = new LodQuadTreeDimension(Minecraft.getInstance().world.getDimensionType(), Minecraft.getInstance().world, 10); + lodWorld.addLodDimension(newLodDimension); + + LodQuadTreeDimension lodDimension = lodWorld.getLodDimension(Minecraft.getInstance().world.getDimensionType()); + lodDimension.move(0,0); + /* + I will now generate some fake LodNodeData. This in the final implementation will be generated by a builder + this lodNodeData will be put at level 6 of the QuadTree. This LodNodeData represent a block of width + */ + LodNodeData lodNodeData1 = new LodNodeData((byte) 6, 4, 4, 64, 0, new Color(0,200,0),true); + LodNodeData lodNodeData2 = new LodNodeData((byte) 6, 4, 5, 64, 0, new Color(0,200,0),true); + LodNodeData lodNodeData3 = new LodNodeData((byte) 6, 5, 4, 64, 0, new Color(0,0,200),true); + /* + add like this + */ + lodDimension.addNode(lodNodeData1); + lodDimension.addNode(lodNodeData2); + lodDimension.addNode(lodNodeData3); + /* + Automatic generation + + */ + List nodeToGenerate = (List) lodDimension.getRegion(0,0).getNodeToGenerate(0,0, (byte) 3,1000,0); + Collections.sort(nodeToGenerate, Map.Entry.comparingByValue(); + + /* + Call the builder to generate all the useful node + */ + + } +} From 9e24ee0ef7b39c6adf04876aaf44c92cb20034c5 Mon Sep 17 00:00:00 2001 From: Morippi Date: Wed, 7 Jul 2021 00:53:32 +0200 Subject: [PATCH 02/46] Fixed LodQuadTree Added QuadTreeImage to visualize how the quadTree is builded --- build.gradle | 31 +- .../seibel/lod/builders/LodNodeBuilder.java | 377 ++++++++++++++---- .../lod/objects/quadTree/LodNodeData.java | 1 + .../lod/objects/quadTree/LodQuadTree.java | 128 ++++-- .../quadTree/LodQuadTreeDimension.java | 12 +- .../lod/objects/quadTree/QuadTreeImage.java | 195 +++++++++ .../lod/objects/quadTree/UsesExamples.java | 32 +- 7 files changed, 637 insertions(+), 139 deletions(-) create mode 100644 src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java diff --git a/build.gradle b/build.gradle index f326b9a3b..c253ceb27 100644 --- a/build.gradle +++ b/build.gradle @@ -116,12 +116,39 @@ minecraft { // Include resources generated by data generators. sourceSets.main.resources { srcDir 'src/generated/resources' } +repositories { + mavenCentral() + maven { url 'https://jitpack.io' } +} + dependencies { // Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed // that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied. // The userdev artifact is a special name and will get all sorts of transformations applied to it. - minecraft 'net.minecraftforge:forge:1.16.5-36.1.0' - + minecraft 'net.minecraftforge:forge:1.16.4-35.1.4' + + /* + classpath group: 'com.github.KaptainWutax', name: 'BiomeUtils-lib', version: '-SNAPSHOT' + classpath group: 'com.github.KaptainWutax', name: 'SeedUtils', version: '-SNAPSHOT' + classpath group: 'com.github.KaptainWutax', name: 'MCUtils', version: '-SNAPSHOT' + classpath group: 'com.github.KaptainWutax', name: 'NoiseUtils', version: 'main-SNAPSHOT' + classpath group: 'com.github.KaptainWutax', name: 'TerrainUtils', version: '-SNAPSHOT' + */ + compile('com.github.KaptainWutax:BiomeUtils:1.0.0') { + transitive = false + } + compile('com.github.KaptainWutax:SeedUtils:-SNAPSHOT') { + transitive = false + } + compile('com.github.KaptainWutax:MCUtils:1.0.0') { + transitive = false + } + compile('com.github.KaptainWutax:NoiseUtils:1.0.0') { + transitive = false + } + compile('com.github.KaptainWutax:TerrainUtils:1.0.0') { + transitive = false + } // these were added to hopefully allow for cloning // configuredFeatures to allow for safe diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java index 5f2d00988..3bc365d54 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java @@ -1,25 +1,20 @@ package com.seibel.lod.builders; -import com.seibel.lod.enums.LodDetail; -import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDataPoint; import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.LodWorld; import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; import com.seibel.lod.objects.quadTree.LodQuadTreeWorld; -import kaptainwutax.biomeutils.source.BiomeSource; -import kaptainwutax.biomeutils.source.OverworldBiomeSource; -import kaptainwutax.mcutils.state.Dimension; -import kaptainwutax.mcutils.version.MCVersion; -import net.minecraft.util.ResourceLocation; +import com.seibel.lod.util.LodUtil; +import net.minecraft.block.*; import net.minecraft.world.DimensionType; import net.minecraft.world.IWorld; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.chunk.ChunkSection; import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.gen.Heightmap; import java.awt.*; -import java.util.Iterator; -import java.util.OptionalLong; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -28,24 +23,32 @@ public class LodNodeBuilder { private long seed; private DimensionType dimension; - /** Default size of any LOD regions we use */ + public static final int CHUNK_DATA_WIDTH = LodNodeData.CHUNK_WIDTH; + public static final int CHUNK_SECTION_HEIGHT = 256; + public static final Heightmap.Type DEFAULT_HEIGHTMAP = Heightmap.Type.WORLD_SURFACE_WG; + + /** + * Default size of any LOD regions we use + */ public int regionWidth = 5; - /** fast biome calculator */ - private BiomeSource biomeSource; + /** + * fast biome calculator + */ + //private BiomeSource biomeSource; //Biome biome=biomeSource.getBiome(x,y,z); // here y is always 0 no matter what you pass - public LodNodeBuilder(){ + public LodNodeBuilder() { } +/* public setApproxGenerator(long seed){ //Dimension.OVERWORLD; //Dimension.END; //Dimension.NETHER; biomeSource = BiomeSource.of(Dimension.OVERWORLD ,MCVersion.v1_16_4, seed); } - public void generateLodNodeAsync(List dataList){ Thread thread = new Thread(() ->{ for(LodNodeData data : dataList){ @@ -57,9 +60,9 @@ public class LodNodeBuilder { return; } + */ - public void generateLodNodeAsync(IChunk chunk, LodWorld lodWorld, IWorld world) - { + public void generateLodNodeAsync(IChunk chunk, LodQuadTreeWorld lodWorld, IWorld world) { if (lodWorld == null || !lodWorld.getIsWorldLoaded()) return; @@ -71,28 +74,22 @@ public class LodNodeBuilder { Thread thread = new Thread(() -> { - try - { - DimensionType dim = world.getDimensionType(); + try { + DimensionType dim = world.dimensionType(); - LodChunk lod = generateLodFromChunk(chunk, config); + LodNodeData node = generateLodNodeFromChunk(chunk); - LodDimension lodDim; + LodQuadTreeDimension lodDim; - if (lodWorld.getLodDimension(dim) == null) - { - lodDim = new LodDimension(dim, lodWorld, regionWidth); + if (lodWorld.getLodDimension(dim) == null) { + lodDim = new LodQuadTreeDimension(dim, lodWorld, regionWidth); lodWorld.addLodDimension(lodDim); - } - else - { + } else { lodDim = lodWorld.getLodDimension(dim); } - lodDim.addLod(lod); - } - catch(IllegalArgumentException | NullPointerException e) - { + lodDim.addNode(node); + } catch (IllegalArgumentException | NullPointerException e) { // if the world changes while LODs are being generated // they will throw errors as they try to access things that no longer // exist. @@ -104,69 +101,295 @@ public class LodNodeBuilder { } - - - /** * Creates a LodChunk for a chunk in the given world. * - * @throws IllegalArgumentException - * thrown if either the chunk or world is null. + * @throws IllegalArgumentException thrown if either the chunk or world is null. */ - public LodChunk generateLodFromChunk(IChunk chunk) throws IllegalArgumentException - { - return generateLodFromChunk(chunk, new LodBuilderConfig()); + public LodNodeData generateLodNodeFromChunk(IChunk chunk) throws IllegalArgumentException { + return generateLodNodeFromChunk(chunk, new LodBuilderConfig()); } /** * Creates a LodChunk for a chunk in the given world. * - * @throws IllegalArgumentException - * thrown if either the chunk or world is null. + * @throws IllegalArgumentException thrown if either the chunk or world is null. + * @return */ - public LodChunk generateLodFromChunk(IChunk chunk, LodBuilderConfig config) throws IllegalArgumentException - { - if(chunk == null) + public LodNodeData generateLodNodeFromChunk(IChunk chunk, LodBuilderConfig config) throws IllegalArgumentException { + if (chunk == null) throw new IllegalArgumentException("generateLodFromChunk given a null chunk"); - LodDetail detail = LodConfig.CLIENT.lodDetail.get(); - LodDataPoint[][] dataPoints = new LodDataPoint[detail.lengthCount][detail.lengthCount]; + int startX = chunk.getPos().getMinBlockX(); + int startZ = chunk.getPos().getMinBlockZ(); + int endX = chunk.getPos().getMaxBlockX(); + int endZ = chunk.getPos().getMaxBlockZ(); - for(int i = 0; i < detail.lengthCount * detail.lengthCount; i++) - { - int startX = detail.startX[i]; - int startZ = detail.startZ[i]; - int endX = detail.endX[i]; - int endZ = detail.endZ[i]; + Color color = generateLodColorForArea(chunk, config, startX, startZ, endX, endZ); - Color color; + short height; + short depth; - color = generateLodColorForArea(chunk, config, startX, startZ, endX, endZ); + /**TODO I HAVE TO RE-ADD THE HEIGHTMAP**/ + height = determineHeightPointForArea(chunk.getSections(), startX, startZ, endX, endZ); + depth = determineBottomPointForArea(chunk.getSections(), startX, startZ, endX, endZ); - short height; - short depth; - - if (!config.useHeightmap) - { - height = determineHeightPointForArea(chunk.getSections(), startX, startZ, endX, endZ); - depth = determineBottomPointForArea(chunk.getSections(), startX, startZ, endX, endZ); - } - else - { - height = determineHeightPoint(chunk.getHeightmap(LodChunk.DEFAULT_HEIGHTMAP), startX, startZ, endX, endZ); - depth = 0; - } - - int x = i / detail.lengthCount; - int z = i % detail.lengthCount; - - dataPoints[x][z] = new LodDataPoint(height, depth, color); - } - - return new LodChunk(chunk.getPos(), dataPoints, detail); + return new LodNodeData(LodNodeData.CHUNK_LEVEL, chunk.getPos().x, chunk.getPos().z, height, depth, color, true); } + //=====================// + // constructor helpers // + //=====================// + + + /** + * Find the lowest valid point from the bottom. + * + * @param chunkSections + * @param startX + * @param startZ + * @param endX + * @param endZ + */ + private short determineBottomPointForArea(ChunkSection[] chunkSections, + int startX, int startZ, int endX, int endZ) { + int numberOfBlocksRequired = ((endX - startX) * (endZ - startZ) / 2); + + // search from the bottom up + for (int section = 0; section < CHUNK_DATA_WIDTH; section++) { + for (int y = 0; y < CHUNK_SECTION_HEIGHT; y++) { + int numberOfBlocksFound = 0; + + for (int x = startX; x < endX; x++) { + for (int z = startZ; z < endZ; z++) { + if (isLayerValidLodPoint(chunkSections, section, y, x, z)) { + numberOfBlocksFound++; + + if (numberOfBlocksFound >= numberOfBlocksRequired) { + // we found + // enough blocks in this + // layer to count as an + // LOD point + return (short) (y + (section * CHUNK_SECTION_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) { + // 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 + * + * @param chunkSections + * @param startX + * @param startZ + * @param endX + * @param endZ + */ + private short determineHeightPointForArea(ChunkSection[] chunkSections, + int startX, int startZ, int endX, int endZ) { + int numberOfBlocksRequired = ((endX - startX) * (endZ - startZ) / 2); + // search from the top down + for (int section = chunkSections.length - 1; section >= 0; section--) { + for (int y = CHUNK_DATA_WIDTH - 1; y >= 0; y--) { + int numberOfBlocksFound = 0; + + for (int x = startX; x < endX; x++) { + for (int z = startZ; z < endZ; z++) { + if (isLayerValidLodPoint(chunkSections, section, y, x, z)) { + numberOfBlocksFound++; + + if (numberOfBlocksFound >= numberOfBlocksRequired) { + // we found + // enough blocks in this + // layer to count as an + // LOD point + return (short) (y + (section * CHUNK_SECTION_HEIGHT)); + } + } + } + } + } + } + + // we never found a valid LOD point + return -1; + } + + /** + * Find the highest point from the Top + */ + private short determineHeightPoint(Heightmap heightmap, + int startX, int startZ, int endX, int endZ) { + short highest = 0; + for (int x = startX; x < endX; x++) { + for (int z = startZ; z < endZ; z++) { + short newHeight = (short) heightmap.getFirstAvailable(x, z); + if (newHeight > highest) + highest = newHeight; + } + } + + return highest; + } + + /** + * Generate the color for the given chunk using biome + * water color, foliage color, and grass color. + * + * @param config_useSolidBlocksInColorGen
+ * If true we look down from the top of the
+ * chunk until we find a non-invisible block, and then use
+ * its color. If false we generate the color immediately for
+ * each x and z. + * @param config_useBiomeColors
+ * If true use biome foliage, water, and grass colors,
+ * otherwise use the + */ + private Color generateLodColorForArea(IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ) { + ChunkSection[] chunkSections = chunk.getSections(); + + int numbOfBlocks = 0; + int red = 0; + int green = 0; + int blue = 0; + + + for (int x = startX; x < endX; x++) { + for (int z = startZ; z < endZ; z++) { + boolean foundBlock = false; + + // go top down + for (int i = chunkSections.length - 1; !foundBlock && i >= 0; i--) { + if (!foundBlock && (chunkSections[i] != null || !config.useSolidBlocksInColorGen)) { + for (int y = CHUNK_SECTION_HEIGHT - 1; !foundBlock && y >= 0; y--) { + int colorInt = 0; + BlockState blockState = null; + + if (chunkSections[i] != null) { + blockState = chunkSections[i].getBlockState(x, y, z); + colorInt = blockState.materialColor.col; + } + + if (colorInt == 0 && config.useSolidBlocksInColorGen) { + // skip air or invisible blocks + continue; + } + + if (config.useBiomeColors) { + Biome biome = chunk.getBiomes().getNoiseBiome(x, y + i * chunkSections.length, z); + + if (biome.getBiomeCategory() == Biome.Category.OCEAN || + biome.getBiomeCategory() == Biome.Category.RIVER) { + colorInt = biome.getWaterColor(); + } else if (biome.getBiomeCategory() == Biome.Category.EXTREME_HILLS) { + colorInt = Blocks.STONE.defaultMaterialColor().col; + } else if (biome.getBiomeCategory() == Biome.Category.ICY) { + colorInt = LodUtil.colorToInt(Color.WHITE); + } else if (biome.getBiomeCategory() == Biome.Category.THEEND) { + colorInt = Blocks.END_STONE.defaultBlockState().materialColor.col; + } else if (config.useSolidBlocksInColorGen) { + colorInt = getColorForBlock(x, z, blockState, biome); + } else { + colorInt = biome.getGrassColor(x, z); + } + } else { + Biome biome = chunk.getBiomes().getNoiseBiome(x, y + i * chunkSections.length, z); + colorInt = getColorForBlock(x, z, blockState, biome); + } + + + Color c = LodUtil.intToColor(colorInt); + + 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); + } + + + /** + * Returns a color int for a given block. + */ + private int getColorForBlock(int x, int z, BlockState blockState, Biome biome) { + int colorInt = 0; + + if (blockState == Blocks.AIR.defaultBlockState()) { + colorInt = biome.getGrassColor(x, z); + } else if (blockState.getBlock() instanceof LeavesBlock) { + Color leafColor = LodUtil.intToColor(biome.getFoliageColor()).darker(); + colorInt = LodUtil.colorToInt(leafColor); + } else if (blockState.getBlock() instanceof GrassBlock) { + colorInt = biome.getGrassColor(x, z); + } else if (blockState.getBlock() instanceof FlowingFluidBlock) { + colorInt = biome.getWaterColor(); + } else { + colorInt = blockState.materialColor.col; + } + + return colorInt; + } + + + /** + * Is the layer between the given X, Z, and dataIndex + * values a valid LOD point? + */ + private boolean isLayerValidLodPoint( + ChunkSection[] chunkSections, + int sectionIndex, int y, + int x, int 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) { + return true; + } + } + + return false; + } } diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java b/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java index b354ee826..b341dd2c2 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java @@ -62,6 +62,7 @@ public class LodNodeData { //if dirty is true, then this node have unsaved changes public boolean dirty; + /** * Creates and empty LodDataPoint * This LodDataPoint only contains the position data diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index 9202b1c7c..ef5c8e149 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -3,7 +3,6 @@ package com.seibel.lod.objects.quadTree; import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; - /** * This object contains all data useful to render LodBlock in a region (32x32 chunk o 512x512 block) * for every node it contains the border of the block, the size, the position at it's level, the color, the height and the depth. @@ -36,7 +35,7 @@ public class LodQuadTree { //data useful to render //if children are present then lodNodeData should be a combination of the lodData of the child. This can be //turned off by deselecting the recursive update in all update method. - private final LodNodeData lodNodeData; + private LodNodeData lodNodeData; /* .____.____. | NW | NE | | @@ -137,8 +136,8 @@ public class LodQuadTree { int posX = newLodNodeData.posX; int posZ = newLodNodeData.posZ; short widthRatio = (short) (lodNodeData.width / newLodNodeData.width); - int NS = (posX / widthRatio) % lodNodeData.posX; - int WE = (posZ / widthRatio) % lodNodeData.posZ; + int NS = (posX / widthRatio) % 2; + int WE = (posZ / widthRatio) % 2; if (getChild(NS, WE) == null) { setChild(NS, WE); } @@ -147,10 +146,10 @@ public class LodQuadTree { return false; } else { if (targetLevel == currentLevel - 1) { - child.setLodNodeData(lodNodeData, updateHigherLevel); + child.setLodNodeData(newLodNodeData, true); return true; } else { - return child.setNodeAtLowerLevel(lodNodeData, updateHigherLevel); + return child.setNodeAtLowerLevel(newLodNodeData, updateHigherLevel); } } } else { @@ -159,6 +158,32 @@ public class LodQuadTree { } + /** + * @param posX + * @param posZ + * @param level + * @return + */ + public LodNodeData getNodeAtLevelPosition(int posX, int posZ, byte level) { + byte targetLevel = level; + byte currentLevel = lodNodeData.level; + if (targetLevel == currentLevel) { + return lodNodeData; + } else if (targetLevel < currentLevel) { + short widthRatio = (short) (lodNodeData.width / Math.pow(2, level)); + int NS = (posX / widthRatio) % lodNodeData.posX; + int WE = (posZ / widthRatio) % lodNodeData.posZ; + if (getChild(NS, WE) == null) { + return lodNodeData; + } + LodQuadTree child = getChild(NS, WE); + return child.getNodeAtLevelPosition(posX, posZ, level); + } else { + return null; + } + + } + public LodQuadTree getChild(int NS, int WE) { return children[NS][WE]; } @@ -223,7 +248,7 @@ public class LodQuadTree { nodeFull = isFull; nodeEmpty = isEmpty; lodNodeData.combineData(dataList); - if (lodNodeData.level > 0 && recursiveUpdate) { + if (lodNodeData.level < 9 && recursiveUpdate) { this.parent.updateLevel(recursiveUpdate); } } @@ -262,20 +287,26 @@ public class LodQuadTree { } /** - * method to get certain nodes from the LodQuadTree - * @return list of nodes + * This method will return all the nodes that can be rendered based on the data given + * + * @param x position of the player + * @param z position of the player + * @param targetLevel minimum level that can be rendered + * @param maxDistance maximum distance from the player + * @param minDistance minimum distance from the player + * @return */ - public List getNodeToRender(int x, int z, byte targetLevel, int maxDistance, int minDistance){ - int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX,2) + Math.pow(z + lodNodeData.centerZ,2)); + public List getNodeToRender(int x, int z, byte targetLevel, int maxDistance, int minDistance) { + int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX, 2) + Math.pow(z + lodNodeData.centerZ, 2)); List nodeList = new ArrayList<>(); - if(distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level) { + if (distance > maxDistance || distance < minDistance || targetLevel < lodNodeData.level) { return nodeList; } - if(targetLevel == lodNodeData.level || !isThereAnyChild()){ - if(!lodNodeData.voidNode){ + if (targetLevel == lodNodeData.level || !isThereAnyChild()) { + if (!lodNodeData.voidNode) { nodeList.add(lodNodeData); return nodeList; - }else{ + } else { return nodeList; } } else { @@ -283,7 +314,7 @@ public class LodQuadTree { for (int WE = 0; WE <= 1; WE++) { LodQuadTree child = children[NS][WE]; if (child != null) { - nodeList.addAll(child.getNodeToRender(x,z,targetLevel,maxDistance,minDistance)); + nodeList.addAll(child.getNodeToRender(x, z, targetLevel, maxDistance, minDistance)); } } } @@ -292,33 +323,40 @@ public class LodQuadTree { } /** - * method to get certain nodes from the LodQuadTree - * @return list of nodes + * Nodes that can be generated in the approximated version + * A level is generated only if it has child and is higher than the target level + * @param x + * @param z + * @param targetLevel + * @param maxDistance + * @param minDistance + * @return */ - public List> getNodeToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance){ - int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX,2) + Math.pow(z + lodNodeData.centerZ,2)); - List> nodeList = new ArrayList<>(); - if(distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level) { + public List> getLevelToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance) { + int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX, 2) + Math.pow(z + lodNodeData.centerZ, 2)); + List> nodeList = new ArrayList<>(); + if (distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level || lodNodeData.real) { return nodeList; } - if(targetLevel == lodNodeData.level){ - return nodeList; - } else { - if(!isThereAnyChild()){ + if(isThereAnyChild()) { + //THIS LEVEL HAS CHILD SO IT'S GENERATED. + if (targetLevel != lodNodeData.level) { for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { - LodQuadTree child = children[NS][WE]; - if (child != null) { - nodeList.addAll(child.getNodeToGenerate(x,z,targetLevel,maxDistance,minDistance)); + if (children[NS][WE] == null) { + setChild(NS,WE); } + LodQuadTree child = children[NS][WE]; + nodeList.addAll(child.getLevelToGenerate(x, z, targetLevel, maxDistance, minDistance)); } } - }else{ - nodeList.add( new AbstractMap.SimpleEntry<>(lodNodeData,distance)); } + } else { + nodeList.add(new AbstractMap.SimpleEntry<>(this, distance)); } return nodeList; } + /** * simple getter for lodNodeData * @@ -335,7 +373,11 @@ public class LodQuadTree { * @param updateHigherLevel if true it will update all the upper levels. */ public void setLodNodeData(LodNodeData newLodNodeData, boolean updateHigherLevel) { - this.lodNodeData.update(lodNodeData); + if (this.lodNodeData == null) { + this.lodNodeData = newLodNodeData; + } else { + this.lodNodeData.update(newLodNodeData); + } //a recursive update is necessary to change higher level if (parent != null && updateHigherLevel) parent.updateLevel(true); } @@ -345,7 +387,7 @@ public class LodQuadTree { } public boolean isThereAnyChild() { - return nodeEmpty; + return !nodeEmpty; } public boolean isNodeReal() { @@ -355,9 +397,19 @@ public class LodQuadTree { public boolean isRenderable() { return (lodNodeData != null); } -} -/* -EXAMPLES OF USES - - */ + public String toString(){ + String s = lodNodeData.toString(); + if(isThereAnyChild()){ + for (int NS = 0; NS <= 1; NS++) { + for (int WE = 0; WE <= 1; WE++) { + LodQuadTree child = children[NS][WE]; + if (child != null) { + s += '\n' + child.toString(); + } + } + } + } + return s; + } +} \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java index c864f6134..33e4a5bc4 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -29,7 +29,7 @@ public class LodQuadTreeDimension { private LodQuadTreeDimensionFileHandler fileHandler; - public LodQuadTreeDimension(DimensionType newDimension, LodWorld lodWorld, int newMaxWidth) + public LodQuadTreeDimension(DimensionType newDimension, LodQuadTreeWorld lodWorld, int newMaxWidth) { dimension = newDimension; width = newMaxWidth; @@ -39,7 +39,7 @@ public class LodQuadTreeDimension { Minecraft mc = Minecraft.getInstance(); File saveDir; - if(mc.isIntegratedServerRunning()) + if(mc.hasSingleplayerServer()) { // local world @@ -47,15 +47,15 @@ public class LodQuadTreeDimension { seed = serverWorld.getSeed(); // provider needs a separate variable to prevent // the compiler from complaining - ServerChunkProvider provider = serverWorld.getChunkProvider(); - saveDir = new File(provider.getSavedData().folder.getCanonicalFile().getPath() + File.separatorChar + "lod"); + ServerChunkProvider provider = serverWorld.getChunkSource(); + saveDir = new File(provider.dataStorage.dataFolder.getCanonicalFile().getPath() + File.separatorChar + "lod"); } else { // connected to server - saveDir = new File(mc.gameDir.getCanonicalFile().getPath() + - File.separatorChar + "lod server data" + File.separatorChar + LodUtil.getDimensionIDFromWorld(mc.world)); + saveDir = new File(mc.gameDirectory.getCanonicalFile().getPath() + + File.separatorChar + "lod server data" + File.separatorChar + LodUtil.getDimensionIDFromWorld(mc.level)); } fileHandler = new LodQuadTreeDimensionFileHandler(saveDir, this); diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java new file mode 100644 index 000000000..ac21dc5e3 --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -0,0 +1,195 @@ +package com.seibel.lod.objects.quadTree; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import javax.swing.JFrame; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import javax.swing.Timer; +@SuppressWarnings("serial") +public class QuadTreeImage extends JPanel { + private static final int PREF_W = 600; + private static final int PREF_H = PREF_W; + private List drawables = new ArrayList<>(); + + public QuadTreeImage() { + setBackground(Color.white); + } + + public void addMyDrawable(MyDrawable myDrawable) { + drawables.add(myDrawable); + repaint(); + } + + @Override + // make it bigger + public Dimension getPreferredSize() { + if (isPreferredSizeSet()) { + return super.getPreferredSize(); + } + return new Dimension(PREF_W, PREF_H); + } + + @Override + protected void paintComponent(Graphics g) { + super.paintComponent(g); + Graphics2D g2 = (Graphics2D) g; + g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + for (MyDrawable myDrawable : drawables) { + myDrawable.draw(g2); + } + } + + public void clearAll() { + drawables.clear(); + repaint(); + } + + private static void createAndShowGui( ) { + LodQuadTree lodQuadTree = new LodQuadTree(0,0); + for(int i = 0; i<9; i++){ + List> levelToGenerate= lodQuadTree.getLevelToGenerate(0,0,(byte) (9-i),1000,0); + boolean bw= true; + System.out.println(levelToGenerate); + for(AbstractMap.SimpleEntry levelDist : levelToGenerate){ + LodQuadTree level = levelDist.getKey(); + Color color ; + if(bw){ + color = Color.red; + bw = false; + }else{ + color = Color.blue; + bw = true; + } + + int posZ = level.getLodNodeData().startX/LodNodeData.BLOCK_WIDTH; + int posX = level.getLodNodeData().startZ/LodNodeData.BLOCK_WIDTH; + System.out.println(posX + " " + posZ); + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true); + + posZ = level.getLodNodeData().endX/LodNodeData.BLOCK_WIDTH; + posX = level.getLodNodeData().startZ/LodNodeData.BLOCK_WIDTH; + System.out.println(posX + " " + posZ); + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true); + + posZ = level.getLodNodeData().startX/LodNodeData.BLOCK_WIDTH; + posX = level.getLodNodeData().endX/LodNodeData.BLOCK_WIDTH; + System.out.println(posX + " " + posZ); + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true); + + posZ = level.getLodNodeData().endX/LodNodeData.BLOCK_WIDTH; + posX = level.getLodNodeData().endZ/LodNodeData.BLOCK_WIDTH; + System.out.println(posX + " " + posZ); + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true); + } + } + System.out.println(lodQuadTree.getNodeList(false,false,false)); + + Collection lodList = lodQuadTree.getNodeList(false,false,false); + + final List myDrawables = new ArrayList<>(); + for(LodNodeData data : lodList) { + myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX+100, data.startZ+100, data.width, data.width), + data.color, new BasicStroke(1))); + } + + final QuadTreeImage quadTreeImage = new QuadTreeImage(); + + JFrame frame = new JFrame("DrawChit"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.getContentPane().add(quadTreeImage); + frame.pack(); + frame.setLocationByPlatform(true); + frame.setVisible(true); + + int timerDelay = 1; + new Timer(timerDelay, new ActionListener() { + private int drawCount = 0; + + @Override + public void actionPerformed(ActionEvent e) { + if (drawCount >= myDrawables.size()) { + drawCount = 0; + quadTreeImage.clearAll(); + } else { + quadTreeImage.addMyDrawable(myDrawables.get(drawCount)); + drawCount++; + } + } + }).start(); + } + public static void main(String[] args) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + createAndShowGui(); + } + }); + } +} + +class MyDrawable { + private Shape shape; + private Color color; + private Stroke stroke; + + public MyDrawable(Shape shape, Color color, Stroke stroke) { + this.shape = shape; + this.color = color; + this.stroke = stroke; + } + + public Shape getShape() { + return shape; + } + + public Color getColor() { + return color; + } + + public Stroke getStroke() { + return stroke; + } + + public void draw(Graphics2D g2) { + Color oldColor = g2.getColor(); + Stroke oldStroke = g2.getStroke(); + + g2.setColor(color); + g2.setStroke(stroke); + g2.draw(shape); + + g2.setColor(oldColor); + g2.setStroke(oldStroke); + } + + public void fill(Graphics2D g2) { + Color oldColor = g2.getColor(); + Stroke oldStroke = g2.getStroke(); + + g2.setColor(color); + g2.setStroke(stroke); + g2.fill(shape); + + g2.setColor(oldColor); + g2.setStroke(oldStroke); + } + +} diff --git a/src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java b/src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java index 338b27035..9d7b0d47d 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java @@ -1,6 +1,5 @@ package com.seibel.lod.objects.quadTree; -import com.seibel.lod.builders.LodBuilder; import com.seibel.lod.builders.LodNodeBuilder; import com.seibel.lod.objects.LodDimension; import net.minecraft.client.Minecraft; @@ -23,36 +22,37 @@ public class UsesExamples { * Complete the new renderer * add everything to ClientProxy for the first test * */ - +/* LodQuadTreeWorld lodWorld = new LodQuadTreeWorld(); LodQuadTreeDimension newLodDimension = new LodQuadTreeDimension(Minecraft.getInstance().world.getDimensionType(), Minecraft.getInstance().world, 10); lodWorld.addLodDimension(newLodDimension); LodQuadTreeDimension lodDimension = lodWorld.getLodDimension(Minecraft.getInstance().world.getDimensionType()); lodDimension.move(0,0); - /* - I will now generate some fake LodNodeData. This in the final implementation will be generated by a builder - this lodNodeData will be put at level 6 of the QuadTree. This LodNodeData represent a block of width - */ + + //I will now generate some fake LodNodeData. This in the final implementation will be generated by a builder + //this lodNodeData will be put at level 6 of the QuadTree. This LodNodeData represent a block of width + LodNodeData lodNodeData1 = new LodNodeData((byte) 6, 4, 4, 64, 0, new Color(0,200,0),true); LodNodeData lodNodeData2 = new LodNodeData((byte) 6, 4, 5, 64, 0, new Color(0,200,0),true); LodNodeData lodNodeData3 = new LodNodeData((byte) 6, 5, 4, 64, 0, new Color(0,0,200),true); - /* - add like this - */ + + //add like this + lodDimension.addNode(lodNodeData1); lodDimension.addNode(lodNodeData2); lodDimension.addNode(lodNodeData3); - /* - Automatic generation - */ + //Automatic generation + List nodeToGenerate = (List) lodDimension.getRegion(0,0).getNodeToGenerate(0,0, (byte) 3,1000,0); - Collections.sort(nodeToGenerate, Map.Entry.comparingByValue(); + Collections.sort(nodeToGenerate, Map.Entry.comparingByValue()); + + + // Call the builder to generate all the useful node + + */ - /* - Call the builder to generate all the useful node - */ } } From c6a96ae710bde7417232d303d0eafb513f994814 Mon Sep 17 00:00:00 2001 From: Morippi Date: Wed, 7 Jul 2021 19:44:10 +0200 Subject: [PATCH 03/46] Fixed QuadTreeImage --- .../lod/objects/quadTree/LodQuadTree.java | 26 ++++++++++-- .../lod/objects/quadTree/QuadTreeImage.java | 40 ++++++++++--------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index ef5c8e149..285768478 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -333,12 +333,12 @@ public class LodQuadTree { * @return */ public List> getLevelToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance) { - int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX, 2) + Math.pow(z + lodNodeData.centerZ, 2)); + int distance = (int) Math.sqrt(Math.pow(x - lodNodeData.centerX, 2) + Math.pow(z - lodNodeData.centerZ, 2)); List> nodeList = new ArrayList<>(); - if (distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level || lodNodeData.real) { + if (distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level) { return nodeList; } - if(isThereAnyChild()) { + if(isNodeFull()) { //THIS LEVEL HAS CHILD SO IT'S GENERATED. if (targetLevel != lodNodeData.level) { for (int NS = 0; NS <= 1; NS++) { @@ -353,6 +353,23 @@ public class LodQuadTree { } } else { nodeList.add(new AbstractMap.SimpleEntry<>(this, distance)); + /* + if(isThereAnyChild()){ + for (int NS = 0; NS <= 1; NS++) { + for (int WE = 0; WE <= 1; WE++) { + if (children[NS][WE] == null) { + setChild(NS,WE); + LodQuadTree child = children[NS][WE]; + distance = (int) Math.sqrt(Math.pow(x - child.lodNodeData.centerX, 2) + Math.pow(z - child.lodNodeData.centerZ, 2)); + nodeList.add(new AbstractMap.SimpleEntry<>(child, distance)); + } + } + } + }else{ + nodeList.add(new AbstractMap.SimpleEntry<>(this, distance)); + } + + */ } return nodeList; } @@ -400,6 +417,8 @@ public class LodQuadTree { public String toString(){ String s = lodNodeData.toString(); + return s; + /* if(isThereAnyChild()){ for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { @@ -411,5 +430,6 @@ public class LodQuadTree { } } return s; + */ } } \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index ac21dc5e3..0c1785854 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -65,8 +65,9 @@ public class QuadTreeImage extends JPanel { private static void createAndShowGui( ) { LodQuadTree lodQuadTree = new LodQuadTree(0,0); - for(int i = 0; i<9; i++){ - List> levelToGenerate= lodQuadTree.getLevelToGenerate(0,0,(byte) (9-i),1000,0); + + for(int i = 0; i<6; i++){ + List> levelToGenerate= lodQuadTree.getLevelToGenerate(0,0,(byte) (7),350,0); boolean bw= true; System.out.println(levelToGenerate); for(AbstractMap.SimpleEntry levelDist : levelToGenerate){ @@ -80,25 +81,28 @@ public class QuadTreeImage extends JPanel { bw = true; } - int posZ = level.getLodNodeData().startX/LodNodeData.BLOCK_WIDTH; - int posX = level.getLodNodeData().startZ/LodNodeData.BLOCK_WIDTH; - System.out.println(posX + " " + posZ); - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true); + int startX = level.getLodNodeData().startX; + int startZ = level.getLodNodeData().startZ; + int endX = level.getLodNodeData().endX; + int endZ = level.getLodNodeData().endZ; + int width = level.getLodNodeData().width; + byte otherLevel = LodNodeData.BLOCK_LEVEL; + int otherWidth = LodNodeData.BLOCK_WIDTH; + int posZ = 2*startX/otherWidth; + int posX = 2*startZ/otherWidth; + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color,true),true); - posZ = level.getLodNodeData().endX/LodNodeData.BLOCK_WIDTH; - posX = level.getLodNodeData().startZ/LodNodeData.BLOCK_WIDTH; - System.out.println(posX + " " + posZ); - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true); + posZ = 2*endX/otherWidth; + posX = 2*startZ/otherWidth; + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color,true),true); - posZ = level.getLodNodeData().startX/LodNodeData.BLOCK_WIDTH; - posX = level.getLodNodeData().endX/LodNodeData.BLOCK_WIDTH; - System.out.println(posX + " " + posZ); - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true); + posZ = 2*startX/otherWidth; + posX = 2*endZ/otherWidth; + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color,true),true); - posZ = level.getLodNodeData().endX/LodNodeData.BLOCK_WIDTH; - posX = level.getLodNodeData().endZ/LodNodeData.BLOCK_WIDTH; - System.out.println(posX + " " + posZ); - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(LodNodeData.BLOCK_LEVEL, posX, posZ, 0, 0, color,true),true); + posZ = 2*endX/otherWidth; + posX = 2*endZ/otherWidth; + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color,true),true); } } System.out.println(lodQuadTree.getNodeList(false,false,false)); From 86e4ab7e83dc466d7a7a0ed87996f5679ecbf0b5 Mon Sep 17 00:00:00 2001 From: Morippi Date: Wed, 7 Jul 2021 20:22:05 +0200 Subject: [PATCH 04/46] Map works correctly --- build.gradle | 3 + .../lod/objects/quadTree/QuadTreeImage.java | 95 ++- .../com/seibel/lod/util/BiomeColorsUtils.java | 581 ++++++++++++++++++ 3 files changed, 626 insertions(+), 53 deletions(-) create mode 100644 src/main/java/com/seibel/lod/util/BiomeColorsUtils.java diff --git a/build.gradle b/build.gradle index c253ceb27..36e41725f 100644 --- a/build.gradle +++ b/build.gradle @@ -146,6 +146,9 @@ dependencies { compile('com.github.KaptainWutax:NoiseUtils:1.0.0') { transitive = false } + compile('com.github.KaptainWutax:MathUtils:-SNAPSHOT') { + transitive = false + } compile('com.github.KaptainWutax:TerrainUtils:1.0.0') { transitive = false } diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 0c1785854..1915834d1 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -1,5 +1,8 @@ package com.seibel.lod.objects.quadTree; - +import com.seibel.lod.util.BiomeColorsUtils; +import kaptainwutax.biomeutils.biome.Biome; +import kaptainwutax.biomeutils.source.OverworldBiomeSource; +import kaptainwutax.mcutils.version.MCVersion; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; @@ -65,44 +68,42 @@ public class QuadTreeImage extends JPanel { private static void createAndShowGui( ) { LodQuadTree lodQuadTree = new LodQuadTree(0,0); + OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 0); + for(int i = 0; i<9; i++){ + for(int j = 0; j<8; j++) { + List> levelToGenerate = lodQuadTree.getLevelToGenerate(150, 260, (byte) (9-i), (int) 50 * (9 - i), 0); + boolean bw = true; + //System.out.println(levelToGenerate); + for (AbstractMap.SimpleEntry levelDist : levelToGenerate) { + LodQuadTree level = levelDist.getKey(); + Color color; + int startX = level.getLodNodeData().startX; + int startZ = level.getLodNodeData().startZ; + int endX = level.getLodNodeData().endX; + int endZ = level.getLodNodeData().endZ; + int width = level.getLodNodeData().width; + byte otherLevel = LodNodeData.BLOCK_LEVEL; + int otherWidth = LodNodeData.BLOCK_WIDTH; + int posX = 2 * startX / otherWidth; + int posZ = 2 * startZ / otherWidth; + color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); - for(int i = 0; i<6; i++){ - List> levelToGenerate= lodQuadTree.getLevelToGenerate(0,0,(byte) (7),350,0); - boolean bw= true; - System.out.println(levelToGenerate); - for(AbstractMap.SimpleEntry levelDist : levelToGenerate){ - LodQuadTree level = levelDist.getKey(); - Color color ; - if(bw){ - color = Color.red; - bw = false; - }else{ - color = Color.blue; - bw = true; + posX = 2 * endX / otherWidth; + posZ = 2 * startZ / otherWidth; + color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); + + posX = 2 * startX / otherWidth; + posZ = 2 * endZ / otherWidth; + color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); + + posX = 2 * endX / otherWidth; + posZ = 2 * endZ / otherWidth; + color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); } - - int startX = level.getLodNodeData().startX; - int startZ = level.getLodNodeData().startZ; - int endX = level.getLodNodeData().endX; - int endZ = level.getLodNodeData().endZ; - int width = level.getLodNodeData().width; - byte otherLevel = LodNodeData.BLOCK_LEVEL; - int otherWidth = LodNodeData.BLOCK_WIDTH; - int posZ = 2*startX/otherWidth; - int posX = 2*startZ/otherWidth; - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color,true),true); - - posZ = 2*endX/otherWidth; - posX = 2*startZ/otherWidth; - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color,true),true); - - posZ = 2*startX/otherWidth; - posX = 2*endZ/otherWidth; - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color,true),true); - - posZ = 2*endX/otherWidth; - posX = 2*endZ/otherWidth; - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color,true),true); } } System.out.println(lodQuadTree.getNodeList(false,false,false)); @@ -124,21 +125,9 @@ public class QuadTreeImage extends JPanel { frame.setLocationByPlatform(true); frame.setVisible(true); - int timerDelay = 1; - new Timer(timerDelay, new ActionListener() { - private int drawCount = 0; - - @Override - public void actionPerformed(ActionEvent e) { - if (drawCount >= myDrawables.size()) { - drawCount = 0; - quadTreeImage.clearAll(); - } else { - quadTreeImage.addMyDrawable(myDrawables.get(drawCount)); - drawCount++; - } - } - }).start(); + for(int i=0; i Date: Wed, 7 Jul 2021 21:16:18 +0200 Subject: [PATCH 05/46] Map works correctly --- .../lod/objects/quadTree/LodQuadTree.java | 7 +++- .../lod/objects/quadTree/QuadTreeImage.java | 39 ++++++++++++------- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index 285768478..b6614af50 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -135,7 +135,7 @@ public class LodQuadTree { if (targetLevel < currentLevel) { int posX = newLodNodeData.posX; int posZ = newLodNodeData.posZ; - short widthRatio = (short) (lodNodeData.width / newLodNodeData.width); + short widthRatio = (short) (lodNodeData.width / (2 * newLodNodeData.width)); int NS = (posX / widthRatio) % 2; int WE = (posZ / widthRatio) % 2; if (getChild(NS, WE) == null) { @@ -335,7 +335,10 @@ public class LodQuadTree { public List> getLevelToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance) { int distance = (int) Math.sqrt(Math.pow(x - lodNodeData.centerX, 2) + Math.pow(z - lodNodeData.centerZ, 2)); List> nodeList = new ArrayList<>(); - if (distance > maxDistance || distance < minDistance || targetLevel > lodNodeData.level) { + if ( targetLevel > lodNodeData.level) { + return nodeList; + } + if (distance > maxDistance || distance < minDistance){ return nodeList; } if(isNodeFull()) { diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 1915834d1..44292ad5f 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -68,10 +68,18 @@ public class QuadTreeImage extends JPanel { private static void createAndShowGui( ) { LodQuadTree lodQuadTree = new LodQuadTree(0,0); - OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 0); + int playerX = 150; + int playerZ = 260; + OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 20); for(int i = 0; i<9; i++){ - for(int j = 0; j<8; j++) { - List> levelToGenerate = lodQuadTree.getLevelToGenerate(150, 260, (byte) (9-i), (int) 50 * (9 - i), 0); + for(int j = 0; j<2; j++) { + int dist; + if (i == 9) { + dist = 500; + }else{ + dist = 100; + } + List> levelToGenerate = lodQuadTree.getLevelToGenerate(playerX, playerZ, (byte) (9-i), (int) dist * (9 - i), 0); boolean bw = true; //System.out.println(levelToGenerate); for (AbstractMap.SimpleEntry levelDist : levelToGenerate) { @@ -84,38 +92,39 @@ public class QuadTreeImage extends JPanel { int width = level.getLodNodeData().width; byte otherLevel = LodNodeData.BLOCK_LEVEL; int otherWidth = LodNodeData.BLOCK_WIDTH; - int posX = 2 * startX / otherWidth; - int posZ = 2 * startZ / otherWidth; + int posX = startX / otherWidth; + int posZ = startZ / otherWidth; color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); - posX = 2 * endX / otherWidth; - posZ = 2 * startZ / otherWidth; + posX = endX / otherWidth; + posZ = startZ / otherWidth; color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); - posX = 2 * startX / otherWidth; - posZ = 2 * endZ / otherWidth; + posX = startX / otherWidth; + posZ = endZ / otherWidth; color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); - posX = 2 * endX / otherWidth; - posZ = 2 * endZ / otherWidth; + posX = endX / otherWidth; + posZ = endZ / otherWidth; color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); } } } - System.out.println(lodQuadTree.getNodeList(false,false,false)); - Collection lodList = lodQuadTree.getNodeList(false,false,false); + Collection lodList = lodQuadTree.getNodeList(false,false,true); final List myDrawables = new ArrayList<>(); for(LodNodeData data : lodList) { - myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX+100, data.startZ+100, data.width, data.width), + myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX, data.startZ, data.width, data.width), data.color, new BasicStroke(1))); } + myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerZ-10,playerX-10, 20, 20), + Color.yellow, new BasicStroke(1))); final QuadTreeImage quadTreeImage = new QuadTreeImage(); JFrame frame = new JFrame("DrawChit"); @@ -167,6 +176,8 @@ class MyDrawable { g2.setColor(color); g2.fill(shape); + + g2.setStroke(stroke); g2.draw(shape); g2.setColor(oldColor); From 6c8d0f98a67da9a689ebb89ce55ba6f41101e95d Mon Sep 17 00:00:00 2001 From: Morippi Date: Wed, 7 Jul 2021 22:43:44 +0200 Subject: [PATCH 06/46] Added circular rendering, Fixed get node to render --- .../lod/objects/quadTree/LodQuadTree.java | 33 ++++++++++++++++--- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index b6614af50..4926019fa 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -297,16 +297,31 @@ public class LodQuadTree { * @return */ public List getNodeToRender(int x, int z, byte targetLevel, int maxDistance, int minDistance) { - int distance = (int) Math.sqrt(Math.pow(x + lodNodeData.centerX, 2) + Math.pow(z + lodNodeData.centerZ, 2)); + int distance = (int) Math.sqrt(Math.pow(x - lodNodeData.centerX, 2) + Math.pow(z - lodNodeData.centerZ, 2)); + List distances = new ArrayList(); + distances.add(distance); + distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.startX, 2) + Math.pow(z - lodNodeData.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.startX, 2) + Math.pow(z - lodNodeData.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.endX, 2) + Math.pow(z - lodNodeData.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.endX, 2) + Math.pow(z - lodNodeData.endZ, 2))); + int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); + int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List nodeList = new ArrayList<>(); - if (distance > maxDistance || distance < minDistance || targetLevel < lodNodeData.level) { + if (min > maxDistance || max < minDistance || targetLevel > lodNodeData.level) { + System.out.println("test1"); + System.out.println(lodNodeData); return nodeList; } - if (targetLevel == lodNodeData.level || !isThereAnyChild()) { - if (!lodNodeData.voidNode) { + if (targetLevel == lodNodeData.level || !isNodeFull()) { + if (lodNodeData.voidNode) { + System.out.println("test2"); + System.out.println(lodNodeData); nodeList.add(lodNodeData); return nodeList; } else { + System.out.println("test3"); + System.out.println(lodNodeData); + nodeList.add(lodNodeData); return nodeList; } } else { @@ -334,11 +349,19 @@ public class LodQuadTree { */ public List> getLevelToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance) { int distance = (int) Math.sqrt(Math.pow(x - lodNodeData.centerX, 2) + Math.pow(z - lodNodeData.centerZ, 2)); + List distances = new ArrayList(); + distances.add(distance); + distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.startX, 2) + Math.pow(z - lodNodeData.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.startX, 2) + Math.pow(z - lodNodeData.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.endX, 2) + Math.pow(z - lodNodeData.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.endX, 2) + Math.pow(z - lodNodeData.endZ, 2))); + int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); + int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List> nodeList = new ArrayList<>(); if ( targetLevel > lodNodeData.level) { return nodeList; } - if (distance > maxDistance || distance < minDistance){ + if (min > maxDistance || max < minDistance){ return nodeList; } if(isNodeFull()) { From 62b6d9ea30feadcecbad463582674106b98f98ae Mon Sep 17 00:00:00 2001 From: Morippi Date: Wed, 7 Jul 2021 22:44:53 +0200 Subject: [PATCH 07/46] Modified to used getNodeToRender --- .../seibel/lod/objects/quadTree/QuadTreeImage.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 44292ad5f..29a3201ff 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -72,10 +72,10 @@ public class QuadTreeImage extends JPanel { int playerZ = 260; OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 20); for(int i = 0; i<9; i++){ - for(int j = 0; j<2; j++) { + for(int j = 0; j<5; j++) { int dist; if (i == 9) { - dist = 500; + dist = 100; }else{ dist = 100; } @@ -115,15 +115,15 @@ public class QuadTreeImage extends JPanel { } } - Collection lodList = lodQuadTree.getNodeList(false,false,true); - + Collection lodList = lodQuadTree.getNodeToRender(playerX,playerZ,(byte) 0,10000,0); + System.out.println(lodList); final List myDrawables = new ArrayList<>(); for(LodNodeData data : lodList) { myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX, data.startZ, data.width, data.width), data.color, new BasicStroke(1))); } - myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerZ-10,playerX-10, 20, 20), + myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerX-10,playerZ-10, 20, 20), Color.yellow, new BasicStroke(1))); final QuadTreeImage quadTreeImage = new QuadTreeImage(); @@ -177,7 +177,7 @@ class MyDrawable { g2.setColor(color); g2.fill(shape); - g2.setStroke(stroke); + //g2.setStroke(stroke); g2.draw(shape); g2.setColor(oldColor); From b623f1581fcf5b2b4feca43c2fd2fed55e15d489 Mon Sep 17 00:00:00 2001 From: Morippi Date: Wed, 7 Jul 2021 23:12:45 +0200 Subject: [PATCH 08/46] various fix --- .../java/com/seibel/lod/objects/quadTree/LodNodeData.java | 5 ++++- .../java/com/seibel/lod/objects/quadTree/LodQuadTree.java | 6 ------ .../java/com/seibel/lod/objects/quadTree/QuadTreeImage.java | 5 +++-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java b/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java index b341dd2c2..d0b15f41c 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java @@ -193,7 +193,10 @@ public class LodNodeData { short depth = (short) dataList.stream().mapToInt(x -> (int) x.depth).max().getAsInt(); height = height; depth = depth; - color = dataList.get(0).color; + int red= dataList.stream().mapToInt(x -> x.color.getRed()).sum()/dataList.size(); + int green= dataList.stream().mapToInt(x -> x.color.getGreen()).sum()/dataList.size(); + int blue = dataList.stream().mapToInt(x -> x.color.getBlue()).sum()/dataList.size(); + color = new Color(red,green,blue); real = dataList.stream().filter(x -> x.real).count() == 4; voidNode = dataList.stream().filter(x -> !x.voidNode).count() == 0; } diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index 4926019fa..4043062f1 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -308,19 +308,13 @@ public class LodQuadTree { int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List nodeList = new ArrayList<>(); if (min > maxDistance || max < minDistance || targetLevel > lodNodeData.level) { - System.out.println("test1"); - System.out.println(lodNodeData); return nodeList; } if (targetLevel == lodNodeData.level || !isNodeFull()) { if (lodNodeData.voidNode) { - System.out.println("test2"); - System.out.println(lodNodeData); nodeList.add(lodNodeData); return nodeList; } else { - System.out.println("test3"); - System.out.println(lodNodeData); nodeList.add(lodNodeData); return nodeList; } diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 29a3201ff..c338a51f7 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -115,7 +115,8 @@ public class QuadTreeImage extends JPanel { } } - Collection lodList = lodQuadTree.getNodeToRender(playerX,playerZ,(byte) 0,10000,0); + Collection lodList = lodQuadTree.getNodeToRender(playerX,playerZ,(byte) 2,10000,0); + //lodList = lodQuadTree.getNodeList(false,false,true); System.out.println(lodList); final List myDrawables = new ArrayList<>(); for(LodNodeData data : lodList) { @@ -123,7 +124,7 @@ public class QuadTreeImage extends JPanel { data.color, new BasicStroke(1))); } - myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerX-10,playerZ-10, 20, 20), + myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerZ-10,playerX-10, 20, 20), Color.yellow, new BasicStroke(1))); final QuadTreeImage quadTreeImage = new QuadTreeImage(); From 95bcc71d237f8728d3b5048165b0265c33056234 Mon Sep 17 00:00:00 2001 From: Morippi Date: Thu, 8 Jul 2021 12:40:36 +0200 Subject: [PATCH 09/46] various fix --- build.gradle | 71 +++++----- .../lod/objects/quadTree/LodQuadTree.java | 10 +- .../lod/objects/quadTree/QuadTreeImage.java | 127 ++++++++++++------ .../com/seibel/lod/util/BiomeColorsUtils.java | 120 ++++++++++++++++- 4 files changed, 244 insertions(+), 84 deletions(-) diff --git a/build.gradle b/build.gradle index 36e41725f..8c16ed141 100644 --- a/build.gradle +++ b/build.gradle @@ -3,13 +3,13 @@ buildscript { maven { url = 'https://files.minecraftforge.net/maven' } jcenter() mavenCentral() - maven { url = 'https://repo.spongepowered.org/maven/' } - // potential replacement in case of problems: - // https://dist.creeper.host/Sponge/maven + maven { url = 'https://repo.spongepowered.org/maven/' } + // potential replacement in case of problems: + // https://dist.creeper.host/Sponge/maven } dependencies { classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true - classpath group: 'org.spongepowered', name: 'mixingradle', version: '0.7-SNAPSHOT' + classpath group: 'org.spongepowered', name: 'mixingradle', version: '0.7-SNAPSHOT' } } apply plugin: 'net.minecraftforge.gradle' @@ -18,7 +18,7 @@ apply plugin: 'org.spongepowered.mixin' apply plugin: 'eclipse' apply plugin: 'maven-publish' -version = 'a1.2' +version = 'a1.3' group = 'com.backsun.lod' archivesBaseName = 'lod_1.16.5' @@ -31,10 +31,10 @@ minecraft { // stable_# Stables are built at the discretion of the MCP team. // Use non-default mappings at your own risk. they may not always work. // Simply re-run your setup task after changing the mappings to update your workspace. - mappings channel: 'official', version: '1.16.5' + mappings channel: 'official', version: '1.16.5' // makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable. - + accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg') // Default run configurations. @@ -42,10 +42,10 @@ minecraft { runs { client { workingDirectory project.file('run') - arg "-mixin.config=lod.mixins.json" + arg "-mixin.config=lod.mixins.json" // Recommended logging data for a userdev environment - // The markers can be changed as needed. + // The markers can be changed as needed. // "SCAN": For mods scan. // "REGISTRIES": For firing of registry events. // "REGISTRYDUMP": For getting the contents of all registries. @@ -65,10 +65,10 @@ minecraft { server { workingDirectory project.file('run') - arg "-mixin.config=lod.mixins.json" - + arg "-mixin.config=lod.mixins.json" + // Recommended logging data for a userdev environment - // The markers can be changed as needed. + // The markers can be changed as needed. // "SCAN": For mods scan. // "REGISTRIES": For firing of registry events. // "REGISTRYDUMP": For getting the contents of all registries. @@ -90,7 +90,7 @@ minecraft { workingDirectory project.file('run') // Recommended logging data for a userdev environment - // The markers can be changed as needed. + // The markers can be changed as needed. // "SCAN": For mods scan. // "REGISTRIES": For firing of registry events. // "REGISTRYDUMP": For getting the contents of all registries. @@ -120,12 +120,11 @@ repositories { mavenCentral() maven { url 'https://jitpack.io' } } - dependencies { // Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed // that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied. // The userdev artifact is a special name and will get all sorts of transformations applied to it. - minecraft 'net.minecraftforge:forge:1.16.4-35.1.4' + minecraft 'net.minecraftforge:forge:1.16.5-36.1.0' /* classpath group: 'com.github.KaptainWutax', name: 'BiomeUtils-lib', version: '-SNAPSHOT' @@ -152,20 +151,19 @@ dependencies { compile('com.github.KaptainWutax:TerrainUtils:1.0.0') { transitive = false } - - // these were added to hopefully allow for cloning - // configuredFeatures to allow for safe - // multi threaded feature generation. Sadly I couldn't find - // a way to duplicate lambda functions (which features use) - // so for now I'm not sure what to do. - //implementation 'io.github.kostaskougios:cloning:1.10.3' - // - //implementation ('com.esotericsoftware:kryo:5.1.1') { - // exclude group: "org.objenesis" - //} - //implementation 'org.objenesis:objenesis:3.2' - - + // these were added to hopefully allow for cloning + // configuredFeatures to allow for safe + // multi threaded feature generation. Sadly I couldn't find + // a way to duplicate lambda functions (which features use) + // so for now I'm not sure what to do. + //implementation 'io.github.kostaskougios:cloning:1.10.3' + // + //implementation ('com.esotericsoftware:kryo:5.1.1') { + // exclude group: "org.objenesis" + //} + //implementation 'org.objenesis:objenesis:3.2' + + // You may put jars on which you depend on in ./libs or you may define them like so.. // compile "some.group:artifact:version:classifier" // compile "some.group:artifact:version" @@ -190,19 +188,19 @@ dependencies { jar { manifest { attributes([ - "Specification-Title": "Levels of Detail", - "Specification-Version": "1", // We are version 1 of ourselves - "Implementation-Title": project.name, - "Implementation-Version": "{version}", - "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), - "MixinConfigs": "lod.mixins.json", + "Specification-Title": "Level of Detail", + "Specification-Version": "1", // We are version 1 of ourselves + "Implementation-Title": project.name, + "Implementation-Version": "{version}", + "Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), + "MixinConfigs": "lod.mixins.json", ]) } } // Example configuration to allow publishing using the maven-publish task // This is the preferred method to reobfuscate your jar file -jar.finalizedBy('reobfJar') +jar.finalizedBy('reobfJar') // However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing //publish.dependsOn('reobfJar') @@ -222,3 +220,4 @@ publishing { mixin { add sourceSets.main, "lod.refmap.json" } + diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index 4043062f1..1f4d652a3 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -333,7 +333,7 @@ public class LodQuadTree { /** * Nodes that can be generated in the approximated version - * A level is generated only if it has child and is higher than the target level + * A level is generated only if it has child and is higher than the target level and in the distance range * @param x * @param z * @param targetLevel @@ -352,10 +352,11 @@ public class LodQuadTree { int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List> nodeList = new ArrayList<>(); - if ( targetLevel > lodNodeData.level) { + if ( targetLevel > lodNodeData.level ) { return nodeList; } - if (min > maxDistance || max < minDistance){ + // + if ((min > maxDistance || max < minDistance) && !isCoordinateInLevel(x,z)){ return nodeList; } if(isNodeFull()) { @@ -435,6 +436,9 @@ public class LodQuadTree { return (lodNodeData != null); } + public boolean isCoordinateInLevel(int x, int z){ + return !(lodNodeData.startX > x || lodNodeData.startZ > z || lodNodeData.endX < x || lodNodeData.endZ < z); + } public String toString(){ String s = lodNodeData.toString(); return s; diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index c338a51f7..66ce3cd92 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -1,8 +1,10 @@ package com.seibel.lod.objects.quadTree; + import com.seibel.lod.util.BiomeColorsUtils; import kaptainwutax.biomeutils.biome.Biome; import kaptainwutax.biomeutils.source.OverworldBiomeSource; import kaptainwutax.mcutils.version.MCVersion; + import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; @@ -17,18 +19,22 @@ import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.io.File; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.Timer; + @SuppressWarnings("serial") public class QuadTreeImage extends JPanel { - private static final int PREF_W = 600; + private static final int PREF_W = 1024; private static final int PREF_H = PREF_W; private List drawables = new ArrayList<>(); @@ -66,22 +72,25 @@ public class QuadTreeImage extends JPanel { repaint(); } - private static void createAndShowGui( ) { - LodQuadTree lodQuadTree = new LodQuadTree(0,0); + private static void createAndShowGui() { + LodQuadTree lodQuadTree = new LodQuadTree(0, 0); + final QuadTreeImage quadTreeImage = new QuadTreeImage(); + + System.out.println(lodQuadTree.getLodNodeData().endX); int playerX = 150; int playerZ = 260; - OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 20); - for(int i = 0; i<9; i++){ - for(int j = 0; j<5; j++) { + List> listOfList = new ArrayList<>(); + OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 0); + for (int i = 0; i <= (9 - 2); i++) { + for (int j = 0; j < 1; j++) { int dist; if (i == 9) { - dist = 100; - }else{ - dist = 100; + dist = 500; + } else { + dist = 50; } - List> levelToGenerate = lodQuadTree.getLevelToGenerate(playerX, playerZ, (byte) (9-i), (int) dist * (9 - i), 0); - boolean bw = true; - //System.out.println(levelToGenerate); + List> levelToGenerate = lodQuadTree.getLevelToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist * (9 - i + 1), 0); + System.out.println(levelToGenerate); for (AbstractMap.SimpleEntry levelDist : levelToGenerate) { LodQuadTree level = levelDist.getKey(); Color color; @@ -89,44 +98,51 @@ public class QuadTreeImage extends JPanel { int startZ = level.getLodNodeData().startZ; int endX = level.getLodNodeData().endX; int endZ = level.getLodNodeData().endZ; + int centerX = level.getLodNodeData().centerX; + int centerZ = level.getLodNodeData().centerZ; int width = level.getLodNodeData().width; byte otherLevel = LodNodeData.BLOCK_LEVEL; int otherWidth = LodNodeData.BLOCK_WIDTH; - int posX = startX / otherWidth; - int posZ = startZ / otherWidth; - color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); - posX = endX / otherWidth; - posZ = startZ / otherWidth; - color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); + List posXs = new ArrayList<>(); + List posZs = new ArrayList<>(); + if(level.getLodNodeData().level == 0){ + posXs.add(startX / otherWidth); + posZs.add(startZ / otherWidth); + }else if(level.getLodNodeData().level == 2){ + posXs.add(startX / otherWidth); + posXs.add(endX / otherWidth); + posZs.add(startZ / otherWidth); + posZs.add(endZ / otherWidth); + }else{ + posXs.add(startX / otherWidth); + posXs.add((centerX / otherWidth)-1); + posXs.add(centerX / otherWidth); + posXs.add(endX / otherWidth); + posZs.add(startZ / otherWidth); + posZs.add((centerZ / otherWidth)-1); + posZs.add(centerZ / otherWidth); + posZs.add(endZ / otherWidth); + } - posX = startX / otherWidth; - posZ = endZ / otherWidth; - color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); - - posX = endX / otherWidth; - posZ = endZ / otherWidth; - color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ,0,posX).getId()); - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); + for(Integer posXI : posXs){ + for(Integer posZI : posZs){ + int posX = posXI.intValue(); + int posZ = posZI.intValue(); + color = BiomeColorsUtils.getColorFromBiomeBlock(biomeSource.getBiome(posZ, 0, posX)); + //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); + } + } } } - } - Collection lodList = lodQuadTree.getNodeToRender(playerX,playerZ,(byte) 2,10000,0); - //lodList = lodQuadTree.getNodeList(false,false,true); - System.out.println(lodList); - final List myDrawables = new ArrayList<>(); - for(LodNodeData data : lodList) { - myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX, data.startZ, data.width, data.width), - data.color, new BasicStroke(1))); - } + Collection lodList = lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 0, 10000, 0); - myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerZ-10,playerX-10, 20, 20), - Color.yellow, new BasicStroke(1))); - final QuadTreeImage quadTreeImage = new QuadTreeImage(); + //lodList = lodQuadTree.getNodeList(false,false,false); + listOfList.add(lodList); + System.out.println(listOfList.size()); + } JFrame frame = new JFrame("DrawChit"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); @@ -134,11 +150,34 @@ public class QuadTreeImage extends JPanel { frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); + int timerDelay = 1000; + new Timer(timerDelay, new ActionListener() { + private int drawCount = 0; - for(int i=0; i= listOfList.size()) { + drawCount = 0; + quadTreeImage.clearAll(); + } else { + final List myDrawables = new ArrayList<>(); + int amp = 2; + Collection lodList = listOfList.get(drawCount); + for (LodNodeData data : lodList) { + myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX * amp, data.startZ * amp, data.width * amp, data.width * amp), + data.color, new BasicStroke(1))); + } + myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerZ * amp - 10, playerX * amp - 10, 20, 20), + Color.yellow, new BasicStroke(1))); + for (int k = 0; k < myDrawables.size(); k++) { + quadTreeImage.addMyDrawable(myDrawables.get(k)); + } + drawCount++; + } + } + }).start(); } + public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { diff --git a/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java b/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java index df5a584dc..ce7732818 100644 --- a/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java +++ b/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java @@ -1,7 +1,7 @@ package com.seibel.lod.util; import net.minecraft.block.Blocks; -import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.*; import java.awt.*; @@ -171,6 +171,124 @@ public class BiomeColorsUtils { return new Color(color); } + /** + * methods that gives the ChunkBase color of biomes + * @param biome to check + * @return color of the biome + */ + public static Color getColorFromBiomeBlock(kaptainwutax.biomeutils.biome.Biome biome){ + int color = 0; + switch(biome.getCategory()) { + case BEACH: + case DESERT: + color = Blocks.SAND.defaultMaterialColor().col; + break; + case EXTREME_HILLS: + color = Blocks.SNOW.defaultMaterialColor().col; + break; + case FOREST: + color = Blocks.OAK_LEAVES.defaultMaterialColor().col; + break; + case SAVANNA: + color = Blocks.ACACIA_LEAVES.defaultMaterialColor().col; + break; + case JUNGLE: + color = Blocks.JUNGLE_LEAVES.defaultMaterialColor().col; + break; + case TAIGA: + color = Blocks.SPRUCE_LEAVES.defaultMaterialColor().col; + break; + case MUSHROOM: + color = Blocks.MYCELIUM.defaultMaterialColor().col; + break; + case PLAINS: + color = Blocks.GRASS_BLOCK.defaultMaterialColor().col; + break; + case OCEAN: + case RIVER: + color = Blocks.WATER.defaultMaterialColor().col; + case SWAMP: + color = Blocks.LILY_PAD.defaultMaterialColor().col; + break; + case ICY: + color = Blocks.PACKED_ICE.defaultMaterialColor().col; + break; + case THE_END: + color = Blocks.END_STONE.defaultMaterialColor().col; + break; + case NETHER: + color = Blocks.NETHERRACK.defaultMaterialColor().col; + break; + case BADLANDS_PLATEAU: + case MESA: + color = Blocks.RED_SAND.defaultMaterialColor().col; + break; + case NONE: + default: + color = 0; + } + return new Color(color); + } + + /** + * methods that gives the ChunkBase color of biomes + * @param biome to check + * @return color of the biome + */ + public static Color getColorFromBiomeManual(kaptainwutax.biomeutils.biome.Biome biome){ + Color color; + switch(biome.getCategory()) { + case BEACH: + case DESERT: + color = new Color(); + break; + case EXTREME_HILLS: + color = Blocks.SNOW.defaultMaterialColor().col; + break; + case FOREST: + color = Blocks.OAK_LEAVES.defaultMaterialColor().col; + break; + case SAVANNA: + color = Blocks.ACACIA_LEAVES.defaultMaterialColor().col; + break; + case JUNGLE: + color = Blocks.JUNGLE_LEAVES.defaultMaterialColor().col; + break; + case TAIGA: + color = Blocks.SPRUCE_LEAVES.defaultMaterialColor().col; + break; + case MUSHROOM: + color = Blocks.MYCELIUM.defaultMaterialColor().col; + break; + case PLAINS: + color = Blocks.GRASS_BLOCK.defaultMaterialColor().col; + break; + case OCEAN: + case RIVER: + color = Blocks.WATER.defaultMaterialColor().col; + case SWAMP: + color = Blocks.LILY_PAD.defaultMaterialColor().col; + break; + case ICY: + color = Blocks.PACKED_ICE.defaultMaterialColor().col; + break; + case THE_END: + color = Blocks.END_STONE.defaultMaterialColor().col; + break; + case NETHER: + color = Blocks.NETHERRACK.defaultMaterialColor().col; + break; + case BADLANDS_PLATEAU: + case MESA: + color = Blocks.RED_SAND.defaultMaterialColor().col; + break; + case NONE: + default: + color = 0; + } + return color; + } + /** * methods that gives the ChunkBase color of biomes * @param biomeId id of the biome From 280d281604ea6bcbb13f0c19a458e4f34262cfc6 Mon Sep 17 00:00:00 2001 From: Morippi Date: Thu, 8 Jul 2021 12:52:50 +0200 Subject: [PATCH 10/46] various fix --- .../lod/objects/quadTree/QuadTreeImage.java | 35 +++++++++++++------ .../com/seibel/lod/util/BiomeColorsUtils.java | 30 ++++++++-------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 66ce3cd92..8ecb55d6d 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -76,6 +76,12 @@ public class QuadTreeImage extends JPanel { LodQuadTree lodQuadTree = new LodQuadTree(0, 0); final QuadTreeImage quadTreeImage = new QuadTreeImage(); + JFrame frame = new JFrame("DrawChit"); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + frame.getContentPane().add(quadTreeImage); + frame.pack(); + frame.setLocationByPlatform(true); + frame.setVisible(true); System.out.println(lodQuadTree.getLodNodeData().endX); int playerX = 150; int playerZ = 260; @@ -87,7 +93,7 @@ public class QuadTreeImage extends JPanel { if (i == 9) { dist = 500; } else { - dist = 50; + dist = 500; } List> levelToGenerate = lodQuadTree.getLevelToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist * (9 - i + 1), 0); System.out.println(levelToGenerate); @@ -129,8 +135,8 @@ public class QuadTreeImage extends JPanel { for(Integer posZI : posZs){ int posX = posXI.intValue(); int posZ = posZI.intValue(); - color = BiomeColorsUtils.getColorFromBiomeBlock(biomeSource.getBiome(posZ, 0, posX)); - //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); + //color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); + color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); } } @@ -141,16 +147,22 @@ public class QuadTreeImage extends JPanel { //lodList = lodQuadTree.getNodeList(false,false,false); listOfList.add(lodList); - System.out.println(listOfList.size()); + + final List myDrawables = new ArrayList<>(); + int amp = 2; + for (LodNodeData data : lodList) { + myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX * amp, data.startZ * amp, data.width * amp, data.width * amp), + data.color, new BasicStroke(1))); + } + myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerZ * amp - 10, playerX * amp - 10, 20, 20), + Color.yellow, new BasicStroke(1))); + for (int k = 0; k < myDrawables.size(); k++) { + quadTreeImage.addMyDrawable(myDrawables.get(k)); + } } - JFrame frame = new JFrame("DrawChit"); - frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); - frame.getContentPane().add(quadTreeImage); - frame.pack(); - frame.setLocationByPlatform(true); - frame.setVisible(true); - int timerDelay = 1000; + /* + int timerDelay = 100; new Timer(timerDelay, new ActionListener() { private int drawCount = 0; @@ -176,6 +188,7 @@ public class QuadTreeImage extends JPanel { } } }).start(); + */ } public static void main(String[] args) { diff --git a/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java b/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java index ce7732818..3482404d2 100644 --- a/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java +++ b/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java @@ -240,51 +240,51 @@ public class BiomeColorsUtils { switch(biome.getCategory()) { case BEACH: case DESERT: - color = new Color(); + color = new Color(65,85,40); break; case EXTREME_HILLS: - color = Blocks.SNOW.defaultMaterialColor().col; + color = new Color(81,129,60); break; case FOREST: - color = Blocks.OAK_LEAVES.defaultMaterialColor().col; + color = new Color(81,129,60); break; case SAVANNA: - color = Blocks.ACACIA_LEAVES.defaultMaterialColor().col; + color = new Color(119,113,53); break; case JUNGLE: - color = Blocks.JUNGLE_LEAVES.defaultMaterialColor().col; + color = new Color(41,141,4); break; case TAIGA: - color = Blocks.SPRUCE_LEAVES.defaultMaterialColor().col; + color = new Color(70,95,68); break; case MUSHROOM: - color = Blocks.MYCELIUM.defaultMaterialColor().col; + color = new Color(123,105,109); break; case PLAINS: - color = Blocks.GRASS_BLOCK.defaultMaterialColor().col; + color = new Color(65,85,40); break; case OCEAN: case RIVER: - color = Blocks.WATER.defaultMaterialColor().col; + color = new Color(42,63,110); case SWAMP: - color = Blocks.LILY_PAD.defaultMaterialColor().col; + color = new Color(57,67,53); break; case ICY: - color = Blocks.PACKED_ICE.defaultMaterialColor().col; + color = new Color(199,217,254); break; case THE_END: - color = Blocks.END_STONE.defaultMaterialColor().col; + color = new Color(100,100,0); break; case NETHER: - color = Blocks.NETHERRACK.defaultMaterialColor().col; + color = new Color(100,0,0); break; case BADLANDS_PLATEAU: case MESA: - color = Blocks.RED_SAND.defaultMaterialColor().col; + color = new Color(188,103,39); break; case NONE: default: - color = 0; + color = new Color(0,0,0,0); } return color; } From d5b2512e27b5dd2f56c11525602d1bd0fb72adc3 Mon Sep 17 00:00:00 2001 From: Morippi Date: Thu, 8 Jul 2021 13:00:29 +0200 Subject: [PATCH 11/46] various fix --- .../lod/objects/quadTree/QuadTreeImage.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 8ecb55d6d..dfe7a7c22 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -122,13 +122,13 @@ public class QuadTreeImage extends JPanel { posZs.add(endZ / otherWidth); }else{ posXs.add(startX / otherWidth); - posXs.add((centerX / otherWidth)-1); + //posXs.add((centerX / otherWidth)-1); posXs.add(centerX / otherWidth); - posXs.add(endX / otherWidth); + //posXs.add(endX / otherWidth); posZs.add(startZ / otherWidth); - posZs.add((centerZ / otherWidth)-1); + //posZs.add((centerZ / otherWidth)-1); posZs.add(centerZ / otherWidth); - posZs.add(endZ / otherWidth); + //posZs.add(endZ / otherWidth); } for(Integer posXI : posXs){ @@ -147,7 +147,7 @@ public class QuadTreeImage extends JPanel { //lodList = lodQuadTree.getNodeList(false,false,false); listOfList.add(lodList); - +/* final List myDrawables = new ArrayList<>(); int amp = 2; for (LodNodeData data : lodList) { @@ -158,11 +158,12 @@ public class QuadTreeImage extends JPanel { Color.yellow, new BasicStroke(1))); for (int k = 0; k < myDrawables.size(); k++) { quadTreeImage.addMyDrawable(myDrawables.get(k)); + } + */ } - /* - int timerDelay = 100; + int timerDelay = 500; new Timer(timerDelay, new ActionListener() { private int drawCount = 0; @@ -188,7 +189,6 @@ public class QuadTreeImage extends JPanel { } } }).start(); - */ } public static void main(String[] args) { From 804f91058467f41aa187dd3928d1b527278cfcd2 Mon Sep 17 00:00:00 2001 From: Morippi Date: Thu, 8 Jul 2021 19:31:27 +0200 Subject: [PATCH 12/46] added region in image + various fix --- .../lod/objects/quadTree/LodQuadTree.java | 5 +- .../lod/objects/quadTree/QuadTreeImage.java | 134 +++++++++++------- 2 files changed, 84 insertions(+), 55 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index 1f4d652a3..64e3f4ffe 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -307,7 +307,10 @@ public class LodQuadTree { int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List nodeList = new ArrayList<>(); - if (min > maxDistance || max < minDistance || targetLevel > lodNodeData.level) { + if (targetLevel > lodNodeData.level) { + return nodeList; + } + if ((min > maxDistance || max < minDistance) && !isCoordinateInLevel(x,z)){ return nodeList; } if (targetLevel == lodNodeData.level || !isNodeFull()) { diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index dfe7a7c22..6173f3713 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -73,7 +73,17 @@ public class QuadTreeImage extends JPanel { } private static void createAndShowGui() { - LodQuadTree lodQuadTree = new LodQuadTree(0, 0); + int playerX = 600; + int playerZ = 260; + LodQuadTree lodQuadTree1 = new LodQuadTree(0, 0); + LodQuadTree lodQuadTree3 = new LodQuadTree(1, 0); + LodQuadTree lodQuadTree2 = new LodQuadTree(0, 1); + LodQuadTree lodQuadTree4 = new LodQuadTree(1, 1); + List lodQuadTreeList = new ArrayList<>(); + lodQuadTreeList.add(lodQuadTree1); + lodQuadTreeList.add(lodQuadTree2); + lodQuadTreeList.add(lodQuadTree3); + lodQuadTreeList.add(lodQuadTree4); final QuadTreeImage quadTreeImage = new QuadTreeImage(); JFrame frame = new JFrame("DrawChit"); @@ -82,68 +92,79 @@ public class QuadTreeImage extends JPanel { frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); - System.out.println(lodQuadTree.getLodNodeData().endX); - int playerX = 150; - int playerZ = 260; List> listOfList = new ArrayList<>(); - OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 0); + OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 100); for (int i = 0; i <= (9 - 2); i++) { for (int j = 0; j < 1; j++) { - int dist; - if (i == 9) { - dist = 500; - } else { - dist = 500; - } - List> levelToGenerate = lodQuadTree.getLevelToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist * (9 - i + 1), 0); - System.out.println(levelToGenerate); - for (AbstractMap.SimpleEntry levelDist : levelToGenerate) { - LodQuadTree level = levelDist.getKey(); - Color color; - int startX = level.getLodNodeData().startX; - int startZ = level.getLodNodeData().startZ; - int endX = level.getLodNodeData().endX; - int endZ = level.getLodNodeData().endZ; - int centerX = level.getLodNodeData().centerX; - int centerZ = level.getLodNodeData().centerZ; - int width = level.getLodNodeData().width; - byte otherLevel = LodNodeData.BLOCK_LEVEL; - int otherWidth = LodNodeData.BLOCK_WIDTH; - List posXs = new ArrayList<>(); - List posZs = new ArrayList<>(); - if(level.getLodNodeData().level == 0){ - posXs.add(startX / otherWidth); - posZs.add(startZ / otherWidth); - }else if(level.getLodNodeData().level == 2){ - posXs.add(startX / otherWidth); - posXs.add(endX / otherWidth); - posZs.add(startZ / otherWidth); - posZs.add(endZ / otherWidth); - }else{ - posXs.add(startX / otherWidth); - //posXs.add((centerX / otherWidth)-1); - posXs.add(centerX / otherWidth); - //posXs.add(endX / otherWidth); - posZs.add(startZ / otherWidth); - //posZs.add((centerZ / otherWidth)-1); - posZs.add(centerZ / otherWidth); - //posZs.add(endZ / otherWidth); + for (LodQuadTree lodQuadTree : lodQuadTreeList) { + int dist; + if (i == 9) { + dist = 1000; + } else { + dist = 100; } + List> levelToGenerate = lodQuadTree.getLevelToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist * (9 - i + 1), 0); - for(Integer posXI : posXs){ - for(Integer posZI : posZs){ - int posX = posXI.intValue(); - int posZ = posZI.intValue(); - //color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); - color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); + for (AbstractMap.SimpleEntry levelDist : levelToGenerate) { + LodQuadTree level = levelDist.getKey(); + Color color; + int startX = level.getLodNodeData().startX; + int startZ = level.getLodNodeData().startZ; + int endX = level.getLodNodeData().endX; + int endZ = level.getLodNodeData().endZ; + int centerX = level.getLodNodeData().centerX; + int centerZ = level.getLodNodeData().centerZ; + int width = level.getLodNodeData().width; + byte otherLevel = LodNodeData.BLOCK_LEVEL; + int otherWidth = LodNodeData.BLOCK_WIDTH; + + List posXs = new ArrayList<>(); + List posZs = new ArrayList<>(); + if (level.getLodNodeData().level == 0) { + posXs.add(startX / otherWidth); + posZs.add(startZ / otherWidth); + } else if (level.getLodNodeData().level == 2) { + posXs.add(startX / otherWidth); + posXs.add(endX / otherWidth); + posZs.add(startZ / otherWidth); + posZs.add(endZ / otherWidth); + } else { + posXs.add(startX / otherWidth); + //posXs.add((centerX / otherWidth)-1); + posXs.add(centerX / otherWidth); + //posXs.add(endX / otherWidth); + posZs.add(startZ / otherWidth); + //posZs.add((centerZ / otherWidth)-1); + posZs.add(centerZ / otherWidth); + //posZs.add(endZ / otherWidth); + } + + for (Integer posXI : posXs) { + for (Integer posZI : posZs) { + int posZ = posXI.intValue(); + int posX = posZI.intValue(); + //color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); + color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); + lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); + } } } } } + Collection lodList = new ArrayList<>(); + for (LodQuadTree lodQuadTree : lodQuadTreeList) { + //lodList.addAll(lodQuadTree.getNodeList(false, false,true)); + lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 0, 10000, 0)); + /* + lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); + lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); + lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 4, 400, 200)); + lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 5, 10000, 400)); - Collection lodList = lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 0, 10000, 0); + */ + + } //lodList = lodQuadTree.getNodeList(false,false,false); listOfList.add(lodList); @@ -163,6 +184,11 @@ public class QuadTreeImage extends JPanel { */ } + for (LodQuadTree lodQuadTree : lodQuadTreeList) { + System.out.println(lodQuadTree.getLodNodeData().posX + " " + lodQuadTree.getLodNodeData().posZ ); + System.out.println(lodQuadTree.getLodNodeData().startX + " " + lodQuadTree.getLodNodeData().startZ ); + } + int timerDelay = 500; new Timer(timerDelay, new ActionListener() { private int drawCount = 0; @@ -174,13 +200,13 @@ public class QuadTreeImage extends JPanel { quadTreeImage.clearAll(); } else { final List myDrawables = new ArrayList<>(); - int amp = 2; + int amp = 1; Collection lodList = listOfList.get(drawCount); for (LodNodeData data : lodList) { myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX * amp, data.startZ * amp, data.width * amp, data.width * amp), data.color, new BasicStroke(1))); } - myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerZ * amp - 10, playerX * amp - 10, 20, 20), + myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerX * amp - 10, playerZ * amp - 10, 20, 20), Color.yellow, new BasicStroke(1))); for (int k = 0; k < myDrawables.size(); k++) { quadTreeImage.addMyDrawable(myDrawables.get(k)); From 4a9bc7ca741198621cd80047faeed39d95683daf Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 13:11:25 +0200 Subject: [PATCH 13/46] fixed LodQuadTreeDimension --- .../quadTree/LodQuadTreeDimension.java | 68 +++++++++++++------ 1 file changed, 46 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java index 33e4a5bc4..ce828a802 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -11,7 +11,8 @@ import net.minecraft.world.server.ServerWorld; import java.io.File; import java.io.IOException; -import java.util.List; +import java.util.*; +import java.util.stream.Collectors; public class LodQuadTreeDimension { public final DimensionType dimension; @@ -227,7 +228,28 @@ public class LodQuadTreeDimension { } - + /** + *this method create all the regions that are null + */ + public void initializeNullRegions(LodNodeData lodNodeData){ + int n = regions.length; + int xIndex; + int zIndex; + LodQuadTree region; + for(int xRegion=0; xRegion getNodeToRender(int x, int z, byte level, int maxDistance, int minDistance){ + int n = regions.length; + List listOfData = new ArrayList<>(); + for(int i=0; i getNodeToGenerate(int x, int z, byte level, int maxDistance, int minDistance){ + int n = regions.length; + List> listOfQuadTree = new ArrayList<>(); + for(int i=0; i entry.getKey()).collect(Collectors.toList()); } /** @@ -343,12 +372,6 @@ public class LodQuadTreeDimension { return xIndex >= 0 && xIndex < width && zIndex >= 0 && zIndex < width; } - - - - - - public int getCenterX() { return centerX; @@ -361,6 +384,7 @@ public class LodQuadTreeDimension { /** + * TODO THIS METHOD HAVE TO BE CHANGES. IS NOT THE SAME AS NUMER OF CHUNK * Returns how many non-null LodChunks * are stored in this LodDimension. */ From 2b5b0234721de23c5507e3698bac0f3081e8d11c Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 13:33:11 +0200 Subject: [PATCH 14/46] fixed LodQuadTreeDimension --- .../quadTree/LodQuadTreeDimension.java | 28 +++- .../lod/objects/quadTree/QuadTreeImage.java | 133 ++++++++---------- 2 files changed, 83 insertions(+), 78 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java index ce828a802..dc4c980a3 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -35,6 +35,7 @@ public class LodQuadTreeDimension { dimension = newDimension; width = newMaxWidth; + /* try { Minecraft mc = Minecraft.getInstance(); @@ -60,12 +61,13 @@ public class LodQuadTreeDimension { } fileHandler = new LodQuadTreeDimensionFileHandler(saveDir, this); + } catch(IOException e) { // the file handler wasn't able to be created // we won't be able to read or write any files - } + } */ regions = new LodQuadTree[width][width]; @@ -231,7 +233,7 @@ public class LodQuadTreeDimension { /** *this method create all the regions that are null */ - public void initializeNullRegions(LodNodeData lodNodeData){ + public void initializeNullRegions(){ int n = regions.length; int xIndex; int zIndex; @@ -278,11 +280,14 @@ public class LodQuadTreeDimension { region = new LodQuadTree(pos.x, pos.z); setRegion(region); } - + System.out.println("Adding this node"); + System.out.println(lodNodeData); + System.out.println("to"); + System.out.println(region); region.setNodeAtLowerLevel(lodNodeData, true); // don't save empty place holders to disk - if (!lodNodeData.real && fileHandler != null) + if (lodNodeData.real && fileHandler != null) { // mark the region as dirty so it will be saved to disk int xIndex = (pos.x - centerX) + halfWidth; @@ -347,6 +352,21 @@ public class LodQuadTreeDimension { return listOfQuadTree.stream().map(entry -> entry.getKey()).collect(Collectors.toList()); } + /** + * getNodes + * @return list of quadTrees + */ + public List getNodes(boolean getOnlyReal, boolean getOnlyDirty, boolean getOnlyLeaf){ + int n = regions.length; + List listOfNodes = new ArrayList<>(); + for(int i=0; i lodQuadTreeList = new ArrayList<>(); - lodQuadTreeList.add(lodQuadTree1); - lodQuadTreeList.add(lodQuadTree2); - lodQuadTreeList.add(lodQuadTree3); - lodQuadTreeList.add(lodQuadTree4); + LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 10); + dim.move(playerX / 512, playerZ / 512); + dim.initializeNullRegions(); + System.out.println(dim.getRegion(0, 0)); + List levelToGenerate2 = dim.getNodeToGenerate(playerX, playerZ, (byte) 0, 1000, 0); + System.out.println(levelToGenerate2); + final QuadTreeImage quadTreeImage = new QuadTreeImage(); JFrame frame = new JFrame("DrawChit"); @@ -94,77 +92,68 @@ public class QuadTreeImage extends JPanel { frame.setVisible(true); List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 100); - for (int i = 0; i <= (9 - 2); i++) { + for (int i = 0; i <= (9 - 8); i++) { for (int j = 0; j < 1; j++) { + int dist; + if (i == 9) { + dist = 1000; + } else { + dist = 100; + } + List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist * (9 - i + 1), 0); - for (LodQuadTree lodQuadTree : lodQuadTreeList) { - int dist; - if (i == 9) { - dist = 1000; + for (LodQuadTree level : levelToGenerate) { + System.out.println(level); + Color color; + int startX = level.getLodNodeData().startX; + int startZ = level.getLodNodeData().startZ; + int endX = level.getLodNodeData().endX; + int endZ = level.getLodNodeData().endZ; + int centerX = level.getLodNodeData().centerX; + int centerZ = level.getLodNodeData().centerZ; + int width = level.getLodNodeData().width; + byte otherLevel = LodNodeData.BLOCK_LEVEL; + int otherWidth = LodNodeData.BLOCK_WIDTH; + + List posXs = new ArrayList<>(); + List posZs = new ArrayList<>(); + if (level.getLodNodeData().level == 0) { + posXs.add(startX / otherWidth); + posZs.add(startZ / otherWidth); + } else if (level.getLodNodeData().level == 2) { + posXs.add(startX / otherWidth); + posXs.add(endX / otherWidth); + posZs.add(startZ / otherWidth); + posZs.add(endZ / otherWidth); } else { - dist = 100; + posXs.add(startX / otherWidth); + //posXs.add((centerX / otherWidth)-1); + //posXs.add(centerX / otherWidth); + //posXs.add(endX / otherWidth); + posZs.add(startZ / otherWidth); + //posZs.add((centerZ / otherWidth)-1); + //posZs.add(centerZ / otherWidth); + //posZs.add(endZ / otherWidth); } - List> levelToGenerate = lodQuadTree.getLevelToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist * (9 - i + 1), 0); - for (AbstractMap.SimpleEntry levelDist : levelToGenerate) { - LodQuadTree level = levelDist.getKey(); - Color color; - int startX = level.getLodNodeData().startX; - int startZ = level.getLodNodeData().startZ; - int endX = level.getLodNodeData().endX; - int endZ = level.getLodNodeData().endZ; - int centerX = level.getLodNodeData().centerX; - int centerZ = level.getLodNodeData().centerZ; - int width = level.getLodNodeData().width; - byte otherLevel = LodNodeData.BLOCK_LEVEL; - int otherWidth = LodNodeData.BLOCK_WIDTH; - - List posXs = new ArrayList<>(); - List posZs = new ArrayList<>(); - if (level.getLodNodeData().level == 0) { - posXs.add(startX / otherWidth); - posZs.add(startZ / otherWidth); - } else if (level.getLodNodeData().level == 2) { - posXs.add(startX / otherWidth); - posXs.add(endX / otherWidth); - posZs.add(startZ / otherWidth); - posZs.add(endZ / otherWidth); - } else { - posXs.add(startX / otherWidth); - //posXs.add((centerX / otherWidth)-1); - posXs.add(centerX / otherWidth); - //posXs.add(endX / otherWidth); - posZs.add(startZ / otherWidth); - //posZs.add((centerZ / otherWidth)-1); - posZs.add(centerZ / otherWidth); - //posZs.add(endZ / otherWidth); - } - - for (Integer posXI : posXs) { - for (Integer posZI : posZs) { - int posZ = posXI.intValue(); - int posX = posZI.intValue(); - //color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); - color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); - lodQuadTree.setNodeAtLowerLevel(new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true), true); - } + for (Integer posXI : posXs) { + for (Integer posZI : posZs) { + int posZ = posXI.intValue(); + int posX = posZI.intValue(); + //color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); + color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); + LodNodeData node = new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true); + dim.addNode(node); } } } } - Collection lodList = new ArrayList<>(); - for (LodQuadTree lodQuadTree : lodQuadTreeList) { - //lodList.addAll(lodQuadTree.getNodeList(false, false,true)); - lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 0, 10000, 0)); - /* - lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); - lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); - lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 4, 400, 200)); - lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 5, 10000, 400)); + Collection lodList = dim.getNodes(false, false, true); + // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); + // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); + // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 4, 400, 200)); + // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 5, 10000, 400)); - */ - - } //lodList = lodQuadTree.getNodeList(false,false,false); listOfList.add(lodList); @@ -184,10 +173,6 @@ public class QuadTreeImage extends JPanel { */ } - for (LodQuadTree lodQuadTree : lodQuadTreeList) { - System.out.println(lodQuadTree.getLodNodeData().posX + " " + lodQuadTree.getLodNodeData().posZ ); - System.out.println(lodQuadTree.getLodNodeData().startX + " " + lodQuadTree.getLodNodeData().startZ ); - } int timerDelay = 500; new Timer(timerDelay, new ActionListener() { From 712d9db2fa3356bd04e0da0559684535215a172c Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 14:58:48 +0200 Subject: [PATCH 15/46] fixed LodQuadTreeDimension --- .../lod/objects/quadTree/LodQuadTree.java | 4 +- .../quadTree/LodQuadTreeDimension.java | 91 ++++++++++--------- .../lod/objects/quadTree/QuadTreeImage.java | 68 +++++++------- .../java/com/seibel/lod/util/LodUtil.java | 4 +- 4 files changed, 87 insertions(+), 80 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index 64e3f4ffe..83f806d41 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -136,8 +136,8 @@ public class LodQuadTree { int posX = newLodNodeData.posX; int posZ = newLodNodeData.posZ; short widthRatio = (short) (lodNodeData.width / (2 * newLodNodeData.width)); - int NS = (posX / widthRatio) % 2; - int WE = (posZ / widthRatio) % 2; + int NS = Math.abs((posX / widthRatio) % 2); + int WE = Math.abs((posZ / widthRatio) % 2); if (getChild(NS, WE) == null) { setChild(NS, WE); } diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java index dc4c980a3..5a9f508e7 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -34,40 +34,34 @@ public class LodQuadTreeDimension { { dimension = newDimension; width = newMaxWidth; + if(newDimension != null && lodWorld != null) { + try { + Minecraft mc = Minecraft.getInstance(); - /* - try - { - Minecraft mc = Minecraft.getInstance(); + File saveDir; + if (mc.hasSingleplayerServer()) { + // local world - File saveDir; - if(mc.hasSingleplayerServer()) - { - // local world + ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(newDimension); + seed = serverWorld.getSeed(); + // provider needs a separate variable to prevent + // the compiler from complaining + ServerChunkProvider provider = serverWorld.getChunkSource(); + saveDir = new File(provider.dataStorage.dataFolder.getCanonicalFile().getPath() + File.separatorChar + "lod"); + } else { + // connected to server - ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(newDimension); - seed = serverWorld.getSeed(); - // provider needs a separate variable to prevent - // the compiler from complaining - ServerChunkProvider provider = serverWorld.getChunkSource(); - saveDir = new File(provider.dataStorage.dataFolder.getCanonicalFile().getPath() + File.separatorChar + "lod"); + saveDir = new File(mc.gameDirectory.getCanonicalFile().getPath() + + File.separatorChar + "lod server data" + File.separatorChar + LodUtil.getDimensionIDFromWorld(mc.level)); + } + + fileHandler = new LodQuadTreeDimensionFileHandler(saveDir, this); + + } catch (IOException e) { + // the file handler wasn't able to be created + // we won't be able to read or write any files } - else - { - // connected to server - - saveDir = new File(mc.gameDirectory.getCanonicalFile().getPath() + - File.separatorChar + "lod server data" + File.separatorChar + LodUtil.getDimensionIDFromWorld(mc.level)); - } - - fileHandler = new LodQuadTreeDimensionFileHandler(saveDir, this); - } - catch(IOException e) - { - // the file handler wasn't able to be created - // we won't be able to read or write any files - } */ regions = new LodQuadTree[width][width]; @@ -262,8 +256,8 @@ public class LodQuadTreeDimension { public void addNode(LodNodeData lodNodeData) { RegionPos pos = new RegionPos( - lodNodeData.posX / lodNodeData.width, - lodNodeData.posZ / lodNodeData.width + lodNodeData.startX / 512, + lodNodeData.startZ / 512 ); // don't continue if the region can't be saved @@ -280,10 +274,6 @@ public class LodQuadTreeDimension { region = new LodQuadTree(pos.x, pos.z); setRegion(region); } - System.out.println("Adding this node"); - System.out.println(lodNodeData); - System.out.println("to"); - System.out.println(region); region.setNodeAtLowerLevel(lodNodeData, true); // don't save empty place holders to disk @@ -341,11 +331,22 @@ public class LodQuadTreeDimension { * @return list of quadTrees */ public List getNodeToGenerate(int x, int z, byte level, int maxDistance, int minDistance){ + int n = regions.length; + int xIndex; + int zIndex; + LodQuadTree region; List> listOfQuadTree = new ArrayList<>(); - for(int i=0; i getNodes(boolean getOnlyReal, boolean getOnlyDirty, boolean getOnlyLeaf){ int n = regions.length; List listOfNodes = new ArrayList<>(); - for(int i=0; i levelToGenerate2 = dim.getNodeToGenerate(playerX, playerZ, (byte) 0, 1000, 0); - System.out.println(levelToGenerate2); - + dim.move(playerX/512,playerZ/512); + System.out.println(dim.getCenterX()); + System.out.println(dim.getCenterZ()); + System.out.println(dim.getWidth()); final QuadTreeImage quadTreeImage = new QuadTreeImage(); + JFrame frame = new JFrame("DrawChit"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.getContentPane().add(quadTreeImage); @@ -92,18 +92,16 @@ public class QuadTreeImage extends JPanel { frame.setVisible(true); List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 100); - for (int i = 0; i <= (9 - 8); i++) { + for (int i = 0; i <= (9 - 5); i++) { for (int j = 0; j < 1; j++) { int dist; if (i == 9) { - dist = 1000; + dist = 10000; } else { dist = 100; } - List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist * (9 - i + 1), 0); - + List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist, 0); for (LodQuadTree level : levelToGenerate) { - System.out.println(level); Color color; int startX = level.getLodNodeData().startX; int startZ = level.getLodNodeData().startZ; @@ -117,6 +115,7 @@ public class QuadTreeImage extends JPanel { List posXs = new ArrayList<>(); List posZs = new ArrayList<>(); + /* if (level.getLodNodeData().level == 0) { posXs.add(startX / otherWidth); posZs.add(startZ / otherWidth); @@ -135,6 +134,11 @@ public class QuadTreeImage extends JPanel { //posZs.add(centerZ / otherWidth); //posZs.add(endZ / otherWidth); } + */ + posXs.add(startX / otherWidth); + //posXs.add(centerX / otherWidth); + posZs.add(startZ / otherWidth); + //posXs.add(centerZ / otherWidth); for (Integer posXI : posXs) { for (Integer posZI : posZs) { @@ -148,29 +152,13 @@ public class QuadTreeImage extends JPanel { } } } - Collection lodList = dim.getNodes(false, false, true); + Collection lodList = dim.getNodes(false, false, false); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 4, 400, 200)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 5, 10000, 400)); - - - //lodList = lodQuadTree.getNodeList(false,false,false); listOfList.add(lodList); -/* - final List myDrawables = new ArrayList<>(); - int amp = 2; - for (LodNodeData data : lodList) { - myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX * amp, data.startZ * amp, data.width * amp, data.width * amp), - data.color, new BasicStroke(1))); - } - myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerZ * amp - 10, playerX * amp - 10, 20, 20), - Color.yellow, new BasicStroke(1))); - for (int k = 0; k < myDrawables.size(); k++) { - quadTreeImage.addMyDrawable(myDrawables.get(k)); - - } - */ + System.out.println(lodList); } @@ -182,16 +170,26 @@ public class QuadTreeImage extends JPanel { public void actionPerformed(ActionEvent e) { if (drawCount >= listOfList.size()) { drawCount = 0; - quadTreeImage.clearAll(); } else { + if(drawCount==0) quadTreeImage.clearAll(); final List myDrawables = new ArrayList<>(); - int amp = 1; + double amp = 1; + int xOffset = (dim.getCenterX() - (dim.getWidth()/2))*512; + int zOffset = (dim.getCenterZ() - (dim.getWidth()/2))*512; Collection lodList = listOfList.get(drawCount); for (LodNodeData data : lodList) { - myDrawables.add(new MyDrawable(new Rectangle2D.Double(data.startX * amp, data.startZ * amp, data.width * amp, data.width * amp), + myDrawables.add(new MyDrawable(new Rectangle2D.Double( + ((data.startX - xOffset ) * amp), + ((data.startZ - zOffset) * amp), + data.width * amp, + data.width * amp), data.color, new BasicStroke(1))); } - myDrawables.add(new MyDrawable(new Rectangle2D.Double(playerX * amp - 10, playerZ * amp - 10, 20, 20), + myDrawables.add(new MyDrawable(new Rectangle2D.Double( + (playerX - 10 + xOffset) * amp, + (playerZ - 10 + zOffset) * amp, + 20, + 20), Color.yellow, new BasicStroke(1))); for (int k = 0; k < myDrawables.size(); k++) { quadTreeImage.addMyDrawable(myDrawables.get(k)); diff --git a/src/main/java/com/seibel/lod/util/LodUtil.java b/src/main/java/com/seibel/lod/util/LodUtil.java index a36df9819..92d1fe72b 100644 --- a/src/main/java/com/seibel/lod/util/LodUtil.java +++ b/src/main/java/com/seibel/lod/util/LodUtil.java @@ -79,8 +79,8 @@ public class LodUtil public static RegionPos convertChunkPosToRegionPos(ChunkPos pos) { RegionPos rPos = new RegionPos(); - rPos.x = pos.x / LodRegion.SIZE; - rPos.z = pos.z / LodRegion.SIZE; + rPos.x = pos.x / 512; + rPos.z = pos.z / 512; // prevent issues if X/Z is negative and less than 16 if (pos.x < 0) From 604089cfa8a379dcc4eca5f195caeb9e60c91d1e Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 15:08:48 +0200 Subject: [PATCH 16/46] fixed LodQuadTreeDimension --- .../seibel/lod/objects/quadTree/LodQuadTreeDimension.java | 5 +++-- .../java/com/seibel/lod/objects/quadTree/QuadTreeImage.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java index 5a9f508e7..e0380b05d 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -253,7 +253,7 @@ public class LodQuadTreeDimension { * stored in the LOD. If an LOD already exists at the given * coordinates it will be overwritten. */ - public void addNode(LodNodeData lodNodeData) + public Boolean addNode(LodNodeData lodNodeData) { RegionPos pos = new RegionPos( lodNodeData.startX / 512, @@ -274,7 +274,7 @@ public class LodQuadTreeDimension { region = new LodQuadTree(pos.x, pos.z); setRegion(region); } - region.setNodeAtLowerLevel(lodNodeData, true); + boolean coorectlyAdded = region.setNodeAtLowerLevel(lodNodeData, true); // don't save empty place holders to disk if (lodNodeData.real && fileHandler != null) @@ -285,6 +285,7 @@ public class LodQuadTreeDimension { isRegionDirty[xIndex][zIndex] = true; fileHandler.saveDirtyRegionsToFileAsync(); } + return coorectlyAdded; } /** diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 28ea17c41..e0983ca52 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -98,10 +98,11 @@ public class QuadTreeImage extends JPanel { if (i == 9) { dist = 10000; } else { - dist = 100; + dist = 1000; } List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist, 0); for (LodQuadTree level : levelToGenerate) { + System.out.println(level); Color color; int startX = level.getLodNodeData().startX; int startZ = level.getLodNodeData().startZ; @@ -147,7 +148,7 @@ public class QuadTreeImage extends JPanel { //color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); LodNodeData node = new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true); - dim.addNode(node); + System.out.println(dim.addNode(node)); } } } From 14f1b6db5478b2cf4b51f9fdbdad13a884719476 Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 15:26:03 +0200 Subject: [PATCH 17/46] fixed LodQuadTreeDimension --- .../quadTree/LodQuadTreeDimension.java | 2 +- .../lod/objects/quadTree/QuadTreeImage.java | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java index e0380b05d..21ffc818d 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -263,7 +263,7 @@ public class LodQuadTreeDimension { // don't continue if the region can't be saved if (!regionIsInRange(pos.x, pos.z)) { - return; + return false; } LodQuadTree region = getRegion(pos.x, pos.z); diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index e0983ca52..02932c225 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -75,7 +75,7 @@ public class QuadTreeImage extends JPanel { private static void createAndShowGui() { int playerX = 0; int playerZ = 0; - LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 8); + LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 2); System.out.println(dim.getRegion(0, 0)); dim.move(playerX/512,playerZ/512); System.out.println(dim.getCenterX()); @@ -101,6 +101,7 @@ public class QuadTreeImage extends JPanel { dist = 1000; } List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist, 0); + System.out.println(levelToGenerate); for (LodQuadTree level : levelToGenerate) { System.out.println(level); Color color; @@ -137,9 +138,9 @@ public class QuadTreeImage extends JPanel { } */ posXs.add(startX / otherWidth); - //posXs.add(centerX / otherWidth); + posXs.add(centerX / otherWidth); posZs.add(startZ / otherWidth); - //posXs.add(centerZ / otherWidth); + posZs.add(centerZ / otherWidth); for (Integer posXI : posXs) { for (Integer posZI : posZs) { @@ -202,11 +203,26 @@ public class QuadTreeImage extends JPanel { } public static void main(String[] args) { + + /* + LodQuadTreeDimension dim2 = new LodQuadTreeDimension(null, null, 8); + List levelToGenerate = dim2.getNodeToGenerate(0, 0, (byte) 0, (int) 10000, 0); + System.out.println(levelToGenerate); + dim2.addNode(new LodNodeData((byte) 0,0,0,-1,-1, new Color(100,100,100),true)); + dim2.addNode(new LodNodeData((byte) 0,256,0,-1,-1, new Color(100,100,100),true)); + dim2.addNode(new LodNodeData((byte) 0,0,256,-1,-1, new Color(100,100,100),true)); + dim2.addNode(new LodNodeData((byte) 0,256,256,-1,-1, new Color(100,100,100),true)); + levelToGenerate = dim2.getNodeToGenerate(0, 0, (byte) 0, (int) 10000, 0); + System.out.println(levelToGenerate); + + */ + SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); + } } From 63b01f3ec79a9c25040b1617763fbaed1c0d8d67 Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 15:53:32 +0200 Subject: [PATCH 18/46] fixed LodQuadTreeDimension --- .../quadTree/LodQuadTreeDimension.java | 8 +-- .../lod/objects/quadTree/QuadTreeImage.java | 57 +++++++------------ 2 files changed, 26 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java index 21ffc818d..b0d050084 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -200,7 +200,7 @@ public class LodQuadTreeDimension { regions[xIndex][zIndex] = getRegionFromFile(regionX, regionZ); if (regions[xIndex][zIndex] == null) { - regions[xIndex][zIndex] = new LodQuadTree(regionX, regionZ); + regions[xIndex][zIndex] = new LodQuadTree(regionZ, regionX); } } @@ -240,7 +240,7 @@ public class LodQuadTreeDimension { if (region == null) { // if no region exists, create it - region = new LodQuadTree(xIndex, zIndex); + region = new LodQuadTree(zIndex, xIndex); setRegion(region); } } @@ -271,7 +271,7 @@ public class LodQuadTreeDimension { if (region == null) { // if no region exists, create it - region = new LodQuadTree(pos.x, pos.z); + region = new LodQuadTree(pos.z, pos.x); setRegion(region); } boolean coorectlyAdded = region.setNodeAtLowerLevel(lodNodeData, true); @@ -344,7 +344,7 @@ public class LodQuadTreeDimension { zIndex = (zRegion + centerZ) - halfWidth; region = getRegion(xIndex,zIndex); if (region == null){ - region = new LodQuadTree(xIndex, zIndex); + region = new LodQuadTree(zIndex, xIndex); setRegion(region); } listOfQuadTree.addAll(region.getLevelToGenerate(x,z,level,maxDistance,minDistance)); diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 02932c225..3fa42a6fe 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -73,9 +73,9 @@ public class QuadTreeImage extends JPanel { } private static void createAndShowGui() { - int playerX = 0; - int playerZ = 0; - LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 2); + int playerX = 1000; + int playerZ = 3000; + LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 8); System.out.println(dim.getRegion(0, 0)); dim.move(playerX/512,playerZ/512); System.out.println(dim.getCenterX()); @@ -90,20 +90,18 @@ public class QuadTreeImage extends JPanel { frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); - List> listOfList = new ArrayList<>(); + List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 100); - for (int i = 0; i <= (9 - 5); i++) { + for (int i = 0; i <= (9 - 0); i++) { for (int j = 0; j < 1; j++) { int dist; if (i == 9) { - dist = 10000; + dist = 200; } else { - dist = 1000; + dist = 200; } - List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist, 0); - System.out.println(levelToGenerate); + List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist*(9-i), 0); for (LodQuadTree level : levelToGenerate) { - System.out.println(level); Color color; int startX = level.getLodNodeData().startX; int startZ = level.getLodNodeData().startZ; @@ -117,30 +115,15 @@ public class QuadTreeImage extends JPanel { List posXs = new ArrayList<>(); List posZs = new ArrayList<>(); - /* if (level.getLodNodeData().level == 0) { posXs.add(startX / otherWidth); posZs.add(startZ / otherWidth); - } else if (level.getLodNodeData().level == 2) { - posXs.add(startX / otherWidth); - posXs.add(endX / otherWidth); - posZs.add(startZ / otherWidth); - posZs.add(endZ / otherWidth); } else { posXs.add(startX / otherWidth); - //posXs.add((centerX / otherWidth)-1); - //posXs.add(centerX / otherWidth); - //posXs.add(endX / otherWidth); + posXs.add(centerX / otherWidth); posZs.add(startZ / otherWidth); - //posZs.add((centerZ / otherWidth)-1); - //posZs.add(centerZ / otherWidth); - //posZs.add(endZ / otherWidth); + posZs.add(centerZ / otherWidth); } - */ - posXs.add(startX / otherWidth); - posXs.add(centerX / otherWidth); - posZs.add(startZ / otherWidth); - posZs.add(centerZ / otherWidth); for (Integer posXI : posXs) { for (Integer posZI : posZs) { @@ -149,22 +132,26 @@ public class QuadTreeImage extends JPanel { //color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); LodNodeData node = new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true); - System.out.println(dim.addNode(node)); + dim.addNode(node); } } } } - Collection lodList = dim.getNodes(false, false, false); + List lodList = dim.getNodeToRender(playerX,playerZ,(byte) 0, 10000,0); + //Collection lodList = dim.getNodes(false,false,false); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 4, 400, 200)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 5, 10000, 400)); listOfList.add(lodList); - System.out.println(lodList); } - int timerDelay = 500; + int timerDelay = 250; + System.out.println("STARTING"); + System.out.println(listOfList.get(0).get(0).startX); + System.out.println(dim.getWidth()); + System.out.println(dim.getCenterX()); new Timer(timerDelay, new ActionListener() { private int drawCount = 0; @@ -188,10 +175,10 @@ public class QuadTreeImage extends JPanel { data.color, new BasicStroke(1))); } myDrawables.add(new MyDrawable(new Rectangle2D.Double( - (playerX - 10 + xOffset) * amp, - (playerZ - 10 + zOffset) * amp, - 20, - 20), + (playerX - 10 - xOffset) * amp, + (playerZ - 10 - zOffset) * amp, + 20* amp, + 20* amp), Color.yellow, new BasicStroke(1))); for (int k = 0; k < myDrawables.size(); k++) { quadTreeImage.addMyDrawable(myDrawables.get(k)); From f181d073a3af0fcf3c201f6b7e54652de0a84885 Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 17:56:44 +0200 Subject: [PATCH 19/46] fixed LodQuadTreeDimension --- .../lod/objects/quadTree/QuadTreeImage.java | 49 +++++++++++++------ .../com/seibel/lod/util/BiomeColorsUtils.java | 11 +++-- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 3fa42a6fe..0929102de 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -21,6 +21,7 @@ import java.awt.geom.Rectangle2D; import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.io.File; +import java.io.IOException; import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; @@ -34,7 +35,7 @@ import javax.swing.Timer; @SuppressWarnings("serial") public class QuadTreeImage extends JPanel { - private static final int PREF_W = 1024; + private static final int PREF_W = (int) 0.1*16*512; private static final int PREF_H = PREF_W; private List drawables = new ArrayList<>(); @@ -73,9 +74,9 @@ public class QuadTreeImage extends JPanel { } private static void createAndShowGui() { - int playerX = 1000; - int playerZ = 3000; - LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 8); + int playerX = 8*512; + int playerZ = (8*512); + LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 16); System.out.println(dim.getRegion(0, 0)); dim.move(playerX/512,playerZ/512); System.out.println(dim.getCenterX()); @@ -92,15 +93,15 @@ public class QuadTreeImage extends JPanel { frame.setVisible(true); List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 100); - for (int i = 0; i <= (9 - 0); i++) { + for (int i = 0; i <= (9 - 2); i++) { for (int j = 0; j < 1; j++) { int dist; if (i == 9) { - dist = 200; + dist = 30; } else { - dist = 200; + dist = 30; } - List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), (int) dist*(9-i), 0); + List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), (int) (dist*Math.pow(9-i,2.5)), 0); for (LodQuadTree level : levelToGenerate) { Color color; int startX = level.getLodNodeData().startX; @@ -129,15 +130,20 @@ public class QuadTreeImage extends JPanel { for (Integer posZI : posZs) { int posZ = posXI.intValue(); int posX = posZI.intValue(); - //color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); - color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); + color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); + //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); LodNodeData node = new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true); dim.addNode(node); } } } } - List lodList = dim.getNodeToRender(playerX,playerZ,(byte) 0, 10000,0); + List lodList = dim.getNodeToRender(playerX,playerZ,(byte) 8, 10000,4000); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 7, 4000,2000)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 6, 2000,1000)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 5, 1000,500)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 4, 500,0)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 3, 250,0)); //Collection lodList = dim.getNodes(false,false,false); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); @@ -147,11 +153,14 @@ public class QuadTreeImage extends JPanel { } - int timerDelay = 250; + int timerDelay = 5000; System.out.println("STARTING"); - System.out.println(listOfList.get(0).get(0).startX); System.out.println(dim.getWidth()); System.out.println(dim.getCenterX()); + int xOffset = listOfList.stream().mapToInt(x -> x.stream().mapToInt(y -> y.startX).min().getAsInt()).min().getAsInt(); + int zOffset = listOfList.stream().mapToInt(x -> x.stream().mapToInt(y -> y.startZ).min().getAsInt()).min().getAsInt(); + System.out.println(xOffset); + System.out.println(zOffset); new Timer(timerDelay, new ActionListener() { private int drawCount = 0; @@ -162,11 +171,10 @@ public class QuadTreeImage extends JPanel { } else { if(drawCount==0) quadTreeImage.clearAll(); final List myDrawables = new ArrayList<>(); - double amp = 1; - int xOffset = (dim.getCenterX() - (dim.getWidth()/2))*512; - int zOffset = (dim.getCenterZ() - (dim.getWidth()/2))*512; + double amp = 0.1; Collection lodList = listOfList.get(drawCount); for (LodNodeData data : lodList) { + System.out.println(); myDrawables.add(new MyDrawable(new Rectangle2D.Double( ((data.startX - xOffset ) * amp), ((data.startZ - zOffset) * amp), @@ -183,6 +191,15 @@ public class QuadTreeImage extends JPanel { for (int k = 0; k < myDrawables.size(); k++) { quadTreeImage.addMyDrawable(myDrawables.get(k)); } + BufferedImage img = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_RGB); + Graphics2D g2d = img.createGraphics(); + frame.printAll(g2d); + g2d.dispose(); + try { + ImageIO.write(img, "png", new File("Img" + drawCount+".png")); + } catch (IOException ioException) { + ioException.printStackTrace(); + } drawCount++; } } diff --git a/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java b/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java index 3482404d2..5ab35491e 100644 --- a/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java +++ b/src/main/java/com/seibel/lod/util/BiomeColorsUtils.java @@ -240,7 +240,7 @@ public class BiomeColorsUtils { switch(biome.getCategory()) { case BEACH: case DESERT: - color = new Color(65,85,40); + color = new Color(220,214,170); break; case EXTREME_HILLS: color = new Color(81,129,60); @@ -261,13 +261,14 @@ public class BiomeColorsUtils { color = new Color(123,105,109); break; case PLAINS: - color = new Color(65,85,40); + color = new Color(96,125,59); break; case OCEAN: case RIVER: - color = new Color(42,63,110); + color = new Color(54,73,229); + break; case SWAMP: - color = new Color(57,67,53); + color = new Color(83,86,67); break; case ICY: color = new Color(199,217,254); @@ -283,6 +284,8 @@ public class BiomeColorsUtils { color = new Color(188,103,39); break; case NONE: + color = new Color(96,125,59); + break; default: color = new Color(0,0,0,0); } From 03ce4d9c421efce29107df49a1752ff601518043 Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 19:23:14 +0200 Subject: [PATCH 20/46] Several chages to converto to quadTree --- .../lod/builders/LodNodeBufferBuilder.java | 357 ++++++++ .../lod/objects/quadTree/LodNodeData.java | 1 - .../lod/objects/quadTree/LodQuadTree.java | 12 +- .../quadTree/LodQuadTreeDimension.java | 8 +- .../lod/objects/quadTree/QuadTreeImage.java | 32 +- .../com/seibel/lod/proxy/ClientProxy.java | 12 +- .../seibel/lod/render/LodNodeRenderer.java | 844 ++++++++++++++++++ 7 files changed, 1241 insertions(+), 25 deletions(-) create mode 100644 src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java create mode 100644 src/main/java/com/seibel/lod/render/LodNodeRenderer.java diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java new file mode 100644 index 000000000..52823b3ad --- /dev/null +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -0,0 +1,357 @@ +package com.seibel.lod.builders; + +import com.seibel.lod.builders.worldGeneration.LodChunkGenWorker; +import com.seibel.lod.handlers.LodConfig; +import com.seibel.lod.objects.LodChunk; +import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.NearFarBuffer; +import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.objects.quadTree.LodQuadTree; +import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.render.LodRenderer; +import com.seibel.lod.util.LodUtil; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.biome.BiomeContainer; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.WorldWorkerManager; +import org.lwjgl.opengl.GL11; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * This object is used to create NearFarBuffer objects. + * + * @author James Seibel + * @version 06-19-2021 + */ +public class LodNodeBufferBuilder +{ + private Minecraft mc; + + /** This holds the thread used to generate new LODs off the main thread. */ + private ExecutorService genThread = Executors.newSingleThreadExecutor(); + + private LodChunkBuilder lodChunkBuilder; + + /** The buffers that are used to create LODs using near fog */ + public volatile BufferBuilder buildableNearBuffer; + /** The buffers that are used to create LODs using far fog */ + public volatile BufferBuilder buildableFarBuffer; + + /** if this is true the LOD buffers are currently being + * regenerated. */ + public volatile boolean generatingBuffers = false; + + /** if this is true new LOD buffers have been generated + * and are waiting to be swapped with the drawable buffers*/ + private volatile boolean switchBuffers = false; + + /** If this is greater than 0 no new chunk generation requests will be made + * this is to prevent chunks from being generated for a long time in an area + * the player is no longer in. */ + public volatile int numberOfChunksWaitingToGenerate = 0; + + /** how many chunks to generate outside of the player's + * view distance at one time. (or more specifically how + * many requests to make at one time) */ + public int maxChunkGenRequests = Runtime.getRuntime().availableProcessors(); + + + public LodNodeBufferBuilder(LodChunkBuilder newLodBuilder) + { + mc = Minecraft.getInstance(); + lodChunkBuilder = newLodBuilder; + } + + + private BiomeContainer biomeContainer = null; + private LodDimension previousDimension = null; + + + /** + * Create a thread to asynchronously generate LOD buffers + * centered around the given camera X and Z. + *
+ * This method will write to the drawableNearBuffers and drawableFarBuffers. + *
+ * After the buildable buffers have been generated they must be + * swapped with the drawable buffers in the LodRenderer to be drawn. + */ + public void generateLodBuffersAsync(LodRenderer renderer, LodQuadTreeDimension lodDim, + double playerX, double playerZ, int numbChunksWide) + { + // only allow one generation process to happen at a time + if (generatingBuffers) + return; + + if (buildableNearBuffer == null || buildableFarBuffer == null) + throw new IllegalStateException("generateLodBuffersAsync was called before the buildableNearBuffer and buildableFarBuffer were created."); + + if (previousDimension != lodDim) + { + biomeContainer = LodUtil.getServerWorldFromDimension(lodDim.dimension).getChunk(0, 0, ChunkStatus.EMPTY).getBiomes(); + previousDimension = lodDim; + } + + + + generatingBuffers = true; + + + + // this seemingly useless math is required, + // just using (int) playerX/Z doesn't work + int playerXChunkOffset = ((int) playerX / LodChunk.WIDTH) * LodChunk.WIDTH; + int playerZChunkOffset = ((int) playerZ / LodChunk.WIDTH) * LodChunk.WIDTH; + // this is where we will start drawing squares + // (exactly half the total width) + int startX = (-LodChunk.WIDTH * (numbChunksWide / 2)) + playerXChunkOffset; + int startZ = (-LodChunk.WIDTH * (numbChunksWide / 2)) + playerZChunkOffset; + + + Thread t = new Thread(()-> + { + // index of the chunk currently being added to the + // generation list + int chunkGenIndex = 0; + + ChunkPos[] chunksToGen = new ChunkPos[maxChunkGenRequests]; + // if we don't have a full number of chunks to generate in chunksToGen + // we can top it off from the reserve + ChunkPos[] chunksToGenReserve = new ChunkPos[maxChunkGenRequests]; + int minChunkDist = Integer.MAX_VALUE; + ChunkPos playerChunkPos = new ChunkPos((int)playerX / LodChunk.WIDTH, (int)playerZ / LodChunk.WIDTH); + + + // generate our new buildable buffers + buildableNearBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); + buildableFarBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); + + // x axis + for (int i = 0; i < numbChunksWide; i++) + { + // z axis + for (int j = 0; j < numbChunksWide; j++) + { + int chunkX = i + (startX / LodChunk.WIDTH); + int chunkZ = j + (startZ / LodChunk.WIDTH); + + // skip any chunks that Minecraft is going to render + if(isCoordInCenterArea(i, j, (numbChunksWide / 2)) + && renderer.vanillaRenderedChunks.contains(new ChunkPos(chunkX, chunkZ))) + { + continue; + } + + + // set where this square will be drawn in the world + double xOffset = (LodChunk.WIDTH * i) + // offset by the number of LOD blocks + startX; // offset so the center LOD block is centered underneath the player + double yOffset = 0; + double zOffset = (LodChunk.WIDTH * j) + startZ; + + LodChunk lod = lodDim.getLodFromCoordinates(chunkX, chunkZ, LodNodeData.CHUNK_LEVEL); + + if (lod == null || lod.isLodEmpty()) + { + // generate a new chunk if no chunk currently exists + // and we aren't waiting on any other chunks to generate + if (lod == null && numberOfChunksWaitingToGenerate < maxChunkGenRequests) + { + ChunkPos pos = new ChunkPos(chunkX, chunkZ); + + // determine if this position is closer to the player + // than the previous + int newDistance = playerChunkPos.getChessboardDistance(pos); + + if (newDistance < minChunkDist) + { + // this chunk is closer, clear any previous + // positions and update the new minimum distance + minChunkDist = newDistance; + chunksToGenReserve = chunksToGen; + + chunkGenIndex = 0; + chunksToGen = new ChunkPos[maxChunkGenRequests]; + chunksToGen[chunkGenIndex] = pos; + chunkGenIndex++; + } + else if (newDistance <= minChunkDist) + { + // this chunk position is as close or closers than the + // minimum distance + if(chunkGenIndex < maxChunkGenRequests) + { + // we are still under the number of chunks to generate + // add this position to the list + chunksToGen[chunkGenIndex] = pos; + chunkGenIndex++; + } + } + + } + // don't render this null chunk + continue; + } + + + BufferBuilder currentBuffer = null; + if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2)) + currentBuffer = buildableNearBuffer; + else + currentBuffer = buildableFarBuffer; + + // get the desired LodTemplate and + // add this LOD to the buffer + LodConfig.CLIENT.lodTemplate.get(). + template.addLodToBuffer(currentBuffer, lodDim, lod, + xOffset, yOffset, zOffset, renderer.debugging); + } + } + + // TODO add a way for a server side mod to generate chunks requested here + if(mc.hasSingleplayerServer()) + { + ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension); + + // make sure we have as many chunks to generate as we are allowed + if (chunkGenIndex < maxChunkGenRequests) + { + for(int i = chunkGenIndex, j = 0; i < maxChunkGenRequests; i++, j++) + { + chunksToGen[i] = chunksToGenReserve[j]; + } + } + + // start chunk generation + for(ChunkPos chunkPos : chunksToGen) + { + if(chunkPos == null) + break; + + numberOfChunksWaitingToGenerate++; + + LodChunkGenWorker genWorker = new LodChunkGenWorker(chunkPos, renderer, lodChunkBuilder, this, lodDim, serverWorld, biomeContainer); + WorldWorkerManager.addWorker(genWorker); + } + } + + // finish the buffer building + buildableNearBuffer.end(); + buildableFarBuffer.end(); + + // mark that the buildable buffers as ready to swap + generatingBuffers = false; + switchBuffers = true; + }); + + genThread.execute(t); + + return; + } + + + + + + + + + + + //====================// + // generation helpers // + //====================// + + /** + * Returns if the given coordinate is in the loaded area of the world. + * @param centerCoordinate the center of the loaded world + */ + private boolean isCoordInCenterArea(int i, int j, int centerCoordinate) + { + return (i >= centerCoordinate - mc.options.renderDistance + && i <= centerCoordinate + mc.options.renderDistance) + && + (j >= centerCoordinate - mc.options.renderDistance + && j <= centerCoordinate + mc.options.renderDistance); + } + + + /** + * Find the coordinates that are in the center half of the given + * 2D matrix, starting at (0,0) and going to (2 * lodRadius, 2 * lodRadius). + */ + private static boolean isCoordinateInNearFogArea(int chunkX, int chunkZ, int lodRadius) + { + int halfRadius = lodRadius / 2; + + return (chunkX >= lodRadius - halfRadius + && chunkX <= lodRadius + halfRadius) + && + (chunkZ >= lodRadius - halfRadius + && chunkZ <= lodRadius + halfRadius); + } + + + + + + //===============================// + // BufferBuilder related methods // + //===============================// + + + /** + * Called from the LodRenderer to create the + * BufferBuilders at the right size. + * + * @param bufferMaxCapacity + */ + public void setupBuffers(int bufferMaxCapacity) + { + buildableNearBuffer = new BufferBuilder(bufferMaxCapacity); + buildableFarBuffer = new BufferBuilder(bufferMaxCapacity); + } + + /** + * Swap the drawable and buildable buffers and return + * the old drawable buffers. + * @param drawableNearBuffer + * @param drawableFarBuffer + */ + public NearFarBuffer swapBuffers(BufferBuilder drawableNearBuffer, BufferBuilder drawableFarBuffer) + { + // swap the BufferBuilders + BufferBuilder tmp = buildableNearBuffer; + buildableNearBuffer = drawableNearBuffer; + drawableNearBuffer = tmp; + + tmp = buildableFarBuffer; + buildableFarBuffer = drawableFarBuffer; + drawableFarBuffer = tmp; + + + // the buffers have been swapped + switchBuffers = false; + + return new NearFarBuffer(drawableNearBuffer, drawableFarBuffer); + } + + /** + * If this is true the buildable near and far + * buffers have been generated and are ready to be + * sent to the LodRenderer. + */ + public boolean newBuffersAvaliable() + { + return switchBuffers; + } + + + + +} \ No newline at end of file diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java b/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java index d0b15f41c..7a818fa30 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java @@ -204,7 +204,6 @@ public class LodNodeData { } - public int hashCode(){ return Objects.hash(this.real, this.level, this.posX, this.posZ, this.color, this.real, this.voidNode); } diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index 83f806d41..625014f0e 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -171,10 +171,10 @@ public class LodQuadTree { return lodNodeData; } else if (targetLevel < currentLevel) { short widthRatio = (short) (lodNodeData.width / Math.pow(2, level)); - int NS = (posX / widthRatio) % lodNodeData.posX; - int WE = (posZ / widthRatio) % lodNodeData.posZ; + int NS = Math.abs((posX / widthRatio) % lodNodeData.posX); + int WE = Math.abs((posZ / widthRatio) % lodNodeData.posZ); if (getChild(NS, WE) == null) { - return lodNodeData; + return null; } LodQuadTree child = getChild(NS, WE); return child.getNodeAtLevelPosition(posX, posZ, level); @@ -184,6 +184,7 @@ public class LodQuadTree { } + public LodQuadTree getChild(int NS, int WE) { return children[NS][WE]; } @@ -439,9 +440,14 @@ public class LodQuadTree { return (lodNodeData != null); } + public LodNodeData getLodFromCoordinate(int x, int z, byte level){ + + } + public boolean isCoordinateInLevel(int x, int z){ return !(lodNodeData.startX > x || lodNodeData.startZ > z || lodNodeData.endX < x || lodNodeData.endZ < z); } + public String toString(){ String s = lodNodeData.toString(); return s; diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java index b0d050084..9f78ef4c3 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -297,15 +297,15 @@ public class LodQuadTreeDimension { */ public LodNodeData getLodFromCoordinates(int posX, int posZ, byte level) { - /*TODO */ - return null; + LodQuadTree region = getRegion(posX/(512/Math.pow(level,2)),posZ/(512/Math.pow(level,2))); + if(region == null) + return null; + return region.getLodFromCoordinate(posX, posZ, level); /* RegionPos pos = LodUtil.convertChunkPosToRegionPos(new ChunkPos(chunkX, chunkZ)); LodQuadTree region = getRegion(pos.x, pos.z); - if(region == null) - return null; return region.getNode(chunkX, chunkZ); diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 0929102de..0fdf86342 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -2,6 +2,7 @@ package com.seibel.lod.objects.quadTree; import com.seibel.lod.util.BiomeColorsUtils; import kaptainwutax.biomeutils.biome.Biome; +import kaptainwutax.biomeutils.source.EndBiomeSource; import kaptainwutax.biomeutils.source.OverworldBiomeSource; import kaptainwutax.mcutils.version.MCVersion; @@ -35,7 +36,7 @@ import javax.swing.Timer; @SuppressWarnings("serial") public class QuadTreeImage extends JPanel { - private static final int PREF_W = (int) 0.1*16*512; + private static final int PREF_W = 1000; private static final int PREF_H = PREF_W; private List drawables = new ArrayList<>(); @@ -74,9 +75,9 @@ public class QuadTreeImage extends JPanel { } private static void createAndShowGui() { - int playerX = 8*512; - int playerZ = (8*512); - LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 16); + int playerX = 32*512; + int playerZ = (32*512); + LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 64); System.out.println(dim.getRegion(0, 0)); dim.move(playerX/512,playerZ/512); System.out.println(dim.getCenterX()); @@ -92,16 +93,18 @@ public class QuadTreeImage extends JPanel { frame.setLocationByPlatform(true); frame.setVisible(true); List> listOfList = new ArrayList<>(); - OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 100); + //OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 1000); + EndBiomeSource biomeSource = new EndBiomeSource(MCVersion.v1_16_5, 1000); + int[] distances = {100000,8000,4000,2000,1000,500,250,100,50,25}; for (int i = 0; i <= (9 - 2); i++) { for (int j = 0; j < 1; j++) { int dist; - if (i == 9) { - dist = 30; + if (i == 0) { + dist = 2000; } else { - dist = 30; + dist = 32; } - List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), (int) (dist*Math.pow(9-i,2.5)), 0); + List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), distances[i], 0); for (LodQuadTree level : levelToGenerate) { Color color; int startX = level.getLodNodeData().startX; @@ -138,12 +141,15 @@ public class QuadTreeImage extends JPanel { } } } - List lodList = dim.getNodeToRender(playerX,playerZ,(byte) 8, 10000,4000); + List lodList = new ArrayList<>(); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 9, 100000,8000)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 8, 8000,4000)); lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 7, 4000,2000)); lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 6, 2000,1000)); lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 5, 1000,500)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 4, 500,0)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 4, 500,250)); lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 3, 250,0)); + System.out.println(lodList.size()); //Collection lodList = dim.getNodes(false,false,false); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); @@ -171,7 +177,7 @@ public class QuadTreeImage extends JPanel { } else { if(drawCount==0) quadTreeImage.clearAll(); final List myDrawables = new ArrayList<>(); - double amp = 0.1; + double amp = 0.025; Collection lodList = listOfList.get(drawCount); for (LodNodeData data : lodList) { System.out.println(); @@ -196,7 +202,7 @@ public class QuadTreeImage extends JPanel { frame.printAll(g2d); g2d.dispose(); try { - ImageIO.write(img, "png", new File("Img" + drawCount+".png")); + ImageIO.write(img, "png", new File("ImgEnd" + drawCount+".png")); } catch (IOException ioException) { ioException.printStackTrace(); } diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index 02a450897..66ceb45bc 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -1,5 +1,9 @@ package com.seibel.lod.proxy; +import com.seibel.lod.builders.LodNodeBufferBuilder; +import com.seibel.lod.builders.LodNodeBuilder; +import com.seibel.lod.objects.quadTree.LodQuadTreeWorld; +import com.seibel.lod.render.LodNodeRenderer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -31,10 +35,10 @@ public class ClientProxy { public static final Logger LOGGER = LogManager.getLogger("LOD"); - private static LodWorld lodWorld = new LodWorld(); - private static LodChunkBuilder lodChunkBuilder = new LodChunkBuilder(); - private static LodBufferBuilder lodBufferBuilder = new LodBufferBuilder(lodChunkBuilder); - private static LodRenderer renderer = new LodRenderer(lodBufferBuilder); + private static LodQuadTreeWorld lodWorld = new LodQuadTreeWorld(); + private static LodNodeBuilder lodChunkBuilder = new LodNodeBuilder(); + private static LodNodeBufferBuilder lodBufferBuilder = new LodNodeBufferBuilder(lodChunkBuilder); + private static LodNodeRenderer renderer = new LodNodeRenderer(lodBufferBuilder); Minecraft mc = Minecraft.getInstance(); diff --git a/src/main/java/com/seibel/lod/render/LodNodeRenderer.java b/src/main/java/com/seibel/lod/render/LodNodeRenderer.java new file mode 100644 index 000000000..71d297d4e --- /dev/null +++ b/src/main/java/com/seibel/lod/render/LodNodeRenderer.java @@ -0,0 +1,844 @@ +package com.seibel.lod.render; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import com.seibel.lod.builders.LodBufferBuilder; +import com.seibel.lod.builders.LodNodeBufferBuilder; +import com.seibel.lod.enums.FogDistance; +import com.seibel.lod.enums.FogDrawOverride; +import com.seibel.lod.enums.FogQuality; +import com.seibel.lod.handlers.LodConfig; +import com.seibel.lod.handlers.ReflectionHandler; +import com.seibel.lod.objects.LodChunk; +import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.NearFarBuffer; +import com.seibel.lod.objects.NearFarFogSettings; +import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.proxy.ClientProxy; +import net.minecraft.client.Minecraft; +import net.minecraft.client.entity.player.ClientPlayerEntity; +import net.minecraft.client.renderer.*; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import net.minecraft.client.renderer.vertex.VertexBuffer; +import net.minecraft.client.renderer.vertex.VertexFormat; +import net.minecraft.potion.Effects; +import net.minecraft.profiler.IProfiler; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.vector.Matrix4f; +import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.util.math.vector.Vector3f; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.NVFogDistance; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.FloatBuffer; +import java.util.HashSet; + + +/** + * This is where all the magic happens.
+ * This is where LODs are draw to the world. + * + * @author James Seibel + * @version 07-4-2021 + */ +public class LodNodeRenderer +{ + /** this is the light used when rendering the LODs, + * it should be something different than what is used by Minecraft */ + private static final int LOD_GL_LIGHT_NUMBER = GL11.GL_LIGHT2; + + /** + * 64 MB by default is the maximum amount of memory that + * can be directly allocated.

+ * + * I know there are commands to change that amount + * (specifically "-XX:MaxDirectMemorySize"), but + * I have no idea how to access that amount.
+ * So I guess this will be the hard limit for now.

+ * + * https://stackoverflow.com/questions/50499238/bytebuffer-allocatedirect-and-xmx + */ + public static final int MAX_ALOCATEABLE_DIRECT_MEMORY = 64 * 1024 * 1024; + + /** Does this computer's GPU support fancy fog? */ + public static boolean fancyFogAvailable = false; + + + + /** If true the LODs colors will be replaced with + * a checkerboard, this can be used for debugging. */ + public boolean debugging = false; + + private Minecraft mc; + private GameRenderer gameRender; + private IProfiler profiler; + private float farPlaneDistance; + private ReflectionHandler reflectionHandler; + + + /** This is used to generate the buildable buffers */ + private LodNodeBufferBuilder lodNodeBufferBuilder; + + /** The buffers that are used to draw LODs using near fog */ + private volatile BufferBuilder drawableNearBuffer; + /** The buffers that are used to draw LODs using far fog */ + private volatile BufferBuilder drawableFarBuffer; + + /** This is the VertexBuffer used to draw any LODs that use near fog */ + private volatile VertexBuffer nearVbo; + /** This is the VertexBuffer used to draw any LODs that use far fog */ + private volatile VertexBuffer farVbo; + public static final VertexFormat LOD_VERTEX_FORMAT = DefaultVertexFormats.POSITION_COLOR; + + + /** This is used to determine if the LODs should be regenerated */ + private int previousChunkRenderDistance = 0; + /** This is used to determine if the LODs should be regenerated */ + private int prevChunkX = 0; + /** This is used to determine if the LODs should be regenerated */ + private int prevChunkZ = 0; + /** This is used to determine if the LODs should be regenerated */ + private FogDistance prevFogDistance = FogDistance.NEAR_AND_FAR; + + /** if this is true the LOD buffers should be regenerated, + * provided they aren't already being regenerated. */ + private volatile boolean regen = false; + + /** This HashSet contains every chunk that Vanilla Minecraft + * is going to render */ + public HashSet vanillaRenderedChunks = new HashSet<>(); + + + + public LodNodeRenderer(LodNodeBufferBuilder newLodNodeBufferBuilder) + { + mc = Minecraft.getInstance(); + gameRender = mc.gameRenderer; + + reflectionHandler = new ReflectionHandler(); + lodNodeBufferBuilder = newLodNodeBufferBuilder; + } + + + /** + * Besides drawing the LODs this method also starts + * the async process of generating the Buffers that hold those LODs. + * + * @param newDimension The dimension to draw, if null doesn't replace the current dimension. + * @param partialTicks how far into the current tick this method was called. + */ + public void drawLODs(LodDimension lodDim, float partialTicks, IProfiler newProfiler) + { + if (lodDim == null) + { + // if there aren't any loaded LodChunks + // don't try drawing anything + return; + } + + + + + + + //===============// + // initial setup // + //===============// + + profiler = newProfiler; + profiler.push("LOD setup"); + + ClientPlayerEntity player = mc.player; + + // should LODs be regenerated? + if ((int)player.getX() / LodChunk.WIDTH != prevChunkX || + (int)player.getZ() / LodChunk.WIDTH != prevChunkZ || + previousChunkRenderDistance != mc.options.renderDistance || + prevFogDistance != LodConfig.CLIENT.fogDistance.get()) + { + // yes + regen = true; + + prevChunkX = (int)player.getX() / LodChunk.WIDTH; + prevChunkZ = (int)player.getZ() / LodChunk.WIDTH; + prevFogDistance = LodConfig.CLIENT.fogDistance.get(); + } + else + { + // nope, the player hasn't moved, the + // render distance hasn't changed, and + // the dimension is the same + } + + // did the user change the debug setting? + if (LodConfig.CLIENT.debugMode.get() != debugging) + { + debugging = LodConfig.CLIENT.debugMode.get(); + regen = true; + } + + + // determine how far the game's render distance is currently set + int renderDistWidth = mc.options.renderDistance; + farPlaneDistance = renderDistWidth * LodChunk.WIDTH; + + // set how big the LODs will be and how far they will go + int totalLength = (int) farPlaneDistance * LodConfig.CLIENT.lodChunkRadiusMultiplier.get() * 10; + int numbChunksWide = (totalLength / LodChunk.WIDTH); + + // determine which LODs should not be rendered close to the player + HashSet chunkPosToSkip = getNearbyLodChunkPosToSkip(lodDim, player.blockPosition()); + + // see if the chunks Minecraft is going to render are the + // same as last time + if (!vanillaRenderedChunks.containsAll(chunkPosToSkip)) + { + regen = true; + vanillaRenderedChunks = chunkPosToSkip; + } + + + + + + //=================// + // create the LODs // + //=================// + + // only regenerate the LODs if: + // 1. we want to regenerate LODs + // 2. we aren't already regenerating the LODs + // 3. we aren't waiting for the build and draw buffers to swap + // (this is to prevent thread conflicts) + if (regen && !lodNodeBufferBuilder.generatingBuffers && !lodNodeBufferBuilder.newBuffersAvaliable()) + { + // this will mainly happen when the view distance is changed + if (drawableNearBuffer == null || drawableFarBuffer == null || + previousChunkRenderDistance != mc.options.renderDistance) + setupBuffers(numbChunksWide); + + // generate the LODs on a separate thread to prevent stuttering or freezing + lodNodeBufferBuilder.generateLodBuffersAsync(this, lodDim, player.getX(), player.getZ(), numbChunksWide); + + // the regen process has been started, + // it will be done when lodBufferBuilder.newBuffersAvaliable + // is true + regen = false; + } + + // replace the buffers used to draw and build, + // this is only done when the createLodBufferGenerationThread + // has finished executing on a parallel thread. + if (lodBufferBuilder.newBuffersAvaliable()) + { + swapBuffers(); + } + + + + + + //===========================// + // GL settings for rendering // + //===========================// + + // set the required open GL settings + GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glDisable(GL11.GL_TEXTURE_2D); + GL11.glEnable(GL11.GL_CULL_FACE); + GL11.glEnable(GL11.GL_COLOR_MATERIAL); + GL11.glEnable(GL11.GL_DEPTH_TEST); + + // disable the lights Minecraft uses + GL11.glDisable(GL11.GL_LIGHT0); + GL11.glDisable(GL11.GL_LIGHT1); + + // get the default projection matrix so we can + // reset it after drawing the LODs + float[] defaultProjMatrix = new float[16]; + GL11.glGetFloatv(GL11.GL_PROJECTION_MATRIX, defaultProjMatrix); + + Matrix4f modelViewMatrix = generateModelViewMatrix(partialTicks); + + setupProjectionMatrix(partialTicks); + setupLighting(lodDim, partialTicks); + + NearFarFogSettings fogSettings = determineFogSettings(); + + // determine the current fog settings so they can be + // reset after drawing the LODs + float defaultFogStartDist = GL11.glGetFloat(GL11.GL_FOG_START); + float defaultFogEndDist = GL11.glGetFloat(GL11.GL_FOG_END); + int defaultFogMode = GL11.glGetInteger(GL11.GL_FOG_MODE); + int defaultFogDistance = GL11.glGetInteger(NVFogDistance.GL_FOG_DISTANCE_MODE_NV); + + + + + + + //===========// + // rendering // + //===========// + profiler.popPush("LOD draw"); + + setupFog(fogSettings.near.distance, fogSettings.near.quality); + sendLodsToGpuAndDraw(nearVbo, modelViewMatrix); + + setupFog(fogSettings.far.distance, fogSettings.far.quality); + sendLodsToGpuAndDraw(farVbo, modelViewMatrix); + + + + + + //=========// + // cleanup // + //=========// + + profiler.popPush("LOD cleanup"); + + GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); + GL11.glEnable(GL11.GL_TEXTURE_2D); + GL11.glDisable(LOD_GL_LIGHT_NUMBER); + // re-enable the lights Minecraft uses + GL11.glEnable(GL11.GL_LIGHT0); + GL11.glEnable(GL11.GL_LIGHT1); + RenderSystem.disableLighting(); + + // this can't be called until after the buffers are built + // because otherwise the buffers may be set to the wrong size + previousChunkRenderDistance = mc.options.renderDistance; + + // reset the fog settings so the normal chunks + // will be drawn correctly + cleanupFog(fogSettings, defaultFogStartDist, defaultFogEndDist, defaultFogMode, defaultFogDistance); + + // reset the projection matrix so anything drawn after + // the LODs will use the correct projection matrix + Matrix4f mvm = new Matrix4f(defaultProjMatrix); + mvm.transpose(); + gameRender.resetProjectionMatrix(mvm); + + // clear the depth buffer so anything drawn is drawn + // over the LODs + GL11.glClear(GL11.GL_DEPTH_BUFFER_BIT); + + + // end of internal LOD profiling + profiler.pop(); + } + + + + /** + * This is where the actual drawing happens. + * + * @param buffers the buffers sent to the GPU to draw + */ + private void sendLodsToGpuAndDraw(VertexBuffer vbo, Matrix4f modelViewMatrix) + { + if (vbo == null) + return; + + vbo.bind(); + // 0L is the starting pointer + LOD_VERTEX_FORMAT.setupBufferState(0L); + + vbo.draw(modelViewMatrix, GL11.GL_QUADS); + + VertexBuffer.unbind(); + LOD_VERTEX_FORMAT.clearBufferState(); + } + + + + + + + + //=================// + // Setup Functions // + //=================// + + @SuppressWarnings("deprecation") + private void setupFog(FogDistance fogDistance, FogQuality fogQuality) + { + if(fogQuality == FogQuality.OFF) + { + FogRenderer.setupNoFog(); + RenderSystem.disableFog(); + return; + } + + if(fogDistance == FogDistance.NEAR_AND_FAR) + { + throw new IllegalArgumentException("setupFog doesn't accept the NEAR_AND_FAR fog distance."); + } + + + // determine the fog distance mode to use + int glFogDistanceMode = NVFogDistance.GL_EYE_RADIAL_NV; + if (fogQuality == FogQuality.FANCY) + { + // fancy fog (fragment distance based fog) + glFogDistanceMode = NVFogDistance.GL_EYE_RADIAL_NV; + } + else + { + // fast fog (frustum distance based fog) + glFogDistanceMode = NVFogDistance.GL_EYE_PLANE_ABSOLUTE_NV; + } + + + // the multipliers are percentages + // of the regular view distance. + if(fogDistance == FogDistance.NEAR) + { + // the reason that I wrote fogEnd then fogStart backwards + // is because we are using fog backwards to how + // it is normally used, with it hiding near objects + // instead of far objects. + + if (fogQuality == FogQuality.FANCY) + { + RenderSystem.fogEnd(farPlaneDistance * 1.75f); + RenderSystem.fogStart(farPlaneDistance * 1.95f); + } + else if(fogQuality == FogQuality.FAST) + { + // for the far fog of the normal chunks + // to start right where the LODs' end use: + // end = 0.8f, start = 1.5f + + RenderSystem.fogEnd(farPlaneDistance * 1.5f); + RenderSystem.fogStart(farPlaneDistance * 2.0f); + } + } + else if(fogDistance == FogDistance.FAR) + { + if (fogQuality == FogQuality.FANCY) + { + RenderSystem.fogStart(farPlaneDistance * 0.85f * LodConfig.CLIENT.lodChunkRadiusMultiplier.get()); + RenderSystem.fogEnd(farPlaneDistance * 1.0f * LodConfig.CLIENT.lodChunkRadiusMultiplier.get()); + } + else if(fogQuality == FogQuality.FAST) + { + RenderSystem.fogStart(farPlaneDistance * 0.5f * LodConfig.CLIENT.lodChunkRadiusMultiplier.get()); + RenderSystem.fogEnd(farPlaneDistance * 0.75f * LodConfig.CLIENT.lodChunkRadiusMultiplier.get()); + } + } + + + GL11.glEnable(GL11.GL_FOG); + RenderSystem.enableFog(); + RenderSystem.setupNvFogDistance(); + RenderSystem.fogMode(GlStateManager.FogMode.LINEAR); + GL11.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, glFogDistanceMode); + } + + /** + * Revert any changes that were made to the fog. + */ + private void cleanupFog(NearFarFogSettings fogSettings, + float defaultFogStartDist, float defaultFogEndDist, + int defaultFogMode, int defaultFogDistance) + { + RenderSystem.fogStart(defaultFogStartDist); + RenderSystem.fogEnd(defaultFogEndDist); + RenderSystem.fogMode(defaultFogMode); + GL11.glFogi(NVFogDistance.GL_FOG_DISTANCE_MODE_NV, defaultFogDistance); + + // disable fog if Minecraft wasn't rendering fog + // but we were + if(!fogSettings.vanillaIsRenderingFog && + (fogSettings.near.quality != FogQuality.OFF || + fogSettings.far.quality != FogQuality.OFF)) + { + GL11.glDisable(GL11.GL_FOG); + } + } + + + /** + * Create the model view matrix to move the LODs + * from object space into world space. + */ + private Matrix4f generateModelViewMatrix(float partialTicks) + { + // get all relevant camera info + ActiveRenderInfo renderInfo = mc.gameRenderer.getMainCamera(); + Vector3d projectedView = renderInfo.getPosition(); + + + // generate the model view matrix + MatrixStack matrixStack = new MatrixStack(); + matrixStack.pushPose(); + // translate and rotate to the current camera location + matrixStack.mulPose(Vector3f.XP.rotationDegrees(renderInfo.getXRot())); + matrixStack.mulPose(Vector3f.YP.rotationDegrees(renderInfo.getYRot() + 180)); + matrixStack.translate(-projectedView.x, -projectedView.y, -projectedView.z); + + return matrixStack.last().pose(); + } + + + /** + * create a new projection matrix and send it over to the GPU + *

+ * A lot of this code is copied from renderLevel (line 567) + * in the GameRender class. The code copied is anything with + * a matrixStack and is responsible for making sure the LOD + * objects distort correctly relative to the rest of the world. + * Distortions are caused by: standing in a nether portal, + * nausea potion effect, walking bobbing. + * + * @param partialTicks how many ticks into the frame we are + */ + private void setupProjectionMatrix(float partialTicks) + { + // Note: if the LOD objects don't distort correctly + // compared to regular minecraft terrain, make sure + // all the transformations in renderWorld are here too + + MatrixStack matrixStack = new MatrixStack(); + matrixStack.pushPose(); + + gameRender.bobHurt(matrixStack, partialTicks); + if (this.mc.options.bobView) { + gameRender.bobView(matrixStack, partialTicks); + } + + // potion and nausea effects + float f = MathHelper.lerp(partialTicks, this.mc.player.oPortalTime, this.mc.player.portalTime) * this.mc.options.screenEffectScale * this.mc.options.screenEffectScale; + if (f > 0.0F) { + int i = this.mc.player.hasEffect(Effects.CONFUSION) ? 7 : 20; + float f1 = 5.0F / (f * f + 5.0F) - f * 0.04F; + f1 = f1 * f1; + Vector3f vector3f = new Vector3f(0.0F, MathHelper.SQRT_OF_TWO / 2.0F, MathHelper.SQRT_OF_TWO / 2.0F); + matrixStack.mulPose(vector3f.rotationDegrees((gameRender.tick + partialTicks) * i)); + matrixStack.scale(1.0F / f1, 1.0F, 1.0F); + float f2 = -(gameRender.tick + partialTicks) * i; + matrixStack.mulPose(vector3f.rotationDegrees(f2)); + } + + + + // this projection matrix allows us to see past the normal + // world render distance + Matrix4f projectionMatrix = + Matrix4f.perspective( + getFov(partialTicks, true), + (float)this.mc.getWindow().getScreenWidth() / (float)this.mc.getWindow().getScreenHeight(), + 0.5F, + this.farPlaneDistance * LodConfig.CLIENT.lodChunkRadiusMultiplier.get() * 2); + + // add the screen space distortions + projectionMatrix.multiply(matrixStack.last().pose()); + gameRender.resetProjectionMatrix(projectionMatrix); + return; + } + + + /** + * setup the lighting to be used for the LODs + */ + private void setupLighting(LodDimension lodDimension, float partialTicks) + { + float sunBrightness = lodDimension.dimension.hasSkyLight() ? mc.level.getSkyDarken(partialTicks) : 0.2f; + float gammaMultiplyer = (float)mc.options.gamma - 0.5f; + float lightStrength = ((sunBrightness / 2f) - 0.2f) + (gammaMultiplyer * 0.2f); + + float lightAmbient[] = {lightStrength, lightStrength, lightStrength, 1.0f}; + + // can be used for debugging +// if (partialTicks < 0.005) +// ClientProxy.LOGGER.debug(lightStrength); + + ByteBuffer temp = ByteBuffer.allocateDirect(16); + temp.order(ByteOrder.nativeOrder()); + GL11.glLightfv(LOD_GL_LIGHT_NUMBER, GL11.GL_AMBIENT, (FloatBuffer) temp.asFloatBuffer().put(lightAmbient).flip()); + GL11.glEnable(LOD_GL_LIGHT_NUMBER); // Enable the above lighting + + RenderSystem.enableLighting(); + } + + /** + * Create all buffers that will be used. + */ + private void setupBuffers(int numbChunksWide) + { + // calculate the max amount of memory needed (in bytes) + int bufferMemory = RenderUtil.getBufferMemoryForRadiusMultiplier(LodConfig.CLIENT.lodChunkRadiusMultiplier.get()); + + // if the required memory is greater than the + // MAX_ALOCATEABLE_DIRECT_MEMORY lower the lodChunkRadiusMultiplier + // to fit. + if (bufferMemory > MAX_ALOCATEABLE_DIRECT_MEMORY) + { + int maxRadiusMultiplier = RenderUtil.getMaxRadiusMultiplierWithAvaliableMemory(LodConfig.CLIENT.lodTemplate.get(), LodConfig.CLIENT.lodDetail.get()); + + ClientProxy.LOGGER.warn("The lodChunkRadiusMultiplier was set too high " + + "and had to be lowered to fit memory constraints " + + "from " + LodConfig.CLIENT.lodChunkRadiusMultiplier.get() + " " + + "to " + maxRadiusMultiplier); + + LodConfig.CLIENT.lodChunkRadiusMultiplier.set( + maxRadiusMultiplier); + + bufferMemory = RenderUtil.getBufferMemoryForRadiusMultiplier(maxRadiusMultiplier); + } + + drawableNearBuffer = new BufferBuilder(bufferMemory); + drawableFarBuffer = new BufferBuilder(bufferMemory); + + lodNodeBufferBuilder.setupBuffers(bufferMemory); + } + + + + + + //======================// + // Other Misc Functions // + //======================// + + /** + * If this is called then the next time "drawLODs" is called + * the LODs will be regenerated; the same as if the player moved. + */ + public void regenerateLODsNextFrame() + { + regen = true; + } + + + /** + * Replace the current drawable buffers with the newly + * created buffers from the lodBufferBuilder. + */ + private void swapBuffers() + { + // replace the drawable buffers with + // the newly created buffers from the lodBufferBuilder + NearFarBuffer newBuffers = lodNodeBufferBuilder.swapBuffers(drawableNearBuffer, drawableFarBuffer); + drawableNearBuffer = newBuffers.nearBuffer; + drawableFarBuffer = newBuffers.farBuffer; + + + // bind the buffers with their respective VBOs + if (nearVbo != null) + nearVbo.close(); + + nearVbo = new VertexBuffer(LOD_VERTEX_FORMAT); + nearVbo.upload(drawableNearBuffer); + + + if (farVbo != null) + farVbo.close(); + + farVbo = new VertexBuffer(LOD_VERTEX_FORMAT); + farVbo.upload(drawableFarBuffer); + } + + + private double getFov(float partialTicks, boolean useFovSetting) + { + return mc.gameRenderer.getFov(mc.gameRenderer.getMainCamera(), partialTicks, useFovSetting); + } + + + /** + * Return what fog settings should be used when rendering. + */ + private NearFarFogSettings determineFogSettings() + { + NearFarFogSettings fogSettings = new NearFarFogSettings(); + + + FogQuality quality = reflectionHandler.getFogQuality(); + FogDrawOverride override = LodConfig.CLIENT.fogDrawOverride.get(); + + + if (quality == FogQuality.OFF) + fogSettings.vanillaIsRenderingFog = false; + else + fogSettings.vanillaIsRenderingFog = true; + + + // use any fog overrides the user may have set + switch(override) + { + case ALWAYS_DRAW_FOG_FANCY: + quality = FogQuality.FANCY; + break; + + case NEVER_DRAW_FOG: + quality = FogQuality.OFF; + break; + + case ALWAYS_DRAW_FOG_FAST: + quality = FogQuality.FAST; + break; + + case USE_OPTIFINE_FOG_SETTING: + // don't override anything + break; + } + + + // only use fancy fog if the user's GPU can deliver + if (!fancyFogAvailable && quality == FogQuality.FANCY) + { + quality = FogQuality.FAST; + } + + + // how different distances are drawn depends on the quality set + switch(quality) + { + case FANCY: + fogSettings.near.quality = FogQuality.FANCY; + fogSettings.far.quality = FogQuality.FANCY; + + switch(LodConfig.CLIENT.fogDistance.get()) + { + case NEAR_AND_FAR: + fogSettings.near.distance = FogDistance.NEAR; + fogSettings.far.distance = FogDistance.FAR; + break; + + case NEAR: + fogSettings.near.distance = FogDistance.NEAR; + fogSettings.far.distance = FogDistance.NEAR; + break; + + case FAR: + fogSettings.near.distance = FogDistance.FAR; + fogSettings.far.distance = FogDistance.FAR; + break; + } + break; + + case FAST: + fogSettings.near.quality = FogQuality.FAST; + fogSettings.far.quality = FogQuality.FAST; + + // fast fog setting should only have one type of + // fog, since the LODs are separated into a near + // and far portion; and fast fog is rendered from the + // frustrum's perspective instead of the camera + switch(LodConfig.CLIENT.fogDistance.get()) + { + case NEAR_AND_FAR: + fogSettings.near.distance = FogDistance.NEAR; + fogSettings.far.distance = FogDistance.NEAR; + break; + + case NEAR: + fogSettings.near.distance = FogDistance.NEAR; + fogSettings.far.distance = FogDistance.NEAR; + break; + + case FAR: + fogSettings.near.distance = FogDistance.FAR; + fogSettings.far.distance = FogDistance.FAR; + break; + } + break; + + case OFF: + + fogSettings.near.quality = FogQuality.OFF; + fogSettings.far.quality = FogQuality.OFF; + break; + + } + + + return fogSettings; + } + + + + /** + * Get a HashSet of all ChunkPos within the normal render distance + * that should not be rendered. + */ + private HashSet getNearbyLodChunkPosToSkip(LodDimension lodDim, BlockPos playerPos) + { + int chunkRenderDist = mc.options.renderDistance; + int blockRenderDist = chunkRenderDist * 16; + ChunkPos centerChunk = new ChunkPos(playerPos); + + // skip chunks that are already going to be rendered by Minecraft + HashSet posToSkip = getRenderedChunks(); + + + // go through each chunk within the normal view distance + for(int x = centerChunk.x - chunkRenderDist; x < centerChunk.x + chunkRenderDist; x++) + { + for(int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++) + { + LodNodeData lod = lodDim.getLodFromCoordinates(x, z); + if (lod != null) + { + short lodHighestPoint = lod.height(); + + if (playerPos.getY() < lodHighestPoint) + { + // don't draw Lod's that are taller than the player + // to prevent LODs being drawn on top of the player + posToSkip.add(new ChunkPos(x, z)); + } + else if (blockRenderDist < Math.abs(playerPos.getY() - lodHighestPoint)) + { + // draw Lod's that are lower than the player's view range + posToSkip.remove(new ChunkPos(x, z)); + } + } + } + } + + return posToSkip; + } + + /** + * This method returns the ChunkPos of all chunks that Minecraft + * is going to render this frame.

+ * + * Note: This isn't perfect. It will return some chunks that are outside + * the clipping plane. (For example, if you are high above the ground some chunks + * will be incorrectly added, even though they are outside render range). + */ + public static HashSet getRenderedChunks() + { + HashSet loadedPos = new HashSet<>(); + + Minecraft mc = Minecraft.getInstance(); + + // Wow those are some long names! + + // go through every RenderInfo to get the compiled chunks + for(WorldRenderer.LocalRenderInformationContainer worldrenderer$localrenderinformationcontainer : mc.levelRenderer.renderChunks) + { + if (!worldrenderer$localrenderinformationcontainer.chunk.getCompiledChunk().hasNoRenderableLayers()) + { + // add the ChunkPos for every empty compiled chunk + BlockPos bpos = worldrenderer$localrenderinformationcontainer.chunk.getOrigin(); + + loadedPos.add(new ChunkPos(bpos.getX() / 16, bpos.getZ() / 16)); + } + } + + return loadedPos; + } + + +} \ No newline at end of file From f9bb248eef2a9c1ec148cad130d8c3af7abf6cfc Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 21:01:17 +0200 Subject: [PATCH 21/46] Several chages to converto to quadTree --- .../lod/builders/LodNodeBufferBuilder.java | 68 ++++++++++++------- .../lod/objects/quadTree/LodQuadTree.java | 3 - .../quadTree/LodQuadTreeDimension.java | 4 +- .../seibel/lod/render/LodNodeRenderer.java | 13 ++-- 4 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java index 52823b3ad..6adf53599 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -1,6 +1,5 @@ package com.seibel.lod.builders; -import com.seibel.lod.builders.worldGeneration.LodChunkGenWorker; import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; @@ -8,6 +7,7 @@ import com.seibel.lod.objects.NearFarBuffer; import com.seibel.lod.objects.quadTree.LodNodeData; import com.seibel.lod.objects.quadTree.LodQuadTree; import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.render.LodNodeRenderer; import com.seibel.lod.render.LodRenderer; import com.seibel.lod.util.LodUtil; import net.minecraft.client.Minecraft; @@ -19,6 +19,8 @@ import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.WorldWorkerManager; import org.lwjgl.opengl.GL11; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -35,7 +37,7 @@ public class LodNodeBufferBuilder /** This holds the thread used to generate new LODs off the main thread. */ private ExecutorService genThread = Executors.newSingleThreadExecutor(); - private LodChunkBuilder lodChunkBuilder; + private LodNodeBuilder lodChunkBuilder; /** The buffers that are used to create LODs using near fog */ public volatile BufferBuilder buildableNearBuffer; @@ -61,7 +63,7 @@ public class LodNodeBufferBuilder public int maxChunkGenRequests = Runtime.getRuntime().availableProcessors(); - public LodNodeBufferBuilder(LodChunkBuilder newLodBuilder) + public LodNodeBufferBuilder(LodNodeBuilder newLodBuilder) { mc = Minecraft.getInstance(); lodChunkBuilder = newLodBuilder; @@ -69,7 +71,7 @@ public class LodNodeBufferBuilder private BiomeContainer biomeContainer = null; - private LodDimension previousDimension = null; + private LodQuadTreeDimension previousDimension = null; /** @@ -81,7 +83,7 @@ public class LodNodeBufferBuilder * After the buildable buffers have been generated they must be * swapped with the drawable buffers in the LodRenderer to be drawn. */ - public void generateLodBuffersAsync(LodRenderer renderer, LodQuadTreeDimension lodDim, + public void generateLodBuffersAsync(LodNodeRenderer renderer, LodQuadTreeDimension lodDim, double playerX, double playerZ, int numbChunksWide) { // only allow one generation process to happen at a time @@ -130,8 +132,35 @@ public class LodNodeBufferBuilder // generate our new buildable buffers buildableNearBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); buildableFarBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); - + + + List lodList = new ArrayList<>(); + lodList.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 9, 100000,8000)); + lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 8, 8000,4000)); + lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 7, 4000,2000)); + lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 6, 2000,1000)); + lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 5, 1000,500)); + lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 4, 500,250)); + lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 3, 250,0)); + + for(LodNodeData data : lodList){ + BufferBuilder currentBuffer = null; +/* + if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2)) + currentBuffer = buildableNearBuffer; + else + currentBuffer = buildableFarBuffer; + */ + currentBuffer = buildableFarBuffer; + + // get the desired LodTemplate and + // add this LOD to the buffer + LodConfig.CLIENT.lodTemplate.get(). + template.addLodToBuffer(currentBuffer, lodDim, data, + data.startX, 0, data.startZ, renderer.debugging); + } // x axis + /* for (int i = 0; i < numbChunksWide; i++) { // z axis @@ -153,10 +182,10 @@ public class LodNodeBufferBuilder startX; // offset so the center LOD block is centered underneath the player double yOffset = 0; double zOffset = (LodChunk.WIDTH * j) + startZ; + + LodNodeData lod = lodDim.getLodFromCoordinates(chunkX, chunkZ, LodNodeData.CHUNK_LEVEL); - LodChunk lod = lodDim.getLodFromCoordinates(chunkX, chunkZ, LodNodeData.CHUNK_LEVEL); - - if (lod == null || lod.isLodEmpty()) + if (lod == null || lod.voidNode) { // generate a new chunk if no chunk currently exists // and we aren't waiting on any other chunks to generate @@ -197,23 +226,15 @@ public class LodNodeBufferBuilder // don't render this null chunk continue; } + + - - BufferBuilder currentBuffer = null; - if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2)) - currentBuffer = buildableNearBuffer; - else - currentBuffer = buildableFarBuffer; - - // get the desired LodTemplate and - // add this LOD to the buffer - LodConfig.CLIENT.lodTemplate.get(). - template.addLodToBuffer(currentBuffer, lodDim, lod, - xOffset, yOffset, zOffset, renderer.debugging); + } } - + */ // TODO add a way for a server side mod to generate chunks requested here + /* if(mc.hasSingleplayerServer()) { ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension); @@ -235,10 +256,11 @@ public class LodNodeBufferBuilder numberOfChunksWaitingToGenerate++; - LodChunkGenWorker genWorker = new LodChunkGenWorker(chunkPos, renderer, lodChunkBuilder, this, lodDim, serverWorld, biomeContainer); + LodChunkGenWorker.java genWorker = new LodChunkGenWorker.java(chunkPos, renderer, lodChunkBuilder, this, lodDim, serverWorld, biomeContainer); WorldWorkerManager.addWorker(genWorker); } } + */ // finish the buffer building buildableNearBuffer.end(); diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index 625014f0e..ae27f69da 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -440,9 +440,6 @@ public class LodQuadTree { return (lodNodeData != null); } - public LodNodeData getLodFromCoordinate(int x, int z, byte level){ - - } public boolean isCoordinateInLevel(int x, int z){ return !(lodNodeData.startX > x || lodNodeData.startZ > z || lodNodeData.endX < x || lodNodeData.endZ < z); diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java index 9f78ef4c3..cbdef1caa 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -297,10 +297,10 @@ public class LodQuadTreeDimension { */ public LodNodeData getLodFromCoordinates(int posX, int posZ, byte level) { - LodQuadTree region = getRegion(posX/(512/Math.pow(level,2)),posZ/(512/Math.pow(level,2))); + LodQuadTree region = getRegion((int) (posX/(512/Math.pow(level,2))),(int) (posZ/(512/Math.pow(level,2)))); if(region == null) return null; - return region.getLodFromCoordinate(posX, posZ, level); + return region.getNodeAtLevelPosition(posX, posZ, level); /* RegionPos pos = LodUtil.convertChunkPosToRegionPos(new ChunkPos(chunkX, chunkZ)); diff --git a/src/main/java/com/seibel/lod/render/LodNodeRenderer.java b/src/main/java/com/seibel/lod/render/LodNodeRenderer.java index 71d297d4e..7cec53a77 100644 --- a/src/main/java/com/seibel/lod/render/LodNodeRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodNodeRenderer.java @@ -15,6 +15,7 @@ import com.seibel.lod.objects.LodDimension; import com.seibel.lod.objects.NearFarBuffer; import com.seibel.lod.objects.NearFarFogSettings; import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; import com.seibel.lod.proxy.ClientProxy; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; @@ -132,7 +133,7 @@ public class LodNodeRenderer * @param newDimension The dimension to draw, if null doesn't replace the current dimension. * @param partialTicks how far into the current tick this method was called. */ - public void drawLODs(LodDimension lodDim, float partialTicks, IProfiler newProfiler) + public void drawLODs(LodQuadTreeDimension lodDim, float partialTicks, IProfiler newProfiler) { if (lodDim == null) { @@ -234,7 +235,7 @@ public class LodNodeRenderer // replace the buffers used to draw and build, // this is only done when the createLodBufferGenerationThread // has finished executing on a parallel thread. - if (lodBufferBuilder.newBuffersAvaliable()) + if (lodNodeBufferBuilder.newBuffersAvaliable()) { swapBuffers(); } @@ -549,7 +550,7 @@ public class LodNodeRenderer /** * setup the lighting to be used for the LODs */ - private void setupLighting(LodDimension lodDimension, float partialTicks) + private void setupLighting(LodQuadTreeDimension lodDimension, float partialTicks) { float sunBrightness = lodDimension.dimension.hasSkyLight() ? mc.level.getSkyDarken(partialTicks) : 0.2f; float gammaMultiplyer = (float)mc.options.gamma - 0.5f; @@ -771,7 +772,7 @@ public class LodNodeRenderer * Get a HashSet of all ChunkPos within the normal render distance * that should not be rendered. */ - private HashSet getNearbyLodChunkPosToSkip(LodDimension lodDim, BlockPos playerPos) + private HashSet getNearbyLodChunkPosToSkip(LodQuadTreeDimension lodDim, BlockPos playerPos) { int chunkRenderDist = mc.options.renderDistance; int blockRenderDist = chunkRenderDist * 16; @@ -786,10 +787,10 @@ public class LodNodeRenderer { for(int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++) { - LodNodeData lod = lodDim.getLodFromCoordinates(x, z); + LodNodeData lod = lodDim.getLodFromCoordinates(x, z, (byte) 4); if (lod != null) { - short lodHighestPoint = lod.height(); + short lodHighestPoint = lod.height; if (playerPos.getY() < lodHighestPoint) { From 829c9531faed30a9e51a92a9a0dd8ca54e06858a Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 21:01:37 +0200 Subject: [PATCH 22/46] Several chages to converto to quadTree --- src/main/java/com/seibel/lod/proxy/ClientProxy.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index 66ceb45bc..02a450897 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -1,9 +1,5 @@ package com.seibel.lod.proxy; -import com.seibel.lod.builders.LodNodeBufferBuilder; -import com.seibel.lod.builders.LodNodeBuilder; -import com.seibel.lod.objects.quadTree.LodQuadTreeWorld; -import com.seibel.lod.render.LodNodeRenderer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -35,10 +31,10 @@ public class ClientProxy { public static final Logger LOGGER = LogManager.getLogger("LOD"); - private static LodQuadTreeWorld lodWorld = new LodQuadTreeWorld(); - private static LodNodeBuilder lodChunkBuilder = new LodNodeBuilder(); - private static LodNodeBufferBuilder lodBufferBuilder = new LodNodeBufferBuilder(lodChunkBuilder); - private static LodNodeRenderer renderer = new LodNodeRenderer(lodBufferBuilder); + private static LodWorld lodWorld = new LodWorld(); + private static LodChunkBuilder lodChunkBuilder = new LodChunkBuilder(); + private static LodBufferBuilder lodBufferBuilder = new LodBufferBuilder(lodChunkBuilder); + private static LodRenderer renderer = new LodRenderer(lodBufferBuilder); Minecraft mc = Minecraft.getInstance(); From f91479829d1b82bec19853ef8d34264e33d3aa55 Mon Sep 17 00:00:00 2001 From: Morippi Date: Fri, 9 Jul 2021 21:07:00 +0200 Subject: [PATCH 23/46] Several chages to converto to quadTree --- .../lod/builders/LodNodeBufferBuilder.java | 105 ------------------ .../lod/objects/quadTree/QuadTreeImage.java | 6 +- .../lod/objects/quadTree/UsesExamples.java | 58 ---------- 3 files changed, 3 insertions(+), 166 deletions(-) delete mode 100644 src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java index 6adf53599..cb8abb78f 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -155,113 +155,8 @@ public class LodNodeBufferBuilder // get the desired LodTemplate and // add this LOD to the buffer - LodConfig.CLIENT.lodTemplate.get(). - template.addLodToBuffer(currentBuffer, lodDim, data, - data.startX, 0, data.startZ, renderer.debugging); } // x axis - /* - for (int i = 0; i < numbChunksWide; i++) - { - // z axis - for (int j = 0; j < numbChunksWide; j++) - { - int chunkX = i + (startX / LodChunk.WIDTH); - int chunkZ = j + (startZ / LodChunk.WIDTH); - - // skip any chunks that Minecraft is going to render - if(isCoordInCenterArea(i, j, (numbChunksWide / 2)) - && renderer.vanillaRenderedChunks.contains(new ChunkPos(chunkX, chunkZ))) - { - continue; - } - - - // set where this square will be drawn in the world - double xOffset = (LodChunk.WIDTH * i) + // offset by the number of LOD blocks - startX; // offset so the center LOD block is centered underneath the player - double yOffset = 0; - double zOffset = (LodChunk.WIDTH * j) + startZ; - - LodNodeData lod = lodDim.getLodFromCoordinates(chunkX, chunkZ, LodNodeData.CHUNK_LEVEL); - - if (lod == null || lod.voidNode) - { - // generate a new chunk if no chunk currently exists - // and we aren't waiting on any other chunks to generate - if (lod == null && numberOfChunksWaitingToGenerate < maxChunkGenRequests) - { - ChunkPos pos = new ChunkPos(chunkX, chunkZ); - - // determine if this position is closer to the player - // than the previous - int newDistance = playerChunkPos.getChessboardDistance(pos); - - if (newDistance < minChunkDist) - { - // this chunk is closer, clear any previous - // positions and update the new minimum distance - minChunkDist = newDistance; - chunksToGenReserve = chunksToGen; - - chunkGenIndex = 0; - chunksToGen = new ChunkPos[maxChunkGenRequests]; - chunksToGen[chunkGenIndex] = pos; - chunkGenIndex++; - } - else if (newDistance <= minChunkDist) - { - // this chunk position is as close or closers than the - // minimum distance - if(chunkGenIndex < maxChunkGenRequests) - { - // we are still under the number of chunks to generate - // add this position to the list - chunksToGen[chunkGenIndex] = pos; - chunkGenIndex++; - } - } - - } - // don't render this null chunk - continue; - } - - - - - } - } - */ - // TODO add a way for a server side mod to generate chunks requested here - /* - if(mc.hasSingleplayerServer()) - { - ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension); - - // make sure we have as many chunks to generate as we are allowed - if (chunkGenIndex < maxChunkGenRequests) - { - for(int i = chunkGenIndex, j = 0; i < maxChunkGenRequests; i++, j++) - { - chunksToGen[i] = chunksToGenReserve[j]; - } - } - - // start chunk generation - for(ChunkPos chunkPos : chunksToGen) - { - if(chunkPos == null) - break; - - numberOfChunksWaitingToGenerate++; - - LodChunkGenWorker.java genWorker = new LodChunkGenWorker.java(chunkPos, renderer, lodChunkBuilder, this, lodDim, serverWorld, biomeContainer); - WorldWorkerManager.addWorker(genWorker); - } - } - */ - // finish the buffer building buildableNearBuffer.end(); buildableFarBuffer.end(); diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 0fdf86342..118f67827 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -93,8 +93,8 @@ public class QuadTreeImage extends JPanel { frame.setLocationByPlatform(true); frame.setVisible(true); List> listOfList = new ArrayList<>(); - //OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 1000); - EndBiomeSource biomeSource = new EndBiomeSource(MCVersion.v1_16_5, 1000); + OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 1000); + //EndBiomeSource biomeSource = new EndBiomeSource(MCVersion.v1_16_5, 1000); int[] distances = {100000,8000,4000,2000,1000,500,250,100,50,25}; for (int i = 0; i <= (9 - 2); i++) { for (int j = 0; j < 1; j++) { @@ -159,7 +159,7 @@ public class QuadTreeImage extends JPanel { } - int timerDelay = 5000; + int timerDelay = 0; System.out.println("STARTING"); System.out.println(dim.getWidth()); System.out.println(dim.getCenterX()); diff --git a/src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java b/src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java deleted file mode 100644 index 9d7b0d47d..000000000 --- a/src/main/java/com/seibel/lod/objects/quadTree/UsesExamples.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.seibel.lod.objects.quadTree; - -import com.seibel.lod.builders.LodNodeBuilder; -import com.seibel.lod.objects.LodDimension; -import net.minecraft.client.Minecraft; -import net.minecraft.world.DimensionType; - -import java.awt.*; -import java.lang.reflect.Array; -import java.util.AbstractMap; -import java.util.Collections; -import java.util.Map; - -public class UsesExamples { - public static void main(String[] args){ - //THIS CODE DOESN'T WORK AT THE MOMENT - /**TODO - * Complete all the new Lod objects - * Complete the getNodeToGenerate in LodQuadTreeDimension - * Complete the getNodeToRender in LodQuadTreeDimension - * Complete the node builder - * Complete the new renderer - * add everything to ClientProxy for the first test - * */ -/* - LodQuadTreeWorld lodWorld = new LodQuadTreeWorld(); - LodQuadTreeDimension newLodDimension = new LodQuadTreeDimension(Minecraft.getInstance().world.getDimensionType(), Minecraft.getInstance().world, 10); - lodWorld.addLodDimension(newLodDimension); - - LodQuadTreeDimension lodDimension = lodWorld.getLodDimension(Minecraft.getInstance().world.getDimensionType()); - lodDimension.move(0,0); - - //I will now generate some fake LodNodeData. This in the final implementation will be generated by a builder - //this lodNodeData will be put at level 6 of the QuadTree. This LodNodeData represent a block of width - - LodNodeData lodNodeData1 = new LodNodeData((byte) 6, 4, 4, 64, 0, new Color(0,200,0),true); - LodNodeData lodNodeData2 = new LodNodeData((byte) 6, 4, 5, 64, 0, new Color(0,200,0),true); - LodNodeData lodNodeData3 = new LodNodeData((byte) 6, 5, 4, 64, 0, new Color(0,0,200),true); - - //add like this - - lodDimension.addNode(lodNodeData1); - lodDimension.addNode(lodNodeData2); - lodDimension.addNode(lodNodeData3); - - //Automatic generation - - List nodeToGenerate = (List) lodDimension.getRegion(0,0).getNodeToGenerate(0,0, (byte) 3,1000,0); - Collections.sort(nodeToGenerate, Map.Entry.comparingByValue()); - - - // Call the builder to generate all the useful node - - */ - - - } -} From f95d57ab6dceaed99a64c50918503507ab56b57d Mon Sep 17 00:00:00 2001 From: Morippi Date: Sat, 10 Jul 2021 12:43:23 +0200 Subject: [PATCH 24/46] Several chages to converto to quadTree + first fix for negative coordinate --- .../lod/builders/LodNodeBufferBuilder.java | 25 +- .../AbstractLodNodeTemplate.java | 38 ++ .../CubicLodNodeTemplate.java | 155 +++++ .../DynamicLodNodeTemplate.java | 35 ++ .../TriangularLodNodeTemplate.java | 33 + .../worldGeneration/LodNodeGenWorker.java | 574 ++++++++++++++++++ .../lod/objects/quadTree/LodQuadTree.java | 16 +- .../quadTree/LodQuadTreeDimension.java | 8 +- .../lod/objects/quadTree/QuadTreeImage.java | 16 +- 9 files changed, 871 insertions(+), 29 deletions(-) create mode 100644 src/main/java/com/seibel/lod/builders/lodNodeTemplates/AbstractLodNodeTemplate.java create mode 100644 src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java create mode 100644 src/main/java/com/seibel/lod/builders/lodNodeTemplates/DynamicLodNodeTemplate.java create mode 100644 src/main/java/com/seibel/lod/builders/lodNodeTemplates/TriangularLodNodeTemplate.java create mode 100644 src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java index cb8abb78f..c0137843f 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -1,5 +1,6 @@ package com.seibel.lod.builders; +import com.seibel.lod.builders.worldGeneration.LodChunkGenWorker; import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; @@ -134,16 +135,18 @@ public class LodNodeBufferBuilder buildableFarBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); - List lodList = new ArrayList<>(); - lodList.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 9, 100000,8000)); - lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 8, 8000,4000)); - lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 7, 4000,2000)); - lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 6, 2000,1000)); - lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 5, 1000,500)); - lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 4, 500,250)); - lodList.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 3, 250,0)); - - for(LodNodeData data : lodList){ + List lodToRender = new ArrayList<>(); + lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 0, 100000,0)); + /* + lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 9, 100000,8000)); + lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 8, 8000,4000)); + lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 7, 4000,2000)); + lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 6, 2000,1000)); + lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 5, 1000,500)); + lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 4, 500,250)); + lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 3, 250,0)); +*/ + for(LodNodeData data : lodToRender){ BufferBuilder currentBuffer = null; /* if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2)) @@ -156,6 +159,8 @@ public class LodNodeBufferBuilder // get the desired LodTemplate and // add this LOD to the buffer } + + // x axis // finish the buffer building buildableNearBuffer.end(); diff --git a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/AbstractLodNodeTemplate.java b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/AbstractLodNodeTemplate.java new file mode 100644 index 000000000..1c7645b4b --- /dev/null +++ b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/AbstractLodNodeTemplate.java @@ -0,0 +1,38 @@ +package com.seibel.lod.builders.lodNodeTemplates; + +import com.seibel.lod.enums.LodDetail; +import com.seibel.lod.objects.LodChunk; +import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import net.minecraft.client.renderer.BufferBuilder; + +/** + * This is the abstract class used to create different + * BufferBuilders. + * + * @author James Seibel + * @version 06-16-2021 + */ +public abstract class AbstractLodNodeTemplate +{ + public abstract void addLodToBuffer(BufferBuilder buffer, + LodQuadTreeDimension lodDim, LodNodeData lod, + double xOffset, double yOffset, double zOffset, + boolean debugging); + + /** add the given position and color to the buffer */ + protected void addPosAndColor(BufferBuilder buffer, + double x, double y, double z, + int red, int green, int blue, int alpha) + { + buffer.vertex(x, y, z).color(red, green, blue, alpha).endVertex(); + } + + /** Returns in bytes how much buffer memory is required + * for one LOD object */ + public abstract int getBufferMemoryForSingleLod(); + + + +} diff --git a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java new file mode 100644 index 000000000..e9f820464 --- /dev/null +++ b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java @@ -0,0 +1,155 @@ +package com.seibel.lod.builders.lodNodeTemplates; + +import com.seibel.lod.enums.ColorDirection; +import com.seibel.lod.enums.LodDetail; +import com.seibel.lod.handlers.LodConfig; +import com.seibel.lod.objects.LodChunk; +import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import net.minecraft.client.renderer.BufferBuilder; +import net.minecraft.util.math.AxisAlignedBB; + +import java.awt.*; + +/** + * Builds LODs as rectangular prisms. + * + * @author James Seibel + * @version 06-16-2021 + */ +public class CubicLodNodeTemplate extends AbstractLodNodeTemplate { + + public CubicLodNodeTemplate() { + + } + + + @Override + public void addLodToBuffer(BufferBuilder buffer, + LodQuadTreeDimension lodDim, LodNodeData lod, + double xOffset, double yOffset, double zOffset, + boolean debugging) { + AxisAlignedBB bbox; + + // Add this LOD to the BufferBuilder + // using the quality setting set by the config + LodDetail detail = LodConfig.CLIENT.lodDetail.get(); + + int halfWidth = lod.width / 2; + int startX = lod.startX; + int startZ = lod.startZ; + int endX = lod.startX + lod.width; + int endZ = lod.startZ + lod.width; + + // returns null if the lod is empty at the given location + bbox = generateBoundingBox( + lod.height, + lod.height, + detail.dataPointWidth, + xOffset - (halfWidth / 2) + startX, + yOffset, + zOffset - (halfWidth / 2) + startZ); + + if (bbox != null) { + addBoundingBoxToBuffer(buffer, bbox, lod.color); + } + } + + + private AxisAlignedBB generateBoundingBox(int height, int depth, int width, double xOffset, double yOffset, double zOffset) { + // don't add an LOD if it is empty + if (height == -1 && depth == -1) + return null; + + if (depth == height) { + // if the top and bottom points are at the same height + // render this LOD as 1 block thick + height++; + } + + return new AxisAlignedBB(0, depth, 0, width, height, width).move(xOffset, yOffset, zOffset); + } + + + private void addBoundingBoxToBuffer(BufferBuilder buffer, AxisAlignedBB bb, Color c) { + // top (facing up) + addPosAndColor(buffer, bb.minX, bb.maxY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.minX, bb.maxY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + // bottom (facing down) + addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + + // south (facing -Z) + addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.minX, bb.maxY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + // north (facing +Z) + addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.minX, bb.maxY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + + // west (facing -X) + addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.minX, bb.maxY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.minX, bb.maxY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + // east (facing +X) + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, c.getRed(), c.getGreen(), c.getBlue(), c.getAlpha()); + } + + + @SuppressWarnings("unused") + private void addBoundingBoxToBuffer(BufferBuilder buffer, AxisAlignedBB bb, Color[] c) { + // top (facing up) + addPosAndColor(buffer, bb.minX, bb.maxY, bb.minZ, c[ColorDirection.TOP.value].getRed(), c[ColorDirection.TOP.value].getGreen(), c[ColorDirection.TOP.value].getBlue(), c[ColorDirection.TOP.value].getAlpha()); + addPosAndColor(buffer, bb.minX, bb.maxY, bb.maxZ, c[ColorDirection.TOP.value].getRed(), c[ColorDirection.TOP.value].getGreen(), c[ColorDirection.TOP.value].getBlue(), c[ColorDirection.TOP.value].getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, c[ColorDirection.TOP.value].getRed(), c[ColorDirection.TOP.value].getGreen(), c[ColorDirection.TOP.value].getBlue(), c[ColorDirection.TOP.value].getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, c[ColorDirection.TOP.value].getRed(), c[ColorDirection.TOP.value].getGreen(), c[ColorDirection.TOP.value].getBlue(), c[ColorDirection.TOP.value].getAlpha()); + // bottom (facing down) + addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, c[ColorDirection.BOTTOM.value].getRed(), c[ColorDirection.BOTTOM.value].getGreen(), c[ColorDirection.BOTTOM.value].getBlue(), c[ColorDirection.BOTTOM.value].getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, c[ColorDirection.BOTTOM.value].getRed(), c[ColorDirection.BOTTOM.value].getGreen(), c[ColorDirection.BOTTOM.value].getBlue(), c[ColorDirection.BOTTOM.value].getAlpha()); + addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, c[ColorDirection.BOTTOM.value].getRed(), c[ColorDirection.BOTTOM.value].getGreen(), c[ColorDirection.BOTTOM.value].getBlue(), c[ColorDirection.BOTTOM.value].getAlpha()); + addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, c[ColorDirection.BOTTOM.value].getRed(), c[ColorDirection.BOTTOM.value].getGreen(), c[ColorDirection.BOTTOM.value].getBlue(), c[ColorDirection.BOTTOM.value].getAlpha()); + + // south (facing -Z) + addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, c[ColorDirection.SOUTH.value].getRed(), c[ColorDirection.SOUTH.value].getGreen(), c[ColorDirection.SOUTH.value].getBlue(), c[ColorDirection.SOUTH.value].getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, c[ColorDirection.SOUTH.value].getRed(), c[ColorDirection.SOUTH.value].getGreen(), c[ColorDirection.SOUTH.value].getBlue(), c[ColorDirection.SOUTH.value].getAlpha()); + addPosAndColor(buffer, bb.minX, bb.maxY, bb.maxZ, c[ColorDirection.SOUTH.value].getRed(), c[ColorDirection.SOUTH.value].getGreen(), c[ColorDirection.SOUTH.value].getBlue(), c[ColorDirection.SOUTH.value].getAlpha()); + addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, c[ColorDirection.SOUTH.value].getRed(), c[ColorDirection.SOUTH.value].getGreen(), c[ColorDirection.SOUTH.value].getBlue(), c[ColorDirection.SOUTH.value].getAlpha()); + // north (facing +Z) + addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, c[ColorDirection.NORTH.value].getRed(), c[ColorDirection.NORTH.value].getGreen(), c[ColorDirection.NORTH.value].getBlue(), c[ColorDirection.NORTH.value].getAlpha()); + addPosAndColor(buffer, bb.minX, bb.maxY, bb.minZ, c[ColorDirection.NORTH.value].getRed(), c[ColorDirection.NORTH.value].getGreen(), c[ColorDirection.NORTH.value].getBlue(), c[ColorDirection.NORTH.value].getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, c[ColorDirection.NORTH.value].getRed(), c[ColorDirection.NORTH.value].getGreen(), c[ColorDirection.NORTH.value].getBlue(), c[ColorDirection.NORTH.value].getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, c[ColorDirection.NORTH.value].getRed(), c[ColorDirection.NORTH.value].getGreen(), c[ColorDirection.NORTH.value].getBlue(), c[ColorDirection.NORTH.value].getAlpha()); + + // west (facing -X) + addPosAndColor(buffer, bb.minX, bb.minY, bb.minZ, c[ColorDirection.WEST.value].getRed(), c[ColorDirection.WEST.value].getGreen(), c[ColorDirection.WEST.value].getBlue(), c[ColorDirection.WEST.value].getAlpha()); + addPosAndColor(buffer, bb.minX, bb.minY, bb.maxZ, c[ColorDirection.WEST.value].getRed(), c[ColorDirection.WEST.value].getGreen(), c[ColorDirection.WEST.value].getBlue(), c[ColorDirection.WEST.value].getAlpha()); + addPosAndColor(buffer, bb.minX, bb.maxY, bb.maxZ, c[ColorDirection.WEST.value].getRed(), c[ColorDirection.WEST.value].getGreen(), c[ColorDirection.WEST.value].getBlue(), c[ColorDirection.WEST.value].getAlpha()); + addPosAndColor(buffer, bb.minX, bb.maxY, bb.minZ, c[ColorDirection.WEST.value].getRed(), c[ColorDirection.WEST.value].getGreen(), c[ColorDirection.WEST.value].getBlue(), c[ColorDirection.WEST.value].getAlpha()); + // east (facing +X) + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.minZ, c[ColorDirection.EAST.value].getRed(), c[ColorDirection.EAST.value].getGreen(), c[ColorDirection.EAST.value].getBlue(), c[ColorDirection.EAST.value].getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.maxY, bb.maxZ, c[ColorDirection.EAST.value].getRed(), c[ColorDirection.EAST.value].getGreen(), c[ColorDirection.EAST.value].getBlue(), c[ColorDirection.EAST.value].getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.minY, bb.maxZ, c[ColorDirection.EAST.value].getRed(), c[ColorDirection.EAST.value].getGreen(), c[ColorDirection.EAST.value].getBlue(), c[ColorDirection.EAST.value].getAlpha()); + addPosAndColor(buffer, bb.maxX, bb.minY, bb.minZ, c[ColorDirection.EAST.value].getRed(), c[ColorDirection.EAST.value].getGreen(), c[ColorDirection.EAST.value].getBlue(), c[ColorDirection.EAST.value].getAlpha()); + } + + + @Override + public int getBufferMemoryForSingleLod() { + // (sidesOnACube * pointsInASquare * (positionPoints + colorPoints))) * howManyPointsPerLodChunk + return (6 * 4 * (3 + 4)); + } + + +} diff --git a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/DynamicLodNodeTemplate.java b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/DynamicLodNodeTemplate.java new file mode 100644 index 000000000..a5e1f078f --- /dev/null +++ b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/DynamicLodNodeTemplate.java @@ -0,0 +1,35 @@ +package com.seibel.lod.builders.lodNodeTemplates; + +import com.seibel.lod.enums.LodDetail; +import com.seibel.lod.objects.LodChunk; +import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import net.minecraft.client.renderer.BufferBuilder; + +/** + * TODO DynamicLodTemplate + * Chunks smoothly transition between + * each other, unless a neighboring chunk + * is at a significantly different height. + * + * @author James Seibel + * @version 06-16-2021 + */ +public class DynamicLodNodeTemplate extends AbstractLodNodeTemplate +{ + @Override + public void addLodToBuffer(BufferBuilder buffer, + LodQuadTreeDimension lodDim, LodNodeData lod, + double xOffset, double yOffset, double zOffset, + boolean debugging) + { + System.err.println("DynamicLodTemplate not implemented!"); + } + + @Override + public int getBufferMemoryForSingleLod() { + // TODO Auto-generated method stub + return 0; + } +} diff --git a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/TriangularLodNodeTemplate.java b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/TriangularLodNodeTemplate.java new file mode 100644 index 000000000..2a4d5612d --- /dev/null +++ b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/TriangularLodNodeTemplate.java @@ -0,0 +1,33 @@ +package com.seibel.lod.builders.lodNodeTemplates; + +import com.seibel.lod.enums.LodDetail; +import com.seibel.lod.objects.LodChunk; +import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import net.minecraft.client.renderer.BufferBuilder; + +/** + * TODO #21 TriangularLodTemplate + * Builds each LOD chunk as a singular rectangular prism. + * + * @author James Seibel + * @version 06-16-2021 + */ +public class TriangularLodNodeTemplate extends AbstractLodNodeTemplate +{ + @Override + public void addLodToBuffer(BufferBuilder buffer, + LodQuadTreeDimension lodDim, LodNodeData lod, + double xOffset, double yOffset, double zOffset, + boolean debugging) + { + System.err.println("DynamicLodTemplate not implemented!"); + } + + @Override + public int getBufferMemoryForSingleLod() { + // TODO Auto-generated method stub + return 0; + } +} diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java new file mode 100644 index 000000000..f91817e71 --- /dev/null +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java @@ -0,0 +1,574 @@ +package com.seibel.lod.builders.worldGeneration; + +import com.seibel.lod.builders.*; +import com.seibel.lod.enums.DistanceGenerationMode; +import com.seibel.lod.handlers.LodConfig; +import com.seibel.lod.objects.LodChunk; +import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.LodRegion; +import com.seibel.lod.objects.quadTree.LodNodeData; +import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.proxy.ClientProxy; +import com.seibel.lod.render.LodNodeRenderer; +import com.seibel.lod.render.LodRenderer; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.WeightedList.Entry; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.palette.UpgradeData; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.biome.BiomeContainer; +import net.minecraft.world.chunk.ChunkPrimer; +import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.chunk.IChunk; +import net.minecraft.world.gen.ChunkGenerator; +import net.minecraft.world.gen.Heightmap; +import net.minecraft.world.gen.blockstateprovider.WeightedBlockStateProvider; +import net.minecraft.world.gen.feature.*; +import net.minecraft.world.gen.placement.ConfiguredPlacement; +import net.minecraft.world.gen.placement.DecoratedPlacementConfig; +import net.minecraft.world.gen.placement.IPlacementConfig; +import net.minecraft.world.gen.placement.NoiseDependant; +import net.minecraft.world.server.ServerChunkProvider; +import net.minecraft.world.server.ServerWorld; +import net.minecraft.world.server.ServerWorldLightManager; +import net.minecraftforge.common.WorldWorkerManager.IWorker; + +import java.util.ConcurrentModificationException; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.function.Supplier; + +/** + * This is used to generate a LodChunk at a given ChunkPos. + * + * @author James Seibel + * @version 7-4-2021 + */ +public class LodNodeGenWorker implements IWorker +{ + public static final ExecutorService genThreads = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); + + private boolean threadStarted = false; + private LodChunkGenThread thread; + + /** If a configured feature fails for whatever reason, + * add it to this list, this is to hopefully remove any + * features that could cause issues down the line. */ + private static ConcurrentHashMap> configuredFeaturesToAvoid = new ConcurrentHashMap<>(); + + + + public LodNodeGenWorker(ChunkPos newPos, LodNodeRenderer newLodRenderer, + LodNodeBuilder newLodBuilder, LodNodeBufferBuilder newLodBufferBuilder, + LodQuadTreeDimension newLodDimension, ServerWorld newServerWorld, + BiomeContainer newBiomeContainer) + { + if (newServerWorld == null) + throw new IllegalArgumentException("LodChunkGenWorker must have a non-null ServerWorld"); + + thread = new LodChunkGenThread(newPos, newLodRenderer, + newLodBuilder, newLodBufferBuilder, + newLodDimension, newServerWorld); + } + + @Override + public boolean doWork() + { + if (!threadStarted) + { + // make sure we don't generate this chunk again + thread.lodDim.addNode(new LodNodeData(LodNodeData.CHUNK_LEVEL,thread.pos.x, thread.pos.z)); + + thread.lodBufferBuilder.numberOfChunksWaitingToGenerate--; + + if (LodConfig.CLIENT.distanceGenerationMode.get() == DistanceGenerationMode.SERVER) + { + // if we are using SERVER generation that has to be done + // synchronously to prevent crashing and harmful + // interactions with the normal world generator + thread.run(); + } + else + { + // Every other method can + // be done asynchronously + genThreads.execute(thread); + } + + threadStarted = true; + + // useful for debugging +// ClientProxy.LOGGER.info(thread.lodDim.getNumberOfLods()); + } + + return false; + } + + @Override + public boolean hasWork() + { + return !threadStarted; + } + + + + + private class LodChunkGenThread implements Runnable + { + public final ServerWorld serverWorld; + public final LodQuadTreeDimension lodDim; + public final LodNodeBuilder lodChunkBuilder; + public final LodNodeRenderer lodRenderer; + private LodNodeBufferBuilder lodBufferBuilder; + + private ChunkPos pos; + + public LodChunkGenThread(ChunkPos newPos, LodNodeRenderer newLodRenderer, + LodNodeBuilder newLodBuilder, LodNodeBufferBuilder newLodBufferBuilder, + LodQuadTreeDimension newLodDimension, ServerWorld newServerWorld) + { + pos = newPos; + lodRenderer = newLodRenderer; + lodChunkBuilder = newLodBuilder; + lodBufferBuilder = newLodBufferBuilder; + lodDim = newLodDimension; + serverWorld = newServerWorld; + } + + @Override + public void run() + { + // only generate LodChunks if they can + // be added to the current LodDimension + if (lodDim.regionIsInRange(pos.x / LodRegion.SIZE, pos.z / LodRegion.SIZE)) + { +// long startTime = System.currentTimeMillis(); + + switch(LodConfig.CLIENT.distanceGenerationMode.get()) + { + case BIOME_ONLY: + case BIOME_ONLY_SIMULATE_HEIGHT: + // fastest + generateUsingBiomesOnly(); + break; + case SURFACE: + // faster + generateUsingSurface(); + break; + case FEATURES: + // fast + generateUsingFeatures(); + break; + case SERVER: + // very slow + generateWithServer(); + break; + } + + lodRenderer.regenerateLODsNextFrame(); + + +// if (lodDim.getLodFromCoordinates(pos.x, pos.z) != null) +// ClientProxy.LOGGER.info(pos.x + " " + pos.z + " Success!"); +// else +// ClientProxy.LOGGER.info(pos.x + " " + pos.z); + +// long endTime = System.currentTimeMillis(); +// System.out.println(endTime - startTime); + + }// if in range + + }// run + + + + /** + * takes about 2-5 ms + */ + private void generateUsingBiomesOnly() + { + List chunkList = new LinkedList<>(); + ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); + chunkList.add(chunk); + + ServerChunkProvider chunkSource = serverWorld.getChunkSource(); + ChunkGenerator chunkGen = chunkSource.generator; + + + // generate the terrain (this is thread safe) + ChunkStatus.EMPTY.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + // override the chunk status so we can run the next generator stage + chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); + ChunkStatus.BIOMES.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); + + + // generate fake height data for this LOD + int seaLevel = serverWorld.getSeaLevel(); + + boolean simulateHeight = LodConfig.CLIENT.distanceGenerationMode.get() == DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT; + boolean inTheEnd = false; + + // add fake heightmap data so our LODs aren't at height 0 + Heightmap heightmap = new Heightmap(chunk, LodChunk.DEFAULT_HEIGHTMAP); + for(int x = 0; x < LodChunk.WIDTH && !inTheEnd; x++) + { + for(int z = 0; z < LodChunk.WIDTH && !inTheEnd; z++) + { + if (simulateHeight) + { + // TODO use the biomes around each block to smooth out the transition + + // these heights are of course aren't super accurate, + // they are just to simulate height data where there isn't any + switch(chunk.getBiomes().getNoiseBiome(x, seaLevel, z).getBiomeCategory()) + { + case NETHER: + heightmap.setHeight(x, z, serverWorld.getHeight() / 2); + break; + + case EXTREME_HILLS: + heightmap.setHeight(x, z, seaLevel + 30); + break; + case MESA: + heightmap.setHeight(x, z, seaLevel + 20); + break; + case JUNGLE: + heightmap.setHeight(x, z, seaLevel + 20); + break; + case BEACH: + heightmap.setHeight(x, z, seaLevel + 5); + break; + case NONE: + heightmap.setHeight(x, z, 0); + break; + + case OCEAN: + case RIVER: + heightmap.setHeight(x, z, seaLevel); + break; + + case THEEND: + inTheEnd = true; + break; + + // DESERT + // FOREST + // ICY + // MUSHROOM + // SAVANNA + // SWAMP + // TAIGA + // PLAINS + default: + heightmap.setHeight(x, z, seaLevel + 10); + break; + }// heightmap switch + } + else + { + // we aren't simulating height + // always use sea level + heightmap.setHeight(x, z, seaLevel); + } + }// z + }// x + + chunk.setHeightmap(LodChunk.DEFAULT_HEIGHTMAP, heightmap.getRawData()); + + + LodNodeData lod; + if (!inTheEnd) + { + lod = lodChunkBuilder.generateLodNodeFromChunk(chunk, new LodBuilderConfig(true, true, false)); + } + else + { + // if we are in the end, don't generate any chunks. + // Since we don't know where the islands are, everything + // generates the same and it looks really bad. + lod = new LodNodeData(LodNodeData.CHUNK_LEVEL,chunk.getPos().x, chunk.getPos().z); + } + lodDim.addNode(lod); + } + + + /** + * takes about 10 - 20 ms + */ + private void generateUsingSurface() + { + List chunkList = new LinkedList<>(); + ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); + chunkList.add(chunk); + LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk); + + ServerChunkProvider chunkSource = serverWorld.getChunkSource(); + ChunkGenerator chunkGen = chunkSource.generator; + + + // generate the terrain (this is thread safe) + ChunkStatus.EMPTY.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + // override the chunk status so we can run the next generator stage + chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); + ChunkStatus.BIOMES.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + ChunkStatus.NOISE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + ChunkStatus.SURFACE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + + // this feature has proved to be thread safe + // so we will add it + IceAndSnowFeature snowFeature = new IceAndSnowFeature(NoFeatureConfig.CODEC); + snowFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition(), null); + + LodNodeData lod = lodChunkBuilder.generateLodNodeFromChunk(chunk, new LodBuilderConfig(true, true, false)); + lodDim.addNode(lod); + } + + + /** + * takes about 15 - 20 ms + * + * Causes concurrentModification Exceptions, + * which could cause instability or world generation bugs + */ + private void generateUsingFeatures() + { + List chunkList = new LinkedList<>(); + ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); + chunkList.add(chunk); + LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk); + + ServerChunkProvider chunkSource = serverWorld.getChunkSource(); + ChunkGenerator chunkGen = chunkSource.generator; + + + // generate the terrain (this is thread safe) + ChunkStatus.EMPTY.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + // override the chunk status so we can run the next generator stage + chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); + ChunkStatus.BIOMES.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + ChunkStatus.NOISE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + ChunkStatus.SURFACE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); + + + // get all the biomes in the chunk + HashSet biomes = new HashSet<>(); + for (int x = 0; x < LodChunk.WIDTH; x++) + { + for (int z = 0; z < LodChunk.WIDTH; z++) + { + Biome biome = chunk.getBiomes().getNoiseBiome(x, serverWorld.getSeaLevel(), z); + + // Issue #35 + // For some reason Jungle biomes cause incredible lag + // the features here must be interacting with each other + // in unpredictable ways (specifically tree feature generation). + // When generating Features my CPU usage generally hovers around 30 - 40% + // when generating Jungles it spikes to 100%. + if (biome.getBiomeCategory() != Biome.Category.JUNGLE) + { + // should probably use the heightmap here instead of seaLevel, + // but this seems to get the job done well enough + biomes.add(biome); + } + } + } + + + // generate all the features related to this chunk. + // this may or may not be thread safe + for (Biome biome : biomes) + { + List>>> featuresForState = biome.generationSettings.features(); + + for(int featureStateToGenerate = 0; featureStateToGenerate < featuresForState.size(); featureStateToGenerate++) + { + for(Supplier> featureSupplier : featuresForState.get(featureStateToGenerate)) + { + ConfiguredFeature configuredFeature = featureSupplier.get(); + + if (configuredFeaturesToAvoid.containsKey(configuredFeature.hashCode())) + continue; + + + try + { + configuredFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition()); + } + catch(ConcurrentModificationException e) + { + // This will happen. I'm not sure what to do about it + // except pray that it doesn't effect the normal world generation + // in any harmful way + + // Issue #35 + // I tried cloning the config for each feature, but that + // path was blocked since I can't clone lambda methods. + // I tried using a deep cloning library and discovered + // the problem there. + // ( https://github.com/kostaskougios/cloning ) + + configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); +// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); + } + catch(UnsupportedOperationException e) + { + // This will happen when the LodServerWorld + // isn't able to return something that a feature + // generator needs + + configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); +// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); + } + catch(Exception e) + { + // I'm not sure what happened, print to the log + + System.out.println(); + System.out.println(); + e.printStackTrace(); + System.out.println(); + //ClientProxy.LOGGER.error("error class: \"" + configuredfeature.config.getClass() + "\""); + System.out.println(); + + configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); +// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); + } + } + } + } + + // generate a Lod like normal + + LodNodeData lod = lodChunkBuilder.generateLodNodeFromChunk(chunk, new LodBuilderConfig(true, true, false)); + lodDim.addNode(lod); + } + + + /** + * on pre generated chunks 0 - 1 ms + * on un generated chunks 0 - 50 ms + * with the median seeming to hover around 15 - 30 ms + * and outliers in the 100 - 200 ms range + * + * Note this should not be multithreaded and does cause server/simulation lag + * (Higher lag for generating than loading) + */ + private void generateWithServer() { + //lodChunkBuilder.generateLodNodeAsync(serverWorld.getChunk(pos.x, pos.z, ChunkStatus.FEATURES), ClientProxy.getLodWorld(), serverWorld); + } + + + + + + + //================// + // Unused methods // + //================// + + // Sadly I wasn't able to get these to work, + // they are here for documentation purposes + + @SuppressWarnings({ "rawtypes", "unchecked", "unused" }) + private DecoratedFeatureConfig cloneDecoratedFeatureConfig(DecoratedFeatureConfig config) + { + IPlacementConfig placementConfig = null; + + Class oldConfigClass = config.decorator.config().getClass(); + + if (oldConfigClass == FeatureSpreadConfig.class) + { + FeatureSpreadConfig oldPlacementConfig = (FeatureSpreadConfig) config.decorator.config(); + FeatureSpread oldSpread = oldPlacementConfig.count(); + + placementConfig = new FeatureSpreadConfig(oldSpread); + } + else if(oldConfigClass == DecoratedPlacementConfig.class) + { + DecoratedPlacementConfig oldPlacementConfig = (DecoratedPlacementConfig) config.decorator.config(); + placementConfig = new DecoratedPlacementConfig(oldPlacementConfig.inner(), oldPlacementConfig.outer()); + } + else if(oldConfigClass == NoiseDependant.class) + { + NoiseDependant oldPlacementConfig = (NoiseDependant) config.decorator.config(); + placementConfig = new NoiseDependant(oldPlacementConfig.noiseLevel, oldPlacementConfig.belowNoise, oldPlacementConfig.aboveNoise); + } + else + { +// ClientProxy.LOGGER.debug("unkown decorated placement config: \"" + config.decorator.config().getClass() + "\""); + return config; + } + + + ConfiguredPlacement newPlacement = new ConfiguredPlacement(config.decorator.decorator, placementConfig); + return new DecoratedFeatureConfig(config.feature, newPlacement); + } + + + @SuppressWarnings("unused") + private BlockClusterFeatureConfig cloneBlockClusterFeatureConfig(BlockClusterFeatureConfig config) + { + WeightedBlockStateProvider provider = new WeightedBlockStateProvider(); + for(Entry state : ((WeightedBlockStateProvider) config.stateProvider).weightedList.entries) + provider.weightedList.entries.add(state); + + HashSet whitelist = new HashSet<>(); + for(Block block : config.whitelist) + whitelist.add(block); + + HashSet blacklist = new HashSet<>(); + for(BlockState state : config.blacklist) + blacklist.add(state); + + + BlockClusterFeatureConfig.Builder builder = new BlockClusterFeatureConfig.Builder(provider, config.blockPlacer); + builder.whitelist(whitelist); + builder.blacklist(blacklist); + builder.xspread(config.xspread); + builder.yspread(config.yspread); + builder.zspread(config.zspread); + if(config.canReplace) { builder.canReplace(); } + if(config.needWater) { builder.needWater(); } + if(config.project) { builder.noProjection(); } + builder.tries(config.tries); + + + return builder.build(); + } + + } + + + /* + * 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.EMPTY 0 - 1 ms false (empty, what did you expect? :P) + ChunkStatus.STRUCTURE_REFERENCES 1 - 2 ms false (no height, only generates some chunks) + ChunkStatus.BIOMES 1 - 10 ms false (no height) + ChunkStatus.NOISE 4 - 15 ms true (all blocks are stone) + ChunkStatus.LIQUID_CARVERS 6 - 12 ms true (no snow/trees, just grass) + ChunkStatus.SURFACE 5 - 15 ms true (no snow/trees, just grass) + ChunkStatus.CARVERS 5 - 30 ms true (no snow/trees, just grass) + ChunkStatus.FEATURES 7 - 25 ms true + ChunkStatus.HEIGHTMAPS 20 - 40 ms true + ChunkStatus.LIGHT 20 - 40 ms true + ChunkStatus.FULL 30 - 50 ms true + ChunkStatus.SPAWN 50 - 80 ms true + + + 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) + */ +} diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index ae27f69da..8edcf81e8 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -133,11 +133,11 @@ public class LodQuadTree { byte targetLevel = newLodNodeData.level; byte currentLevel = lodNodeData.level; if (targetLevel < currentLevel) { - int posX = newLodNodeData.posX; - int posZ = newLodNodeData.posZ; + int posX = Math.abs(newLodNodeData.posX); + int posZ = Math.abs(newLodNodeData.posZ); short widthRatio = (short) (lodNodeData.width / (2 * newLodNodeData.width)); - int NS = Math.abs((posX / widthRatio) % 2); - int WE = Math.abs((posZ / widthRatio) % 2); + int WE = Math.abs((posX / widthRatio) % 2); + int NS = Math.abs((posZ / widthRatio) % 2); if (getChild(NS, WE) == null) { setChild(NS, WE); } @@ -171,8 +171,8 @@ public class LodQuadTree { return lodNodeData; } else if (targetLevel < currentLevel) { short widthRatio = (short) (lodNodeData.width / Math.pow(2, level)); - int NS = Math.abs((posX / widthRatio) % lodNodeData.posX); - int WE = Math.abs((posZ / widthRatio) % lodNodeData.posZ); + int WE = Math.abs((posX / widthRatio) % lodNodeData.posX); + int NS = Math.abs((posZ / widthRatio) % lodNodeData.posZ); if (getChild(NS, WE) == null) { return null; } @@ -209,8 +209,8 @@ public class LodQuadTree { */ public void setChild(LodNodeData newLodNodeData) { if (newLodNodeData.level == lodNodeData.level - 1) { - int NS = newLodNodeData.posX % lodNodeData.posX; - int WE = newLodNodeData.posZ % lodNodeData.posZ; + int WE = newLodNodeData.posX % lodNodeData.posX; + int NS = newLodNodeData.posZ % lodNodeData.posZ; children[NS][WE] = new LodQuadTree(this, lodNodeData); } } diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java index cbdef1caa..474aa7b3f 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java @@ -200,7 +200,7 @@ public class LodQuadTreeDimension { regions[xIndex][zIndex] = getRegionFromFile(regionX, regionZ); if (regions[xIndex][zIndex] == null) { - regions[xIndex][zIndex] = new LodQuadTree(regionZ, regionX); + regions[xIndex][zIndex] = new LodQuadTree(regionX, regionZ); } } @@ -240,7 +240,7 @@ public class LodQuadTreeDimension { if (region == null) { // if no region exists, create it - region = new LodQuadTree(zIndex, xIndex); + region = new LodQuadTree(xIndex, zIndex); setRegion(region); } } @@ -271,7 +271,7 @@ public class LodQuadTreeDimension { if (region == null) { // if no region exists, create it - region = new LodQuadTree(pos.z, pos.x); + region = new LodQuadTree(pos.x, pos.z); setRegion(region); } boolean coorectlyAdded = region.setNodeAtLowerLevel(lodNodeData, true); @@ -344,7 +344,7 @@ public class LodQuadTreeDimension { zIndex = (zRegion + centerZ) - halfWidth; region = getRegion(xIndex,zIndex); if (region == null){ - region = new LodQuadTree(zIndex, xIndex); + region = new LodQuadTree(xIndex, zIndex); setRegion(region); } listOfQuadTree.addAll(region.getLevelToGenerate(x,z,level,maxDistance,minDistance)); diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 118f67827..bf09f9f17 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -75,9 +75,9 @@ public class QuadTreeImage extends JPanel { } private static void createAndShowGui() { - int playerX = 32*512; - int playerZ = (32*512); - LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 64); + int playerX =-0*511; + int playerZ =-0*511; + LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 16); System.out.println(dim.getRegion(0, 0)); dim.move(playerX/512,playerZ/512); System.out.println(dim.getCenterX()); @@ -105,6 +105,7 @@ public class QuadTreeImage extends JPanel { dist = 32; } List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), distances[i], 0); + System.out.println(levelToGenerate); for (LodQuadTree level : levelToGenerate) { Color color; int startX = level.getLodNodeData().startX; @@ -131,8 +132,9 @@ public class QuadTreeImage extends JPanel { for (Integer posXI : posXs) { for (Integer posZI : posZs) { - int posZ = posXI.intValue(); - int posX = posZI.intValue(); + int posX = posXI.intValue(); + int posZ = posZI.intValue(); + //System.out.println(posX + " " + posZ); color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); LodNodeData node = new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true); @@ -159,6 +161,7 @@ public class QuadTreeImage extends JPanel { } + System.out.println(listOfList); int timerDelay = 0; System.out.println("STARTING"); System.out.println(dim.getWidth()); @@ -177,10 +180,9 @@ public class QuadTreeImage extends JPanel { } else { if(drawCount==0) quadTreeImage.clearAll(); final List myDrawables = new ArrayList<>(); - double amp = 0.025; + double amp = 0.1; Collection lodList = listOfList.get(drawCount); for (LodNodeData data : lodList) { - System.out.println(); myDrawables.add(new MyDrawable(new Rectangle2D.Double( ((data.startX - xOffset ) * amp), ((data.startZ - zOffset) * amp), From 6cb1d2f8f4a4d5cd5fd535c74c906509bd70475f Mon Sep 17 00:00:00 2001 From: Morippi Date: Sat, 10 Jul 2021 13:36:15 +0200 Subject: [PATCH 25/46] second fix for negative coordinate --- .../lod/objects/quadTree/LodQuadTree.java | 30 ++++++++++++------- .../lod/objects/quadTree/QuadTreeImage.java | 28 ++++++++--------- 2 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index 8edcf81e8..4e3961e40 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -133,11 +133,19 @@ public class LodQuadTree { byte targetLevel = newLodNodeData.level; byte currentLevel = lodNodeData.level; if (targetLevel < currentLevel) { - int posX = Math.abs(newLodNodeData.posX); - int posZ = Math.abs(newLodNodeData.posZ); + int posX = newLodNodeData.posX; + int posZ = newLodNodeData.posZ; short widthRatio = (short) (lodNodeData.width / (2 * newLodNodeData.width)); - int WE = Math.abs((posX / widthRatio) % 2); - int NS = Math.abs((posZ / widthRatio) % 2); + int WE = Math.abs(Math.floorDiv(posX , widthRatio) % 2); + int NS = Math.abs(Math.floorDiv(posZ , widthRatio) % 2); + //These two if fix the negative coordinate problema + //I don't know why, there is some problem with the %2 operation + /* + if(posX<0) WE = 1 - WE; + if(posZ<0) NS = 1 - NS; + + */ + if (getChild(NS, WE) == null) { setChild(NS, WE); } @@ -170,9 +178,9 @@ public class LodQuadTree { if (targetLevel == currentLevel) { return lodNodeData; } else if (targetLevel < currentLevel) { - short widthRatio = (short) (lodNodeData.width / Math.pow(2, level)); - int WE = Math.abs((posX / widthRatio) % lodNodeData.posX); - int NS = Math.abs((posZ / widthRatio) % lodNodeData.posZ); + short widthRatio = (short) (lodNodeData.width / (2 * Math.pow(2, level))); + int WE = Math.abs(Math.floorDiv(posX , widthRatio) % 2); + int NS = Math.abs(Math.floorDiv(posZ , widthRatio) % 2); if (getChild(NS, WE) == null) { return null; } @@ -311,7 +319,7 @@ public class LodQuadTree { if (targetLevel > lodNodeData.level) { return nodeList; } - if ((min > maxDistance || max < minDistance) && !isCoordinateInLevel(x,z)){ + if ((min > maxDistance || max < minDistance) /*&& !isCoordinateInLevel(x,z)*/){ return nodeList; } if (targetLevel == lodNodeData.level || !isNodeFull()) { @@ -325,7 +333,7 @@ public class LodQuadTree { } else { for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { - LodQuadTree child = children[NS][WE]; + LodQuadTree child = getChild(NS,WE); if (child != null) { nodeList.addAll(child.getNodeToRender(x, z, targetLevel, maxDistance, minDistance)); } @@ -368,10 +376,10 @@ public class LodQuadTree { if (targetLevel != lodNodeData.level) { for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { - if (children[NS][WE] == null) { + if (getChild(NS,WE) == null) { setChild(NS,WE); } - LodQuadTree child = children[NS][WE]; + LodQuadTree child = getChild(NS,WE); nodeList.addAll(child.getLevelToGenerate(x, z, targetLevel, maxDistance, minDistance)); } } diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index bf09f9f17..8450cbf5f 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -75,11 +75,13 @@ public class QuadTreeImage extends JPanel { } private static void createAndShowGui() { - int playerX =-0*511; - int playerZ =-0*511; + int playerX =-40; + int playerZ =-250; LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 16); System.out.println(dim.getRegion(0, 0)); - dim.move(playerX/512,playerZ/512); + dim.move(Math.floorDiv(playerX,512),Math.floorDiv(playerZ,512)); + + System.out.println(playerX/512 + " " + playerZ/512); System.out.println(dim.getCenterX()); System.out.println(dim.getCenterZ()); System.out.println(dim.getWidth()); @@ -98,12 +100,6 @@ public class QuadTreeImage extends JPanel { int[] distances = {100000,8000,4000,2000,1000,500,250,100,50,25}; for (int i = 0; i <= (9 - 2); i++) { for (int j = 0; j < 1; j++) { - int dist; - if (i == 0) { - dist = 2000; - } else { - dist = 32; - } List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), distances[i], 0); System.out.println(levelToGenerate); for (LodQuadTree level : levelToGenerate) { @@ -135,7 +131,7 @@ public class QuadTreeImage extends JPanel { int posX = posXI.intValue(); int posZ = posZI.intValue(); //System.out.println(posX + " " + posZ); - color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posZ, 0, posX)); + color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posX, 0, posZ)); //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); LodNodeData node = new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true); dim.addNode(node); @@ -144,13 +140,13 @@ public class QuadTreeImage extends JPanel { } } List lodList = new ArrayList<>(); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 9, 100000,8000)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 8, 8000,4000)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 7, 4000,2000)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 6, 2000,1000)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 5, 1000,500)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 4, 500,250)); lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 3, 250,0)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 4, 500,250)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 5, 1000,500)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 6, 2000,1000)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 7, 4000,2000)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 8, 8000,4000)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 9, 100000,8000)); System.out.println(lodList.size()); //Collection lodList = dim.getNodes(false,false,false); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); From 7854f659a3af8d732b4a062da95645f601d1a2ef Mon Sep 17 00:00:00 2001 From: Morippi Date: Sat, 10 Jul 2021 15:02:26 +0200 Subject: [PATCH 26/46] various change --- .../lod/objects/quadTree/LodQuadTree.java | 12 ++--- .../lod/objects/quadTree/QuadTreeImage.java | 48 ++++++++++++------- 2 files changed, 38 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java index 4e3961e40..16bd0a101 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java @@ -143,8 +143,9 @@ public class LodQuadTree { /* if(posX<0) WE = 1 - WE; if(posZ<0) NS = 1 - NS; - - */ + */ + if(posX<0) System.out.println(WE); + if(posZ<0) System.out.println(NS); if (getChild(NS, WE) == null) { setChild(NS, WE); @@ -246,8 +247,8 @@ public class LodQuadTree { List dataList = new ArrayList<>(); for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { - if (children[NS][WE] != null) { - dataList.add(children[NS][WE].getLodNodeData()); + if (getChild(NS,WE) != null) { + dataList.add(getChild(NS,WE).getLodNodeData()); isEmpty = false; } else { isFull = false; @@ -367,8 +368,7 @@ public class LodQuadTree { if ( targetLevel > lodNodeData.level ) { return nodeList; } - // - if ((min > maxDistance || max < minDistance) && !isCoordinateInLevel(x,z)){ + if ((min > maxDistance || max < minDistance)/* && !isCoordinateInLevel(x,z)*/){ return nodeList; } if(isNodeFull()) { diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java index 8450cbf5f..7dd221151 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java @@ -75,16 +75,28 @@ public class QuadTreeImage extends JPanel { } private static void createAndShowGui() { - int playerX =-40; - int playerZ =-250; - LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 16); + int playerX = 0; + int playerZ = 0; + LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 4); System.out.println(dim.getRegion(0, 0)); dim.move(Math.floorDiv(playerX,512),Math.floorDiv(playerZ,512)); - System.out.println(playerX/512 + " " + playerZ/512); System.out.println(dim.getCenterX()); System.out.println(dim.getCenterZ()); System.out.println(dim.getWidth()); + LodQuadTree level2 = dim.getRegion( + -1, + -1 + ); + + int startX2 = level2.getLodNodeData().startX; + int startZ2 = level2.getLodNodeData().startZ; + int endX2 = level2.getLodNodeData().endX; + int endZ2 = level2.getLodNodeData().endZ; + int centerX2 = level2.getLodNodeData().centerX; + int centerZ2 = level2.getLodNodeData().centerZ; + int width2 = level2.getLodNodeData().width; + System.out.println(startX2+" "+startZ2+" "+centerX2+" "+centerZ2); final QuadTreeImage quadTreeImage = new QuadTreeImage(); @@ -101,7 +113,7 @@ public class QuadTreeImage extends JPanel { for (int i = 0; i <= (9 - 2); i++) { for (int j = 0; j < 1; j++) { List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), distances[i], 0); - System.out.println(levelToGenerate); + //System.out.println(levelToGenerate); for (LodQuadTree level : levelToGenerate) { Color color; int startX = level.getLodNodeData().startX; @@ -117,15 +129,18 @@ public class QuadTreeImage extends JPanel { List posXs = new ArrayList<>(); List posZs = new ArrayList<>(); if (level.getLodNodeData().level == 0) { - posXs.add(startX / otherWidth); - posZs.add(startZ / otherWidth); + posXs.add(Math.floorDiv(startX , otherWidth)); + posZs.add(Math.floorDiv(startZ , otherWidth)); } else { - posXs.add(startX / otherWidth); - posXs.add(centerX / otherWidth); - posZs.add(startZ / otherWidth); - posZs.add(centerZ / otherWidth); + posXs.add(Math.floorDiv(startX , otherWidth)); + posXs.add(Math.floorDiv(centerX + 1, otherWidth)); + posZs.add(Math.floorDiv(startZ, otherWidth)); + posZs.add(Math.floorDiv(centerZ +1 , otherWidth)); } + //System.out.println(posXs); + //System.out.println(posZs); + for (Integer posXI : posXs) { for (Integer posZI : posZs) { int posX = posXI.intValue(); @@ -139,6 +154,7 @@ public class QuadTreeImage extends JPanel { } } } + /* List lodList = new ArrayList<>(); lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 3, 250,0)); lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 4, 500,250)); @@ -148,7 +164,8 @@ public class QuadTreeImage extends JPanel { lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 8, 8000,4000)); lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 9, 100000,8000)); System.out.println(lodList.size()); - //Collection lodList = dim.getNodes(false,false,false); + */ + List lodList = dim.getNodes(false,false,false); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 4, 400, 200)); @@ -157,7 +174,6 @@ public class QuadTreeImage extends JPanel { } - System.out.println(listOfList); int timerDelay = 0; System.out.println("STARTING"); System.out.println(dim.getWidth()); @@ -176,7 +192,7 @@ public class QuadTreeImage extends JPanel { } else { if(drawCount==0) quadTreeImage.clearAll(); final List myDrawables = new ArrayList<>(); - double amp = 0.1; + double amp = 0.4; Collection lodList = listOfList.get(drawCount); for (LodNodeData data : lodList) { myDrawables.add(new MyDrawable(new Rectangle2D.Double( @@ -262,9 +278,9 @@ class MyDrawable { Stroke oldStroke = g2.getStroke(); g2.setColor(color); - g2.fill(shape); + //g2.fill(shape); - //g2.setStroke(stroke); + g2.setStroke(stroke); g2.draw(shape); g2.setColor(oldColor); From e8b46a6fd26e6fc8624c8ff22123b99a0835e40e Mon Sep 17 00:00:00 2001 From: Leonardo Date: Tue, 13 Jul 2021 00:52:24 +0200 Subject: [PATCH 27/46] Converting the quadTree to use the LodDataPoint class --- .../com/seibel/lod/objects/LodDataPoint.java | 14 +- .../objects/{quadTree => }/LodQuadTree.java | 176 +++++++++--------- .../LodNodeData.java => LodQuadTreeNode.java} | 88 ++++----- 3 files changed, 143 insertions(+), 135 deletions(-) rename src/main/java/com/seibel/lod/objects/{quadTree => }/LodQuadTree.java (67%) rename src/main/java/com/seibel/lod/objects/{quadTree/LodNodeData.java => LodQuadTreeNode.java} (76%) diff --git a/src/main/java/com/seibel/lod/objects/LodDataPoint.java b/src/main/java/com/seibel/lod/objects/LodDataPoint.java index 964d541c5..bed05956e 100644 --- a/src/main/java/com/seibel/lod/objects/LodDataPoint.java +++ b/src/main/java/com/seibel/lod/objects/LodDataPoint.java @@ -1,6 +1,7 @@ package com.seibel.lod.objects; import java.awt.Color; +import java.util.Objects; import com.seibel.lod.handlers.LodDimensionFileHandler; @@ -55,8 +56,17 @@ public class LodDataPoint depth = (short) newDepth; color = newColor; } - - + + public int hashCode(){ + return Objects.hash(this.height, this.depth, this.color); + } + + public boolean equals(LodDataPoint other){ + return (this.height == other.height + && this.depth == other.depth + && this.color == other.color); + } + /** * Outputs all data in a csv format * with the given delimiter. diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/LodQuadTree.java similarity index 67% rename from src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java rename to src/main/java/com/seibel/lod/objects/LodQuadTree.java index 16bd0a101..82378f58b 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -1,8 +1,10 @@ -package com.seibel.lod.objects.quadTree; +package com.seibel.lod.objects; import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; +import java.util.Set; + /** * This object contains all data useful to render LodBlock in a region (32x32 chunk o 512x512 block) * for every node it contains the border of the block, the size, the position at it's level, the color, the height and the depth. @@ -35,7 +37,7 @@ public class LodQuadTree { //data useful to render //if children are present then lodNodeData should be a combination of the lodData of the child. This can be //turned off by deselecting the recursive update in all update method. - private LodNodeData lodNodeData; + private LodQuadTreeNode lodQuadTreeNode; /* .____.____. | NW | NE | | @@ -71,7 +73,7 @@ public class LodQuadTree { */ //maybe the use of useLevelCoordinate could be changed. I could use a builder to do all this work. public LodQuadTree(int regionX, int regionZ) { - this(null, new LodNodeData(LodNodeData.REGION_LEVEL, regionX, regionZ)); + this(null, new LodQuadTreeNode(LodQuadTreeNode.REGION_LEVEL, regionX, regionZ)); } /** @@ -83,17 +85,17 @@ public class LodQuadTree { * @param posZ position z in the level */ public LodQuadTree(LodQuadTree parent, byte level, int posX, int posZ) { - this(parent, new LodNodeData(level, posX, posZ)); + this(parent, new LodQuadTreeNode(level, posX, posZ)); } /** * Constructor for generic level via the LodNodeData * - * @param lodNodeData object containing all the information of this node + * @param lodQuadTreeNode object containing all the information of this node */ - public LodQuadTree(LodQuadTree parent, LodNodeData lodNodeData) { + public LodQuadTree(LodQuadTree parent, LodQuadTreeNode lodQuadTreeNode) { this.parent = parent; - this.lodNodeData = lodNodeData; + this.lodQuadTreeNode = lodQuadTreeNode; this.children = new LodQuadTree[2][2]; this.nodeEmpty = true; this.nodeFull = false; @@ -106,8 +108,8 @@ public class LodQuadTree { * @param regionX x region coordinate * @param regionZ z region coordinate */ - public LodQuadTree(List dataList, int regionX, int regionZ) { - this(null, new LodNodeData(LodNodeData.REGION_LEVEL, regionX, regionZ)); + public LodQuadTree(List dataList, int regionX, int regionZ) { + this(null, new LodQuadTreeNode(LodQuadTreeNode.REGION_LEVEL, regionX, regionZ)); this.setNodesAtLowerLevel(dataList, true); } @@ -116,26 +118,26 @@ public class LodQuadTree { * @param dataList list of data to put in the node * @param updateHigherLevel will update the color and height of higher level only if true */ - public void setNodesAtLowerLevel(List dataList, boolean updateHigherLevel) { - for (LodNodeData lodNodeData : dataList) { + public void setNodesAtLowerLevel(List dataList, boolean updateHigherLevel) { + for (LodQuadTreeNode lodQuadTreeNode : dataList) { //this is slow, you could set update to false and use an only top down update method. - this.setNodeAtLowerLevel(lodNodeData, updateHigherLevel); + this.setNodeAtLowerLevel(lodQuadTreeNode, updateHigherLevel); } } /** - * @param newLodNodeData data to put in the node + * @param newLodQuadTreeNode data to put in the node * @param updateHigherLevel will update the color and height of higher level only if true * @return true only if the QuadTree has been changed */ - public boolean setNodeAtLowerLevel(LodNodeData newLodNodeData, boolean updateHigherLevel) { + public boolean setNodeAtLowerLevel(LodQuadTreeNode newLodQuadTreeNode, boolean updateHigherLevel) { //check if we try to introduce a level that is higher or equal than the current one - byte targetLevel = newLodNodeData.level; - byte currentLevel = lodNodeData.level; + byte targetLevel = newLodQuadTreeNode.level; + byte currentLevel = lodQuadTreeNode.level; if (targetLevel < currentLevel) { - int posX = newLodNodeData.posX; - int posZ = newLodNodeData.posZ; - short widthRatio = (short) (lodNodeData.width / (2 * newLodNodeData.width)); + int posX = newLodQuadTreeNode.posX; + int posZ = newLodQuadTreeNode.posZ; + short widthRatio = (short) (lodQuadTreeNode.width / (2 * newLodQuadTreeNode.width)); int WE = Math.abs(Math.floorDiv(posX , widthRatio) % 2); int NS = Math.abs(Math.floorDiv(posZ , widthRatio) % 2); //These two if fix the negative coordinate problema @@ -151,14 +153,14 @@ public class LodQuadTree { setChild(NS, WE); } LodQuadTree child = getChild(NS, WE); - if (!newLodNodeData.real && child.isNodeReal()) { + if (!newLodQuadTreeNode.real && child.isNodeReal()) { return false; } else { if (targetLevel == currentLevel - 1) { - child.setLodNodeData(newLodNodeData, true); + child.setLodNodeData(newLodQuadTreeNode, true); return true; } else { - return child.setNodeAtLowerLevel(newLodNodeData, updateHigherLevel); + return child.setNodeAtLowerLevel(newLodQuadTreeNode, updateHigherLevel); } } } else { @@ -173,13 +175,13 @@ public class LodQuadTree { * @param level * @return */ - public LodNodeData getNodeAtLevelPosition(int posX, int posZ, byte level) { + public LodQuadTreeNode getNodeAtLevelPosition(int posX, int posZ, byte level) { byte targetLevel = level; - byte currentLevel = lodNodeData.level; + byte currentLevel = lodQuadTreeNode.level; if (targetLevel == currentLevel) { - return lodNodeData; + return lodQuadTreeNode; } else if (targetLevel < currentLevel) { - short widthRatio = (short) (lodNodeData.width / (2 * Math.pow(2, level))); + short widthRatio = (short) (lodQuadTreeNode.width / (2 * Math.pow(2, level))); int WE = Math.abs(Math.floorDiv(posX , widthRatio) % 2); int NS = Math.abs(Math.floorDiv(posZ , widthRatio) % 2); if (getChild(NS, WE) == null) { @@ -201,26 +203,26 @@ public class LodQuadTree { /** * setChild will put a child with given data in the given position * - * @param newLodNodeData data to put in the child + * @param newLodQuadTreeNode data to put in the child * @param NS North-South position * @param WE West-East position */ - public void setChild(LodNodeData newLodNodeData, int NS, int WE) { - if (newLodNodeData.level == lodNodeData.level - 1) { - children[NS][WE] = new LodQuadTree(this, lodNodeData); + public void setChild(LodQuadTreeNode newLodQuadTreeNode, int NS, int WE) { + if (newLodQuadTreeNode.level == lodQuadTreeNode.level - 1) { + children[NS][WE] = new LodQuadTree(this, lodQuadTreeNode); } } /** * setChild will put a child with given data in the given position * - * @param newLodNodeData data to put in the child + * @param newLodQuadTreeNode data to put in the child */ - public void setChild(LodNodeData newLodNodeData) { - if (newLodNodeData.level == lodNodeData.level - 1) { - int WE = newLodNodeData.posX % lodNodeData.posX; - int NS = newLodNodeData.posZ % lodNodeData.posZ; - children[NS][WE] = new LodQuadTree(this, lodNodeData); + public void setChild(LodQuadTreeNode newLodQuadTreeNode) { + if (newLodQuadTreeNode.level == lodQuadTreeNode.level - 1) { + int WE = newLodQuadTreeNode.posX % lodQuadTreeNode.posX; + int NS = newLodQuadTreeNode.posZ % lodQuadTreeNode.posZ; + children[NS][WE] = new LodQuadTree(this, lodQuadTreeNode); } } @@ -231,9 +233,9 @@ public class LodQuadTree { * @param WE West-East position */ public void setChild(int NS, int WE) { - int childX = lodNodeData.posX * 2 + WE; - int childZ = lodNodeData.posZ * 2 + NS; - children[NS][WE] = new LodQuadTree(this, (byte) (lodNodeData.level - 1), childX, childZ); + int childX = lodQuadTreeNode.posX * 2 + WE; + int childZ = lodQuadTreeNode.posZ * 2 + NS; + children[NS][WE] = new LodQuadTree(this, (byte) (lodQuadTreeNode.level - 1), childX, childZ); } /** @@ -244,7 +246,7 @@ public class LodQuadTree { private void updateLevel(boolean recursiveUpdate) { boolean isFull = true; boolean isEmpty = true; - List dataList = new ArrayList<>(); + List dataList = new ArrayList<>(); for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { if (getChild(NS,WE) != null) { @@ -257,42 +259,46 @@ public class LodQuadTree { } nodeFull = isFull; nodeEmpty = isEmpty; - lodNodeData.combineData(dataList); - if (lodNodeData.level < 9 && recursiveUpdate) { + lodQuadTreeNode.combineData(dataList); + if (lodQuadTreeNode.level < 9 && recursiveUpdate) { this.parent.updateLevel(recursiveUpdate); } } /** + * * method to get certain nodes from the LodQuadTree * - * @param getOnlyReal if true it will return only real nodes + * @param complexityMask set of complexity to accept * @param getOnlyDirty if true it will return only dirty nodes * @param getOnlyLeaf if true it will return only leaf nodes * @return list of nodes */ - public List getNodeList(boolean getOnlyReal, boolean getOnlyDirty, boolean getOnlyLeaf) { - List nodeList = new ArrayList<>(); - if (!isThereAnyChild()) { - if (!(getOnlyReal && !lodNodeData.dirty) - && !(getOnlyReal && !lodNodeData.real)) { - nodeList.add(lodNodeData); - } - } else { + public List getNodeList(Set complexityMask, boolean getOnlyDirty, boolean getOnlyLeaf) { + List nodeList = new ArrayList<>(); + if (isThereAnyChild()) { + //There is at least 1 child if (!getOnlyLeaf - && !(getOnlyDirty && !lodNodeData.dirty) - && !(getOnlyReal && !lodNodeData.real)) { - nodeList.add(lodNodeData); + && !(getOnlyDirty && !lodQuadTreeNode.dirty) + && complexityMask.contains(lodQuadTreeNode.complexity)) { + nodeList.add(lodQuadTreeNode); } for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { LodQuadTree child = children[NS][WE]; if (child != null) { - nodeList.addAll(child.getNodeList(getOnlyReal, getOnlyDirty, getOnlyLeaf)); + nodeList.addAll(child.getNodeList(complexityMask, getOnlyDirty, getOnlyLeaf)); } } } + } else { + //There are no children + if (!(getOnlyDirty && !lodQuadTreeNode.dirty) + || (complexityMask.contains((int) lodQuadTreeNode.complexity))){ + nodeList.add(lodQuadTreeNode); + } } + return nodeList; } @@ -306,29 +312,29 @@ public class LodQuadTree { * @param minDistance minimum distance from the player * @return */ - public List getNodeToRender(int x, int z, byte targetLevel, int maxDistance, int minDistance) { - int distance = (int) Math.sqrt(Math.pow(x - lodNodeData.centerX, 2) + Math.pow(z - lodNodeData.centerZ, 2)); + public List getNodeToRender(int x, int z, byte targetLevel, int maxDistance, int minDistance) { + int distance = (int) Math.sqrt(Math.pow(x - lodQuadTreeNode.centerX, 2) + Math.pow(z - lodQuadTreeNode.centerZ, 2)); List distances = new ArrayList(); distances.add(distance); - distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.startX, 2) + Math.pow(z - lodNodeData.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.startX, 2) + Math.pow(z - lodNodeData.endZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.endX, 2) + Math.pow(z - lodNodeData.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.endX, 2) + Math.pow(z - lodNodeData.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); - List nodeList = new ArrayList<>(); - if (targetLevel > lodNodeData.level) { + List nodeList = new ArrayList<>(); + if (targetLevel > lodQuadTreeNode.level) { return nodeList; } if ((min > maxDistance || max < minDistance) /*&& !isCoordinateInLevel(x,z)*/){ return nodeList; } - if (targetLevel == lodNodeData.level || !isNodeFull()) { - if (lodNodeData.voidNode) { - nodeList.add(lodNodeData); + if (targetLevel == lodQuadTreeNode.level || !isNodeFull()) { + if (lodQuadTreeNode.voidNode) { + nodeList.add(lodQuadTreeNode); return nodeList; } else { - nodeList.add(lodNodeData); + nodeList.add(lodQuadTreeNode); return nodeList; } } else { @@ -355,17 +361,17 @@ public class LodQuadTree { * @return */ public List> getLevelToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance) { - int distance = (int) Math.sqrt(Math.pow(x - lodNodeData.centerX, 2) + Math.pow(z - lodNodeData.centerZ, 2)); + int distance = (int) Math.sqrt(Math.pow(x - lodQuadTreeNode.centerX, 2) + Math.pow(z - lodQuadTreeNode.centerZ, 2)); List distances = new ArrayList(); distances.add(distance); - distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.startX, 2) + Math.pow(z - lodNodeData.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.startX, 2) + Math.pow(z - lodNodeData.endZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.endX, 2) + Math.pow(z - lodNodeData.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodNodeData.endX, 2) + Math.pow(z - lodNodeData.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List> nodeList = new ArrayList<>(); - if ( targetLevel > lodNodeData.level ) { + if ( targetLevel > lodQuadTreeNode.level ) { return nodeList; } if ((min > maxDistance || max < minDistance)/* && !isCoordinateInLevel(x,z)*/){ @@ -373,7 +379,7 @@ public class LodQuadTree { } if(isNodeFull()) { //THIS LEVEL HAS CHILD SO IT'S GENERATED. - if (targetLevel != lodNodeData.level) { + if (targetLevel != lodQuadTreeNode.level) { for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { if (getChild(NS,WE) == null) { @@ -412,21 +418,21 @@ public class LodQuadTree { * * @return lodNodeData */ - public LodNodeData getLodNodeData() { - return lodNodeData; + public LodQuadTreeNode getLodNodeData() { + return lodQuadTreeNode; } /** * setter for lodNodeData, to maintain a correct relationship between level this method force update on all parent * - * @param newLodNodeData data to set + * @param newLodQuadTreeNode data to set * @param updateHigherLevel if true it will update all the upper levels. */ - public void setLodNodeData(LodNodeData newLodNodeData, boolean updateHigherLevel) { - if (this.lodNodeData == null) { - this.lodNodeData = newLodNodeData; + public void setLodNodeData(LodQuadTreeNode newLodQuadTreeNode, boolean updateHigherLevel) { + if (this.lodQuadTreeNode == null) { + this.lodQuadTreeNode = newLodQuadTreeNode; } else { - this.lodNodeData.update(newLodNodeData); + this.lodQuadTreeNode.update(newLodQuadTreeNode); } //a recursive update is necessary to change higher level if (parent != null && updateHigherLevel) parent.updateLevel(true); @@ -441,20 +447,20 @@ public class LodQuadTree { } public boolean isNodeReal() { - return lodNodeData.real; + return lodQuadTreeNode.real; } public boolean isRenderable() { - return (lodNodeData != null); + return (lodQuadTreeNode != null); } public boolean isCoordinateInLevel(int x, int z){ - return !(lodNodeData.startX > x || lodNodeData.startZ > z || lodNodeData.endX < x || lodNodeData.endZ < z); + return !(lodQuadTreeNode.startX > x || lodQuadTreeNode.startZ > z || lodQuadTreeNode.endX < x || lodQuadTreeNode.endZ < z); } public String toString(){ - String s = lodNodeData.toString(); + String s = lodQuadTreeNode.toString(); return s; /* if(isThereAnyChild()){ diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java similarity index 76% rename from src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java rename to src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java index 7a818fa30..a5edd4ebe 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodNodeData.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java @@ -1,4 +1,4 @@ -package com.seibel.lod.objects.quadTree; +package com.seibel.lod.objects; import com.seibel.lod.handlers.LodQuadTreeDimensionFileHandler; @@ -6,7 +6,7 @@ import java.awt.*; import java.util.*; import java.util.List; -public class LodNodeData { +public class LodQuadTreeNode { /** This is what separates each piece of data in the toData method */ private static final char DATA_DELIMITER = LodQuadTreeDimensionFileHandler.DATA_DELIMITER; @@ -17,6 +17,11 @@ public class LodNodeData { private static final Color INVISIBLE = new Color(0,0,0,0); + //Complexity indicate how complex is this node. For example a node that has been generated starting + //from a real chunk have the maximum complexity. A node that is generated starting from a fake approximated chunk + //has a low complexity + public byte complexity; + //level height goes from 0 to 9 with 0 the deepest (block size) and 9 the highest (region size) public final byte level; public static final byte REGION_LEVEL = 9; //at level 9 we reach the dimension of a single region @@ -48,16 +53,9 @@ public class LodNodeData { public final int centerX; public final int centerZ; - /** highest point */ - public short height; + public LodDataPoint lodDataPoint; - /** lowest point */ - public short depth; - - /** The average color for the 6 cardinal directions */ - public Color color; - - public boolean real; + //void node is used public boolean voidNode; //if dirty is true, then this node have unsaved changes public boolean dirty; @@ -70,7 +68,7 @@ public class LodNodeData { * @param posX position x in the level * @param posZ posizion z in the level */ - public LodNodeData(byte level, int posX, int posZ){ + public LodQuadTreeNode(byte level, int posX, int posZ){ this.level = level; this.posX = posX; this.posZ = posZ; @@ -81,9 +79,7 @@ public class LodNodeData { endZ = startZ + width - 1; centerX = startX + width/2; centerZ = startZ + width/2; - height = -1; - depth = -1; - color = INVISIBLE; + lodDataPoint = new LodDataPoint() real = false; dirty = true; voidNode = true; @@ -94,12 +90,9 @@ public class LodNodeData { * @param level level of this * @param posX * @param posZ - * @param height - * @param depth - * @param color - * @param real + * @param complexity */ - public LodNodeData(byte level, int posX, int posZ, short height, short depth, Color color, boolean real){ + public LodQuadTreeNode(byte level, int posX, int posZ, LodDataPoint lodDataPoint, byte complexity){ this.level = level; this.posX = posX; this.posZ = posZ; @@ -110,19 +103,13 @@ public class LodNodeData { endZ = startZ + width - 1; centerX = startX + width/2; centerZ = startZ + width/2; - this.height = height; - this.depth = depth; - this.color = color; + this.lodDataPoint = lodDataPoint; this.real = real; dirty = true; voidNode = false; } - public LodNodeData(byte level, int posX, int posZ, int height, int depth, Color color, boolean real) { - this(level, posX, posZ, (short) height,(short) depth, color, real); - } - - public LodNodeData(String data) + public LodQuadTreeNode(String data) { int index = 0; int lastIndex = 0; @@ -160,7 +147,7 @@ public class LodNodeData { int a = Integer.parseInt(data.substring(lastIndex+1,index)); this.color = new Color(r,g,b,a); - int val = Integer.parseInt(data.substring(lastIndex+1,index)); + int complexity = Integer.parseInt(data.substring(lastIndex+1,index)); this.real = (val == 1); width = (short) Math.pow(2, level); @@ -175,29 +162,34 @@ public class LodNodeData { dirty = false; } - public void update(LodNodeData lodNodeData){ - this.height = lodNodeData.height; - this.depth = lodNodeData.depth; - this.color = lodNodeData.color; - this.real = lodNodeData.real; + public void update(LodQuadTreeNode lodQuadTreeNode){ + this.lodDataPoint = lodQuadTreeNode.lodDataPoint + this.complexity = lodQuadTreeNode.complexity; + this.voidNode = lodQuadTreeNode.voidNode; dirty = true; } - public void combineData(List dataList){ + public LodDataPoint getLodDataPoint(){ + return lodDataPoint; + } + public byte getComplexity(){ + return complexity; + } + + public void combineData(List dataList){ if(dataList.isEmpty()){ - height = -1; - depth = -1; - color = INVISIBLE; + lodDataPoint = new LodDataPoint(); }else { - short height = (short) dataList.stream().mapToInt(x -> (int) x.height).min().getAsInt(); - short depth = (short) dataList.stream().mapToInt(x -> (int) x.depth).max().getAsInt(); + 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(); height = height; depth = depth; - int red= dataList.stream().mapToInt(x -> x.color.getRed()).sum()/dataList.size(); - int green= dataList.stream().mapToInt(x -> x.color.getGreen()).sum()/dataList.size(); - int blue = dataList.stream().mapToInt(x -> x.color.getBlue()).sum()/dataList.size(); - color = new Color(red,green,blue); - real = dataList.stream().filter(x -> x.real).count() == 4; + 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); + complexity = (byte) dataList.stream().mapToInt(x -> x.complexity).max().getAsInt(); voidNode = dataList.stream().filter(x -> !x.voidNode).count() == 0; } dirty = true; @@ -205,12 +197,12 @@ public class LodNodeData { public int hashCode(){ - return Objects.hash(this.real, this.level, this.posX, this.posZ, this.color, this.real, this.voidNode); + return Objects.hash(this.complexity, this.level, this.posX, this.posZ, this.color, this.real, this.voidNode); } - public boolean equals(LodNodeData other){ - return (this.real == other.real + public boolean equals(LodQuadTreeNode other){ + return (this.complexity == other.complexity && this.level == other.level && this.posX == other.posX && this.posZ == other.posZ From cd06b42b02979133d150d47be8e2725d3c5a921a Mon Sep 17 00:00:00 2001 From: Leonardo Date: Tue, 13 Jul 2021 00:53:24 +0200 Subject: [PATCH 28/46] changed pc --- .../lod/builders/LodNodeBufferBuilder.java | 14 ++++------- .../seibel/lod/builders/LodNodeBuilder.java | 18 +++++++------- .../AbstractLodNodeTemplate.java | 9 +++---- .../CubicLodNodeTemplate.java | 8 +++---- .../DynamicLodNodeTemplate.java | 9 +++---- .../TriangularLodNodeTemplate.java | 9 +++---- .../worldGeneration/LodNodeGenWorker.java | 17 ++++++------- .../LodQuadTreeDimensionFileHandler.java | 16 ++++++------- .../{quadTree => }/LodQuadTreeDimension.java | 24 +++++++++---------- .../{quadTree => }/LodQuadTreeWorld.java | 2 +- .../objects/{quadTree => }/QuadTreeImage.java | 22 +++++++---------- .../seibel/lod/render/LodNodeRenderer.java | 8 +++---- 12 files changed, 62 insertions(+), 94 deletions(-) rename src/main/java/com/seibel/lod/objects/{quadTree => }/LodQuadTreeDimension.java (94%) rename src/main/java/com/seibel/lod/objects/{quadTree => }/LodQuadTreeWorld.java (98%) rename src/main/java/com/seibel/lod/objects/{quadTree => }/QuadTreeImage.java (93%) diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java index c0137843f..a99371552 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -1,13 +1,9 @@ package com.seibel.lod.builders; -import com.seibel.lod.builders.worldGeneration.LodChunkGenWorker; -import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; import com.seibel.lod.objects.NearFarBuffer; -import com.seibel.lod.objects.quadTree.LodNodeData; -import com.seibel.lod.objects.quadTree.LodQuadTree; -import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; +import com.seibel.lod.objects.LodQuadTreeDimension; import com.seibel.lod.render.LodNodeRenderer; import com.seibel.lod.render.LodRenderer; import com.seibel.lod.util.LodUtil; @@ -16,8 +12,6 @@ import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.biome.BiomeContainer; import net.minecraft.world.chunk.ChunkStatus; -import net.minecraft.world.server.ServerWorld; -import net.minecraftforge.common.WorldWorkerManager; import org.lwjgl.opengl.GL11; import java.util.ArrayList; @@ -135,7 +129,7 @@ public class LodNodeBufferBuilder buildableFarBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); - List lodToRender = new ArrayList<>(); + List lodToRender = new ArrayList<>(); lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 0, 100000,0)); /* lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 9, 100000,8000)); @@ -146,7 +140,7 @@ public class LodNodeBufferBuilder lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 4, 500,250)); lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 3, 250,0)); */ - for(LodNodeData data : lodToRender){ + for(LodQuadTreeNode data : lodToRender){ BufferBuilder currentBuffer = null; /* if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2)) diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java index 3bc365d54..ed66c6965 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java @@ -1,10 +1,8 @@ package com.seibel.lod.builders; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.quadTree.LodNodeData; -import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; -import com.seibel.lod.objects.quadTree.LodQuadTreeWorld; +import com.seibel.lod.objects.LodQuadTreeNode; +import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeWorld; import com.seibel.lod.util.LodUtil; import net.minecraft.block.*; import net.minecraft.world.DimensionType; @@ -23,7 +21,7 @@ public class LodNodeBuilder { private long seed; private DimensionType dimension; - public static final int CHUNK_DATA_WIDTH = LodNodeData.CHUNK_WIDTH; + public static final int CHUNK_DATA_WIDTH = LodQuadTreeNode.CHUNK_WIDTH; public static final int CHUNK_SECTION_HEIGHT = 256; public static final Heightmap.Type DEFAULT_HEIGHTMAP = Heightmap.Type.WORLD_SURFACE_WG; @@ -77,7 +75,7 @@ public class LodNodeBuilder { try { DimensionType dim = world.dimensionType(); - LodNodeData node = generateLodNodeFromChunk(chunk); + LodQuadTreeNode node = generateLodNodeFromChunk(chunk); LodQuadTreeDimension lodDim; @@ -106,7 +104,7 @@ public class LodNodeBuilder { * * @throws IllegalArgumentException thrown if either the chunk or world is null. */ - public LodNodeData generateLodNodeFromChunk(IChunk chunk) throws IllegalArgumentException { + public LodQuadTreeNode generateLodNodeFromChunk(IChunk chunk) throws IllegalArgumentException { return generateLodNodeFromChunk(chunk, new LodBuilderConfig()); } @@ -116,7 +114,7 @@ public class LodNodeBuilder { * @throws IllegalArgumentException thrown if either the chunk or world is null. * @return */ - public LodNodeData generateLodNodeFromChunk(IChunk chunk, LodBuilderConfig config) throws IllegalArgumentException { + public LodQuadTreeNode generateLodNodeFromChunk(IChunk chunk, LodBuilderConfig config) throws IllegalArgumentException { if (chunk == null) throw new IllegalArgumentException("generateLodFromChunk given a null chunk"); @@ -136,7 +134,7 @@ public class LodNodeBuilder { depth = determineBottomPointForArea(chunk.getSections(), startX, startZ, endX, endZ); - return new LodNodeData(LodNodeData.CHUNK_LEVEL, chunk.getPos().x, chunk.getPos().z, height, depth, color, true); + return new LodQuadTreeNode(LodQuadTreeNode.CHUNK_LEVEL, chunk.getPos().x, chunk.getPos().z, height, depth, color, true); } diff --git a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/AbstractLodNodeTemplate.java b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/AbstractLodNodeTemplate.java index 1c7645b4b..ab2b2e084 100644 --- a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/AbstractLodNodeTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/AbstractLodNodeTemplate.java @@ -1,10 +1,7 @@ package com.seibel.lod.builders.lodNodeTemplates; -import com.seibel.lod.enums.LodDetail; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.quadTree.LodNodeData; -import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; +import com.seibel.lod.objects.LodQuadTreeDimension; import net.minecraft.client.renderer.BufferBuilder; /** @@ -17,7 +14,7 @@ import net.minecraft.client.renderer.BufferBuilder; public abstract class AbstractLodNodeTemplate { public abstract void addLodToBuffer(BufferBuilder buffer, - LodQuadTreeDimension lodDim, LodNodeData lod, + LodQuadTreeDimension lodDim, LodQuadTreeNode lod, double xOffset, double yOffset, double zOffset, boolean debugging); diff --git a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java index e9f820464..230f74470 100644 --- a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java @@ -3,10 +3,8 @@ package com.seibel.lod.builders.lodNodeTemplates; import com.seibel.lod.enums.ColorDirection; import com.seibel.lod.enums.LodDetail; import com.seibel.lod.handlers.LodConfig; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.quadTree.LodNodeData; -import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; +import com.seibel.lod.objects.LodQuadTreeDimension; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.math.AxisAlignedBB; @@ -27,7 +25,7 @@ public class CubicLodNodeTemplate extends AbstractLodNodeTemplate { @Override public void addLodToBuffer(BufferBuilder buffer, - LodQuadTreeDimension lodDim, LodNodeData lod, + LodQuadTreeDimension lodDim, LodQuadTreeNode lod, double xOffset, double yOffset, double zOffset, boolean debugging) { AxisAlignedBB bbox; diff --git a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/DynamicLodNodeTemplate.java b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/DynamicLodNodeTemplate.java index a5e1f078f..f9eebcb85 100644 --- a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/DynamicLodNodeTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/DynamicLodNodeTemplate.java @@ -1,10 +1,7 @@ package com.seibel.lod.builders.lodNodeTemplates; -import com.seibel.lod.enums.LodDetail; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.quadTree.LodNodeData; -import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; +import com.seibel.lod.objects.LodQuadTreeDimension; import net.minecraft.client.renderer.BufferBuilder; /** @@ -20,7 +17,7 @@ public class DynamicLodNodeTemplate extends AbstractLodNodeTemplate { @Override public void addLodToBuffer(BufferBuilder buffer, - LodQuadTreeDimension lodDim, LodNodeData lod, + LodQuadTreeDimension lodDim, LodQuadTreeNode lod, double xOffset, double yOffset, double zOffset, boolean debugging) { diff --git a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/TriangularLodNodeTemplate.java b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/TriangularLodNodeTemplate.java index 2a4d5612d..045900c09 100644 --- a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/TriangularLodNodeTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/TriangularLodNodeTemplate.java @@ -1,10 +1,7 @@ package com.seibel.lod.builders.lodNodeTemplates; -import com.seibel.lod.enums.LodDetail; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.quadTree.LodNodeData; -import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; +import com.seibel.lod.objects.LodQuadTreeDimension; import net.minecraft.client.renderer.BufferBuilder; /** @@ -18,7 +15,7 @@ public class TriangularLodNodeTemplate extends AbstractLodNodeTemplate { @Override public void addLodToBuffer(BufferBuilder buffer, - LodQuadTreeDimension lodDim, LodNodeData lod, + LodQuadTreeDimension lodDim, LodQuadTreeNode lod, double xOffset, double yOffset, double zOffset, boolean debugging) { diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java index f91817e71..774bdf001 100644 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java +++ b/src/main/java/com/seibel/lod/builders/worldGeneration/LodNodeGenWorker.java @@ -4,13 +4,10 @@ import com.seibel.lod.builders.*; import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; import com.seibel.lod.objects.LodRegion; -import com.seibel.lod.objects.quadTree.LodNodeData; -import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; -import com.seibel.lod.proxy.ClientProxy; +import com.seibel.lod.objects.LodQuadTreeNode; +import com.seibel.lod.objects.LodQuadTreeDimension; import com.seibel.lod.render.LodNodeRenderer; -import com.seibel.lod.render.LodRenderer; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.util.WeightedList.Entry; @@ -82,7 +79,7 @@ public class LodNodeGenWorker implements IWorker if (!threadStarted) { // make sure we don't generate this chunk again - thread.lodDim.addNode(new LodNodeData(LodNodeData.CHUNK_LEVEL,thread.pos.x, thread.pos.z)); + thread.lodDim.addNode(new LodQuadTreeNode(LodQuadTreeNode.CHUNK_LEVEL,thread.pos.x, thread.pos.z)); thread.lodBufferBuilder.numberOfChunksWaitingToGenerate--; @@ -282,7 +279,7 @@ public class LodNodeGenWorker implements IWorker chunk.setHeightmap(LodChunk.DEFAULT_HEIGHTMAP, heightmap.getRawData()); - LodNodeData lod; + LodQuadTreeNode lod; if (!inTheEnd) { lod = lodChunkBuilder.generateLodNodeFromChunk(chunk, new LodBuilderConfig(true, true, false)); @@ -292,7 +289,7 @@ public class LodNodeGenWorker implements IWorker // if we are in the end, don't generate any chunks. // Since we don't know where the islands are, everything // generates the same and it looks really bad. - lod = new LodNodeData(LodNodeData.CHUNK_LEVEL,chunk.getPos().x, chunk.getPos().z); + lod = new LodQuadTreeNode(LodQuadTreeNode.CHUNK_LEVEL,chunk.getPos().x, chunk.getPos().z); } lodDim.addNode(lod); } @@ -325,7 +322,7 @@ public class LodNodeGenWorker implements IWorker IceAndSnowFeature snowFeature = new IceAndSnowFeature(NoFeatureConfig.CODEC); snowFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition(), null); - LodNodeData lod = lodChunkBuilder.generateLodNodeFromChunk(chunk, new LodBuilderConfig(true, true, false)); + LodQuadTreeNode lod = lodChunkBuilder.generateLodNodeFromChunk(chunk, new LodBuilderConfig(true, true, false)); lodDim.addNode(lod); } @@ -445,7 +442,7 @@ public class LodNodeGenWorker implements IWorker // generate a Lod like normal - LodNodeData lod = lodChunkBuilder.generateLodNodeFromChunk(chunk, new LodBuilderConfig(true, true, false)); + LodQuadTreeNode lod = lodChunkBuilder.generateLodNodeFromChunk(chunk, new LodBuilderConfig(true, true, false)); lodDim.addNode(lod); } diff --git a/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java b/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java index 9ab9af696..569ee74ed 100644 --- a/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java +++ b/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java @@ -1,8 +1,8 @@ package com.seibel.lod.handlers; -import com.seibel.lod.objects.quadTree.LodNodeData; -import com.seibel.lod.objects.quadTree.LodQuadTree; -import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; +import com.seibel.lod.objects.LodQuadTree; +import com.seibel.lod.objects.LodQuadTreeDimension; import com.seibel.lod.proxy.ClientProxy; import java.io.*; @@ -83,7 +83,7 @@ public class LodQuadTreeDimensionFileHandler { return null; } - List dataList = new ArrayList<>(); + List dataList = new ArrayList<>(); try { BufferedReader br = new BufferedReader(new FileReader(f)); @@ -144,7 +144,7 @@ public class LodQuadTreeDimensionFileHandler { { try { - dataList.add(new LodNodeData(s)); + dataList.add(new LodQuadTreeNode(s)); } catch(IllegalArgumentException e) { @@ -275,9 +275,9 @@ public class LodQuadTreeDimensionFileHandler { fw.write(LOD_FILE_VERSION_PREFIX + " " + LOD_SAVE_FILE_VERSION + "\n"); // add each LodChunk to the file - for(LodNodeData lodNodeData : Collections.unmodifiableList(region.getNodeList(false, true, true))) { - fw.write(lodNodeData.toData() + "\n"); - lodNodeData.dirty = false; + for(LodQuadTreeNode lodQuadTreeNode : Collections.unmodifiableList(region.getNodeList(false, true, true))) { + fw.write(lodQuadTreeNode.toData() + "\n"); + lodQuadTreeNode.dirty = false; } fw.close(); } diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java similarity index 94% rename from src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java rename to src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java index 474aa7b3f..563695ca3 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java @@ -1,8 +1,6 @@ -package com.seibel.lod.objects.quadTree; +package com.seibel.lod.objects; import com.seibel.lod.handlers.LodQuadTreeDimensionFileHandler; -import com.seibel.lod.objects.LodWorld; -import com.seibel.lod.objects.RegionPos; import com.seibel.lod.util.LodUtil; import net.minecraft.client.Minecraft; import net.minecraft.world.DimensionType; @@ -253,11 +251,11 @@ public class LodQuadTreeDimension { * stored in the LOD. If an LOD already exists at the given * coordinates it will be overwritten. */ - public Boolean addNode(LodNodeData lodNodeData) + public Boolean addNode(LodQuadTreeNode lodQuadTreeNode) { RegionPos pos = new RegionPos( - lodNodeData.startX / 512, - lodNodeData.startZ / 512 + lodQuadTreeNode.startX / 512, + lodQuadTreeNode.startZ / 512 ); // don't continue if the region can't be saved @@ -274,10 +272,10 @@ public class LodQuadTreeDimension { region = new LodQuadTree(pos.x, pos.z); setRegion(region); } - boolean coorectlyAdded = region.setNodeAtLowerLevel(lodNodeData, true); + boolean coorectlyAdded = region.setNodeAtLowerLevel(lodQuadTreeNode, true); // don't save empty place holders to disk - if (lodNodeData.real && fileHandler != null) + if (lodQuadTreeNode.real && fileHandler != null) { // mark the region as dirty so it will be saved to disk int xIndex = (pos.x - centerX) + halfWidth; @@ -295,7 +293,7 @@ public class LodQuadTreeDimension { * Returns null if the LodChunk doesn't exist or * is outside the loaded area. */ - public LodNodeData getLodFromCoordinates(int posX, int posZ, byte level) + public LodQuadTreeNode getLodFromCoordinates(int posX, int posZ, byte level) { LodQuadTree region = getRegion((int) (posX/(512/Math.pow(level,2))),(int) (posZ/(512/Math.pow(level,2)))); if(region == null) @@ -316,9 +314,9 @@ public class LodQuadTreeDimension { * method to get all the nodes that have to be rendered based on the position of the player * @return list of nodes */ - public List getNodeToRender(int x, int z, byte level, int maxDistance, int minDistance){ + public List getNodeToRender(int x, int z, byte level, int maxDistance, int minDistance){ int n = regions.length; - List listOfData = new ArrayList<>(); + List listOfData = new ArrayList<>(); for(int i=0; i getNodes(boolean getOnlyReal, boolean getOnlyDirty, boolean getOnlyLeaf){ + public List getNodes(boolean getOnlyReal, boolean getOnlyDirty, boolean getOnlyLeaf){ int n = regions.length; - List listOfNodes = new ArrayList<>(); + List listOfNodes = new ArrayList<>(); int xIndex; int zIndex; LodQuadTree region; diff --git a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeWorld.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeWorld.java similarity index 98% rename from src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeWorld.java rename to src/main/java/com/seibel/lod/objects/LodQuadTreeWorld.java index 199d7f751..226088836 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/LodQuadTreeWorld.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeWorld.java @@ -1,4 +1,4 @@ -package com.seibel.lod.objects.quadTree; +package com.seibel.lod.objects; import net.minecraft.world.DimensionType; diff --git a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java similarity index 93% rename from src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java rename to src/main/java/com/seibel/lod/objects/QuadTreeImage.java index 7dd221151..73cd770be 100644 --- a/src/main/java/com/seibel/lod/objects/quadTree/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -1,8 +1,6 @@ -package com.seibel.lod.objects.quadTree; +package com.seibel.lod.objects; import com.seibel.lod.util.BiomeColorsUtils; -import kaptainwutax.biomeutils.biome.Biome; -import kaptainwutax.biomeutils.source.EndBiomeSource; import kaptainwutax.biomeutils.source.OverworldBiomeSource; import kaptainwutax.mcutils.version.MCVersion; @@ -16,14 +14,10 @@ import java.awt.Shape; import java.awt.Stroke; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.geom.Ellipse2D; -import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; -import java.awt.geom.RoundRectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.util.AbstractMap; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -106,7 +100,7 @@ public class QuadTreeImage extends JPanel { frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); - List> listOfList = new ArrayList<>(); + List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 1000); //EndBiomeSource biomeSource = new EndBiomeSource(MCVersion.v1_16_5, 1000); int[] distances = {100000,8000,4000,2000,1000,500,250,100,50,25}; @@ -123,8 +117,8 @@ public class QuadTreeImage extends JPanel { int centerX = level.getLodNodeData().centerX; int centerZ = level.getLodNodeData().centerZ; int width = level.getLodNodeData().width; - byte otherLevel = LodNodeData.BLOCK_LEVEL; - int otherWidth = LodNodeData.BLOCK_WIDTH; + byte otherLevel = LodQuadTreeNode.BLOCK_LEVEL; + int otherWidth = LodQuadTreeNode.BLOCK_WIDTH; List posXs = new ArrayList<>(); List posZs = new ArrayList<>(); @@ -148,7 +142,7 @@ public class QuadTreeImage extends JPanel { //System.out.println(posX + " " + posZ); color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posX, 0, posZ)); //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); - LodNodeData node = new LodNodeData(otherLevel, posX, posZ, 0, 0, color, true); + LodQuadTreeNode node = new LodQuadTreeNode(otherLevel, posX, posZ, 0, 0, color, true); dim.addNode(node); } } @@ -165,7 +159,7 @@ public class QuadTreeImage extends JPanel { lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 9, 100000,8000)); System.out.println(lodList.size()); */ - List lodList = dim.getNodes(false,false,false); + List lodList = dim.getNodes(false,false,false); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 4, 400, 200)); @@ -193,8 +187,8 @@ public class QuadTreeImage extends JPanel { if(drawCount==0) quadTreeImage.clearAll(); final List myDrawables = new ArrayList<>(); double amp = 0.4; - Collection lodList = listOfList.get(drawCount); - for (LodNodeData data : lodList) { + Collection lodList = listOfList.get(drawCount); + for (LodQuadTreeNode data : lodList) { myDrawables.add(new MyDrawable(new Rectangle2D.Double( ((data.startX - xOffset ) * amp), ((data.startZ - zOffset) * amp), diff --git a/src/main/java/com/seibel/lod/render/LodNodeRenderer.java b/src/main/java/com/seibel/lod/render/LodNodeRenderer.java index 7cec53a77..ea881d746 100644 --- a/src/main/java/com/seibel/lod/render/LodNodeRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodNodeRenderer.java @@ -3,7 +3,6 @@ package com.seibel.lod.render; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.platform.GlStateManager; import com.mojang.blaze3d.systems.RenderSystem; -import com.seibel.lod.builders.LodBufferBuilder; import com.seibel.lod.builders.LodNodeBufferBuilder; import com.seibel.lod.enums.FogDistance; import com.seibel.lod.enums.FogDrawOverride; @@ -11,11 +10,10 @@ import com.seibel.lod.enums.FogQuality; import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.handlers.ReflectionHandler; import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; import com.seibel.lod.objects.NearFarBuffer; import com.seibel.lod.objects.NearFarFogSettings; -import com.seibel.lod.objects.quadTree.LodNodeData; -import com.seibel.lod.objects.quadTree.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; +import com.seibel.lod.objects.LodQuadTreeDimension; import com.seibel.lod.proxy.ClientProxy; import net.minecraft.client.Minecraft; import net.minecraft.client.entity.player.ClientPlayerEntity; @@ -787,7 +785,7 @@ public class LodNodeRenderer { for(int z = centerChunk.z - chunkRenderDist; z < centerChunk.z + chunkRenderDist; z++) { - LodNodeData lod = lodDim.getLodFromCoordinates(x, z, (byte) 4); + LodQuadTreeNode lod = lodDim.getLodFromCoordinates(x, z, (byte) 4); if (lod != null) { short lodHighestPoint = lod.height; From 2c719c41d9f098bc8d6c6cb94c70a4b37e86610c Mon Sep 17 00:00:00 2001 From: Leonardo Date: Tue, 13 Jul 2021 11:38:08 +0200 Subject: [PATCH 29/46] Various change to support LodDataPoint and the DistanceGenerationMode enum --- .../lod/enums/DistanceGenerationMode.java | 1 - .../com/seibel/lod/objects/LodQuadTree.java | 206 ++++++++---------- .../lod/objects/LodQuadTreeDimension.java | 27 ++- .../seibel/lod/objects/LodQuadTreeNode.java | 168 +++++++++++--- .../com/seibel/lod/objects/QuadTreeImage.java | 13 +- 5 files changed, 253 insertions(+), 162 deletions(-) diff --git a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java b/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java index e309e4ad1..dabf794ed 100644 --- a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java +++ b/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java @@ -47,5 +47,4 @@ public enum DistanceGenerationMode * are adding the mod to a pre-existing world. * Singlethreaded - Slow (15-50 ms, with spikes up to 200 ms) */ SERVER; - } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/LodQuadTree.java index 82378f58b..a9f2bb637 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -1,5 +1,8 @@ package com.seibel.lod.objects; +import com.seibel.lod.enums.DistanceGenerationMode; +import org.lwjgl.system.CallbackI; + import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; @@ -37,7 +40,7 @@ public class LodQuadTree { //data useful to render //if children are present then lodNodeData should be a combination of the lodData of the child. This can be //turned off by deselecting the recursive update in all update method. - private LodQuadTreeNode lodQuadTreeNode; + private LodQuadTreeNode lodNode; /* .____.____. | NW | NE | | @@ -91,11 +94,11 @@ public class LodQuadTree { /** * Constructor for generic level via the LodNodeData * - * @param lodQuadTreeNode object containing all the information of this node + * @param lodNode object containing all the information of this node */ - public LodQuadTree(LodQuadTree parent, LodQuadTreeNode lodQuadTreeNode) { + public LodQuadTree(LodQuadTree parent, LodQuadTreeNode lodNode) { this.parent = parent; - this.lodQuadTreeNode = lodQuadTreeNode; + this.lodNode = lodNode; this.children = new LodQuadTree[2][2]; this.nodeEmpty = true; this.nodeFull = false; @@ -126,18 +129,18 @@ public class LodQuadTree { } /** - * @param newLodQuadTreeNode data to put in the node + * @param newLodNode data to put in the node * @param updateHigherLevel will update the color and height of higher level only if true * @return true only if the QuadTree has been changed */ - public boolean setNodeAtLowerLevel(LodQuadTreeNode newLodQuadTreeNode, boolean updateHigherLevel) { + public boolean setNodeAtLowerLevel(LodQuadTreeNode newLodNode, boolean updateHigherLevel) { //check if we try to introduce a level that is higher or equal than the current one - byte targetLevel = newLodQuadTreeNode.level; - byte currentLevel = lodQuadTreeNode.level; + byte targetLevel = newLodNode.level; + byte currentLevel = lodNode.level; if (targetLevel < currentLevel) { - int posX = newLodQuadTreeNode.posX; - int posZ = newLodQuadTreeNode.posZ; - short widthRatio = (short) (lodQuadTreeNode.width / (2 * newLodQuadTreeNode.width)); + int posX = newLodNode.posX; + int posZ = newLodNode.posZ; + short widthRatio = (short) (lodNode.width / (2 * newLodNode.width)); int WE = Math.abs(Math.floorDiv(posX , widthRatio) % 2); int NS = Math.abs(Math.floorDiv(posZ , widthRatio) % 2); //These two if fix the negative coordinate problema @@ -153,14 +156,16 @@ public class LodQuadTree { setChild(NS, WE); } LodQuadTree child = getChild(NS, WE); - if (!newLodQuadTreeNode.real && child.isNodeReal()) { + if (lodNode.compareComplexity(newLodNode) < 0) { + //the node we want to introduce is less complex than the current node + //we don't want to override higher complexity with lower complexity return false; } else { if (targetLevel == currentLevel - 1) { - child.setLodNodeData(newLodQuadTreeNode, true); + child.setLodNodeData(newLodNode, true); return true; } else { - return child.setNodeAtLowerLevel(newLodQuadTreeNode, updateHigherLevel); + return child.setNodeAtLowerLevel(newLodNode, updateHigherLevel); } } } else { @@ -172,23 +177,22 @@ public class LodQuadTree { /** * @param posX * @param posZ - * @param level + * @param targetLevel * @return */ - public LodQuadTreeNode getNodeAtLevelPosition(int posX, int posZ, byte level) { - byte targetLevel = level; - byte currentLevel = lodQuadTreeNode.level; + public LodQuadTreeNode getNodeAtLevelPosition(int posX, int posZ, byte targetLevel) { + byte currentLevel = lodNode.level; if (targetLevel == currentLevel) { - return lodQuadTreeNode; + return lodNode; } else if (targetLevel < currentLevel) { - short widthRatio = (short) (lodQuadTreeNode.width / (2 * Math.pow(2, level))); + short widthRatio = (short) (lodNode.width / (2 * Math.pow(2, targetLevel))); int WE = Math.abs(Math.floorDiv(posX , widthRatio) % 2); int NS = Math.abs(Math.floorDiv(posZ , widthRatio) % 2); if (getChild(NS, WE) == null) { return null; } LodQuadTree child = getChild(NS, WE); - return child.getNodeAtLevelPosition(posX, posZ, level); + return child.getNodeAtLevelPosition(posX, posZ, targetLevel); } else { return null; } @@ -203,26 +207,26 @@ public class LodQuadTree { /** * setChild will put a child with given data in the given position * - * @param newLodQuadTreeNode data to put in the child + * @param newLodNode data to put in the child * @param NS North-South position * @param WE West-East position */ - public void setChild(LodQuadTreeNode newLodQuadTreeNode, int NS, int WE) { - if (newLodQuadTreeNode.level == lodQuadTreeNode.level - 1) { - children[NS][WE] = new LodQuadTree(this, lodQuadTreeNode); + public void setChild(LodQuadTreeNode newLodNode, int NS, int WE) { + if (newLodNode.level == lodNode.level - 1) { + children[NS][WE] = new LodQuadTree(this, lodNode); } } /** * setChild will put a child with given data in the given position * - * @param newLodQuadTreeNode data to put in the child + * @param newLodNode data to put in the child */ - public void setChild(LodQuadTreeNode newLodQuadTreeNode) { - if (newLodQuadTreeNode.level == lodQuadTreeNode.level - 1) { - int WE = newLodQuadTreeNode.posX % lodQuadTreeNode.posX; - int NS = newLodQuadTreeNode.posZ % lodQuadTreeNode.posZ; - children[NS][WE] = new LodQuadTree(this, lodQuadTreeNode); + public void setChild(LodQuadTreeNode newLodNode) { + if (newLodNode.level == lodNode.level - 1) { + int WE = newLodNode.posX % lodNode.posX; + int NS = newLodNode.posZ % lodNode.posZ; + children[NS][WE] = new LodQuadTree(this, lodNode); } } @@ -233,9 +237,9 @@ public class LodQuadTree { * @param WE West-East position */ public void setChild(int NS, int WE) { - int childX = lodQuadTreeNode.posX * 2 + WE; - int childZ = lodQuadTreeNode.posZ * 2 + NS; - children[NS][WE] = new LodQuadTree(this, (byte) (lodQuadTreeNode.level - 1), childX, childZ); + int childX = lodNode.posX * 2 + WE; + int childZ = lodNode.posZ * 2 + NS; + children[NS][WE] = new LodQuadTree(this, (byte) (lodNode.level - 1), childX, childZ); } /** @@ -259,9 +263,9 @@ public class LodQuadTree { } nodeFull = isFull; nodeEmpty = isEmpty; - lodQuadTreeNode.combineData(dataList); - if (lodQuadTreeNode.level < 9 && recursiveUpdate) { - this.parent.updateLevel(recursiveUpdate); + lodNode.combineData(dataList); + if (lodNode.level < 9 && recursiveUpdate) { + this.parent.updateLevel(true); } } @@ -274,14 +278,14 @@ public class LodQuadTree { * @param getOnlyLeaf if true it will return only leaf nodes * @return list of nodes */ - public List getNodeList(Set complexityMask, boolean getOnlyDirty, boolean getOnlyLeaf) { + public List getNodeList(Set complexityMask, boolean getOnlyDirty, boolean getOnlyLeaf) { List nodeList = new ArrayList<>(); if (isThereAnyChild()) { //There is at least 1 child if (!getOnlyLeaf - && !(getOnlyDirty && !lodQuadTreeNode.dirty) - && complexityMask.contains(lodQuadTreeNode.complexity)) { - nodeList.add(lodQuadTreeNode); + && !(getOnlyDirty && !lodNode.isDirty()) + && complexityMask.contains(lodNode.getComplexity())) { + nodeList.add(lodNode); } for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { @@ -293,9 +297,9 @@ public class LodQuadTree { } } else { //There are no children - if (!(getOnlyDirty && !lodQuadTreeNode.dirty) - || (complexityMask.contains((int) lodQuadTreeNode.complexity))){ - nodeList.add(lodQuadTreeNode); + if (!(getOnlyDirty && !lodNode.isDirty()) + && (complexityMask.contains(lodNode.getComplexity()))){ + nodeList.add(lodNode); } } @@ -312,37 +316,30 @@ public class LodQuadTree { * @param minDistance minimum distance from the player * @return */ - public List getNodeToRender(int x, int z, byte targetLevel, int maxDistance, int minDistance) { - int distance = (int) Math.sqrt(Math.pow(x - lodQuadTreeNode.centerX, 2) + Math.pow(z - lodQuadTreeNode.centerZ, 2)); + public List getNodeToRender(int x, int z, byte targetLevel, Set complexityMask, int maxDistance, int minDistance) { List distances = new ArrayList(); - distances.add(distance); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getCenterX(), 2) + Math.pow(z - lodNode.getCenterX(), 2))); + 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))); + int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List nodeList = new ArrayList<>(); - if (targetLevel > lodQuadTreeNode.level) { - return nodeList; - } - if ((min > maxDistance || max < minDistance) /*&& !isCoordinateInLevel(x,z)*/){ - return nodeList; - } - if (targetLevel == lodQuadTreeNode.level || !isNodeFull()) { - if (lodQuadTreeNode.voidNode) { - nodeList.add(lodQuadTreeNode); - return nodeList; + + if (!(targetLevel > lodNode.level || ((min > maxDistance || max < minDistance) /*&& !isCoordinateInLevel(x,z)*/))) { + if (targetLevel == lodNode.level || !isNodeFull()) { + if (!lodNode.isVoidNode() && complexityMask.contains(lodNode.getComplexity())) { + nodeList.add(lodNode); + } } else { - nodeList.add(lodQuadTreeNode); - return nodeList; - } - } else { - for (int NS = 0; NS <= 1; NS++) { - for (int WE = 0; WE <= 1; WE++) { - LodQuadTree child = getChild(NS,WE); - if (child != null) { - nodeList.addAll(child.getNodeToRender(x, z, targetLevel, maxDistance, minDistance)); + for (int NS = 0; NS <= 1; NS++) { + for (int WE = 0; WE <= 1; WE++) { + LodQuadTree child = getChild(NS, WE); + if (child != null) { + nodeList.addAll(child.getNodeToRender(x, z, targetLevel, complexityMask, maxDistance, minDistance)); + } } } } @@ -350,76 +347,65 @@ public class LodQuadTree { return nodeList; } + /** * Nodes that can be generated in the approximated version * A level is generated only if it has child and is higher than the target level and in the distance range * @param x * @param z * @param targetLevel + * @param complexityToGenerate * @param maxDistance * @param minDistance * @return */ - public List> getLevelToGenerate(int x, int z, byte targetLevel, int maxDistance, int minDistance) { - int distance = (int) Math.sqrt(Math.pow(x - lodQuadTreeNode.centerX, 2) + Math.pow(z - lodQuadTreeNode.centerZ, 2)); + public List> getLevelToGenerate(int x, int z, byte targetLevel, DistanceGenerationMode complexityToGenerate, int maxDistance, int minDistance) { + List distances = new ArrayList(); - distances.add(distance); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.startX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.startZ, 2))); - distances.add((int) Math.sqrt(Math.pow(x - lodQuadTreeNode.endX, 2) + Math.pow(z - lodQuadTreeNode.endZ, 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getCenterX(), 2) + Math.pow(z - lodNode.getCenterX(), 2))); + 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))); + int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List> nodeList = new ArrayList<>(); - if ( targetLevel > lodQuadTreeNode.level ) { - return nodeList; - } - if ((min > maxDistance || max < minDistance)/* && !isCoordinateInLevel(x,z)*/){ + if ( targetLevel > lodNode.level || ((min > maxDistance || max < minDistance)/* && !isCoordinateInLevel(x,z)*/)) { return nodeList; } if(isNodeFull()) { //THIS LEVEL HAS CHILD SO IT'S GENERATED. - if (targetLevel != lodQuadTreeNode.level) { + if (targetLevel != lodNode.level) { for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { if (getChild(NS,WE) == null) { setChild(NS,WE); } LodQuadTree child = getChild(NS,WE); - nodeList.addAll(child.getLevelToGenerate(x, z, targetLevel, maxDistance, minDistance)); - } - } - } - } else { - nodeList.add(new AbstractMap.SimpleEntry<>(this, distance)); - /* - if(isThereAnyChild()){ - for (int NS = 0; NS <= 1; NS++) { - for (int WE = 0; WE <= 1; WE++) { - if (children[NS][WE] == null) { - setChild(NS,WE); - LodQuadTree child = children[NS][WE]; - distance = (int) Math.sqrt(Math.pow(x - child.lodNodeData.centerX, 2) + Math.pow(z - child.lodNodeData.centerZ, 2)); - nodeList.add(new AbstractMap.SimpleEntry<>(child, distance)); - } + nodeList.addAll(child.getLevelToGenerate(x, z, targetLevel, complexityToGenerate, maxDistance, minDistance)); } } }else{ - nodeList.add(new AbstractMap.SimpleEntry<>(this, distance)); + if(this.lodNode.getComplexity().compareTo(complexityToGenerate) > 0) { + //we want to regenerate a level only if we ask for higher complexity + nodeList.add(new AbstractMap.SimpleEntry<>(this, min) + } } - - */ + } else { + nodeList.add(new AbstractMap.SimpleEntry<>(this, min)); } return nodeList; } + /** * simple getter for lodNodeData * * @return lodNodeData */ public LodQuadTreeNode getLodNodeData() { - return lodQuadTreeNode; + return lodNode; } /** @@ -429,10 +415,10 @@ public class LodQuadTree { * @param updateHigherLevel if true it will update all the upper levels. */ public void setLodNodeData(LodQuadTreeNode newLodQuadTreeNode, boolean updateHigherLevel) { - if (this.lodQuadTreeNode == null) { - this.lodQuadTreeNode = newLodQuadTreeNode; + if (this.lodNode == null) { + this.lodNode = newLodQuadTreeNode; } else { - this.lodQuadTreeNode.update(newLodQuadTreeNode); + this.lodNode.update(newLodQuadTreeNode); } //a recursive update is necessary to change higher level if (parent != null && updateHigherLevel) parent.updateLevel(true); @@ -446,21 +432,17 @@ public class LodQuadTree { return !nodeEmpty; } - public boolean isNodeReal() { - return lodQuadTreeNode.real; - } - public boolean isRenderable() { - return (lodQuadTreeNode != null); + return (lodNode != null); } public boolean isCoordinateInLevel(int x, int z){ - return !(lodQuadTreeNode.startX > x || lodQuadTreeNode.startZ > z || lodQuadTreeNode.endX < x || lodQuadTreeNode.endZ < z); + return !(lodNode.getStartX() > x || lodNode.getStartZ() > z || lodNode.getEndX() < x || lodNode.getEndZ() < z); } public String toString(){ - String s = lodQuadTreeNode.toString(); + String s = lodNode.toString(); return s; /* if(isThereAnyChild()){ diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java index 563695ca3..bc317fad7 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java @@ -1,5 +1,6 @@ package com.seibel.lod.objects; +import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.handlers.LodQuadTreeDimensionFileHandler; import com.seibel.lod.util.LodUtil; import net.minecraft.client.Minecraft; @@ -251,11 +252,11 @@ public class LodQuadTreeDimension { * stored in the LOD. If an LOD already exists at the given * coordinates it will be overwritten. */ - public Boolean addNode(LodQuadTreeNode lodQuadTreeNode) + public Boolean addNode(LodQuadTreeNode lodNode) { RegionPos pos = new RegionPos( - lodQuadTreeNode.startX / 512, - lodQuadTreeNode.startZ / 512 + lodNode.getStartX() / 512, + lodNode.getStartZ() / 512 ); // don't continue if the region can't be saved @@ -272,10 +273,10 @@ public class LodQuadTreeDimension { region = new LodQuadTree(pos.x, pos.z); setRegion(region); } - boolean coorectlyAdded = region.setNodeAtLowerLevel(lodQuadTreeNode, true); + boolean coorectlyAdded = region.setNodeAtLowerLevel(lodNode, true); // don't save empty place holders to disk - if (lodQuadTreeNode.real && fileHandler != null) + if (fileHandler != null) { // mark the region as dirty so it will be saved to disk int xIndex = (pos.x - centerX) + halfWidth; @@ -310,16 +311,24 @@ public class LodQuadTreeDimension { */ } + /** + * return true if and only if the node at that position exist + */ + public boolean hasThisPositionBeenGenerated(int posX, int posZ, byte level) + { + return getLodFromCoordinates(posX,posZ,level).level == level + } + /** * method to get all the nodes that have to be rendered based on the position of the player * @return list of nodes */ - public List getNodeToRender(int x, int z, byte level, int maxDistance, int minDistance){ + public List getNodeToRender(int x, int z, byte level, Set complexityMask, int maxDistance, int minDistance){ int n = regions.length; List listOfData = new ArrayList<>(); for(int i=0; i getNodes(boolean getOnlyReal, boolean getOnlyDirty, boolean getOnlyLeaf){ + public List getNodes(Set complexityMask, boolean getOnlyDirty, boolean getOnlyLeaf){ int n = regions.length; List listOfNodes = new ArrayList<>(); int xIndex; @@ -368,7 +377,7 @@ public class LodQuadTreeDimension { zIndex = (zRegion + centerZ) - halfWidth; region = getRegion(xIndex,zIndex); if (region != null){ - listOfNodes.addAll(region.getNodeList(getOnlyReal, getOnlyDirty, getOnlyLeaf)); + listOfNodes.addAll(region.getNodeList(complexityMask, getOnlyDirty, getOnlyLeaf)); } } } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java index a5edd4ebe..288390f38 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java @@ -1,6 +1,8 @@ package com.seibel.lod.objects; +import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.handlers.LodQuadTreeDimensionFileHandler; +import net.minecraftforge.api.distmarker.Dist; import java.awt.*; import java.util.*; @@ -13,14 +15,13 @@ public class LodQuadTreeNode { /** this is how many pieces of data are exported when toData is called */ - public static final int NUMBER_OF_DELIMITERS = 9; + public static final int NUMBER_OF_DELIMITERS = 10; private static final Color INVISIBLE = new Color(0,0,0,0); - //Complexity indicate how complex is this node. For example a node that has been generated starting - //from a real chunk have the maximum complexity. A node that is generated starting from a fake approximated chunk - //has a low complexity - public byte complexity; + + //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 level; @@ -42,7 +43,7 @@ public class LodQuadTreeNode { //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 and levelWidth + //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; @@ -79,20 +80,49 @@ public class LodQuadTreeNode { endZ = startZ + width - 1; centerX = startX + width/2; centerZ = startZ + width/2; - lodDataPoint = new LodDataPoint() - real = false; + lodDataPoint = new LodDataPoint(); + complexity = null; dirty = true; voidNode = 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 level level of this * @param posX * @param posZ + * @param lodDataPoint * @param complexity */ - public LodQuadTreeNode(byte level, int posX, int posZ, LodDataPoint lodDataPoint, byte complexity){ + public LodQuadTreeNode(byte level, int posX, int posZ, LodDataPoint lodDataPoint, DistanceGenerationMode complexity){ this.level = level; this.posX = posX; this.posZ = posZ; @@ -104,7 +134,7 @@ public class LodQuadTreeNode { centerX = startX + width/2; centerZ = startZ + width/2; this.lodDataPoint = lodDataPoint; - this.real = real; + this.complexity = complexity; dirty = true; voidNode = false; } @@ -116,6 +146,9 @@ public class LodQuadTreeNode { index = data.indexOf(DATA_DELIMITER, 0); this.level = (byte) Integer.parseInt(data.substring(0,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); @@ -127,11 +160,11 @@ public class LodQuadTreeNode { lastIndex = index; index = data.indexOf(DATA_DELIMITER, lastIndex+1); - this.height = (short) Integer.parseInt(data.substring(lastIndex+1,index)); + short height = (short) Integer.parseInt(data.substring(lastIndex+1,index)); lastIndex = index; index = data.indexOf(DATA_DELIMITER, lastIndex+1); - this.depth = (short) Integer.parseInt(data.substring(lastIndex+1,index)); + short depth = (short) Integer.parseInt(data.substring(lastIndex+1,index)); lastIndex = index; index = data.indexOf(DATA_DELIMITER, lastIndex+1); @@ -145,14 +178,13 @@ public class LodQuadTreeNode { lastIndex = index; index = data.indexOf(DATA_DELIMITER, lastIndex+1); int a = Integer.parseInt(data.substring(lastIndex+1,index)); - this.color = new Color(r,g,b,a); + Color color = new Color(r,g,b,a); + lodDataPoint = new LodDataPoint(height,depth,color); - int complexity = Integer.parseInt(data.substring(lastIndex+1,index)); - this.real = (val == 1); - width = (short) Math.pow(2, level); - - val = Integer.parseInt(data.substring(lastIndex+1,index)); + int val = Integer.parseInt(data.substring(lastIndex+1,index)); this.voidNode = (val == 1); + + width = (short) Math.pow(2, level); startX = posX * width; startZ = posZ * width; endX = startX + width - 1; @@ -163,7 +195,7 @@ public class LodQuadTreeNode { } public void update(LodQuadTreeNode lodQuadTreeNode){ - this.lodDataPoint = lodQuadTreeNode.lodDataPoint + this.lodDataPoint = lodQuadTreeNode.lodDataPoint; this.complexity = lodQuadTreeNode.complexity; this.voidNode = lodQuadTreeNode.voidNode; dirty = true; @@ -172,9 +204,6 @@ public class LodQuadTreeNode { public LodDataPoint getLodDataPoint(){ return lodDataPoint; } - public byte getComplexity(){ - return complexity; - } public void combineData(List dataList){ if(dataList.isEmpty()){ @@ -189,7 +218,16 @@ public class LodQuadTreeNode { 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); - complexity = (byte) dataList.stream().mapToInt(x -> x.complexity).max().getAsInt(); + + //the new complexity equal to the lowest complexity of the list + DistanceGenerationMode minComplexity = DistanceGenerationMode.SERVER; + dataList.forEach(x -> { + if (minComplexity.compareTo(x.complexity) < 0){ + minComplexity = x.complexity; + } + }); + complexity = minComplexity; + voidNode = dataList.stream().filter(x -> !x.voidNode).count() == 0; } dirty = true; @@ -197,7 +235,11 @@ public class LodQuadTreeNode { public int hashCode(){ - return Objects.hash(this.complexity, this.level, this.posX, this.posZ, this.color, this.real, this.voidNode); + return Objects.hash(this.complexity, this.level, this.posX, this.posZ, this.lodDataPoint, this.voidNode); + } + + public int compareComplexity(LodQuadTreeNode other){ + return this.complexity.compareTo(other.complexity); } @@ -206,8 +248,8 @@ public class LodQuadTreeNode { && this.level == other.level && this.posX == other.posX && this.posZ == other.posZ - && this.color.equals(other.color) - && this.real == other.real + && this.lodDataPoint.equals(other.lodDataPoint) + && this.complexity == other.complexity && this.voidNode == other.voidNode); } @@ -216,18 +258,17 @@ public class LodQuadTreeNode { * Outputs all data in a csv format */ public String toData(){ - String s = Integer.toString(level) + DATA_DELIMITER + String s = ((int) level) + DATA_DELIMITER + + complexity.toString() + DATA_DELIMITER + posX + DATA_DELIMITER + posZ + DATA_DELIMITER - + Integer.toString(height) + DATA_DELIMITER - + Integer.toString(depth) + DATA_DELIMITER - + color.getRed() + DATA_DELIMITER - + color.getGreen() + DATA_DELIMITER - + color.getBlue() + DATA_DELIMITER - + color.getAlpha() + DATA_DELIMITER; - int val = real ? 1 : 0; - s += val + DATA_DELIMITER; - val = voidNode ? 1 : 0; + + ((int) lodDataPoint.height) + DATA_DELIMITER + + ((int) lodDataPoint.depth) + DATA_DELIMITER + + lodDataPoint.color.getRed() + DATA_DELIMITER + + lodDataPoint.color.getGreen() + DATA_DELIMITER + + lodDataPoint.color.getBlue() + DATA_DELIMITER + + lodDataPoint.color.getAlpha() + DATA_DELIMITER; + int val = voidNode ? 1 : 0; s += val + DATA_DELIMITER; return s; } @@ -238,4 +279,59 @@ public class LodQuadTreeNode { { return this.toData(); } + + + // This getters should be used + + public byte getLevel() { + return level; + } + + 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; + } } diff --git a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java index 73cd770be..7396dd319 100644 --- a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -1,5 +1,6 @@ package com.seibel.lod.objects; +import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.util.BiomeColorsUtils; import kaptainwutax.biomeutils.source.OverworldBiomeSource; import kaptainwutax.mcutils.version.MCVersion; @@ -18,9 +19,7 @@ import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; +import java.util.*; import javax.imageio.ImageIO; import javax.swing.JFrame; @@ -159,7 +158,13 @@ public class QuadTreeImage extends JPanel { lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 9, 100000,8000)); System.out.println(lodList.size()); */ - List lodList = dim.getNodes(false,false,false); + Set complexityMask = new HashSet<>(); + complexityMask.add(DistanceGenerationMode.SERVER); + complexityMask.add(DistanceGenerationMode.FEATURES); + complexityMask.add(DistanceGenerationMode.SURFACE); + complexityMask.add(DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT); + complexityMask.add(DistanceGenerationMode.BIOME_ONLY); + List lodList = dim.getNodes(complexityMask,false,false); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 4, 400, 200)); From 3cc78c62a03164e427e9b0a2a3e4ed83b598da37 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Tue, 13 Jul 2021 15:38:20 +0200 Subject: [PATCH 30/46] The lodQuadTree is now correctly converted to use LodDataPoint and DistanceGenerationMode --- .../lod/builders/LodNodeBufferBuilder.java | 2 +- .../seibel/lod/builders/LodNodeBuilder.java | 4 ++- .../CubicLodNodeTemplate.java | 6 ++-- .../lod/enums/DistanceGenerationMode.java | 3 ++ .../LodQuadTreeDimensionFileHandler.java | 2 +- .../com/seibel/lod/objects/LodQuadTree.java | 11 +++---- .../lod/objects/LodQuadTreeDimension.java | 18 +++++++---- .../seibel/lod/objects/LodQuadTreeNode.java | 10 +++---- .../com/seibel/lod/objects/QuadTreeImage.java | 30 ++++++------------- .../seibel/lod/render/LodNodeRenderer.java | 4 +-- 10 files changed, 44 insertions(+), 46 deletions(-) diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java index a99371552..54c29988e 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -130,7 +130,7 @@ public class LodNodeBufferBuilder List lodToRender = new ArrayList<>(); - lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 0, 100000,0)); + lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 0, LodQuadTreeDimension.FULL_COMPLEXITY_MASK, 100000,0)); /* lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 9, 100000,8000)); lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 8, 8000,4000)); diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java index ed66c6965..fbc1b3314 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java @@ -1,5 +1,7 @@ package com.seibel.lod.builders; +import com.seibel.lod.enums.DistanceGenerationMode; +import com.seibel.lod.objects.LodDataPoint; import com.seibel.lod.objects.LodQuadTreeNode; import com.seibel.lod.objects.LodQuadTreeDimension; import com.seibel.lod.objects.LodQuadTreeWorld; @@ -134,7 +136,7 @@ public class LodNodeBuilder { depth = determineBottomPointForArea(chunk.getSections(), startX, startZ, endX, endZ); - return new LodQuadTreeNode(LodQuadTreeNode.CHUNK_LEVEL, chunk.getPos().x, chunk.getPos().z, height, depth, color, true); + return new LodQuadTreeNode(LodQuadTreeNode.CHUNK_LEVEL, chunk.getPos().x, chunk.getPos().z, new LodDataPoint(height, depth, color) , DistanceGenerationMode.SERVER); } diff --git a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java index 230f74470..374644803 100644 --- a/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodNodeTemplates/CubicLodNodeTemplate.java @@ -42,15 +42,15 @@ public class CubicLodNodeTemplate extends AbstractLodNodeTemplate { // returns null if the lod is empty at the given location bbox = generateBoundingBox( - lod.height, - lod.height, + lod.lodDataPoint.height, + lod.lodDataPoint.height, detail.dataPointWidth, xOffset - (halfWidth / 2) + startX, yOffset, zOffset - (halfWidth / 2) + startZ); if (bbox != null) { - addBoundingBoxToBuffer(buffer, bbox, lod.color); + addBoundingBoxToBuffer(buffer, bbox, lod.lodDataPoint.color); } } diff --git a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java b/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java index dabf794ed..6b7fa36b5 100644 --- a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java +++ b/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java @@ -14,6 +14,9 @@ package com.seibel.lod.enums; */ public enum DistanceGenerationMode { + /** No generation has be used*/ + NONE, + /** Only generate the biomes and use biome * grass/foliage color, water color, or ice color * to generate the color. diff --git a/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java b/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java index 569ee74ed..886e19312 100644 --- a/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java +++ b/src/main/java/com/seibel/lod/handlers/LodQuadTreeDimensionFileHandler.java @@ -275,7 +275,7 @@ public class LodQuadTreeDimensionFileHandler { fw.write(LOD_FILE_VERSION_PREFIX + " " + LOD_SAVE_FILE_VERSION + "\n"); // add each LodChunk to the file - for(LodQuadTreeNode lodQuadTreeNode : Collections.unmodifiableList(region.getNodeList(false, true, true))) { + for(LodQuadTreeNode lodQuadTreeNode : Collections.unmodifiableList(region.getNodeList(LodQuadTreeDimension.FULL_COMPLEXITY_MASK , true, true))) { fw.write(lodQuadTreeNode.toData() + "\n"); lodQuadTreeNode.dirty = false; } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/LodQuadTree.java index a9f2bb637..e5f751620 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -149,14 +149,11 @@ public class LodQuadTree { if(posX<0) WE = 1 - WE; if(posZ<0) NS = 1 - NS; */ - if(posX<0) System.out.println(WE); - if(posZ<0) System.out.println(NS); - if (getChild(NS, WE) == null) { setChild(NS, WE); } LodQuadTree child = getChild(NS, WE); - if (lodNode.compareComplexity(newLodNode) < 0) { + if (lodNode.compareComplexity(newLodNode) > 0) { //the node we want to introduce is less complex than the current node //we don't want to override higher complexity with lower complexity return false; @@ -318,7 +315,7 @@ public class LodQuadTree { */ public List getNodeToRender(int x, int z, byte targetLevel, Set complexityMask, int maxDistance, int minDistance) { List distances = new ArrayList(); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getCenterX(), 2) + Math.pow(z - lodNode.getCenterX(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getCenterX(), 2) + Math.pow(z - lodNode.getCenterZ(), 2))); 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))); @@ -362,7 +359,7 @@ public class LodQuadTree { public List> getLevelToGenerate(int x, int z, byte targetLevel, DistanceGenerationMode complexityToGenerate, int maxDistance, int minDistance) { List distances = new ArrayList(); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getCenterX(), 2) + Math.pow(z - lodNode.getCenterX(), 2))); + distances.add((int) Math.sqrt(Math.pow(x - lodNode.getCenterX(), 2) + Math.pow(z - lodNode.getCenterZ(), 2))); 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))); @@ -389,7 +386,7 @@ public class LodQuadTree { }else{ if(this.lodNode.getComplexity().compareTo(complexityToGenerate) > 0) { //we want to regenerate a level only if we ask for higher complexity - nodeList.add(new AbstractMap.SimpleEntry<>(this, min) + nodeList.add(new AbstractMap.SimpleEntry<>(this, min)); } } } else { diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java index bc317fad7..8bf307815 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java @@ -7,6 +7,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.world.DimensionType; import net.minecraft.world.server.ServerChunkProvider; import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.api.distmarker.Dist; import java.io.File; import java.io.IOException; @@ -20,6 +21,14 @@ public class LodQuadTreeDimension { private volatile int halfWidth; public long seed; + public static final Set FULL_COMPLEXITY_MASK = new HashSet(){{ + add(DistanceGenerationMode.BIOME_ONLY); + add(DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT); + add(DistanceGenerationMode.SURFACE); + add(DistanceGenerationMode.FEATURES); + add(DistanceGenerationMode.SERVER); + }}; + public volatile LodQuadTree regions[][]; public volatile boolean isRegionDirty[][]; @@ -316,7 +325,7 @@ public class LodQuadTreeDimension { */ public boolean hasThisPositionBeenGenerated(int posX, int posZ, byte level) { - return getLodFromCoordinates(posX,posZ,level).level == level + return getLodFromCoordinates(posX,posZ,level).level == level; } /** @@ -338,7 +347,7 @@ public class LodQuadTreeDimension { * method to get all the quadtree level that have to be generated based on the position of the player * @return list of quadTrees */ - public List getNodeToGenerate(int x, int z, byte level, int maxDistance, int minDistance){ + public List getNodeToGenerate(int x, int z, byte level, DistanceGenerationMode complexity, int maxDistance, int minDistance){ int n = regions.length; int xIndex; @@ -354,7 +363,7 @@ public class LodQuadTreeDimension { region = new LodQuadTree(xIndex, zIndex); setRegion(region); } - listOfQuadTree.addAll(region.getLevelToGenerate(x,z,level,maxDistance,minDistance)); + listOfQuadTree.addAll(region.getLevelToGenerate(x,z,level,complexity,maxDistance,minDistance)); } } Collections.sort(listOfQuadTree,Map.Entry.comparingByValue()); @@ -438,10 +447,9 @@ public class LodQuadTreeDimension { if(region == null) continue; - numbLods= region.getNodeList(false,false,true).size(); + numbLods= region.getNodeList(FULL_COMPLEXITY_MASK,false,true).size(); } } - return numbLods; } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java index 288390f38..7c089d68f 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java @@ -81,7 +81,7 @@ public class LodQuadTreeNode { centerX = startX + width/2; centerZ = startZ + width/2; lodDataPoint = new LodDataPoint(); - complexity = null; + complexity = DistanceGenerationMode.NONE; dirty = true; voidNode = true; } @@ -221,11 +221,11 @@ public class LodQuadTreeNode { //the new complexity equal to the lowest complexity of the list DistanceGenerationMode minComplexity = DistanceGenerationMode.SERVER; - dataList.forEach(x -> { - if (minComplexity.compareTo(x.complexity) < 0){ - minComplexity = x.complexity; + for(LodQuadTreeNode node: dataList){ + if (minComplexity.compareTo(node.complexity) < 0){ + minComplexity = node.complexity; } - }); + } complexity = minComplexity; voidNode = dataList.stream().filter(x -> !x.voidNode).count() == 0; diff --git a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java index 7396dd319..2b3ca9988 100644 --- a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -68,28 +68,16 @@ public class QuadTreeImage extends JPanel { } private static void createAndShowGui() { - int playerX = 0; - int playerZ = 0; - LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 4); + int playerX = 32*512; + int playerZ = 32*512; + LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 64); System.out.println(dim.getRegion(0, 0)); dim.move(Math.floorDiv(playerX,512),Math.floorDiv(playerZ,512)); System.out.println(dim.getCenterX()); System.out.println(dim.getCenterZ()); System.out.println(dim.getWidth()); - LodQuadTree level2 = dim.getRegion( - -1, - -1 - ); - int startX2 = level2.getLodNodeData().startX; - int startZ2 = level2.getLodNodeData().startZ; - int endX2 = level2.getLodNodeData().endX; - int endZ2 = level2.getLodNodeData().endZ; - int centerX2 = level2.getLodNodeData().centerX; - int centerZ2 = level2.getLodNodeData().centerZ; - int width2 = level2.getLodNodeData().width; - System.out.println(startX2+" "+startZ2+" "+centerX2+" "+centerZ2); final QuadTreeImage quadTreeImage = new QuadTreeImage(); @@ -105,7 +93,7 @@ public class QuadTreeImage extends JPanel { int[] distances = {100000,8000,4000,2000,1000,500,250,100,50,25}; for (int i = 0; i <= (9 - 2); i++) { for (int j = 0; j < 1; j++) { - List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), distances[i], 0); + List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), DistanceGenerationMode.SERVER , distances[i], 0); //System.out.println(levelToGenerate); for (LodQuadTree level : levelToGenerate) { Color color; @@ -141,7 +129,7 @@ public class QuadTreeImage extends JPanel { //System.out.println(posX + " " + posZ); color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posX, 0, posZ)); //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); - LodQuadTreeNode node = new LodQuadTreeNode(otherLevel, posX, posZ, 0, 0, color, true); + LodQuadTreeNode node = new LodQuadTreeNode(otherLevel, posX, posZ, new LodDataPoint(0, 0, color) , DistanceGenerationMode.SERVER); dim.addNode(node); } } @@ -191,7 +179,7 @@ public class QuadTreeImage extends JPanel { } else { if(drawCount==0) quadTreeImage.clearAll(); final List myDrawables = new ArrayList<>(); - double amp = 0.4; + double amp = 0.025; Collection lodList = listOfList.get(drawCount); for (LodQuadTreeNode data : lodList) { myDrawables.add(new MyDrawable(new Rectangle2D.Double( @@ -199,7 +187,7 @@ public class QuadTreeImage extends JPanel { ((data.startZ - zOffset) * amp), data.width * amp, data.width * amp), - data.color, new BasicStroke(1))); + data.lodDataPoint.color, new BasicStroke(1))); } myDrawables.add(new MyDrawable(new Rectangle2D.Double( (playerX - 10 - xOffset) * amp, @@ -277,9 +265,9 @@ class MyDrawable { Stroke oldStroke = g2.getStroke(); g2.setColor(color); - //g2.fill(shape); + g2.fill(shape); - g2.setStroke(stroke); + //g2.setStroke(stroke); g2.draw(shape); g2.setColor(oldColor); diff --git a/src/main/java/com/seibel/lod/render/LodNodeRenderer.java b/src/main/java/com/seibel/lod/render/LodNodeRenderer.java index ea881d746..cde90623e 100644 --- a/src/main/java/com/seibel/lod/render/LodNodeRenderer.java +++ b/src/main/java/com/seibel/lod/render/LodNodeRenderer.java @@ -128,7 +128,7 @@ public class LodNodeRenderer * Besides drawing the LODs this method also starts * the async process of generating the Buffers that hold those LODs. * - * @param newDimension The dimension to draw, if null doesn't replace the current dimension. + * @param newDim The dimension to draw, if null doesn't replace the current dimension. * @param partialTicks how far into the current tick this method was called. */ public void drawLODs(LodQuadTreeDimension lodDim, float partialTicks, IProfiler newProfiler) @@ -788,7 +788,7 @@ public class LodNodeRenderer LodQuadTreeNode lod = lodDim.getLodFromCoordinates(x, z, (byte) 4); if (lod != null) { - short lodHighestPoint = lod.height; + short lodHighestPoint = lod.lodDataPoint.height; if (playerPos.getY() < lodHighestPoint) { From 29b3e9fadc4827787c4f6b0dd1468bb7c5162190 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Tue, 13 Jul 2021 20:40:55 +0200 Subject: [PATCH 31/46] The lodQuadTree is now correctly converted to use LodDataPoint and DistanceGenerationMode --- src/main/java/com/seibel/lod/LodMain.java | 6 +- ...LodBufferBuilder.java => LodBufferBuilder} | 3 + .../lod/builders/LodNodeBufferBuilder.java | 141 ++++- .../seibel/lod/builders/LodNodeBuilder.java | 12 +- .../lodTemplates/AbstractLodTemplate.java | 10 +- .../lodTemplates/CubicLodTemplate.java | 27 +- .../lodTemplates/DynamicLodTemplate.java | 8 +- .../lodTemplates/TriangularLodTemplate.java | 8 +- .../worldGeneration/LodChunkGenWorker.java | 581 ------------------ .../java/com/seibel/lod/objects/HOWTOUSE.txt | 29 + .../com/seibel/lod/proxy/ClientProxy.java | 128 ++-- .../render/{LodRenderer.java => LodRenderer} | 0 .../com/seibel/lod/render/RenderUtil.java | 2 +- 13 files changed, 249 insertions(+), 706 deletions(-) rename src/main/java/com/seibel/lod/builders/{LodBufferBuilder.java => LodBufferBuilder} (99%) delete mode 100644 src/main/java/com/seibel/lod/builders/worldGeneration/LodChunkGenWorker.java create mode 100644 src/main/java/com/seibel/lod/objects/HOWTOUSE.txt rename src/main/java/com/seibel/lod/render/{LodRenderer.java => LodRenderer} (100%) diff --git a/src/main/java/com/seibel/lod/LodMain.java b/src/main/java/com/seibel/lod/LodMain.java index cd54212a9..0d896cbc9 100644 --- a/src/main/java/com/seibel/lod/LodMain.java +++ b/src/main/java/com/seibel/lod/LodMain.java @@ -1,10 +1,10 @@ package com.seibel.lod; +import com.seibel.lod.render.LodNodeRenderer; import org.lwjgl.opengl.GL; import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.proxy.ClientProxy; -import com.seibel.lod.render.LodRenderer; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -42,9 +42,9 @@ public class LodMain Thread setFancyFog = new Thread(() -> { - LodRenderer.fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance; + LodNodeRenderer.fancyFogAvailable = GL.getCapabilities().GL_NV_fog_distance; - if (!LodRenderer.fancyFogAvailable) + if (!LodNodeRenderer.fancyFogAvailable) { ClientProxy.LOGGER.info("This GPU does not support GL_NV_fog_distance. This means that fancy fog options will not be available."); } diff --git a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodBufferBuilder similarity index 99% rename from src/main/java/com/seibel/lod/builders/LodBufferBuilder.java rename to src/main/java/com/seibel/lod/builders/LodBufferBuilder index d97a505d3..fedeb3216 100644 --- a/src/main/java/com/seibel/lod/builders/LodBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodBufferBuilder @@ -205,9 +205,12 @@ public class LodBufferBuilder // get the desired LodTemplate and // add this LOD to the buffer + /* LodConfig.CLIENT.lodTemplate.get(). template.addLodToBuffer(currentBuffer, lodDim, lod, xOffset, yOffset, zOffset, renderer.debugging); + + */ } } diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java index 54c29988e..84ec8df98 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBufferBuilder.java @@ -1,17 +1,18 @@ package com.seibel.lod.builders; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.NearFarBuffer; -import com.seibel.lod.objects.LodQuadTreeNode; -import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.builders.worldGeneration.LodNodeGenWorker; +import com.seibel.lod.enums.DistanceGenerationMode; +import com.seibel.lod.handlers.LodConfig; +import com.seibel.lod.objects.*; import com.seibel.lod.render.LodNodeRenderer; -import com.seibel.lod.render.LodRenderer; import com.seibel.lod.util.LodUtil; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.math.ChunkPos; import net.minecraft.world.biome.BiomeContainer; import net.minecraft.world.chunk.ChunkStatus; +import net.minecraft.world.server.ServerWorld; +import net.minecraftforge.common.WorldWorkerManager; import org.lwjgl.opengl.GL11; import java.util.ArrayList; @@ -125,35 +126,117 @@ public class LodNodeBufferBuilder // generate our new buildable buffers - buildableNearBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); - buildableFarBuffer.begin(GL11.GL_QUADS, LodRenderer.LOD_VERTEX_FORMAT); + buildableNearBuffer.begin(GL11.GL_QUADS, LodNodeRenderer.LOD_VERTEX_FORMAT); + buildableFarBuffer.begin(GL11.GL_QUADS, LodNodeRenderer.LOD_VERTEX_FORMAT); + + // x axis + for (int i = 0; i < numbChunksWide; i++) + { + // z axis + for (int j = 0; j < numbChunksWide; j++) + { + int chunkX = i + (startX / LodChunk.WIDTH); + int chunkZ = j + (startZ / LodChunk.WIDTH); + + // skip any chunks that Minecraft is going to render + if(isCoordInCenterArea(i, j, (numbChunksWide / 2)) + && renderer.vanillaRenderedChunks.contains(new ChunkPos(chunkX, chunkZ))) + { + continue; + } - List lodToRender = new ArrayList<>(); - lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 0, LodQuadTreeDimension.FULL_COMPLEXITY_MASK, 100000,0)); - /* - lodToRender.addAll(lodDim.getNodeToRender((int) playerX,(int)playerZ,(byte) 9, 100000,8000)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 8, 8000,4000)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 7, 4000,2000)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 6, 2000,1000)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 5, 1000,500)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 4, 500,250)); - lodToRender.addAll(lodDim.getNodeToRender((int)playerX,(int)playerZ,(byte) 3, 250,0)); -*/ - for(LodQuadTreeNode data : lodToRender){ - BufferBuilder currentBuffer = null; -/* - if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2)) - currentBuffer = buildableNearBuffer; - else - currentBuffer = buildableFarBuffer; - */ - currentBuffer = buildableFarBuffer; + // set where this square will be drawn in the world + double xOffset = (LodChunk.WIDTH * i) + // offset by the number of LOD blocks + startX; // offset so the center LOD block is centered underneath the player + double yOffset = 0; + double zOffset = (LodChunk.WIDTH * j) + startZ; - // get the desired LodTemplate and - // add this LOD to the buffer + LodQuadTreeNode lod = lodDim.getLodFromCoordinates(chunkX, chunkZ, (byte) 4); + + if (lod == null || lod.getComplexity() == DistanceGenerationMode.NONE) + { + // generate a new chunk if no chunk currently exists + // and we aren't waiting on any other chunks to generate + if (lod == null && numberOfChunksWaitingToGenerate < maxChunkGenRequests) + { + ChunkPos pos = new ChunkPos(chunkX, chunkZ); + + // determine if this position is closer to the player + // than the previous + int newDistance = playerChunkPos.getChessboardDistance(pos); + + if (newDistance < minChunkDist) + { + // this chunk is closer, clear any previous + // positions and update the new minimum distance + minChunkDist = newDistance; + chunksToGenReserve = chunksToGen; + + chunkGenIndex = 0; + chunksToGen = new ChunkPos[maxChunkGenRequests]; + chunksToGen[chunkGenIndex] = pos; + chunkGenIndex++; + } + else if (newDistance <= minChunkDist) + { + // this chunk position is as close or closers than the + // minimum distance + if(chunkGenIndex < maxChunkGenRequests) + { + // we are still under the number of chunks to generate + // add this position to the list + chunksToGen[chunkGenIndex] = pos; + chunkGenIndex++; + } + } + + } + // don't render this null chunk + continue; + } + + + BufferBuilder currentBuffer = null; + if (isCoordinateInNearFogArea(i, j, numbChunksWide / 2)) + currentBuffer = buildableNearBuffer; + else + currentBuffer = buildableFarBuffer; + + // get the desired LodTemplate and + // add this LOD to the buffer + LodConfig.CLIENT.lodTemplate.get(). + template.addLodToBuffer(currentBuffer, lodDim, lod, + xOffset, yOffset, zOffset, renderer.debugging); + } } + // TODO add a way for a server side mod to generate chunks requested here + if(mc.hasSingleplayerServer()) + { + ServerWorld serverWorld = LodUtil.getServerWorldFromDimension(lodDim.dimension); + + // make sure we have as many chunks to generate as we are allowed + if (chunkGenIndex < maxChunkGenRequests) + { + for(int i = chunkGenIndex, j = 0; i < maxChunkGenRequests; i++, j++) + { + chunksToGen[i] = chunksToGenReserve[j]; + } + } + + // start chunk generation + for(ChunkPos chunkPos : chunksToGen) + { + if(chunkPos == null) + break; + + numberOfChunksWaitingToGenerate++; + + LodNodeGenWorker genWorker = new LodNodeGenWorker(chunkPos, renderer, lodChunkBuilder, this, lodDim, serverWorld, biomeContainer); + WorldWorkerManager.addWorker(genWorker); + } + } // x axis // finish the buffer building diff --git a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java index fbc1b3314..4ede0f9f7 100644 --- a/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java +++ b/src/main/java/com/seibel/lod/builders/LodNodeBuilder.java @@ -63,8 +63,10 @@ public class LodNodeBuilder { */ public void generateLodNodeAsync(IChunk chunk, LodQuadTreeWorld lodWorld, IWorld world) { - if (lodWorld == null || !lodWorld.getIsWorldLoaded()) + if (lodWorld == null || !lodWorld.getIsWorldLoaded()) { + System.out.println("This case?"); return; + } // don't try to create an LOD object // if for some reason we aren't @@ -82,20 +84,24 @@ public class LodNodeBuilder { LodQuadTreeDimension lodDim; if (lodWorld.getLodDimension(dim) == null) { + System.out.println("Adding"); lodDim = new LodQuadTreeDimension(dim, lodWorld, regionWidth); lodWorld.addLodDimension(lodDim); } else { + System.out.println("Not adding"); lodDim = lodWorld.getLodDimension(dim); } lodDim.addNode(node); } catch (IllegalArgumentException | NullPointerException e) { + e.printStackTrace(); // if the world changes while LODs are being generated // they will throw errors as they try to access things that no longer // exist. } }); lodGenThreadPool.execute(thread); + System.out.println("Is this ENDING?"); return; } @@ -266,6 +272,8 @@ public class LodNodeBuilder { * otherwise use the */ private Color generateLodColorForArea(IChunk chunk, LodBuilderConfig config, int startX, int startZ, int endX, int endZ) { + return Color.BLUE; + /* ChunkSection[] chunkSections = chunk.getSections(); int numbOfBlocks = 0; @@ -345,6 +353,8 @@ public class LodNodeBuilder { blue /= numbOfBlocks; return new Color(red, green, blue); + + */ } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java index 0c3b79600..56902cfe0 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/AbstractLodTemplate.java @@ -4,6 +4,8 @@ import com.seibel.lod.enums.LodDetail; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; import net.minecraft.client.renderer.BufferBuilder; /** @@ -15,10 +17,10 @@ import net.minecraft.client.renderer.BufferBuilder; */ public abstract class AbstractLodTemplate { - public abstract void addLodToBuffer(BufferBuilder buffer, - LodDimension lodDim, LodChunk lod, - double xOffset, double yOffset, double zOffset, - boolean debugging); + public abstract void addLodToBuffer(BufferBuilder buffer, + LodQuadTreeDimension lodDim, LodQuadTreeNode centerLod, + double xOffset, double yOffset, double zOffset, + boolean debugging); /** add the given position and color to the buffer */ protected void addPosAndColor(BufferBuilder buffer, diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java index c5200df5d..d446a7747 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/CubicLodTemplate.java @@ -8,6 +8,8 @@ import com.seibel.lod.handlers.LodConfig; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; import net.minecraft.client.renderer.BufferBuilder; import net.minecraft.util.math.AxisAlignedBB; @@ -28,9 +30,9 @@ public class CubicLodTemplate extends AbstractLodTemplate @Override public void addLodToBuffer(BufferBuilder buffer, - LodDimension lodDim, LodChunk centerLod, - double xOffset, double yOffset, double zOffset, - boolean debugging) + LodQuadTreeDimension lodDim, LodQuadTreeNode centerLod, + double xOffset, double yOffset, double zOffset, + boolean debugging) { AxisAlignedBB bbox; @@ -39,28 +41,19 @@ public class CubicLodTemplate extends AbstractLodTemplate LodDetail detail = LodConfig.CLIENT.lodDetail.get(); int halfWidth = detail.dataPointWidth / 2; - - for(int i = 0; i < detail.dataPointLengthCount * detail.dataPointLengthCount; i++) - { - int startX = detail.startX[i]; - int startZ = detail.startZ[i]; - int endX = detail.endX[i]; - int endZ = detail.endZ[i]; - // returns null if the lod is empty at the given location bbox = generateBoundingBox( - centerLod.getAverageHeightOverArea(startX, startZ, endX, endZ), - centerLod.getAverageDepthOverArea(startX, startZ, endX, endZ), + centerLod.lodDataPoint.height, + centerLod.lodDataPoint.depth, detail.dataPointWidth, - xOffset - (halfWidth / 2) + detail.startX[i], + xOffset - (centerLod.width / 2), yOffset, - zOffset - (halfWidth / 2) + detail.startZ[i]); + zOffset - (centerLod.width / 2)); if (bbox != null) { - addBoundingBoxToBuffer(buffer, bbox, centerLod.getAverageColorOverArea(startX, startZ, endX, endZ, debugging)); + addBoundingBoxToBuffer(buffer, bbox, centerLod.lodDataPoint.color); } - } } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java index 7203aa273..c50f726ec 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/DynamicLodTemplate.java @@ -4,6 +4,8 @@ import com.seibel.lod.enums.LodDetail; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; import net.minecraft.client.renderer.BufferBuilder; /** @@ -19,9 +21,9 @@ public class DynamicLodTemplate extends AbstractLodTemplate { @Override public void addLodToBuffer(BufferBuilder buffer, - LodDimension lodDim, LodChunk lod, - double xOffset, double yOffset, double zOffset, - boolean debugging) + LodQuadTreeDimension lodDim, LodQuadTreeNode centerLod, + double xOffset, double yOffset, double zOffset, + boolean debugging) { System.err.println("DynamicLodTemplate not implemented!"); } diff --git a/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java b/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java index d1188f6ba..9215ada38 100644 --- a/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java +++ b/src/main/java/com/seibel/lod/builders/lodTemplates/TriangularLodTemplate.java @@ -4,6 +4,8 @@ import com.seibel.lod.enums.LodDetail; import com.seibel.lod.objects.LodChunk; import com.seibel.lod.objects.LodDimension; +import com.seibel.lod.objects.LodQuadTreeDimension; +import com.seibel.lod.objects.LodQuadTreeNode; import net.minecraft.client.renderer.BufferBuilder; /** @@ -17,9 +19,9 @@ public class TriangularLodTemplate extends AbstractLodTemplate { @Override public void addLodToBuffer(BufferBuilder buffer, - LodDimension lodDim, LodChunk lod, - double xOffset, double yOffset, double zOffset, - boolean debugging) + LodQuadTreeDimension lodDim, LodQuadTreeNode centerLod, + double xOffset, double yOffset, double zOffset, + boolean debugging) { System.err.println("DynamicLodTemplate not implemented!"); } diff --git a/src/main/java/com/seibel/lod/builders/worldGeneration/LodChunkGenWorker.java b/src/main/java/com/seibel/lod/builders/worldGeneration/LodChunkGenWorker.java deleted file mode 100644 index 17a769e4e..000000000 --- a/src/main/java/com/seibel/lod/builders/worldGeneration/LodChunkGenWorker.java +++ /dev/null @@ -1,581 +0,0 @@ -package com.seibel.lod.builders.worldGeneration; - -import java.util.ConcurrentModificationException; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.function.Supplier; - -import com.seibel.lod.builders.LodBufferBuilder; -import com.seibel.lod.builders.LodBuilderConfig; -import com.seibel.lod.builders.LodChunkBuilder; -import com.seibel.lod.enums.DistanceGenerationMode; -import com.seibel.lod.handlers.LodConfig; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.LodRegion; -import com.seibel.lod.proxy.ClientProxy; -import com.seibel.lod.render.LodRenderer; - -import net.minecraft.block.Block; -import net.minecraft.block.BlockState; -import net.minecraft.util.WeightedList.Entry; -import net.minecraft.util.math.ChunkPos; -import net.minecraft.util.palette.UpgradeData; -import net.minecraft.world.biome.Biome; -import net.minecraft.world.biome.BiomeContainer; -import net.minecraft.world.chunk.ChunkPrimer; -import net.minecraft.world.chunk.ChunkStatus; -import net.minecraft.world.chunk.IChunk; -import net.minecraft.world.gen.ChunkGenerator; -import net.minecraft.world.gen.Heightmap; -import net.minecraft.world.gen.blockstateprovider.WeightedBlockStateProvider; -import net.minecraft.world.gen.feature.BlockClusterFeatureConfig; -import net.minecraft.world.gen.feature.ConfiguredFeature; -import net.minecraft.world.gen.feature.DecoratedFeatureConfig; -import net.minecraft.world.gen.feature.FeatureSpread; -import net.minecraft.world.gen.feature.FeatureSpreadConfig; -import net.minecraft.world.gen.feature.IceAndSnowFeature; -import net.minecraft.world.gen.feature.NoFeatureConfig; -import net.minecraft.world.gen.placement.ConfiguredPlacement; -import net.minecraft.world.gen.placement.DecoratedPlacementConfig; -import net.minecraft.world.gen.placement.IPlacementConfig; -import net.minecraft.world.gen.placement.NoiseDependant; -import net.minecraft.world.server.ServerChunkProvider; -import net.minecraft.world.server.ServerWorld; -import net.minecraft.world.server.ServerWorldLightManager; -import net.minecraftforge.common.WorldWorkerManager.IWorker; - -/** - * This is used to generate a LodChunk at a given ChunkPos. - * - * @author James Seibel - * @version 7-4-2021 - */ -public class LodChunkGenWorker implements IWorker -{ - public static final ExecutorService genThreads = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()); - - private boolean threadStarted = false; - private LodChunkGenThread thread; - - /** If a configured feature fails for whatever reason, - * add it to this list, this is to hopefully remove any - * features that could cause issues down the line. */ - private static ConcurrentHashMap> configuredFeaturesToAvoid = new ConcurrentHashMap<>(); - - - - public LodChunkGenWorker(ChunkPos newPos, LodRenderer newLodRenderer, - LodChunkBuilder newLodBuilder, LodBufferBuilder newLodBufferBuilder, - LodDimension newLodDimension, ServerWorld newServerWorld, - BiomeContainer newBiomeContainer) - { - if (newServerWorld == null) - throw new IllegalArgumentException("LodChunkGenWorker must have a non-null ServerWorld"); - - thread = new LodChunkGenThread(newPos, newLodRenderer, - newLodBuilder, newLodBufferBuilder, - newLodDimension, newServerWorld); - } - - @Override - public boolean doWork() - { - if (!threadStarted) - { - // make sure we don't generate this chunk again - thread.lodDim.addLod(new LodChunk(thread.pos)); - - thread.lodBufferBuilder.numberOfChunksWaitingToGenerate--; - - if (LodConfig.CLIENT.distanceGenerationMode.get() == DistanceGenerationMode.SERVER) - { - // if we are using SERVER generation that has to be done - // synchronously to prevent crashing and harmful - // interactions with the normal world generator - thread.run(); - } - else - { - // Every other method can - // be done asynchronously - genThreads.execute(thread); - } - - threadStarted = true; - - // useful for debugging -// ClientProxy.LOGGER.info(thread.lodDim.getNumberOfLods()); - } - - return false; - } - - @Override - public boolean hasWork() - { - return !threadStarted; - } - - - - - private class LodChunkGenThread implements Runnable - { - public final ServerWorld serverWorld; - public final LodDimension lodDim; - public final LodChunkBuilder lodChunkBuilder; - public final LodRenderer lodRenderer; - private LodBufferBuilder lodBufferBuilder; - - private ChunkPos pos; - - public LodChunkGenThread(ChunkPos newPos, LodRenderer newLodRenderer, - LodChunkBuilder newLodBuilder, LodBufferBuilder newLodBufferBuilder, - LodDimension newLodDimension, ServerWorld newServerWorld) - { - pos = newPos; - lodRenderer = newLodRenderer; - lodChunkBuilder = newLodBuilder; - lodBufferBuilder = newLodBufferBuilder; - lodDim = newLodDimension; - serverWorld = newServerWorld; - } - - @Override - public void run() - { - // only generate LodChunks if they can - // be added to the current LodDimension - if (lodDim.regionIsInRange(pos.x / LodRegion.SIZE, pos.z / LodRegion.SIZE)) - { -// long startTime = System.currentTimeMillis(); - - switch(LodConfig.CLIENT.distanceGenerationMode.get()) - { - case BIOME_ONLY: - case BIOME_ONLY_SIMULATE_HEIGHT: - // fastest - generateUsingBiomesOnly(); - break; - case SURFACE: - // faster - generateUsingSurface(); - break; - case FEATURES: - // fast - generateUsingFeatures(); - break; - case SERVER: - // very slow - generateWithServer(); - break; - } - - lodRenderer.regenerateLODsNextFrame(); - - -// if (lodDim.getLodFromCoordinates(pos.x, pos.z) != null) -// ClientProxy.LOGGER.info(pos.x + " " + pos.z + " Success!"); -// else -// ClientProxy.LOGGER.info(pos.x + " " + pos.z); - -// long endTime = System.currentTimeMillis(); -// System.out.println(endTime - startTime); - - }// if in range - - }// run - - - - /** - * takes about 2-5 ms - */ - private void generateUsingBiomesOnly() - { - List chunkList = new LinkedList<>(); - ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); - chunkList.add(chunk); - - ServerChunkProvider chunkSource = serverWorld.getChunkSource(); - ChunkGenerator chunkGen = chunkSource.generator; - - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - // override the chunk status so we can run the next generator stage - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - ChunkStatus.BIOMES.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - - - // generate fake height data for this LOD - int seaLevel = serverWorld.getSeaLevel(); - - boolean simulateHeight = LodConfig.CLIENT.distanceGenerationMode.get() == DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT; - boolean inTheEnd = false; - - // add fake heightmap data so our LODs aren't at height 0 - Heightmap heightmap = new Heightmap(chunk, LodChunk.DEFAULT_HEIGHTMAP); - for(int x = 0; x < LodChunk.WIDTH && !inTheEnd; x++) - { - for(int z = 0; z < LodChunk.WIDTH && !inTheEnd; z++) - { - if (simulateHeight) - { - // TODO use the biomes around each block to smooth out the transition - - // these heights are of course aren't super accurate, - // they are just to simulate height data where there isn't any - switch(chunk.getBiomes().getNoiseBiome(x, seaLevel, z).getBiomeCategory()) - { - case NETHER: - heightmap.setHeight(x, z, serverWorld.getHeight() / 2); - break; - - case EXTREME_HILLS: - heightmap.setHeight(x, z, seaLevel + 30); - break; - case MESA: - heightmap.setHeight(x, z, seaLevel + 20); - break; - case JUNGLE: - heightmap.setHeight(x, z, seaLevel + 20); - break; - case BEACH: - heightmap.setHeight(x, z, seaLevel + 5); - break; - case NONE: - heightmap.setHeight(x, z, 0); - break; - - case OCEAN: - case RIVER: - heightmap.setHeight(x, z, seaLevel); - break; - - case THEEND: - inTheEnd = true; - break; - - // DESERT - // FOREST - // ICY - // MUSHROOM - // SAVANNA - // SWAMP - // TAIGA - // PLAINS - default: - heightmap.setHeight(x, z, seaLevel + 10); - break; - }// heightmap switch - } - else - { - // we aren't simulating height - // always use sea level - heightmap.setHeight(x, z, seaLevel); - } - }// z - }// x - - chunk.setHeightmap(LodChunk.DEFAULT_HEIGHTMAP, heightmap.getRawData()); - - - LodChunk lod; - if (!inTheEnd) - { - lod = lodChunkBuilder.generateLodFromChunk(chunk, new LodBuilderConfig(true, true, false)); - } - else - { - // if we are in the end, don't generate any chunks. - // Since we don't know where the islands are, everything - // generates the same and it looks really bad. - lod = new LodChunk(chunk.getPos().x, chunk.getPos().z); - } - lodDim.addLod(lod); - } - - - /** - * takes about 10 - 20 ms - */ - private void generateUsingSurface() - { - List chunkList = new LinkedList<>(); - ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); - chunkList.add(chunk); - LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk); - - ServerChunkProvider chunkSource = serverWorld.getChunkSource(); - ChunkGenerator chunkGen = chunkSource.generator; - - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - // override the chunk status so we can run the next generator stage - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - ChunkStatus.BIOMES.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - ChunkStatus.NOISE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - ChunkStatus.SURFACE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - - // this feature has proved to be thread safe - // so we will add it - IceAndSnowFeature snowFeature = new IceAndSnowFeature(NoFeatureConfig.CODEC); - snowFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition(), null); - - - LodChunk lod = lodChunkBuilder.generateLodFromChunk(chunk, new LodBuilderConfig(false, true, true)); - lodDim.addLod(lod); - } - - - /** - * takes about 15 - 20 ms - * - * Causes concurrentModification Exceptions, - * which could cause instability or world generation bugs - */ - private void generateUsingFeatures() - { - List chunkList = new LinkedList<>(); - ChunkPrimer chunk = new ChunkPrimer(pos, UpgradeData.EMPTY); - chunkList.add(chunk); - LodServerWorld lodServerWorld = new LodServerWorld(serverWorld, chunk); - - ServerChunkProvider chunkSource = serverWorld.getChunkSource(); - ChunkGenerator chunkGen = chunkSource.generator; - - - // generate the terrain (this is thread safe) - ChunkStatus.EMPTY.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - // override the chunk status so we can run the next generator stage - chunk.setStatus(ChunkStatus.STRUCTURE_REFERENCES); - ChunkStatus.BIOMES.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - ChunkStatus.NOISE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - ChunkStatus.SURFACE.generate(serverWorld, chunkGen, serverWorld.getStructureManager(), (ServerWorldLightManager) serverWorld.getLightEngine(), null, chunkList); - - - // get all the biomes in the chunk - HashSet biomes = new HashSet<>(); - for (int x = 0; x < LodChunk.WIDTH; x++) - { - for (int z = 0; z < LodChunk.WIDTH; z++) - { - Biome biome = chunk.getBiomes().getNoiseBiome(x, serverWorld.getSeaLevel(), z); - - // Issue #35 - // For some reason Jungle biomes cause incredible lag - // the features here must be interacting with each other - // in unpredictable ways (specifically tree feature generation). - // When generating Features my CPU usage generally hovers around 30 - 40% - // when generating Jungles it spikes to 100%. - if (biome.getBiomeCategory() != Biome.Category.JUNGLE) - { - // should probably use the heightmap here instead of seaLevel, - // but this seems to get the job done well enough - biomes.add(biome); - } - } - } - - - // generate all the features related to this chunk. - // this may or may not be thread safe - for (Biome biome : biomes) - { - List>>> featuresForState = biome.generationSettings.features(); - - for(int featureStateToGenerate = 0; featureStateToGenerate < featuresForState.size(); featureStateToGenerate++) - { - for(Supplier> featureSupplier : featuresForState.get(featureStateToGenerate)) - { - ConfiguredFeature configuredFeature = featureSupplier.get(); - - if (configuredFeaturesToAvoid.containsKey(configuredFeature.hashCode())) - continue; - - - try - { - configuredFeature.place(lodServerWorld, chunkGen, serverWorld.random, chunk.getPos().getWorldPosition()); - } - catch(ConcurrentModificationException e) - { - // This will happen. I'm not sure what to do about it - // except pray that it doesn't effect the normal world generation - // in any harmful way - - // Issue #35 - // I tried cloning the config for each feature, but that - // path was blocked since I can't clone lambda methods. - // I tried using a deep cloning library and discovered - // the problem there. - // ( https://github.com/kostaskougios/cloning ) - - configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - catch(UnsupportedOperationException e) - { - // This will happen when the LodServerWorld - // isn't able to return something that a feature - // generator needs - - configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - catch(Exception e) - { - // I'm not sure what happened, print to the log - - System.out.println(); - System.out.println(); - e.printStackTrace(); - System.out.println(); - //ClientProxy.LOGGER.error("error class: \"" + configuredfeature.config.getClass() + "\""); - System.out.println(); - - configuredFeaturesToAvoid.put(configuredFeature.hashCode(), configuredFeature); -// ClientProxy.LOGGER.info(configuredFeaturesToAvoid.mappingCount()); - } - } - } - } - - // generate a Lod like normal - LodChunk lod = lodChunkBuilder.generateLodFromChunk(chunk); - lodDim.addLod(lod); - } - - - /** - * on pre generated chunks 0 - 1 ms - * on un generated chunks 0 - 50 ms - * with the median seeming to hover around 15 - 30 ms - * and outliers in the 100 - 200 ms range - * - * Note this should not be multithreaded and does cause server/simulation lag - * (Higher lag for generating than loading) - */ - private void generateWithServer() - { - lodChunkBuilder.generateLodChunkAsync(serverWorld.getChunk(pos.x, pos.z, ChunkStatus.FEATURES), ClientProxy.getLodWorld(), serverWorld); - } - - - - - - - //================// - // Unused methods // - //================// - - // Sadly I wasn't able to get these to work, - // they are here for documentation purposes - - @SuppressWarnings({ "rawtypes", "unchecked", "unused" }) - private DecoratedFeatureConfig cloneDecoratedFeatureConfig(DecoratedFeatureConfig config) - { - IPlacementConfig placementConfig = null; - - Class oldConfigClass = config.decorator.config().getClass(); - - if (oldConfigClass == FeatureSpreadConfig.class) - { - FeatureSpreadConfig oldPlacementConfig = (FeatureSpreadConfig) config.decorator.config(); - FeatureSpread oldSpread = oldPlacementConfig.count(); - - placementConfig = new FeatureSpreadConfig(oldSpread); - } - else if(oldConfigClass == DecoratedPlacementConfig.class) - { - DecoratedPlacementConfig oldPlacementConfig = (DecoratedPlacementConfig) config.decorator.config(); - placementConfig = new DecoratedPlacementConfig(oldPlacementConfig.inner(), oldPlacementConfig.outer()); - } - else if(oldConfigClass == NoiseDependant.class) - { - NoiseDependant oldPlacementConfig = (NoiseDependant) config.decorator.config(); - placementConfig = new NoiseDependant(oldPlacementConfig.noiseLevel, oldPlacementConfig.belowNoise, oldPlacementConfig.aboveNoise); - } - else - { -// ClientProxy.LOGGER.debug("unkown decorated placement config: \"" + config.decorator.config().getClass() + "\""); - return config; - } - - - ConfiguredPlacement newPlacement = new ConfiguredPlacement(config.decorator.decorator, placementConfig); - return new DecoratedFeatureConfig(config.feature, newPlacement); - } - - - @SuppressWarnings("unused") - private BlockClusterFeatureConfig cloneBlockClusterFeatureConfig(BlockClusterFeatureConfig config) - { - WeightedBlockStateProvider provider = new WeightedBlockStateProvider(); - for(Entry state : ((WeightedBlockStateProvider) config.stateProvider).weightedList.entries) - provider.weightedList.entries.add(state); - - HashSet whitelist = new HashSet<>(); - for(Block block : config.whitelist) - whitelist.add(block); - - HashSet blacklist = new HashSet<>(); - for(BlockState state : config.blacklist) - blacklist.add(state); - - - BlockClusterFeatureConfig.Builder builder = new BlockClusterFeatureConfig.Builder(provider, config.blockPlacer); - builder.whitelist(whitelist); - builder.blacklist(blacklist); - builder.xspread(config.xspread); - builder.yspread(config.yspread); - builder.zspread(config.zspread); - if(config.canReplace) { builder.canReplace(); } - if(config.needWater) { builder.needWater(); } - if(config.project) { builder.noProjection(); } - builder.tries(config.tries); - - - return builder.build(); - } - - } - - - /* - * 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.EMPTY 0 - 1 ms false (empty, what did you expect? :P) - ChunkStatus.STRUCTURE_REFERENCES 1 - 2 ms false (no height, only generates some chunks) - ChunkStatus.BIOMES 1 - 10 ms false (no height) - ChunkStatus.NOISE 4 - 15 ms true (all blocks are stone) - ChunkStatus.LIQUID_CARVERS 6 - 12 ms true (no snow/trees, just grass) - ChunkStatus.SURFACE 5 - 15 ms true (no snow/trees, just grass) - ChunkStatus.CARVERS 5 - 30 ms true (no snow/trees, just grass) - ChunkStatus.FEATURES 7 - 25 ms true - ChunkStatus.HEIGHTMAPS 20 - 40 ms true - ChunkStatus.LIGHT 20 - 40 ms true - ChunkStatus.FULL 30 - 50 ms true - ChunkStatus.SPAWN 50 - 80 ms true - - - 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) - */ -} diff --git a/src/main/java/com/seibel/lod/objects/HOWTOUSE.txt b/src/main/java/com/seibel/lod/objects/HOWTOUSE.txt new file mode 100644 index 000000000..c9051e34d --- /dev/null +++ b/src/main/java/com/seibel/lod/objects/HOWTOUSE.txt @@ -0,0 +1,29 @@ +This are the file that you should use + +DistanceGenerationMode (added NONE) +LodQuadTreeDimensionFileHandler +LodDataPoint (added hash and equal function) +LodQuadTreeNode +LodQuadTree +LodQuadTreeDimension +LodQuadTreeWorld (this is identical to LodWorld but uses LodQuadTreeDimension) + +HOW IT WORK +I've tried to make this classes as similar at yours. This way you could even do the same stuff that you are doing now +like using all the Lod with the same quality. LodDetail is not used anywhere and is replaced by a level value in +LodQuadTreeNode. + +A LodQuadTree has a quad tree structure. So it has 4 children of the same type and a LodQuadTreeNode that contain all +the information of the node such as position, level (the level is the depth of the quad tree) and the LodDataPoint. +If in the future you want to add multiple LodDataPoint per position (maybe you want to show floating island) you could still +do it by transforming the lodDataPoint variable in a LodDataPoint array. + +The two most important factor of a Node is the level and the level position. At level 9 you find the region (of width 2^9=512) +at level 4 you find the chunk (of width 2^4=16) and at level 0 you find the blocks (of width 2^0=1). The pos is like the +region pos and the chunk pos but for every level. +The complexity of a node indicate how the node was built, so i've used the DistanceGenerationMode enum. The complexity is +ordered by the order in the enum (NONE -> BIOME_ONLY -> BIOME_ONLY_SIMULATE_HEIGHT -> SURFACE -> FEATURES -> SERVER). The idea +is that you cannot override a node with a node that is less complex. This way you could use different type of generation based +on the distance. + +HOW TO USE diff --git a/src/main/java/com/seibel/lod/proxy/ClientProxy.java b/src/main/java/com/seibel/lod/proxy/ClientProxy.java index 02a450897..1f6f2aaf5 100644 --- a/src/main/java/com/seibel/lod/proxy/ClientProxy.java +++ b/src/main/java/com/seibel/lod/proxy/ClientProxy.java @@ -1,16 +1,13 @@ package com.seibel.lod.proxy; +import com.seibel.lod.builders.LodNodeBufferBuilder; +import com.seibel.lod.builders.LodNodeBuilder; +import com.seibel.lod.objects.*; +import com.seibel.lod.render.LodNodeRenderer; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import com.seibel.lod.builders.LodBufferBuilder; -import com.seibel.lod.builders.LodChunkBuilder; import com.seibel.lod.handlers.LodConfig; -import com.seibel.lod.objects.LodChunk; -import com.seibel.lod.objects.LodDimension; -import com.seibel.lod.objects.LodRegion; -import com.seibel.lod.objects.LodWorld; -import com.seibel.lod.render.LodRenderer; import com.seibel.lod.util.LodUtil; import net.minecraft.client.Minecraft; @@ -31,10 +28,10 @@ public class ClientProxy { public static final Logger LOGGER = LogManager.getLogger("LOD"); - private static LodWorld lodWorld = new LodWorld(); - private static LodChunkBuilder lodChunkBuilder = new LodChunkBuilder(); - private static LodBufferBuilder lodBufferBuilder = new LodBufferBuilder(lodChunkBuilder); - private static LodRenderer renderer = new LodRenderer(lodBufferBuilder); + private static LodQuadTreeWorld lodWorld = new LodQuadTreeWorld(); + private static LodNodeBuilder lodChunkBuilder = new LodNodeBuilder(); + private static LodNodeBufferBuilder lodBufferBuilder = new LodNodeBufferBuilder(lodChunkBuilder); + private static LodNodeRenderer renderer = new LodNodeRenderer(lodBufferBuilder); Minecraft mc = Minecraft.getInstance(); @@ -59,41 +56,39 @@ public class ClientProxy { if (mc == null || mc.player == null || !lodWorld.getIsWorldLoaded()) return; - - // update each regions' width to match the new render distance - int newWidth = Math.max(4, - // TODO is this logic good? - (mc.options.renderDistance * LodChunk.WIDTH * 2 * LodConfig.CLIENT.lodChunkRadiusMultiplier.get()) / LodRegion.SIZE - ); - if (lodChunkBuilder.regionWidth != newWidth) - { - lodWorld.resizeDimensionRegionWidth(newWidth); - lodChunkBuilder.regionWidth = newWidth; - - // skip this frame, hopefully the lodWorld - // should have everything set up by then - return; - } - - LodDimension lodDim = lodWorld.getLodDimension(mc.player.level.dimensionType()); - if (lodDim == null) - return; - - - // offset the regions - double playerX = mc.player.getX(); - double playerZ = mc.player.getZ(); - - int xOffset = ((int)playerX / (LodChunk.WIDTH * LodRegion.SIZE)) - lodDim.getCenterX(); - int zOffset = ((int)playerZ / (LodChunk.WIDTH * LodRegion.SIZE)) - lodDim.getCenterZ(); - - if (xOffset != 0 || zOffset != 0) - { - lodDim.move(xOffset, zOffset); - } - - - // TODO for testing + try { + // update each regions' width to match the new render distance + int newWidth = Math.max(4, + // TODO is this logic good? + (mc.options.renderDistance * LodChunk.WIDTH * 2 * LodConfig.CLIENT.lodChunkRadiusMultiplier.get()) / LodRegion.SIZE + ); + if (lodChunkBuilder.regionWidth != newWidth) { + lodWorld.resizeDimensionRegionWidth(newWidth); + lodChunkBuilder.regionWidth = newWidth; + + // skip this frame, hopefully the lodWorld + // should have everything set up by then + return; + } + + LodQuadTreeDimension lodDim = lodWorld.getLodDimension(mc.player.level.dimensionType()); + if (lodDim == null) + return; + + + // offset the regions + double playerX = mc.player.getX(); + double playerZ = mc.player.getZ(); + + int xOffset = ((int) playerX / (LodChunk.WIDTH * LodRegion.SIZE)) - lodDim.getCenterX(); + int zOffset = ((int) playerZ / (LodChunk.WIDTH * LodRegion.SIZE)) - lodDim.getCenterZ(); + + if (xOffset != 0 || zOffset != 0) { + lodDim.move(xOffset, zOffset); + } + + + // TODO for testing // LodConfig.CLIENT.debugMode.set(false); // LodConfig.CLIENT.lodDetail.set(LodDetail.DOUBLE); // LodConfig.CLIENT.lodColorStyle.set(LodColorStyle.INDIVIDUAL_SIDES); @@ -101,19 +96,22 @@ public class ClientProxy // LodConfig.CLIENT.distanceGenerationMode.set(DistanceGenerationMode.FEATURES); // LodConfig.CLIENT.fogDistance.set(FogDistance.FAR); // LodConfig.CLIENT.fogDrawOverride.set(FogDrawOverride.ALWAYS_DRAW_FOG_FANCY); - - // Note to self: - // if "unspecified" shows up in the pie chart, it is - // possibly because the amount of time between sections - // is too small for the profile to measure - IProfiler profiler = mc.getProfiler(); - profiler.pop(); // get out of "terrain" - profiler.push("LOD"); - - renderer.drawLODs(lodDim, partialTicks, mc.getProfiler()); - - profiler.pop(); // end LOD - profiler.push("terrain"); // restart terrain + + // Note to self: + // if "unspecified" shows up in the pie chart, it is + // possibly because the amount of time between sections + // is too small for the profile to measure + IProfiler profiler = mc.getProfiler(); + profiler.pop(); // get out of "terrain" + profiler.push("LOD"); + + renderer.drawLODs(lodDim, partialTicks, mc.getProfiler()); + + profiler.pop(); // end LOD + profiler.push("terrain"); // restart terrain + }catch (Exception e){ + return; + } } @@ -126,13 +124,15 @@ public class ClientProxy @SubscribeEvent public void chunkLoadEvent(ChunkEvent.Load event) { - lodChunkBuilder.generateLodChunkAsync(event.getChunk(), lodWorld, event.getWorld()); + lodChunkBuilder.generateLodNodeAsync(event.getChunk(), lodWorld, event.getWorld()); } @SubscribeEvent public void worldLoadEvent(WorldEvent.Load event) { + + System.out.println("Loading world"); // the player just loaded a new world/dimension lodWorld.selectWorld(LodUtil.getWorldID(event.getWorld())); // make sure the correct LODs are being rendered @@ -164,7 +164,7 @@ public class ClientProxy event.getClass() == BlockEvent.PortalSpawnEvent.class) { // recreate the LOD where the blocks were changed - lodChunkBuilder.generateLodChunkAsync(event.getWorld().getChunk(event.getPos()), lodWorld, event.getWorld()); + lodChunkBuilder.generateLodNodeAsync(event.getWorld().getChunk(event.getPos()), lodWorld, event.getWorld()); } } @@ -175,17 +175,17 @@ public class ClientProxy // public getters // //================// - public static LodWorld getLodWorld() + public static LodQuadTreeWorld getLodWorld() { return lodWorld; } - public static LodChunkBuilder getLodBuilder() + public static LodNodeBuilder getLodBuilder() { return lodChunkBuilder; } - public static LodRenderer getRenderer() + public static LodNodeRenderer getRenderer() { return renderer; } diff --git a/src/main/java/com/seibel/lod/render/LodRenderer.java b/src/main/java/com/seibel/lod/render/LodRenderer similarity index 100% rename from src/main/java/com/seibel/lod/render/LodRenderer.java rename to src/main/java/com/seibel/lod/render/LodRenderer diff --git a/src/main/java/com/seibel/lod/render/RenderUtil.java b/src/main/java/com/seibel/lod/render/RenderUtil.java index d575d7eda..03210c5db 100644 --- a/src/main/java/com/seibel/lod/render/RenderUtil.java +++ b/src/main/java/com/seibel/lod/render/RenderUtil.java @@ -86,7 +86,7 @@ public class RenderUtil */ public static int getMaxRadiusMultiplierWithAvaliableMemory(LodTemplate lodTemplate, LodDetail lodDetail) { - int maxNumberOfLods = LodRenderer.MAX_ALOCATEABLE_DIRECT_MEMORY / lodTemplate.getBufferMemoryForSingleLod(lodDetail); + int maxNumberOfLods = LodNodeRenderer.MAX_ALOCATEABLE_DIRECT_MEMORY / lodTemplate.getBufferMemoryForSingleLod(lodDetail); int numbLodsWide = (int) Math.sqrt(maxNumberOfLods); return numbLodsWide / (2 * mc.options.renderDistance); From e40ee204604e49b9a2b003335a300642a1d259ae Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 14 Jul 2021 11:14:44 +0200 Subject: [PATCH 32/46] Added GUIDE to Readme.txt --- Readme.txt | 94 ++++++++----------- .../java/com/seibel/lod/enums/LodCorner.java | 26 ----- .../java/com/seibel/lod/objects/HOWTOUSE.txt | 28 ------ 3 files changed, 40 insertions(+), 108 deletions(-) delete mode 100644 src/main/java/com/seibel/lod/enums/LodCorner.java diff --git a/Readme.txt b/Readme.txt index f1a6b586d..0b631d786 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,69 +1,55 @@ -This mod adds a Level Of Detail (LOD) system to Minecraft. -This implementation renders simplified chunks outside the normal render distance -allowing for an increased view distance without harming performance. - -Or in other words: this mod let's you see farther without turning your game into a slide show. -If you want to see a quick demo, check out the video I made here: -https://youtu.be/CCT-3s02tYA - - -Forge version: 1.16.5-36.1.0 - -Notes: -This version has been confirmed to work in Eclipse. - +This branch is used only to test the QuadTree data structure. This branch cannot be used to compile the mode and the classes +that are not listed below in the next section are not updated to the last version of the main branch. ======================== -source code installation +QUADTREE VERSION - HOW IT WORK AND HOW TO USE ======================== +This are the file that you should use if you want to import the quadTree to your current version. -See the Forge Documentation online for more detailed instructions: -http://mcforge.readthedocs.io/en/latest/gettingstarted/ +DistanceGenerationMode (added NONE) +LodQuadTreeDimensionFileHandler +LodDataPoint (added hash and equal function) +LodQuadTreeNode +LodQuadTree +LodQuadTreeDimension +LodQuadTreeWorld (this is identical to LodWorld but uses LodQuadTreeDimension) -Step 1: Create a system variable called "JAVA_MC_HOME" with the location of the JDK 1.8.0_251 (This is needed for gradle to work correctly) +and those two optional classes +BiomeColorsUtils is a class that i've created that contain various static methods to create colors from a biom +QuadTreeImage uses the ChunkBase map generation to test the QuadTree. You should refresh dependencies to import + the KaptainWutax code (check the build.gradle if you want to use them. I still can only use the code in intellij + but can't import it in the final mod jar, because i'm still new to this stuff, so it wouldn't work in game at the moment) -Step 2: replace JAVA_HOME with JAVA_MC_HOME in gradle.bat - -Step 3: open a command line in the project folder - -Step 4: run the command: "./gradlew geneclipseruns" - -Step 5: run the command: "./gradlew eclipse" - -Step 6: Make sure the eclipse has the JDK 1.8.0_251 installed. (This is needed so that eclipse can run minecraft) - -Step 7: Import the project into eclipse +You should then update the builders, the renderer, the templates... to work with this. +--HOW IT WORK +I've tried to make this classes as similar as possible to yours. This way you could even do the same stuff that you are doing now +like using all the Lod with the same quality. LodDetail is not used anywhere and is replaced by a level value in +LodQuadTreeNode. -========= -compiling -========= +A LodQuadTree has a quad tree structure. So it has 4 children of the same type and a LodQuadTreeNode that contain all +the information of the node such as position, level (the level is the depth of the quad tree) and the LodDataPoint. +If in the future you want to add multiple LodDataPoint per position (maybe you want to show floating island) you could still +do it by transforming the lodDataPoint variable in a LodDataPoint array. -Step 1: open a command line in the project folder +The two most important factor of a Node is the level and the level position. At level 9 you find the region (of width 2^9=512) +at level 4 you find the chunk (of width 2^4=16) and at level 0 you find the blocks (of width 2^0=1). The pos is like the +region pos and the chunk pos but for every level. +The complexity of a node indicate how the node was built, so i've used the DistanceGenerationMode enum. The complexity is +ordered by the order in the enum (NONE -> BIOME_ONLY -> BIOME_ONLY_SIMULATE_HEIGHT -> SURFACE -> FEATURES -> SERVER). The idea +is that you cannot override a node with a node that is less complex. This way you could use different type of generation based +on the distance. -Step 2: run the command: "./gradlew build" +LodQuadTreeDimensionFileHandler is used to save all the region (quadTree). I've just converted your method of saving +to work with this. -Step 3: the compiled jar file will be in the folder "build\libs" +--HOW TO USE +You can create the LodQuadTreeWorld and the LodQuadTreeDimension in the same way as yours. +You can build a LodQuadTreeNode by specifying the level, the position in the level, the LodDataPoint, the complexity +(the DistanceGenerationMode setting selected to generate the information of the node or NONE if the node is fake and empty). -============== -Other commands -============== - -"./gradlew --refresh-dependencies" to refresh local dependencies. -"./gradlew clean" to reset everything (this does not affect your code) and then start the process again. - - - -============ -Note to self -============ - -The Minecraft source code is NOT added to your workspace in a editable way. Minecraft is treated like a normal Library. Sources are there for documentation and research purposes only. - -Source code uses mcp mappings not Mojangs. - -The source code can be 'created' with the ./eclipse command and can be found in the following path: -minecraft-lod-mod\build\fg_cache\mcp\ VERSION \joined\ RANDOM_STRING \patch\output.jar +How to select the node that i want to generate? +At the moment you can select this in two ways: the first is to use the getLodNodeToGenerate diff --git a/src/main/java/com/seibel/lod/enums/LodCorner.java b/src/main/java/com/seibel/lod/enums/LodCorner.java deleted file mode 100644 index 97f8f3456..000000000 --- a/src/main/java/com/seibel/lod/enums/LodCorner.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.seibel.lod.enums; - -/** - * NE, SE, SW, NW - * - * @author James Seibel - * @version 1-20-2020 - */ -public enum LodCorner -{ - /** -Z, +X */ - NE(0), - /** +Z, +X */ - SE(1), - /** +Z, -X */ - SW(2), - /** -Z, -X */ - NW(3); - - public final int value; - - private LodCorner(int newValue) - { - value = newValue; - } -} diff --git a/src/main/java/com/seibel/lod/objects/HOWTOUSE.txt b/src/main/java/com/seibel/lod/objects/HOWTOUSE.txt index c9051e34d..8b1378917 100644 --- a/src/main/java/com/seibel/lod/objects/HOWTOUSE.txt +++ b/src/main/java/com/seibel/lod/objects/HOWTOUSE.txt @@ -1,29 +1 @@ -This are the file that you should use -DistanceGenerationMode (added NONE) -LodQuadTreeDimensionFileHandler -LodDataPoint (added hash and equal function) -LodQuadTreeNode -LodQuadTree -LodQuadTreeDimension -LodQuadTreeWorld (this is identical to LodWorld but uses LodQuadTreeDimension) - -HOW IT WORK -I've tried to make this classes as similar at yours. This way you could even do the same stuff that you are doing now -like using all the Lod with the same quality. LodDetail is not used anywhere and is replaced by a level value in -LodQuadTreeNode. - -A LodQuadTree has a quad tree structure. So it has 4 children of the same type and a LodQuadTreeNode that contain all -the information of the node such as position, level (the level is the depth of the quad tree) and the LodDataPoint. -If in the future you want to add multiple LodDataPoint per position (maybe you want to show floating island) you could still -do it by transforming the lodDataPoint variable in a LodDataPoint array. - -The two most important factor of a Node is the level and the level position. At level 9 you find the region (of width 2^9=512) -at level 4 you find the chunk (of width 2^4=16) and at level 0 you find the blocks (of width 2^0=1). The pos is like the -region pos and the chunk pos but for every level. -The complexity of a node indicate how the node was built, so i've used the DistanceGenerationMode enum. The complexity is -ordered by the order in the enum (NONE -> BIOME_ONLY -> BIOME_ONLY_SIMULATE_HEIGHT -> SURFACE -> FEATURES -> SERVER). The idea -is that you cannot override a node with a node that is less complex. This way you could use different type of generation based -on the distance. - -HOW TO USE From d054ac91b1bd50b0727c5be103c3c89054d13f9c Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 14 Jul 2021 14:33:17 +0200 Subject: [PATCH 33/46] Fixed all negative coords bug --- .../com/seibel/lod/objects/LodQuadTree.java | 6 - .../lod/objects/LodQuadTreeDimension.java | 24 ++- .../seibel/lod/objects/LodQuadTreeNode.java | 27 +-- .../com/seibel/lod/objects/QuadTreeImage.java | 176 ++++++++++-------- 4 files changed, 136 insertions(+), 97 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/LodQuadTree.java index e5f751620..1ef9ed594 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -143,12 +143,6 @@ public class LodQuadTree { short widthRatio = (short) (lodNode.width / (2 * newLodNode.width)); int WE = Math.abs(Math.floorDiv(posX , widthRatio) % 2); int NS = Math.abs(Math.floorDiv(posZ , widthRatio) % 2); - //These two if fix the negative coordinate problema - //I don't know why, there is some problem with the %2 operation - /* - if(posX<0) WE = 1 - WE; - if(posZ<0) NS = 1 - NS; - */ if (getChild(NS, WE) == null) { setChild(NS, WE); } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java index 8bf307815..de93dcb01 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java @@ -4,6 +4,7 @@ import com.seibel.lod.enums.DistanceGenerationMode; import com.seibel.lod.handlers.LodQuadTreeDimensionFileHandler; import com.seibel.lod.util.LodUtil; import net.minecraft.client.Minecraft; +import net.minecraft.util.math.ChunkPos; import net.minecraft.world.DimensionType; import net.minecraft.world.server.ServerChunkProvider; import net.minecraft.world.server.ServerWorld; @@ -264,8 +265,8 @@ public class LodQuadTreeDimension { public Boolean addNode(LodQuadTreeNode lodNode) { RegionPos pos = new RegionPos( - lodNode.getStartX() / 512, - lodNode.getStartZ() / 512 + Math.floorDiv(lodNode.getStartX(), 512), + Math.floorDiv(lodNode.getStartZ(), 512) ); // don't continue if the region can't be saved @@ -296,6 +297,19 @@ public class LodQuadTreeDimension { return coorectlyAdded; } + /** + */ + public LodQuadTreeNode getLodFromCoordinates(ChunkPos chunkPos) + { + return getLodFromCoordinates(chunkPos.x, chunkPos.z, LodQuadTreeNode.CHUNK_LEVEL); + } + + /** + */ + public LodQuadTreeNode getLodFromCoordinates(int chunkPosX, int chunkPosZ) + { + return getLodFromCoordinates(chunkPosX, chunkPosZ, LodQuadTreeNode.CHUNK_LEVEL); + } /** * Get the LodNodeData at the given X and Z position in the level * in this dimension. @@ -305,9 +319,11 @@ public class LodQuadTreeDimension { */ public LodQuadTreeNode getLodFromCoordinates(int posX, int posZ, byte level) { - LodQuadTree region = getRegion((int) (posX/(512/Math.pow(level,2))),(int) (posZ/(512/Math.pow(level,2)))); - if(region == null) + LodQuadTree region = getRegion((Math.floorDiv(posX, (int) (512/Math.pow(level,2)))),(Math.floorDiv(posZ, (int) (512/Math.pow(level,2))))); + if(region == null) { + System.out.println("THIS CASE"); return null; + } return region.getNodeAtLevelPosition(posX, posZ, level); /* RegionPos pos = LodUtil.convertChunkPosToRegionPos(new ChunkPos(chunkX, chunkZ)); diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java index 7c089d68f..153b43177 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java @@ -146,9 +146,6 @@ public class LodQuadTreeNode { index = data.indexOf(DATA_DELIMITER, 0); this.level = (byte) Integer.parseInt(data.substring(0,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); @@ -158,6 +155,10 @@ public class LodQuadTreeNode { 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)); @@ -258,18 +259,18 @@ public class LodQuadTreeNode { * Outputs all data in a csv format */ public String toData(){ - String s = ((int) level) + DATA_DELIMITER + String s = Integer.toString((int) level) + DATA_DELIMITER + + Integer.toString(posX) + DATA_DELIMITER + + Integer.toString(posZ) + DATA_DELIMITER + complexity.toString() + DATA_DELIMITER - + posX + DATA_DELIMITER - + posZ + DATA_DELIMITER - + ((int) lodDataPoint.height) + DATA_DELIMITER - + ((int) lodDataPoint.depth) + DATA_DELIMITER - + lodDataPoint.color.getRed() + DATA_DELIMITER - + lodDataPoint.color.getGreen() + DATA_DELIMITER - + lodDataPoint.color.getBlue() + DATA_DELIMITER - + lodDataPoint.color.getAlpha() + DATA_DELIMITER; + + Integer.toString(((int) lodDataPoint.height)) + DATA_DELIMITER + + Integer.toString(((int) 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 += val + DATA_DELIMITER; + s += Integer.toString(val) + DATA_DELIMITER; return s; } diff --git a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java index 2b3ca9988..ffde537d4 100644 --- a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -29,7 +29,7 @@ import javax.swing.Timer; @SuppressWarnings("serial") public class QuadTreeImage extends JPanel { - private static final int PREF_W = 1000; + private static final int PREF_W = 1536; private static final int PREF_H = PREF_W; private List drawables = new ArrayList<>(); @@ -68,15 +68,6 @@ public class QuadTreeImage extends JPanel { } private static void createAndShowGui() { - int playerX = 32*512; - int playerZ = 32*512; - LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, 64); - System.out.println(dim.getRegion(0, 0)); - dim.move(Math.floorDiv(playerX,512),Math.floorDiv(playerZ,512)); - - System.out.println(dim.getCenterX()); - System.out.println(dim.getCenterZ()); - System.out.println(dim.getWidth()); final QuadTreeImage quadTreeImage = new QuadTreeImage(); @@ -90,83 +81,115 @@ public class QuadTreeImage extends JPanel { List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 1000); //EndBiomeSource biomeSource = new EndBiomeSource(MCVersion.v1_16_5, 1000); - int[] distances = {100000,8000,4000,2000,1000,500,250,100,50,25}; - for (int i = 0; i <= (9 - 2); i++) { - for (int j = 0; j < 1; j++) { - List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), DistanceGenerationMode.SERVER , distances[i], 0); - //System.out.println(levelToGenerate); - for (LodQuadTree level : levelToGenerate) { - Color color; - int startX = level.getLodNodeData().startX; - int startZ = level.getLodNodeData().startZ; - int endX = level.getLodNodeData().endX; - int endZ = level.getLodNodeData().endZ; - int centerX = level.getLodNodeData().centerX; - int centerZ = level.getLodNodeData().centerZ; - int width = level.getLodNodeData().width; - byte otherLevel = LodQuadTreeNode.BLOCK_LEVEL; - int otherWidth = LodQuadTreeNode.BLOCK_WIDTH; + int sizeOfTheWorld = 16; - List posXs = new ArrayList<>(); - List posZs = new ArrayList<>(); - if (level.getLodNodeData().level == 0) { - posXs.add(Math.floorDiv(startX , otherWidth)); - posZs.add(Math.floorDiv(startZ , otherWidth)); - } else { - posXs.add(Math.floorDiv(startX , otherWidth)); - posXs.add(Math.floorDiv(centerX + 1, otherWidth)); - posZs.add(Math.floorDiv(startZ, otherWidth)); - posZs.add(Math.floorDiv(centerZ +1 , otherWidth)); - } + LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, sizeOfTheWorld); - //System.out.println(posXs); - //System.out.println(posZs); + //SIMULATING A PLAYER MOVING, + int[] playerXs = {0,100,200,300,400,500}; + int[] playerZs = {0,100,200,300,400,500}; + for(int pos=0; pos<6; pos++) { + int playerX= playerXs[pos]; + int playerZ= playerZs[pos]; - for (Integer posXI : posXs) { - for (Integer posZI : posZs) { - int posX = posXI.intValue(); - int posZ = posZI.intValue(); - //System.out.println(posX + " " + posZ); - color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posX, 0, posZ)); - //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); - LodQuadTreeNode node = new LodQuadTreeNode(otherLevel, posX, posZ, new LodDataPoint(0, 0, color) , DistanceGenerationMode.SERVER); - dim.addNode(node); + //int sizeOfTheWorld=512; //TRY THIS TO SEE A 250'000 BLOCK RENDER DISTANCE + dim.move(Math.floorDiv(playerX, 512), Math.floorDiv(playerZ, 512)); +/* + System.out.println(dim.getRegion(0, 0)); + System.out.println(dim.getCenterX()); + System.out.println(dim.getCenterZ()); + System.out.println(dim.getWidth()); + + System.out.println("GETTING LOD FROM COORDINATE BEFORE GENERETION"); + System.out.println(dim.getLodFromCoordinates(-6, -6)); +*/ + + int[] distances = {100000, 8000, 4000, 2000, 1000, 500, 250, 100, 50, 25}; + for (int i = 0; i <= (9 - 2); i++) { + for (int j = 0; j < 1; j++) { + List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), DistanceGenerationMode.SERVER, distances[i], 0); + //System.out.println(levelToGenerate); + for (LodQuadTree level : levelToGenerate) { + Color color; + int startX = level.getLodNodeData().startX; + int startZ = level.getLodNodeData().startZ; + int endX = level.getLodNodeData().endX; + int endZ = level.getLodNodeData().endZ; + int centerX = level.getLodNodeData().centerX; + int centerZ = level.getLodNodeData().centerZ; + int width = level.getLodNodeData().width; + byte otherLevel = LodQuadTreeNode.BLOCK_LEVEL; + int otherWidth = LodQuadTreeNode.BLOCK_WIDTH; + + List posXs = new ArrayList<>(); + List posZs = new ArrayList<>(); + if (level.getLodNodeData().level == 0) { + posXs.add(Math.floorDiv(startX, otherWidth)); + posZs.add(Math.floorDiv(startZ, otherWidth)); + } else { + posXs.add(Math.floorDiv(startX, otherWidth)); + posXs.add(Math.floorDiv(centerX + 1, otherWidth)); + posZs.add(Math.floorDiv(startZ, otherWidth)); + posZs.add(Math.floorDiv(centerZ + 1, otherWidth)); + } + + //System.out.println(posXs); + //System.out.println(posZs); + + for (Integer posXI : posXs) { + for (Integer posZI : posZs) { + int posX = posXI.intValue(); + int posZ = posZI.intValue(); + //System.out.println(posX + " " + posZ); + color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posX, 0, posZ)); + //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); + LodQuadTreeNode node = new LodQuadTreeNode(otherLevel, posX, posZ, new LodDataPoint(0, 0, color), DistanceGenerationMode.SERVER); + if (dim.addNode(node)) { + } + } } } } - } - /* - List lodList = new ArrayList<>(); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 3, 250,0)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 4, 500,250)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 5, 1000,500)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 6, 2000,1000)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 7, 4000,2000)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 8, 8000,4000)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 9, 100000,8000)); + + //Set complexityMask = new HashSet<>(); + //complexityMask.add(DistanceGenerationMode.SERVER); + //complexityMask.add(DistanceGenerationMode.FEATURES); + //complexityMask.add(DistanceGenerationMode.SURFACE); + //complexityMask.add(DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT); + //complexityMask.add(DistanceGenerationMode.BIOME_ONLY); + + Set complexityMask = LodQuadTreeDimension.FULL_COMPLEXITY_MASK; + + List lodList = new ArrayList<>(); + //The min and max distances should increase quadratically + + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 3, complexityMask, 250,0)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 4, complexityMask,500,250)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 5, complexityMask,1000,500)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 6, complexityMask,2000,1000)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 7, complexityMask,4000,2000)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 8, complexityMask,8000,4000)); + lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 9, complexityMask,100000,8000)); System.out.println(lodList.size()); - */ - Set complexityMask = new HashSet<>(); - complexityMask.add(DistanceGenerationMode.SERVER); - complexityMask.add(DistanceGenerationMode.FEATURES); - complexityMask.add(DistanceGenerationMode.SURFACE); - complexityMask.add(DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT); - complexityMask.add(DistanceGenerationMode.BIOME_ONLY); - List lodList = dim.getNodes(complexityMask,false,false); - // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 2, 100, 0)); - // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 3, 200, 100)); - // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 4, 400, 200)); - // lodList.addAll(lodQuadTree.getNodeToRender(playerX, playerZ, (byte) 5, 10000, 400)); - listOfList.add(lodList); + + + // List lodList = dim.getNodes(complexityMask, false, false); //USE THIS TO SEE AL THE LODS + listOfList.add(lodList); + } } + System.out.println("GETTING LOD FROM COORDINATE AFTER GENERETION"); + System.out.println(dim.getLodFromCoordinates(0,100, (byte) 1)); + //FROM THIS POINT ON THE CODE JUST CREATE THE IMAGE - - int timerDelay = 0; + int timerDelay = 200; System.out.println("STARTING"); System.out.println(dim.getWidth()); System.out.println(dim.getCenterX()); int xOffset = listOfList.stream().mapToInt(x -> x.stream().mapToInt(y -> y.startX).min().getAsInt()).min().getAsInt(); int zOffset = listOfList.stream().mapToInt(x -> x.stream().mapToInt(y -> y.startZ).min().getAsInt()).min().getAsInt(); + int maxX = listOfList.stream().mapToInt(x -> x.stream().mapToInt(y -> y.startX).max().getAsInt()).min().getAsInt(); + int maxZ = listOfList.stream().mapToInt(x -> x.stream().mapToInt(y -> y.startZ).max().getAsInt()).min().getAsInt(); + int maxSize = Math.max(maxX-xOffset,maxZ - zOffset)/512; System.out.println(xOffset); System.out.println(zOffset); new Timer(timerDelay, new ActionListener() { @@ -179,7 +202,7 @@ public class QuadTreeImage extends JPanel { } else { if(drawCount==0) quadTreeImage.clearAll(); final List myDrawables = new ArrayList<>(); - double amp = 0.025; + double amp = ((double) 3)/((double) sizeOfTheWorld); Collection lodList = listOfList.get(drawCount); for (LodQuadTreeNode data : lodList) { myDrawables.add(new MyDrawable(new Rectangle2D.Double( @@ -189,15 +212,19 @@ public class QuadTreeImage extends JPanel { data.width * amp), data.lodDataPoint.color, new BasicStroke(1))); } + /* myDrawables.add(new MyDrawable(new Rectangle2D.Double( (playerX - 10 - xOffset) * amp, (playerZ - 10 - zOffset) * amp, 20* amp, 20* amp), Color.yellow, new BasicStroke(1))); + + */ for (int k = 0; k < myDrawables.size(); k++) { quadTreeImage.addMyDrawable(myDrawables.get(k)); } + /* BufferedImage img = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = img.createGraphics(); frame.printAll(g2d); @@ -207,6 +234,7 @@ public class QuadTreeImage extends JPanel { } catch (IOException ioException) { ioException.printStackTrace(); } + */ drawCount++; } } From 1a8a7be4942c9b6f5c1b7f5e5e83001e650695bc Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 14 Jul 2021 14:33:58 +0200 Subject: [PATCH 34/46] Updated the guide --- Readme.txt | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/Readme.txt b/Readme.txt index 0b631d786..c8c8d7e2e 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,5 +1,8 @@ This branch is used only to test the QuadTree data structure. This branch cannot be used to compile the mode and the classes that are not listed below in the next section are not updated to the last version of the main branch. +If you want to see an example of use check the method createAndShowGui in the QuadTreeImage class + +https://imgur.com/a/PwQnGZT check this for various test ======================== QUADTREE VERSION - HOW IT WORK AND HOW TO USE @@ -23,7 +26,7 @@ QuadTreeImage uses the ChunkBase map generation to test the QuadTree. You You should then update the builders, the renderer, the templates... to work with this. ---HOW IT WORK +--HOW IT WORKs I've tried to make this classes as similar as possible to yours. This way you could even do the same stuff that you are doing now like using all the Lod with the same quality. LodDetail is not used anywhere and is replaced by a level value in LodQuadTreeNode. @@ -44,12 +47,49 @@ on the distance. LodQuadTreeDimensionFileHandler is used to save all the region (quadTree). I've just converted your method of saving to work with this. ---HOW TO USE +---HOW TO USE You can create the LodQuadTreeWorld and the LodQuadTreeDimension in the same way as yours. You can build a LodQuadTreeNode by specifying the level, the position in the level, the LodDataPoint, the complexity (the DistanceGenerationMode setting selected to generate the information of the node or NONE if the node is fake and empty). -How to select the node that i want to generate? -At the moment you can select this in two ways: the first is to use the getLodNodeToGenerate +--How to select the node that i want to generate? +At the moment you can select this in two ways: + +FIRST: use the getLodNodeToGenerate in lodQuadTreeDimension. +getNodeToGenerate(int x, int z, byte level, DistanceGenerationMode complexity, int maxDistance, int minDistance) + +The x and z are the position of the player (or you could just put 0,0 to test the system) the level is the depth at witch +we want to generate the LOD. The complexity indicate the complexity that we want to use to generate. So is a node "node1" +has complexity SERVER and we want to use FEATURES complexity to generate the nodes then "node1" will not be selected +because is more complex and we don't want do override it. maxDistance and minDistance indicate the range of distances +at witch we want to generate the nodes. +IMPORTANT those nodes are given as LodQuadTree and not LodQuadTreeNode. The idea +is that you take a LodQuadTree object, the you put in it 4 lodQuadTreeNode in the startX,startZ,centerX,centerZ coords, +as done in the QuadTreeImage class. To put the node you use the setNodeAtLowerLevel with the UpdateHigherLevel set to true. + +SECOND: you do it in the same way you are doing it now. +The getLodFromCoordinates has been converted to work with quadTree. So you could just threat the quadTree as a matrix +for the generation step. + + +--How to select the node that i want to render? +At the moment you can select this in two ways: + +FIRST: use the getNodeToRender in lodQuadTreeDimension. +getNodeToRender(int x, int z, byte level, Set complexityMask, int maxDistance, int minDistance) + +Works in a similar way to getLodNodeToGenerate. The main difference is that you have to use a complexityMask, which +indicate the complexity that you want to render (this way you could deselect the rendering of a precise type of complexity +like the SERVER or FEATURE for the debug phase). +This method return a list of LodQuadTreeNode. This node may have different width so you should convert the template to +work with this correctly. + +SECOND: you just use the getLodNodeToGenerate at a certain level to get the node that you want to render (if this +node does not exist the it will return NULL) + + + + + From b9d991db637ff7f558128d1c8655598a6f6e777f Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 14 Jul 2021 14:37:48 +0200 Subject: [PATCH 35/46] Updated the guide --- Readme.txt | 53 ++++++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/Readme.txt b/Readme.txt index c8c8d7e2e..d77efc22b 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,5 +1,5 @@ -This branch is used only to test the QuadTree data structure. This branch cannot be used to compile the mode and the classes -that are not listed below in the next section are not updated to the last version of the main branch. +This branch is used only to test the QuadTree data structure. This branch cannot be used to compile the mode and the +classes that are not listed below in the next section are not updated to the last version of the main branch. If you want to see an example of use check the method createAndShowGui in the QuadTreeImage class https://imgur.com/a/PwQnGZT check this for various test @@ -18,31 +18,32 @@ LodQuadTreeDimension LodQuadTreeWorld (this is identical to LodWorld but uses LodQuadTreeDimension) and those two optional classes -BiomeColorsUtils is a class that i've created that contain various static methods to create colors from a biom +BiomeColorsUtils is a class that i've created that contain various static methods to create colors from a biome QuadTreeImage uses the ChunkBase map generation to test the QuadTree. You should refresh dependencies to import the KaptainWutax code (check the build.gradle if you want to use them. I still can only use the code in intellij - but can't import it in the final mod jar, because i'm still new to this stuff, so it wouldn't work in game at the moment) + but can't import it in the final mod jar, because i'm still new to this stuff, so it wouldn't work in game at the + moment) You should then update the builders, the renderer, the templates... to work with this. --HOW IT WORKs -I've tried to make this classes as similar as possible to yours. This way you could even do the same stuff that you are doing now -like using all the Lod with the same quality. LodDetail is not used anywhere and is replaced by a level value in -LodQuadTreeNode. +I've tried to make this classes as similar as possible to yours. This way you could even do the same stuff that you are +doing now like using all the Lod with the same quality. LodDetail is not used anywhere and is replaced by a level value +in LodQuadTreeNode. A LodQuadTree has a quad tree structure. So it has 4 children of the same type and a LodQuadTreeNode that contain all the information of the node such as position, level (the level is the depth of the quad tree) and the LodDataPoint. -If in the future you want to add multiple LodDataPoint per position (maybe you want to show floating island) you could still -do it by transforming the lodDataPoint variable in a LodDataPoint array. +If in the future you want to add multiple LodDataPoint per position (maybe you want to show floating island) you could +still do it by transforming the lodDataPoint variable in a LodDataPoint array. -The two most important factor of a Node is the level and the level position. At level 9 you find the region (of width 2^9=512) -at level 4 you find the chunk (of width 2^4=16) and at level 0 you find the blocks (of width 2^0=1). The pos is like the -region pos and the chunk pos but for every level. -The complexity of a node indicate how the node was built, so i've used the DistanceGenerationMode enum. The complexity is -ordered by the order in the enum (NONE -> BIOME_ONLY -> BIOME_ONLY_SIMULATE_HEIGHT -> SURFACE -> FEATURES -> SERVER). The idea -is that you cannot override a node with a node that is less complex. This way you could use different type of generation based -on the distance. +The two most important factor of a Node is the level and the level position. At level 9 you find the region (of width +2^9=512)at level 4 you find the chunk (of width 2^4=16) and at level 0 you find the blocks (of width 2^0=1). +The pos is like the region pos and the chunk pos but for every level. +The complexity of a node indicate how the node was built, so i've used the DistanceGenerationMode enum. The complexity +is ordered by the order in the enum (NONE -> BIOME_ONLY -> BIOME_ONLY_SIMULATE_HEIGHT -> SURFACE -> FEATURES -> SERVER). +The idea is that you cannot override a node with a node that is less complex. This way you could use different type of +generation based on the distance. LodQuadTreeDimensionFileHandler is used to save all the region (quadTree). I've just converted your method of saving to work with this. @@ -52,7 +53,8 @@ to work with this. You can create the LodQuadTreeWorld and the LodQuadTreeDimension in the same way as yours. You can build a LodQuadTreeNode by specifying the level, the position in the level, the LodDataPoint, the complexity -(the DistanceGenerationMode setting selected to generate the information of the node or NONE if the node is fake and empty). +(the DistanceGenerationMode setting selected to generate the information of the node or NONE if the node is fake and +empty). --How to select the node that i want to generate? At the moment you can select this in two ways: @@ -60,14 +62,15 @@ At the moment you can select this in two ways: FIRST: use the getLodNodeToGenerate in lodQuadTreeDimension. getNodeToGenerate(int x, int z, byte level, DistanceGenerationMode complexity, int maxDistance, int minDistance) -The x and z are the position of the player (or you could just put 0,0 to test the system) the level is the depth at witch -we want to generate the LOD. The complexity indicate the complexity that we want to use to generate. So is a node "node1" -has complexity SERVER and we want to use FEATURES complexity to generate the nodes then "node1" will not be selected -because is more complex and we don't want do override it. maxDistance and minDistance indicate the range of distances -at witch we want to generate the nodes. +The x and z are the position of the player (or you could just put 0,0 to test the system) the level is the depth at +witch we want to generate the LOD. The complexity indicate the complexity that we want to use to generate. So is a node +"node1" has complexity SERVER and we want to use FEATURES complexity to generate the nodes then "node1" will not be +selected because is more complex and we don't want do override it. maxDistance and minDistance indicate the range of +distances at witch we want to generate the nodes. IMPORTANT those nodes are given as LodQuadTree and not LodQuadTreeNode. The idea is that you take a LodQuadTree object, the you put in it 4 lodQuadTreeNode in the startX,startZ,centerX,centerZ coords, -as done in the QuadTreeImage class. To put the node you use the setNodeAtLowerLevel with the UpdateHigherLevel set to true. +as done in the QuadTreeImage class. To put the node you use the setNodeAtLowerLevel with the UpdateHigherLevel set to +true. SECOND: you do it in the same way you are doing it now. The getLodFromCoordinates has been converted to work with quadTree. So you could just threat the quadTree as a matrix @@ -81,8 +84,8 @@ FIRST: use the getNodeToRender in lodQuadTreeDimension. getNodeToRender(int x, int z, byte level, Set complexityMask, int maxDistance, int minDistance) Works in a similar way to getLodNodeToGenerate. The main difference is that you have to use a complexityMask, which -indicate the complexity that you want to render (this way you could deselect the rendering of a precise type of complexity -like the SERVER or FEATURE for the debug phase). +indicate the complexity that you want to render (this way you could deselect the rendering of a precise type of +complexity like the SERVER or FEATURE for the debug phase). This method return a list of LodQuadTreeNode. This node may have different width so you should convert the template to work with this correctly. From 8b941cb95c7da804a214ebe6a2c3269bb76bc459 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 14 Jul 2021 14:41:03 +0200 Subject: [PATCH 36/46] Updated the guide --- Readme.txt | 95 +++++++++++++++++++++++++++++------------------------- 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/Readme.txt b/Readme.txt index d77efc22b..e71119a80 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,6 +1,7 @@ -This branch is used only to test the QuadTree data structure. This branch cannot be used to compile the mode and the -classes that are not listed below in the next section are not updated to the last version of the main branch. -If you want to see an example of use check the method createAndShowGui in the QuadTreeImage class +This branch is used only to test the QuadTree data structure. This branch cannot be used to compile the +mode and the classes that are not listed below in the next section are not updated to the last version +of the main branch. If you want to see an example of use check the method createAndShowGui in the +QuadTreeImage class. https://imgur.com/a/PwQnGZT check this for various test @@ -18,43 +19,46 @@ LodQuadTreeDimension LodQuadTreeWorld (this is identical to LodWorld but uses LodQuadTreeDimension) and those two optional classes -BiomeColorsUtils is a class that i've created that contain various static methods to create colors from a biome -QuadTreeImage uses the ChunkBase map generation to test the QuadTree. You should refresh dependencies to import - the KaptainWutax code (check the build.gradle if you want to use them. I still can only use the code in intellij - but can't import it in the final mod jar, because i'm still new to this stuff, so it wouldn't work in game at the - moment) +BiomeColorsUtils is a class that i've created that contain various static methods to create colors + from a biome +QuadTreeImage uses the ChunkBase map generation to test the QuadTree. You should refresh + dependencies to import the KaptainWutax code (check the build.gradle if you want to use them. + I still can only use the code in intellij but can't import it in the final mod jar, because + i'm still new to this stuff, so it wouldn't work in game at the moment) You should then update the builders, the renderer, the templates... to work with this. --HOW IT WORKs -I've tried to make this classes as similar as possible to yours. This way you could even do the same stuff that you are -doing now like using all the Lod with the same quality. LodDetail is not used anywhere and is replaced by a level value -in LodQuadTreeNode. +I've tried to make this classes as similar as possible to yours. This way you could even do the +same stuff that you are doing now like using all the Lod with the same quality. LodDetail is +not used anywhere and is replaced by a level value in LodQuadTreeNode. -A LodQuadTree has a quad tree structure. So it has 4 children of the same type and a LodQuadTreeNode that contain all -the information of the node such as position, level (the level is the depth of the quad tree) and the LodDataPoint. -If in the future you want to add multiple LodDataPoint per position (maybe you want to show floating island) you could -still do it by transforming the lodDataPoint variable in a LodDataPoint array. +A LodQuadTree has a quad tree structure. So it has 4 children of the same type and a LodQuadTreeNode +that contain all the information of the node such as position, level (the level is the depth of +the quad tree) and the LodDataPoint. If in the future you want to add multiple LodDataPoint per +position (maybe you want to show floating island) you could still do it by transforming the +lodDataPoint variable in a LodDataPoint array. -The two most important factor of a Node is the level and the level position. At level 9 you find the region (of width -2^9=512)at level 4 you find the chunk (of width 2^4=16) and at level 0 you find the blocks (of width 2^0=1). -The pos is like the region pos and the chunk pos but for every level. -The complexity of a node indicate how the node was built, so i've used the DistanceGenerationMode enum. The complexity -is ordered by the order in the enum (NONE -> BIOME_ONLY -> BIOME_ONLY_SIMULATE_HEIGHT -> SURFACE -> FEATURES -> SERVER). -The idea is that you cannot override a node with a node that is less complex. This way you could use different type of -generation based on the distance. +The two most important factor of a Node is the level and the level position. At level 9 you +find the region (of width 2^9=512)at level 4 you find the chunk (of width 2^4=16) and at +level 0 you find the blocks (of width 2^0=1). The pos is like the region pos and the chunk +pos but for every level. The complexity of a node indicate how the node was built, so i've +used the DistanceGenerationMode enum. The complexity is ordered by the order in the enum +(NONE -> BIOME_ONLY -> BIOME_ONLY_SIMULATE_HEIGHT -> SURFACE -> FEATURES -> SERVER). +The idea is that you cannot override a node with a node that is less complex. This way you +could use different type of generation based on the distance. -LodQuadTreeDimensionFileHandler is used to save all the region (quadTree). I've just converted your method of saving -to work with this. +LodQuadTreeDimensionFileHandler is used to save all the region (quadTree). I've just +converted your method of saving to work with this. ---HOW TO USE You can create the LodQuadTreeWorld and the LodQuadTreeDimension in the same way as yours. -You can build a LodQuadTreeNode by specifying the level, the position in the level, the LodDataPoint, the complexity -(the DistanceGenerationMode setting selected to generate the information of the node or NONE if the node is fake and -empty). +You can build a LodQuadTreeNode by specifying the level, the position in the level, +the LodDataPoint, the complexity (the DistanceGenerationMode setting selected to generate +the information of the node or NONE if the node is fake and empty). --How to select the node that i want to generate? At the moment you can select this in two ways: @@ -62,19 +66,21 @@ At the moment you can select this in two ways: FIRST: use the getLodNodeToGenerate in lodQuadTreeDimension. getNodeToGenerate(int x, int z, byte level, DistanceGenerationMode complexity, int maxDistance, int minDistance) -The x and z are the position of the player (or you could just put 0,0 to test the system) the level is the depth at -witch we want to generate the LOD. The complexity indicate the complexity that we want to use to generate. So is a node -"node1" has complexity SERVER and we want to use FEATURES complexity to generate the nodes then "node1" will not be -selected because is more complex and we don't want do override it. maxDistance and minDistance indicate the range of -distances at witch we want to generate the nodes. +The x and z are the position of the player (or you could just put 0,0 to test the system) +the level is the depth at witch we want to generate the LOD. The complexity indicate the +complexity that we want to use to generate. So is a node "node1" has complexity SERVER and +we want to use FEATURES complexity to generate the nodes then "node1" will not be selected +because is more complex and we don't want do override it. maxDistance and minDistance +indicate the range of distances at witch we want to generate the nodes. + IMPORTANT those nodes are given as LodQuadTree and not LodQuadTreeNode. The idea -is that you take a LodQuadTree object, the you put in it 4 lodQuadTreeNode in the startX,startZ,centerX,centerZ coords, -as done in the QuadTreeImage class. To put the node you use the setNodeAtLowerLevel with the UpdateHigherLevel set to -true. +is that you take a LodQuadTree object, the you put in it 4 lodQuadTreeNode in the +startX,startZ,centerX,centerZ coords, as done in the QuadTreeImage class. To put the node +you use the setNodeAtLowerLevel with the UpdateHigherLevel set to true. SECOND: you do it in the same way you are doing it now. -The getLodFromCoordinates has been converted to work with quadTree. So you could just threat the quadTree as a matrix -for the generation step. +The getLodFromCoordinates has been converted to work with quadTree. So you could just threat +the quadTree as a matrix for the generation step. --How to select the node that i want to render? @@ -83,14 +89,15 @@ At the moment you can select this in two ways: FIRST: use the getNodeToRender in lodQuadTreeDimension. getNodeToRender(int x, int z, byte level, Set complexityMask, int maxDistance, int minDistance) -Works in a similar way to getLodNodeToGenerate. The main difference is that you have to use a complexityMask, which -indicate the complexity that you want to render (this way you could deselect the rendering of a precise type of -complexity like the SERVER or FEATURE for the debug phase). -This method return a list of LodQuadTreeNode. This node may have different width so you should convert the template to -work with this correctly. +Works in a similar way to getLodNodeToGenerate. The main difference is that you have to +use a complexityMask, which indicate the complexity that you want to render (this way you +could deselect the rendering of a precise type of complexity like the SERVER or FEATURE for +the debug phase). +This method return a list of LodQuadTreeNode. This node may have different width so you +should convert the template to work with this correctly. -SECOND: you just use the getLodNodeToGenerate at a certain level to get the node that you want to render (if this -node does not exist the it will return NULL) +SECOND: you just use the getLodNodeToGenerate at a certain level to get the node that +you want to render (if this node does not exist the it will return NULL) From d77bb48da1c33f4ffaff1cace4242fa9aef3007c Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 14 Jul 2021 15:07:09 +0200 Subject: [PATCH 37/46] Updated the guide --- Readme.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Readme.txt b/Readme.txt index e71119a80..3ba394a1b 100644 --- a/Readme.txt +++ b/Readme.txt @@ -3,7 +3,8 @@ mode and the classes that are not listed below in the next section are not updat of the main branch. If you want to see an example of use check the method createAndShowGui in the QuadTreeImage class. -https://imgur.com/a/PwQnGZT check this for various test +https://imgur.com/a/PwQnGZT old test +https://imgur.com/a/UCcI2Sc new test (check this) ======================== QUADTREE VERSION - HOW IT WORK AND HOW TO USE From 5b3aa8281748869ca0bb97bb69e505be2bc13435 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 14 Jul 2021 15:08:10 +0200 Subject: [PATCH 38/46] Updated the image creation --- .../com/seibel/lod/objects/QuadTreeImage.java | 121 +++++++++--------- 1 file changed, 59 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java index ffde537d4..ac6288fb8 100644 --- a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -81,16 +81,16 @@ public class QuadTreeImage extends JPanel { List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 1000); //EndBiomeSource biomeSource = new EndBiomeSource(MCVersion.v1_16_5, 1000); - int sizeOfTheWorld = 16; + int sizeOfTheWorld = 64; LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, sizeOfTheWorld); //SIMULATING A PLAYER MOVING, - int[] playerXs = {0,100,200,300,400,500}; - int[] playerZs = {0,100,200,300,400,500}; - for(int pos=0; pos<6; pos++) { - int playerX= playerXs[pos]; - int playerZ= playerZs[pos]; + int[] playerXs = {0, 100, 200, 300, 400, 500}; + int[] playerZs = {0, 100, 200, 300, 400, 500}; + for (int pos = 0; pos < 1; pos++) { + int playerX = playerXs[pos]; + int playerZ = playerZs[pos]; //int sizeOfTheWorld=512; //TRY THIS TO SEE A 250'000 BLOCK RENDER DISTANCE dim.move(Math.floorDiv(playerX, 512), Math.floorDiv(playerZ, 512)); @@ -106,46 +106,44 @@ public class QuadTreeImage extends JPanel { int[] distances = {100000, 8000, 4000, 2000, 1000, 500, 250, 100, 50, 25}; for (int i = 0; i <= (9 - 2); i++) { - for (int j = 0; j < 1; j++) { - List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), DistanceGenerationMode.SERVER, distances[i], 0); - //System.out.println(levelToGenerate); - for (LodQuadTree level : levelToGenerate) { - Color color; - int startX = level.getLodNodeData().startX; - int startZ = level.getLodNodeData().startZ; - int endX = level.getLodNodeData().endX; - int endZ = level.getLodNodeData().endZ; - int centerX = level.getLodNodeData().centerX; - int centerZ = level.getLodNodeData().centerZ; - int width = level.getLodNodeData().width; - byte otherLevel = LodQuadTreeNode.BLOCK_LEVEL; - int otherWidth = LodQuadTreeNode.BLOCK_WIDTH; + List levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), DistanceGenerationMode.SERVER, distances[i], 0); + //System.out.println(levelToGenerate); + for (LodQuadTree level : levelToGenerate) { + Color color; + int startX = level.getLodNodeData().startX; + int startZ = level.getLodNodeData().startZ; + int endX = level.getLodNodeData().endX; + int endZ = level.getLodNodeData().endZ; + int centerX = level.getLodNodeData().centerX; + int centerZ = level.getLodNodeData().centerZ; + int width = level.getLodNodeData().width; + byte otherLevel = LodQuadTreeNode.BLOCK_LEVEL; + int otherWidth = LodQuadTreeNode.BLOCK_WIDTH; - List posXs = new ArrayList<>(); - List posZs = new ArrayList<>(); - if (level.getLodNodeData().level == 0) { - posXs.add(Math.floorDiv(startX, otherWidth)); - posZs.add(Math.floorDiv(startZ, otherWidth)); - } else { - posXs.add(Math.floorDiv(startX, otherWidth)); - posXs.add(Math.floorDiv(centerX + 1, otherWidth)); - posZs.add(Math.floorDiv(startZ, otherWidth)); - posZs.add(Math.floorDiv(centerZ + 1, otherWidth)); - } + List posXs = new ArrayList<>(); + List posZs = new ArrayList<>(); + if (level.getLodNodeData().level == 0) { + posXs.add(Math.floorDiv(startX, otherWidth)); + posZs.add(Math.floorDiv(startZ, otherWidth)); + } else { + posXs.add(Math.floorDiv(startX, otherWidth)); + posXs.add(Math.floorDiv(centerX + 1, otherWidth)); + posZs.add(Math.floorDiv(startZ, otherWidth)); + posZs.add(Math.floorDiv(centerZ + 1, otherWidth)); + } - //System.out.println(posXs); - //System.out.println(posZs); + //System.out.println(posXs); + //System.out.println(posZs); - for (Integer posXI : posXs) { - for (Integer posZI : posZs) { - int posX = posXI.intValue(); - int posZ = posZI.intValue(); - //System.out.println(posX + " " + posZ); - color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posX, 0, posZ)); - //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); - LodQuadTreeNode node = new LodQuadTreeNode(otherLevel, posX, posZ, new LodDataPoint(0, 0, color), DistanceGenerationMode.SERVER); - if (dim.addNode(node)) { - } + for (Integer posXI : posXs) { + for (Integer posZI : posZs) { + int posX = posXI.intValue(); + int posZ = posZI.intValue(); + //System.out.println(posX + " " + posZ); + color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posX, 0, posZ)); + //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); + LodQuadTreeNode node = new LodQuadTreeNode(otherLevel, posX, posZ, new LodDataPoint(0, 0, color), DistanceGenerationMode.SERVER); + if (dim.addNode(node)) { } } } @@ -158,27 +156,28 @@ public class QuadTreeImage extends JPanel { //complexityMask.add(DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT); //complexityMask.add(DistanceGenerationMode.BIOME_ONLY); - Set complexityMask = LodQuadTreeDimension.FULL_COMPLEXITY_MASK; + + } + Set complexityMask = LodQuadTreeDimension.FULL_COMPLEXITY_MASK; List lodList = new ArrayList<>(); //The min and max distances should increase quadratically - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 3, complexityMask, 250,0)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 4, complexityMask,500,250)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 5, complexityMask,1000,500)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 6, complexityMask,2000,1000)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 7, complexityMask,4000,2000)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 8, complexityMask,8000,4000)); - lodList.addAll(dim.getNodeToRender(playerX,playerZ,(byte) 9, complexityMask,100000,8000)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 3, complexityMask, 250, 0)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 4, complexityMask, 500, 250)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 5, complexityMask, 1000, 500)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 6, complexityMask, 2000, 1000)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 7, complexityMask, 4000, 2000)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 8, complexityMask, 8000, 4000)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 9, complexityMask, 10000000, 8000)); System.out.println(lodList.size()); - // List lodList = dim.getNodes(complexityMask, false, false); //USE THIS TO SEE AL THE LODS - listOfList.add(lodList); - } + // List lodList = dim.getNodes(complexityMask, false, false); //USE THIS TO SEE AL THE LODS + listOfList.add(lodList); } System.out.println("GETTING LOD FROM COORDINATE AFTER GENERETION"); - System.out.println(dim.getLodFromCoordinates(0,100, (byte) 1)); + System.out.println(dim.getLodFromCoordinates(0, 100, (byte) 1)); //FROM THIS POINT ON THE CODE JUST CREATE THE IMAGE int timerDelay = 200; @@ -189,7 +188,7 @@ public class QuadTreeImage extends JPanel { int zOffset = listOfList.stream().mapToInt(x -> x.stream().mapToInt(y -> y.startZ).min().getAsInt()).min().getAsInt(); int maxX = listOfList.stream().mapToInt(x -> x.stream().mapToInt(y -> y.startX).max().getAsInt()).min().getAsInt(); int maxZ = listOfList.stream().mapToInt(x -> x.stream().mapToInt(y -> y.startZ).max().getAsInt()).min().getAsInt(); - int maxSize = Math.max(maxX-xOffset,maxZ - zOffset)/512; + int maxSize = Math.max(maxX - xOffset, maxZ - zOffset) / 512; System.out.println(xOffset); System.out.println(zOffset); new Timer(timerDelay, new ActionListener() { @@ -200,13 +199,13 @@ public class QuadTreeImage extends JPanel { if (drawCount >= listOfList.size()) { drawCount = 0; } else { - if(drawCount==0) quadTreeImage.clearAll(); + if (drawCount == 0) quadTreeImage.clearAll(); final List myDrawables = new ArrayList<>(); - double amp = ((double) 3)/((double) sizeOfTheWorld); + double amp = ((double) 3) / ((double) maxSize); Collection lodList = listOfList.get(drawCount); for (LodQuadTreeNode data : lodList) { myDrawables.add(new MyDrawable(new Rectangle2D.Double( - ((data.startX - xOffset ) * amp), + ((data.startX - xOffset) * amp), ((data.startZ - zOffset) * amp), data.width * amp, data.width * amp), @@ -224,17 +223,15 @@ public class QuadTreeImage extends JPanel { for (int k = 0; k < myDrawables.size(); k++) { quadTreeImage.addMyDrawable(myDrawables.get(k)); } - /* BufferedImage img = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = img.createGraphics(); frame.printAll(g2d); g2d.dispose(); try { - ImageIO.write(img, "png", new File("ImgEnd" + drawCount+".png")); + ImageIO.write(img, "png", new File("ImgEnd" + drawCount + ".png")); } catch (IOException ioException) { ioException.printStackTrace(); } - */ drawCount++; } } From 359791ea584b8b7032f468558ce1e156d5e52c5f Mon Sep 17 00:00:00 2001 From: Leonardo Date: Mon, 19 Jul 2021 11:26:05 +0200 Subject: [PATCH 39/46] Fixed getLevelToGenerate. Now it works correctly --- .../com/seibel/lod/objects/LodQuadTree.java | 31 +++--- .../com/seibel/lod/objects/QuadTreeImage.java | 95 +++++++++---------- 2 files changed, 58 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/LodQuadTree.java index 1ef9ed594..0cf08c5fb 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -309,7 +309,6 @@ public class LodQuadTree { */ public List getNodeToRender(int x, int z, byte targetLevel, Set complexityMask, int maxDistance, int minDistance) { List distances = new ArrayList(); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getCenterX(), 2) + Math.pow(z - lodNode.getCenterZ(), 2))); 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))); @@ -319,7 +318,7 @@ public class LodQuadTree { int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List nodeList = new ArrayList<>(); - if (!(targetLevel > lodNode.level || ((min > maxDistance || max < minDistance) /*&& !isCoordinateInLevel(x,z)*/))) { + if (targetLevel <= lodNode.level && ((min <= maxDistance && max >= minDistance) || isCoordinateInLevel(x, z))) { if (targetLevel == lodNode.level || !isNodeFull()) { if (!lodNode.isVoidNode() && complexityMask.contains(lodNode.getComplexity())) { nodeList.add(lodNode); @@ -353,7 +352,6 @@ public class LodQuadTree { public List> getLevelToGenerate(int x, int z, byte targetLevel, DistanceGenerationMode complexityToGenerate, int maxDistance, int minDistance) { List distances = new ArrayList(); - distances.add((int) Math.sqrt(Math.pow(x - lodNode.getCenterX(), 2) + Math.pow(z - lodNode.getCenterZ(), 2))); 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))); @@ -362,29 +360,22 @@ public class LodQuadTree { int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List> nodeList = new ArrayList<>(); - if ( targetLevel > lodNode.level || ((min > maxDistance || max < minDistance)/* && !isCoordinateInLevel(x,z)*/)) { - return nodeList; - } - if(isNodeFull()) { - //THIS LEVEL HAS CHILD SO IT'S GENERATED. - if (targetLevel != lodNode.level) { + if (targetLevel <= lodNode.level && ((min <= maxDistance && max >= minDistance) || isCoordinateInLevel(x, z))) { + if(!isThereAnyChild() || targetLevel == lodNode.level){ + if (this.lodNode.getComplexity().compareTo(complexityToGenerate) <= 0) { + nodeList.add(new AbstractMap.SimpleEntry<>(this, min)); + } + }else { for (int NS = 0; NS <= 1; NS++) { for (int WE = 0; WE <= 1; WE++) { - if (getChild(NS,WE) == null) { - setChild(NS,WE); + if (getChild(NS, WE) == null) { + setChild(NS, WE); } - LodQuadTree child = getChild(NS,WE); + LodQuadTree child = getChild(NS, WE); nodeList.addAll(child.getLevelToGenerate(x, z, targetLevel, complexityToGenerate, maxDistance, minDistance)); } } - }else{ - if(this.lodNode.getComplexity().compareTo(complexityToGenerate) > 0) { - //we want to regenerate a level only if we ask for higher complexity - nodeList.add(new AbstractMap.SimpleEntry<>(this, min)); - } } - } else { - nodeList.add(new AbstractMap.SimpleEntry<>(this, min)); } return nodeList; } @@ -429,7 +420,7 @@ public class LodQuadTree { public boolean isCoordinateInLevel(int x, int z){ - return !(lodNode.getStartX() > x || lodNode.getStartZ() > z || lodNode.getEndX() < x || lodNode.getEndZ() < z); + return (lodNode.getStartX() * lodNode.width <= x && lodNode.getStartZ() * lodNode.width <= z && lodNode.getEndX() * lodNode.width >= x && lodNode.getEndZ() * lodNode.width >= z); } public String toString(){ diff --git a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java index ac6288fb8..a4e8b082d 100644 --- a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -29,7 +29,7 @@ import javax.swing.Timer; @SuppressWarnings("serial") public class QuadTreeImage extends JPanel { - private static final int PREF_W = 1536; + private static final int PREF_W = 1024; private static final int PREF_H = PREF_W; private List drawables = new ArrayList<>(); @@ -81,7 +81,7 @@ public class QuadTreeImage extends JPanel { List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 1000); //EndBiomeSource biomeSource = new EndBiomeSource(MCVersion.v1_16_5, 1000); - int sizeOfTheWorld = 64; + int sizeOfTheWorld = 8; LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, sizeOfTheWorld); @@ -122,26 +122,16 @@ public class QuadTreeImage extends JPanel { List posXs = new ArrayList<>(); List posZs = new ArrayList<>(); - if (level.getLodNodeData().level == 0) { - posXs.add(Math.floorDiv(startX, otherWidth)); - posZs.add(Math.floorDiv(startZ, otherWidth)); - } else { - posXs.add(Math.floorDiv(startX, otherWidth)); - posXs.add(Math.floorDiv(centerX + 1, otherWidth)); - posZs.add(Math.floorDiv(startZ, otherWidth)); - posZs.add(Math.floorDiv(centerZ + 1, otherWidth)); - } - - //System.out.println(posXs); - //System.out.println(posZs); + posXs.add(Math.floorDiv(startX, otherWidth)); + posXs.add(Math.floorDiv(centerX, otherWidth)); + posZs.add(Math.floorDiv(startZ, otherWidth)); + posZs.add(Math.floorDiv(centerZ, otherWidth)); for (Integer posXI : posXs) { for (Integer posZI : posZs) { int posX = posXI.intValue(); int posZ = posZI.intValue(); - //System.out.println(posX + " " + posZ); color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posX, 0, posZ)); - //color = BiomeColorsUtils.getColorFromIdCB(biomeSource.getBiome(posZ, 0, posX).getId()); LodQuadTreeNode node = new LodQuadTreeNode(otherLevel, posX, posZ, new LodDataPoint(0, 0, color), DistanceGenerationMode.SERVER); if (dim.addNode(node)) { } @@ -156,31 +146,40 @@ public class QuadTreeImage extends JPanel { //complexityMask.add(DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT); //complexityMask.add(DistanceGenerationMode.BIOME_ONLY); + Set complexityMask = LodQuadTreeDimension.FULL_COMPLEXITY_MASK; + + + List lodList = new ArrayList<>(); + //The min and max distances should increase quadratically +/* + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 0, complexityMask, 10000000, 0)); +*/ +/* + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 3, complexityMask, 250, 0)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 4, complexityMask, 500, 250)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 5, complexityMask, 1000, 500)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 6, complexityMask, 2000, 1000)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 7, complexityMask, 4000, 2000)); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 8, complexityMask, 8000, 4000)); +*/ + + int[] distances2 = {100000, 8000, 4000, 2000, 1000, 500, 250, 0}; + for (int h = 0; h <= (9 - 3); h++) { + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) (9-h), complexityMask, distances2[h], distances2[h+1])); + } + + System.out.println(lodList.size()); + + //List lodList = dim.getNodes(complexityMask, false, false); //USE THIS TO SEE AL THE LODS + listOfList.add(lodList); } - Set complexityMask = LodQuadTreeDimension.FULL_COMPLEXITY_MASK; - - List lodList = new ArrayList<>(); - //The min and max distances should increase quadratically - - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 3, complexityMask, 250, 0)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 4, complexityMask, 500, 250)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 5, complexityMask, 1000, 500)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 6, complexityMask, 2000, 1000)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 7, complexityMask, 4000, 2000)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 8, complexityMask, 8000, 4000)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 9, complexityMask, 10000000, 8000)); - System.out.println(lodList.size()); - - - // List lodList = dim.getNodes(complexityMask, false, false); //USE THIS TO SEE AL THE LODS - listOfList.add(lodList); } System.out.println("GETTING LOD FROM COORDINATE AFTER GENERETION"); System.out.println(dim.getLodFromCoordinates(0, 100, (byte) 1)); //FROM THIS POINT ON THE CODE JUST CREATE THE IMAGE - int timerDelay = 200; + int timerDelay = 1000; System.out.println("STARTING"); System.out.println(dim.getWidth()); System.out.println(dim.getCenterX()); @@ -201,7 +200,7 @@ public class QuadTreeImage extends JPanel { } else { if (drawCount == 0) quadTreeImage.clearAll(); final List myDrawables = new ArrayList<>(); - double amp = ((double) 3) / ((double) maxSize); + double amp = ((double) 2) / ((double) sizeOfTheWorld); Collection lodList = listOfList.get(drawCount); for (LodQuadTreeNode data : lodList) { myDrawables.add(new MyDrawable(new Rectangle2D.Double( @@ -223,6 +222,7 @@ public class QuadTreeImage extends JPanel { for (int k = 0; k < myDrawables.size(); k++) { quadTreeImage.addMyDrawable(myDrawables.get(k)); } + /* BufferedImage img = new BufferedImage(frame.getWidth(), frame.getHeight(), BufferedImage.TYPE_INT_RGB); Graphics2D g2d = img.createGraphics(); frame.printAll(g2d); @@ -232,6 +232,7 @@ public class QuadTreeImage extends JPanel { } catch (IOException ioException) { ioException.printStackTrace(); } + */ drawCount++; } } @@ -239,26 +240,24 @@ public class QuadTreeImage extends JPanel { } public static void main(String[] args) { - - /* - LodQuadTreeDimension dim2 = new LodQuadTreeDimension(null, null, 8); - List levelToGenerate = dim2.getNodeToGenerate(0, 0, (byte) 0, (int) 10000, 0); +/* + LodQuadTreeDimension dim2 = new LodQuadTreeDimension(null, null, 1); + List levelToGenerate = dim2.getNodeToGenerate(0, 0, (byte) 0,DistanceGenerationMode.SERVER, (int) 10000, 0); System.out.println(levelToGenerate); - dim2.addNode(new LodNodeData((byte) 0,0,0,-1,-1, new Color(100,100,100),true)); - dim2.addNode(new LodNodeData((byte) 0,256,0,-1,-1, new Color(100,100,100),true)); - dim2.addNode(new LodNodeData((byte) 0,0,256,-1,-1, new Color(100,100,100),true)); - dim2.addNode(new LodNodeData((byte) 0,256,256,-1,-1, new Color(100,100,100),true)); - levelToGenerate = dim2.getNodeToGenerate(0, 0, (byte) 0, (int) 10000, 0); + dim2.addNode(new LodQuadTreeNode((byte) 0,0,0,new LodDataPoint(-1,-1, new Color(100,100,100)),DistanceGenerationMode.SERVER)); + dim2.addNode(new LodQuadTreeNode((byte) 0,256,0,new LodDataPoint(-1,-1, new Color(100,100,100)),DistanceGenerationMode.SERVER)); + dim2.addNode(new LodQuadTreeNode((byte) 0,0,256,new LodDataPoint(-1,-1, new Color(100,100,100)),DistanceGenerationMode.SERVER)); + dim2.addNode(new LodQuadTreeNode((byte) 0,256,256,new LodDataPoint(-1,-1, new Color(100,100,100)),DistanceGenerationMode.SERVER)); + levelToGenerate = dim2.getNodeToGenerate(0, 0, (byte) 7,DistanceGenerationMode.SERVER, (int) 10000, 0); System.out.println(levelToGenerate); - - */ - +*/ SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); + } } @@ -290,8 +289,8 @@ class MyDrawable { Stroke oldStroke = g2.getStroke(); g2.setColor(color); - g2.fill(shape); + g2.fill(shape); //g2.setStroke(stroke); g2.draw(shape); From 01183be3832b83ecca2f80f0da2bd56895bbe698 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Mon, 19 Jul 2021 11:32:20 +0200 Subject: [PATCH 40/46] getLevelToGenerate has been renamed getNodesToGenerate. Now it return node and not the complete level --- .../com/seibel/lod/objects/LodQuadTree.java | 8 +++---- .../lod/objects/LodQuadTreeDimension.java | 6 ++--- .../com/seibel/lod/objects/QuadTreeImage.java | 22 +++++++++---------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/LodQuadTree.java index 0cf08c5fb..555247ca2 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -349,7 +349,7 @@ public class LodQuadTree { * @param minDistance * @return */ - public List> getLevelToGenerate(int x, int z, byte targetLevel, DistanceGenerationMode complexityToGenerate, int maxDistance, int minDistance) { + public List> getNodesToGenerate(int x, int z, byte targetLevel, DistanceGenerationMode complexityToGenerate, int maxDistance, int minDistance) { List distances = new ArrayList(); distances.add((int) Math.sqrt(Math.pow(x - lodNode.getStartX(), 2) + Math.pow(z - lodNode.getStartZ(), 2))); @@ -359,11 +359,11 @@ public class LodQuadTree { int min = distances.stream().mapToInt(Integer::intValue).min().getAsInt(); int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); - List> nodeList = new ArrayList<>(); + List> nodeList = new ArrayList<>(); if (targetLevel <= lodNode.level && ((min <= maxDistance && max >= minDistance) || isCoordinateInLevel(x, z))) { if(!isThereAnyChild() || targetLevel == lodNode.level){ if (this.lodNode.getComplexity().compareTo(complexityToGenerate) <= 0) { - nodeList.add(new AbstractMap.SimpleEntry<>(this, min)); + nodeList.add(new AbstractMap.SimpleEntry<>(this.getLodNodeData(), min)); } }else { for (int NS = 0; NS <= 1; NS++) { @@ -372,7 +372,7 @@ public class LodQuadTree { setChild(NS, WE); } LodQuadTree child = getChild(NS, WE); - nodeList.addAll(child.getLevelToGenerate(x, z, targetLevel, complexityToGenerate, maxDistance, minDistance)); + nodeList.addAll(child.getNodesToGenerate(x, z, targetLevel, complexityToGenerate, maxDistance, minDistance)); } } } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java index de93dcb01..fd355223b 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java @@ -363,13 +363,13 @@ public class LodQuadTreeDimension { * method to get all the quadtree level that have to be generated based on the position of the player * @return list of quadTrees */ - public List getNodeToGenerate(int x, int z, byte level, DistanceGenerationMode complexity, int maxDistance, int minDistance){ + public List getNodesToGenerate(int x, int z, byte level, DistanceGenerationMode complexity, int maxDistance, int minDistance){ int n = regions.length; int xIndex; int zIndex; LodQuadTree region; - List> listOfQuadTree = new ArrayList<>(); + List> listOfQuadTree = new ArrayList<>(); for(int xRegion=0; xRegion levelToGenerate = dim.getNodeToGenerate(playerX, playerZ, (byte) (9 - i), DistanceGenerationMode.SERVER, distances[i], 0); + List levelToGenerate = dim.getNodesToGenerate(playerX, playerZ, (byte) (9 - i), DistanceGenerationMode.SERVER, distances[i], 0); //System.out.println(levelToGenerate); - for (LodQuadTree level : levelToGenerate) { + for (LodQuadTreeNode node : levelToGenerate) { Color color; - int startX = level.getLodNodeData().startX; - int startZ = level.getLodNodeData().startZ; - int endX = level.getLodNodeData().endX; - int endZ = level.getLodNodeData().endZ; - int centerX = level.getLodNodeData().centerX; - int centerZ = level.getLodNodeData().centerZ; - int width = level.getLodNodeData().width; + int startX = node.startX; + int startZ = node.startZ; + int endX = node.endX; + int endZ = node.endZ; + int centerX = node.centerX; + int centerZ = node.centerZ; + int width = node.width; byte otherLevel = LodQuadTreeNode.BLOCK_LEVEL; int otherWidth = LodQuadTreeNode.BLOCK_WIDTH; @@ -132,8 +132,8 @@ public class QuadTreeImage extends JPanel { int posX = posXI.intValue(); int posZ = posZI.intValue(); color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posX, 0, posZ)); - LodQuadTreeNode node = new LodQuadTreeNode(otherLevel, posX, posZ, new LodDataPoint(0, 0, color), DistanceGenerationMode.SERVER); - if (dim.addNode(node)) { + LodQuadTreeNode newNode = new LodQuadTreeNode(otherLevel, posX, posZ, new LodDataPoint(0, 0, color), DistanceGenerationMode.SERVER); + if (dim.addNode(newNode)) { } } } From 65ffc93e0f28792ca345ca6ca144aaa0ac03803d Mon Sep 17 00:00:00 2001 From: Leonardo Date: Mon, 19 Jul 2021 11:35:38 +0200 Subject: [PATCH 41/46] Updated the guide --- Readme.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Readme.txt b/Readme.txt index 3ba394a1b..def266624 100644 --- a/Readme.txt +++ b/Readme.txt @@ -100,7 +100,7 @@ should convert the template to work with this correctly. SECOND: you just use the getLodNodeToGenerate at a certain level to get the node that you want to render (if this node does not exist the it will return NULL) - - - - +LATEST CHANGES: +Now the getNodesToGenerate correctly works with any technique of node adding. I was adding 4 node, +1 for each child, but now you could even add just one node and it will work in the same way +(I still think that adding 4 child is the best technique) From c0240c71bfb1b681216dcf975866e4afda3c5801 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Mon, 19 Jul 2021 11:46:22 +0200 Subject: [PATCH 42/46] Updated the guide --- Readme.txt | 1 + .../com/seibel/lod/objects/QuadTreeImage.java | 30 ++++++------------- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/Readme.txt b/Readme.txt index def266624..5e3f4c34f 100644 --- a/Readme.txt +++ b/Readme.txt @@ -104,3 +104,4 @@ LATEST CHANGES: Now the getNodesToGenerate correctly works with any technique of node adding. I was adding 4 node, 1 for each child, but now you could even add just one node and it will work in the same way (I still think that adding 4 child is the best technique) +Check the different technique i've tested https://imgur.com/a/UoZpVaz diff --git a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java index f1b59af05..122035198 100644 --- a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -81,7 +81,7 @@ public class QuadTreeImage extends JPanel { List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 1000); //EndBiomeSource biomeSource = new EndBiomeSource(MCVersion.v1_16_5, 1000); - int sizeOfTheWorld = 8; + int sizeOfTheWorld = 16; LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, sizeOfTheWorld); @@ -105,7 +105,7 @@ public class QuadTreeImage extends JPanel { */ int[] distances = {100000, 8000, 4000, 2000, 1000, 500, 250, 100, 50, 25}; - for (int i = 0; i <= (9 - 2); i++) { + for (int i = 0; i <= (9); i++) { List levelToGenerate = dim.getNodesToGenerate(playerX, playerZ, (byte) (9 - i), DistanceGenerationMode.SERVER, distances[i], 0); //System.out.println(levelToGenerate); for (LodQuadTreeNode node : levelToGenerate) { @@ -122,9 +122,9 @@ public class QuadTreeImage extends JPanel { List posXs = new ArrayList<>(); List posZs = new ArrayList<>(); - posXs.add(Math.floorDiv(startX, otherWidth)); + posXs.add(Math.floorDiv(centerX-1, otherWidth)); posXs.add(Math.floorDiv(centerX, otherWidth)); - posZs.add(Math.floorDiv(startZ, otherWidth)); + posZs.add(Math.floorDiv(centerZ-1, otherWidth)); posZs.add(Math.floorDiv(centerZ, otherWidth)); for (Integer posXI : posXs) { @@ -148,29 +148,17 @@ public class QuadTreeImage extends JPanel { Set complexityMask = LodQuadTreeDimension.FULL_COMPLEXITY_MASK; - +/* List lodList = new ArrayList<>(); //The min and max distances should increase quadratically -/* - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 0, complexityMask, 10000000, 0)); -*/ -/* - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 3, complexityMask, 250, 0)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 4, complexityMask, 500, 250)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 5, complexityMask, 1000, 500)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 6, complexityMask, 2000, 1000)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 7, complexityMask, 4000, 2000)); - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) 8, complexityMask, 8000, 4000)); -*/ - int[] distances2 = {100000, 8000, 4000, 2000, 1000, 500, 250, 0}; for (int h = 0; h <= (9 - 3); h++) { lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) (9-h), complexityMask, distances2[h], distances2[h+1])); } - System.out.println(lodList.size()); +*/ - //List lodList = dim.getNodes(complexityMask, false, false); //USE THIS TO SEE AL THE LODS + List lodList = dim.getNodes(complexityMask, false, false); //USE THIS TO SEE AL THE LODS listOfList.add(lodList); } @@ -290,8 +278,8 @@ class MyDrawable { g2.setColor(color); - g2.fill(shape); - //g2.setStroke(stroke); + //g2.fill(shape); + g2.setStroke(stroke); g2.draw(shape); g2.setColor(oldColor); From bdd1e2410ae5bfb90a4bbbe7c01c6002d166c3ae Mon Sep 17 00:00:00 2001 From: Leonardo Date: Mon, 19 Jul 2021 11:47:26 +0200 Subject: [PATCH 43/46] Updated the guide --- .../java/com/seibel/lod/objects/QuadTreeImage.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java index 122035198..928cbd329 100644 --- a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -122,9 +122,9 @@ public class QuadTreeImage extends JPanel { List posXs = new ArrayList<>(); List posZs = new ArrayList<>(); - posXs.add(Math.floorDiv(centerX-1, otherWidth)); + posXs.add(Math.floorDiv(startX, otherWidth)); posXs.add(Math.floorDiv(centerX, otherWidth)); - posZs.add(Math.floorDiv(centerZ-1, otherWidth)); + posZs.add(Math.floorDiv(startZ, otherWidth)); posZs.add(Math.floorDiv(centerZ, otherWidth)); for (Integer posXI : posXs) { @@ -148,18 +148,18 @@ public class QuadTreeImage extends JPanel { Set complexityMask = LodQuadTreeDimension.FULL_COMPLEXITY_MASK; -/* List lodList = new ArrayList<>(); //The min and max distances should increase quadratically int[] distances2 = {100000, 8000, 4000, 2000, 1000, 500, 250, 0}; for (int h = 0; h <= (9 - 3); h++) { lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) (9-h), complexityMask, distances2[h], distances2[h+1])); } - System.out.println(lodList.size()); -*/ + System.out.println("Number of node to render "lodList.size()); +/* List lodList = dim.getNodes(complexityMask, false, false); //USE THIS TO SEE AL THE LODS listOfList.add(lodList); + */ } } @@ -278,8 +278,8 @@ class MyDrawable { g2.setColor(color); - //g2.fill(shape); - g2.setStroke(stroke); + g2.fill(shape); + //g2.setStroke(stroke); g2.draw(shape); g2.setColor(oldColor); From 98586d6af978d80d8d03f8f64eb774e36c490a66 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Mon, 19 Jul 2021 16:23:14 +0200 Subject: [PATCH 44/46] now different generation setting can be used in the same Dimension without conflict --- .../lod/enums/DistanceGenerationMode.java | 25 +++++-- .../com/seibel/lod/objects/LodQuadTree.java | 14 ++-- .../seibel/lod/objects/LodQuadTreeNode.java | 2 +- .../com/seibel/lod/objects/QuadTreeImage.java | 67 +++++++++++-------- 4 files changed, 66 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java b/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java index 6b7fa36b5..c756e4516 100644 --- a/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java +++ b/src/main/java/com/seibel/lod/enums/DistanceGenerationMode.java @@ -15,14 +15,14 @@ package com.seibel.lod.enums; public enum DistanceGenerationMode { /** No generation has be used*/ - NONE, + NONE(0), /** Only generate the biomes and use biome * grass/foliage color, water color, or ice color * to generate the color. * Doesn't generate height, everything is shown at sea level. * Multithreaded - Fastest (2-5 ms) */ - BIOME_ONLY, + BIOME_ONLY(1), /** * Same as BIOME_ONLY, except instead @@ -30,24 +30,37 @@ public enum DistanceGenerationMode * different biome types (mountain, ocean, forest, etc.) * use predetermined heights to simulate having height data. */ - BIOME_ONLY_SIMULATE_HEIGHT, + BIOME_ONLY_SIMULATE_HEIGHT(2), /** Generate the world surface, * this does NOT include caves, trees, * or structures. * Multithreaded - Faster (10-20 ms) */ - SURFACE, + SURFACE(3), /** Generate everything except structures. * NOTE: This may cause world generation bugs or instability, * since some features cause concurrentModification exceptions. * Multithreaded - Fast (15-20 ms) */ - FEATURES, + FEATURES(4), /** Ask the server to generate/load each chunk. * This is the most compatible, but causes server/simulation lag. * This will also show player made structures if you * are adding the mod to a pre-existing world. * Singlethreaded - Slow (15-50 ms, with spikes up to 200 ms) */ - SERVER; + SERVER(5); + + public final 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 555247ca2..a0ffce20c 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -3,10 +3,7 @@ package com.seibel.lod.objects; import com.seibel.lod.enums.DistanceGenerationMode; import org.lwjgl.system.CallbackI; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; +import java.util.*; /** * This object contains all data useful to render LodBlock in a region (32x32 chunk o 512x512 block) @@ -362,8 +359,10 @@ public class LodQuadTree { List> nodeList = new ArrayList<>(); if (targetLevel <= lodNode.level && ((min <= maxDistance && max >= minDistance) || isCoordinateInLevel(x, z))) { if(!isThereAnyChild() || targetLevel == lodNode.level){ - if (this.lodNode.getComplexity().compareTo(complexityToGenerate) <= 0) { - nodeList.add(new AbstractMap.SimpleEntry<>(this.getLodNodeData(), min)); + if (this.lodNode.getComplexity().compareTo(complexityToGenerate) <= 0 ) { + nodeList.add(new AbstractMap.SimpleEntry(this.lodNode, min)); + }else{ + System.out.println(toString()); } }else { for (int NS = 0; NS <= 1; NS++) { @@ -371,8 +370,7 @@ public class LodQuadTree { if (getChild(NS, WE) == null) { setChild(NS, WE); } - LodQuadTree child = getChild(NS, WE); - nodeList.addAll(child.getNodesToGenerate(x, z, targetLevel, complexityToGenerate, maxDistance, minDistance)); + nodeList.addAll(getChild(NS, WE).getNodesToGenerate(x, z, targetLevel, complexityToGenerate, maxDistance, minDistance)); } } } diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java index 153b43177..d413b616f 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java @@ -223,7 +223,7 @@ public class LodQuadTreeNode { //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){ + if (minComplexity.compareTo(node.complexity) > 0){ minComplexity = node.complexity; } } diff --git a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java index 928cbd329..470627c46 100644 --- a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -81,7 +81,7 @@ public class QuadTreeImage extends JPanel { List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 1000); //EndBiomeSource biomeSource = new EndBiomeSource(MCVersion.v1_16_5, 1000); - int sizeOfTheWorld = 16; + int sizeOfTheWorld = 2; LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, sizeOfTheWorld); @@ -89,8 +89,8 @@ public class QuadTreeImage extends JPanel { int[] playerXs = {0, 100, 200, 300, 400, 500}; int[] playerZs = {0, 100, 200, 300, 400, 500}; for (int pos = 0; pos < 1; pos++) { - int playerX = playerXs[pos]; - int playerZ = playerZs[pos]; + int playerX = 0 + playerXs[pos]; //2097152 + int playerZ = 0 + playerZs[pos]; //int sizeOfTheWorld=512; //TRY THIS TO SEE A 250'000 BLOCK RENDER DISTANCE dim.move(Math.floorDiv(playerX, 512), Math.floorDiv(playerZ, 512)); @@ -104,10 +104,11 @@ public class QuadTreeImage extends JPanel { System.out.println(dim.getLodFromCoordinates(-6, -6)); */ + DistanceGenerationMode[] complexities = {DistanceGenerationMode.BIOME_ONLY, DistanceGenerationMode.BIOME_ONLY, DistanceGenerationMode.BIOME_ONLY, DistanceGenerationMode.SURFACE, DistanceGenerationMode.SURFACE, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES}; int[] distances = {100000, 8000, 4000, 2000, 1000, 500, 250, 100, 50, 25}; for (int i = 0; i <= (9); i++) { - List levelToGenerate = dim.getNodesToGenerate(playerX, playerZ, (byte) (9 - i), DistanceGenerationMode.SERVER, distances[i], 0); - //System.out.println(levelToGenerate); + List levelToGenerate = dim.getNodesToGenerate(playerX, playerZ, (byte) (9 - i), complexities[i], distances[i], 0); + System.out.println(levelToGenerate); for (LodQuadTreeNode node : levelToGenerate) { Color color; int startX = node.startX; @@ -132,7 +133,7 @@ public class QuadTreeImage extends JPanel { int posX = posXI.intValue(); int posZ = posZI.intValue(); color = BiomeColorsUtils.getColorFromBiomeManual(biomeSource.getBiome(posX, 0, posZ)); - LodQuadTreeNode newNode = new LodQuadTreeNode(otherLevel, posX, posZ, new LodDataPoint(0, 0, color), DistanceGenerationMode.SERVER); + LodQuadTreeNode newNode = new LodQuadTreeNode(otherLevel, posX, posZ, new LodDataPoint(0, 0, color), complexities[i]); if (dim.addNode(newNode)) { } } @@ -148,20 +149,20 @@ public class QuadTreeImage extends JPanel { Set complexityMask = LodQuadTreeDimension.FULL_COMPLEXITY_MASK; +/* List lodList = new ArrayList<>(); //The min and max distances should increase quadratically int[] distances2 = {100000, 8000, 4000, 2000, 1000, 500, 250, 0}; for (int h = 0; h <= (9 - 3); h++) { lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) (9-h), complexityMask, distances2[h], distances2[h+1])); } - System.out.println("Number of node to render "lodList.size()); - -/* + System.out.println("Number of node to render " + lodList.size()); + listOfList.add(lodList); + */ List lodList = dim.getNodes(complexityMask, false, false); //USE THIS TO SEE AL THE LODS listOfList.add(lodList); - */ - } + } System.out.println("GETTING LOD FROM COORDINATE AFTER GENERETION"); System.out.println(dim.getLodFromCoordinates(0, 100, (byte) 1)); @@ -198,15 +199,14 @@ public class QuadTreeImage extends JPanel { data.width * amp), data.lodDataPoint.color, new BasicStroke(1))); } - /* - myDrawables.add(new MyDrawable(new Rectangle2D.Double( - (playerX - 10 - xOffset) * amp, - (playerZ - 10 - zOffset) * amp, - 20* amp, - 20* amp), - Color.yellow, new BasicStroke(1))); - - */ + for(int k=0; k<1; k++) { + myDrawables.add(new MyDrawable(new Rectangle2D.Double( + (playerXs[k] - 10 - xOffset) * amp, + (playerZs[k] - 10 - zOffset) * amp, + 20 * amp, + 20 * amp), + Color.yellow, new BasicStroke(1))); + } for (int k = 0; k < myDrawables.size(); k++) { quadTreeImage.addMyDrawable(myDrawables.get(k)); } @@ -228,17 +228,30 @@ public class QuadTreeImage extends JPanel { } public static void main(String[] args) { -/* + /* LodQuadTreeDimension dim2 = new LodQuadTreeDimension(null, null, 1); - List levelToGenerate = dim2.getNodeToGenerate(0, 0, (byte) 0,DistanceGenerationMode.SERVER, (int) 10000, 0); + dim2.move(10000000,10000000); + List levelToGenerate = dim2.getNodesToGenerate(10000000, 10000000, (byte) 7,DistanceGenerationMode.SERVER, (int) 10000, 0); System.out.println(levelToGenerate); dim2.addNode(new LodQuadTreeNode((byte) 0,0,0,new LodDataPoint(-1,-1, new Color(100,100,100)),DistanceGenerationMode.SERVER)); dim2.addNode(new LodQuadTreeNode((byte) 0,256,0,new LodDataPoint(-1,-1, new Color(100,100,100)),DistanceGenerationMode.SERVER)); dim2.addNode(new LodQuadTreeNode((byte) 0,0,256,new LodDataPoint(-1,-1, new Color(100,100,100)),DistanceGenerationMode.SERVER)); dim2.addNode(new LodQuadTreeNode((byte) 0,256,256,new LodDataPoint(-1,-1, new Color(100,100,100)),DistanceGenerationMode.SERVER)); - levelToGenerate = dim2.getNodeToGenerate(0, 0, (byte) 7,DistanceGenerationMode.SERVER, (int) 10000, 0); + levelToGenerate = dim2.getNodesToGenerate(10000000, 10000000, (byte) 7,DistanceGenerationMode.SERVER, (int) 10000, 0); System.out.println(levelToGenerate); -*/ + + */ + /* + System.out.println(DistanceGenerationMode.SERVER.compareTo(DistanceGenerationMode.SERVER)); + System.out.println(DistanceGenerationMode.NONE.compareTo(DistanceGenerationMode.SERVER)); + System.out.println(DistanceGenerationMode.SERVER.compareTo(DistanceGenerationMode.NONE)); + System.out.println(DistanceGenerationMode.BIOME_ONLY.compareTo(DistanceGenerationMode.SURFACE)); + System.out.println(DistanceGenerationMode.SURFACE.compareTo(DistanceGenerationMode.BIOME_ONLY)); + System.out.println(DistanceGenerationMode.BIOME_ONLY.compareTo(DistanceGenerationMode.BIOME_ONLY)); + System.out.println(DistanceGenerationMode.BIOME_ONLY.compareTo(DistanceGenerationMode.NONE)); + System.out.println(DistanceGenerationMode.NONE.compareTo(DistanceGenerationMode.BIOME_ONLY)); + + */ SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); @@ -246,6 +259,7 @@ public class QuadTreeImage extends JPanel { }); + } } @@ -277,9 +291,8 @@ class MyDrawable { Stroke oldStroke = g2.getStroke(); g2.setColor(color); - - g2.fill(shape); - //g2.setStroke(stroke); + //g2.fill(shape); + g2.setStroke(stroke); g2.draw(shape); g2.setColor(oldColor); From 0fc4c5532b1a99c797a2add3c4f8f79ae081f35b Mon Sep 17 00:00:00 2001 From: Leonardo Date: Mon, 19 Jul 2021 17:00:40 +0200 Subject: [PATCH 45/46] Minor fixes --- src/main/java/com/seibel/lod/objects/LodQuadTree.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/LodQuadTree.java index a0ffce20c..692d01755 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -361,8 +361,6 @@ public class LodQuadTree { if(!isThereAnyChild() || targetLevel == lodNode.level){ if (this.lodNode.getComplexity().compareTo(complexityToGenerate) <= 0 ) { nodeList.add(new AbstractMap.SimpleEntry(this.lodNode, min)); - }else{ - System.out.println(toString()); } }else { for (int NS = 0; NS <= 1; NS++) { From bc8188beb0914e9c9d2d15aea0703ca5e7068dc2 Mon Sep 17 00:00:00 2001 From: Leonardo Date: Wed, 21 Jul 2021 10:43:51 +0200 Subject: [PATCH 46/46] Added important TODOs --- .../com/seibel/lod/objects/LodQuadTree.java | 2 +- .../lod/objects/LodQuadTreeDimension.java | 7 +++ .../seibel/lod/objects/LodQuadTreeNode.java | 8 +++ .../com/seibel/lod/objects/QuadTreeImage.java | 63 ++++++++++++------- 4 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTree.java b/src/main/java/com/seibel/lod/objects/LodQuadTree.java index 692d01755..6d6e49ad6 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTree.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTree.java @@ -315,7 +315,7 @@ public class LodQuadTree { int max = distances.stream().mapToInt(Integer::intValue).max().getAsInt(); List nodeList = new ArrayList<>(); - if (targetLevel <= lodNode.level && ((min <= maxDistance && max >= minDistance) || isCoordinateInLevel(x, z))) { + if (targetLevel <= lodNode.level && ((min <= maxDistance && max >= minDistance) /*|| isCoordinateInLevel(x, z)*/)) { if (targetLevel == lodNode.level || !isNodeFull()) { if (!lodNode.isVoidNode() && complexityMask.contains(lodNode.getComplexity())) { nodeList.add(lodNode); diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java index fd355223b..c94057cc3 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeDimension.java @@ -16,6 +16,13 @@ import java.util.*; import java.util.stream.Collectors; public class LodQuadTreeDimension { + + /**TODO a dimension should support two different type of quadTree. + * The ones that are near from the player should always be saved and can be fully generated (even at block level) + * The ones that are far from the player should always be non-savable and at a high level + * If this is not done then you could see how heavy a fully generated 64 region dimension can get. + * IDEA : use a mask like the "isRegionDirty" to achieve this*/ + public final DimensionType dimension; private volatile int width; diff --git a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java index d413b616f..4ada99b1c 100644 --- a/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java +++ b/src/main/java/com/seibel/lod/objects/LodQuadTreeNode.java @@ -62,6 +62,14 @@ public class LodQuadTreeNode { 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 diff --git a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java index 470627c46..eb59ed880 100644 --- a/src/main/java/com/seibel/lod/objects/QuadTreeImage.java +++ b/src/main/java/com/seibel/lod/objects/QuadTreeImage.java @@ -81,16 +81,16 @@ public class QuadTreeImage extends JPanel { List> listOfList = new ArrayList<>(); OverworldBiomeSource biomeSource = new OverworldBiomeSource(MCVersion.v1_16_5, 1000); //EndBiomeSource biomeSource = new EndBiomeSource(MCVersion.v1_16_5, 1000); - int sizeOfTheWorld = 2; + int sizeOfTheWorld = 32; LodQuadTreeDimension dim = new LodQuadTreeDimension(null, null, sizeOfTheWorld); //SIMULATING A PLAYER MOVING, - int[] playerXs = {0, 100, 200, 300, 400, 500}; + int[] playerXs = {0, 100, 200, 300, 400, 1000}; int[] playerZs = {0, 100, 200, 300, 400, 500}; for (int pos = 0; pos < 1; pos++) { int playerX = 0 + playerXs[pos]; //2097152 - int playerZ = 0 + playerZs[pos]; + int playerZ = 0 + playerZs[pos]/2; //int sizeOfTheWorld=512; //TRY THIS TO SEE A 250'000 BLOCK RENDER DISTANCE dim.move(Math.floorDiv(playerX, 512), Math.floorDiv(playerZ, 512)); @@ -104,11 +104,11 @@ public class QuadTreeImage extends JPanel { System.out.println(dim.getLodFromCoordinates(-6, -6)); */ - DistanceGenerationMode[] complexities = {DistanceGenerationMode.BIOME_ONLY, DistanceGenerationMode.BIOME_ONLY, DistanceGenerationMode.BIOME_ONLY, DistanceGenerationMode.SURFACE, DistanceGenerationMode.SURFACE, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES}; - int[] distances = {100000, 8000, 4000, 2000, 1000, 500, 250, 100, 50, 25}; - for (int i = 0; i <= (9); i++) { - List levelToGenerate = dim.getNodesToGenerate(playerX, playerZ, (byte) (9 - i), complexities[i], distances[i], 0); - System.out.println(levelToGenerate); + DistanceGenerationMode[] complexities = {DistanceGenerationMode.BIOME_ONLY, DistanceGenerationMode.BIOME_ONLY, DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT, DistanceGenerationMode.SURFACE, DistanceGenerationMode.SURFACE, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES, DistanceGenerationMode.FEATURES}; + int[] distances = {1000000, 8000, 4000, 2000, 1000, 500, 250, 100, 50, 25}; + for (int i = 0; i <= (9-2); i++) { + List levelToGenerate = dim.getNodesToGenerate(playerX, playerZ, (byte) (9 - i), complexities[i], distances[i]*2, 0); + //System.out.println(levelToGenerate); for (LodQuadTreeNode node : levelToGenerate) { Color color; int startX = node.startX; @@ -146,21 +146,23 @@ public class QuadTreeImage extends JPanel { //complexityMask.add(DistanceGenerationMode.SURFACE); //complexityMask.add(DistanceGenerationMode.BIOME_ONLY_SIMULATE_HEIGHT); //complexityMask.add(DistanceGenerationMode.BIOME_ONLY); - Set complexityMask = LodQuadTreeDimension.FULL_COMPLEXITY_MASK; -/* List lodList = new ArrayList<>(); //The min and max distances should increase quadratically - int[] distances2 = {100000, 8000, 4000, 2000, 1000, 500, 250, 0}; + //int[] distances2 = {100000, 8000, 4000, 2000, 1000, 500, 250, 0}; + int[] distances2 = {0, 250, 500, 1000, 2000, 4000, 8000, 100000}; for (int h = 0; h <= (9 - 3); h++) { - lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) (9-h), complexityMask, distances2[h], distances2[h+1])); + lodList.addAll(dim.getNodeToRender(playerX, playerZ, (byte) (3+h), complexityMask, distances2[h+1], distances2[h])); } System.out.println("Number of node to render " + lodList.size()); listOfList.add(lodList); - */ + System.out.println("Number of list " + listOfList.size()); + /* List lodList = dim.getNodes(complexityMask, false, false); //USE THIS TO SEE AL THE LODS listOfList.add(lodList); + */ + } } @@ -192,6 +194,27 @@ public class QuadTreeImage extends JPanel { double amp = ((double) 2) / ((double) sizeOfTheWorld); Collection lodList = listOfList.get(drawCount); for (LodQuadTreeNode data : lodList) { + Color colorOfComplexity = Color.black; + switch (data.complexity){ + case NONE: + colorOfComplexity = Color.black; + break; + case BIOME_ONLY: + colorOfComplexity = Color.red; + break; + case BIOME_ONLY_SIMULATE_HEIGHT: + colorOfComplexity = Color.yellow; + break; + case SURFACE: + colorOfComplexity = Color.blue; + break; + case FEATURES: + colorOfComplexity = Color.cyan; + break; + case SERVER: + colorOfComplexity = Color.green; + break; + } myDrawables.add(new MyDrawable(new Rectangle2D.Double( ((data.startX - xOffset) * amp), ((data.startZ - zOffset) * amp), @@ -199,14 +222,12 @@ public class QuadTreeImage extends JPanel { data.width * amp), data.lodDataPoint.color, new BasicStroke(1))); } - for(int k=0; k<1; k++) { myDrawables.add(new MyDrawable(new Rectangle2D.Double( - (playerXs[k] - 10 - xOffset) * amp, - (playerZs[k] - 10 - zOffset) * amp, - 20 * amp, - 20 * amp), + (playerXs[0] - xOffset) * amp, + (playerZs[0] - zOffset) * amp, + 20, + 20), Color.yellow, new BasicStroke(1))); - } for (int k = 0; k < myDrawables.size(); k++) { quadTreeImage.addMyDrawable(myDrawables.get(k)); } @@ -291,8 +312,8 @@ class MyDrawable { Stroke oldStroke = g2.getStroke(); g2.setColor(color); - //g2.fill(shape); - g2.setStroke(stroke); + g2.fill(shape); + //g2.setStroke(stroke); g2.draw(shape); g2.setColor(oldColor);