diff --git a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java index 41aa933..2d432ab 100644 --- a/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java +++ b/src/main/java/ru/windcorp/progressia/client/world/ChunkRender.java @@ -102,7 +102,9 @@ public class ChunkRender } public synchronized void render(ShapeRenderHelper renderer) { - model.render(renderer); + if (!data.isEmpty) { + model.render(renderer); + } } public synchronized void update() { diff --git a/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java b/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java index e11509b..967fe4e 100644 --- a/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java +++ b/src/main/java/ru/windcorp/progressia/common/world/DefaultChunkData.java @@ -25,8 +25,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.Objects; - import glm.vec._3.i.Vec3i; import ru.windcorp.progressia.common.world.block.BlockData; @@ -45,6 +45,11 @@ public class DefaultChunkData implements ChunkData { public static final int BLOCKS_PER_CHUNK = Coordinates.CHUNK_SIZE; public static final int CHUNK_RADIUS = BLOCKS_PER_CHUNK / 2; + + public boolean isEmpty = false; + public boolean isOpaque = false; + + public static HashSet transparent; private final Vec3i position = new Vec3i(); private final DefaultWorldData world; @@ -199,6 +204,44 @@ public class DefaultChunkData implements ChunkData { public void setGenerationHint(Object generationHint) { this.generationHint = generationHint; } + + public void computeOpaque() + { + for (int xyz=0;xyz buffer = new ArrayList<>(); private static class ChunkUnloadRequest { @@ -113,16 +116,16 @@ public class ChunkRequestDaemon { } private void processLoadQueues() { - toRequestUnload.forEach(this::scheduleUnload); + toRequestUnload.forEach((pos) -> executor.submit(() -> scheduleUnload(pos))); toRequestUnload.clear(); - toLoad.forEach(getChunkManager()::loadOrGenerateChunk); + toLoad.forEach((pos) -> executor.submit(() -> getChunkManager().loadOrGenerateChunk(pos))); toLoad.clear(); - toGenerate.forEach(getChunkManager()::loadOrGenerateChunk); + toGenerate.forEach((pos) -> executor.submit(() -> getChunkManager().loadOrGenerateChunk(pos))); toGenerate.clear(); - unloadScheduledChunks(); + executor.submit(() -> unloadScheduledChunks()); } private void scheduleUnload(Vec3i chunkPos) { diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetFeatureGenerator.java index 97e2424..205ea43 100644 --- a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetFeatureGenerator.java +++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetFeatureGenerator.java @@ -56,6 +56,9 @@ public class PlanetFeatureGenerator { generateBorderFeatures(server, chunk); } + chunk.computeEmpty(); + chunk.computeOpaque(); + chunk.setGenerationHint(true); } diff --git a/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java b/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java index e52c94c..d15e88f 100644 --- a/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java +++ b/src/main/java/ru/windcorp/progressia/test/TestWorldDiskIO.java @@ -126,7 +126,7 @@ public class TestWorldDiskIO { private static final Logger LOG = LogManager.getLogger("TestWorldDiskIO"); private static HashMap inOutMap; - private static final boolean ENABLE = true; + private static final boolean ENABLE = false; private static int maxSize = 1048576; private static int sectorSize = maxSize / 256; @@ -227,19 +227,19 @@ public class TestWorldDiskIO { private static void setRegionSize(int format) { inOutMap = new HashMap(); switch (format) { - case 0: - case 1: - regionSize = new Vec3i(1); - chunksPerRegion = 1; - currentFormat = format; - extension = ".progressia_chunk"; - break; case 65536: + default: regionSize = new Vec3i(16); chunksPerRegion = 16 * 16 * 16; currentFormat = 65536; extension = ".progressia_region"; break; + case 65537: + regionSize = new Vec3i(16); + chunksPerRegion = 16 * 16 * 16; + currentFormat = 65536; + extension = ".progressia_regionx"; + break; } } @@ -288,63 +288,7 @@ public class TestWorldDiskIO { try { - if (currentFormat == 0) { - LOG.debug( - "Saving {} {} {}", - chunk.getPosition().x, - chunk.getPosition().y, - chunk.getPosition().z - ); - - Files.createDirectories(SAVE_DIR); - - Path path = SAVE_DIR.resolve( - String.format( - "chunk_%+d_%+d_%+d" + extension, - chunk.getPosition().x, - chunk.getPosition().y, - chunk.getPosition().z - ) - ); - - try ( - DataOutputStream output = new DataOutputStream( - new DeflaterOutputStream(new BufferedOutputStream(Files.newOutputStream(path))) - ) - ) { - ChunkIO.save(chunk, output, IOContext.SAVE); - writeGenerationHint(chunk, output, server); - } - } else if (currentFormat == 1) { - LOG.debug( - "Saving {} {} {}", - chunk.getPosition().x, - chunk.getPosition().y, - chunk.getPosition().z - ); - - Files.createDirectories(SAVE_DIR); - - Vec3i saveCoords = getRegion(chunk.getPosition()); - - Path path = SAVE_DIR.resolve( - String.format( - "chunk_%d_%d_%d" + extension, - saveCoords.x, - saveCoords.y, - saveCoords.z - ) - ); - - try ( - DataOutputStream output = new DataOutputStream( - new DeflaterOutputStream(new BufferedOutputStream(Files.newOutputStream(path))) - ) - ) { - ChunkIO.save(chunk, output, IOContext.SAVE); - writeGenerationHint(chunk, output, server); - } - } else if (currentFormat == 65536) { + if (currentFormat == 65536) { LOG.debug( "Saving {} {} {}", chunk.getPosition().x, @@ -430,6 +374,97 @@ public class TestWorldDiskIO { // LOG.info("Used {} sectors",(int) // tempData.length/sectorSize + 1); + } + else if (currentFormat == 65537) { + LOG.debug( + "Saving {} {} {}", + chunk.getPosition().x, + chunk.getPosition().y, + chunk.getPosition().z + ); + + Files.createDirectories(SAVE_DIR); + + Vec3i saveCoords = getRegion(chunk.getPosition()); + + Path path = SAVE_DIR.resolve( + String.format( + "%d_%d_%d" + extension, + saveCoords.x, + saveCoords.y, + saveCoords.z + ) + ); + + + RandomFileMapped outputMap = inOutMap.get(new HashableVec3i(saveCoords)); + //LOG.info("saveCoords {},{},{}", saveCoords.x, saveCoords.y, saveCoords.z); + if (outputMap == null) + { + outputMap = makeNew(path, new HashableVec3i(saveCoords)); + } + RandomAccessFile output = outputMap.file; + + Vec3i pos = getRegionLoc(chunk.getPosition()); + int shortOffset = 4 * (pos.z + regionSize.z * (pos.y + regionSize.y * pos.x)); + int fullOffset = 4 * (chunksPerRegion); + int offset = 0; + + if (outputMap.hasOffset(pos)) + { + offset = outputMap.getOffset(pos); + } + else { + output.seek(shortOffset); + for (int i = 0; i < 3; i++) { + offset *= 256; + offset += output.read(); + } + int sectorLength = output.read(); + if (sectorLength == 0) { + int outputLen = (int) output.length(); + offset = (int) (outputLen - fullOffset) / sectorSize + 1; + int tempOffset = offset; + output.seek(shortOffset); + + byte readOffset[] = new byte[3]; + for (int i = 0; i < 3; i++) { + readOffset[2 - i] = (byte) (tempOffset % 256); + tempOffset >>= 8; + } + output.write(readOffset); + + output.setLength(fullOffset + offset * sectorSize); + } + outputMap.putOffset(pos, offset); + } + + ByteArrayOutputStream tempDataStream = new ByteArrayOutputStream(); + DataOutputStream trueOutput = new DataOutputStream( + new DeflaterOutputStream( + new BufferedOutputStream(tempDataStream) + ) + ); + ChunkIO.save(chunk, trueOutput, IOContext.SAVE); + writeGenerationHint(chunk, trueOutput, server); + + trueOutput.close(); + + byte tempData[] = tempDataStream.toByteArray(); + + output.seek( fullOffset + sectorSize * offset); + + chunk.computeOpaque(); + chunk.computeEmpty(); + output.write((chunk.isOpaque() ? 1 : 0) << 1 + (chunk.isEmpty() ? 1 : 0)); //Writes extra flag byte of whether or not the chunk is empty or solid + output.write(tempData); + + output.seek(shortOffset + 3); + output.write(tempData.length / sectorSize + 1); + outputMap.putLength(pos, tempData.length / sectorSize + 1); + // LOG.info("Used {} sectors",(int) + // tempData.length/sectorSize + 1); + } // else if (currentFormat) } catch (IOException e) { @@ -522,94 +557,7 @@ public class TestWorldDiskIO { } } - if (currentFormat == 0) { - - Path path = SAVE_DIR.resolve( - String.format( - "chunk_%+d_%+d_%+d" + extension, - chunkPos.x, - chunkPos.y, - chunkPos.z - ) - ); - - if (!Files.exists(path)) { - LOG.debug( - "Not found {} {} {}", - chunkPos.x, - chunkPos.y, - chunkPos.z - ); - - return null; - } - - try { - DefaultChunkData result = load(path, chunkPos, world, server); - - LOG.debug( - "Loaded {} {} {}", - chunkPos.x, - chunkPos.y, - chunkPos.z - ); - - return result; - } catch (Exception e) { - e.printStackTrace(); - LOG.debug( - "Could not load {} {} {}", - chunkPos.x, - chunkPos.y, - chunkPos.z - ); - return null; - } - } else if (currentFormat == 1) { - Vec3i saveCoords = getRegion(chunkPos); - - Path path = SAVE_DIR.resolve( - String.format( - "chunk_%d_%d_%d" + extension, - saveCoords.x, - saveCoords.y, - saveCoords.z - ) - ); - - if (!Files.exists(path)) { - LOG.debug( - "Not found {} {} {}", - chunkPos.x, - chunkPos.y, - chunkPos.z - ); - - return null; - } - - try { - DefaultChunkData result = load(path, chunkPos, world, server); - - LOG.debug( - "Loaded {} {} {}", - chunkPos.x, - chunkPos.y, - chunkPos.z - ); - - return result; - } catch (Exception e) { - e.printStackTrace(); - LOG.debug( - "Could not load {} {} {}", - chunkPos.x, - chunkPos.y, - chunkPos.z - ); - return null; - } - } else if (currentFormat == 65536) { + if (currentFormat == 65536) { Vec3i saveCoords = getRegion(chunkPos); Path path = SAVE_DIR.resolve( @@ -654,21 +602,52 @@ public class TestWorldDiskIO { return null; } } - return null; - } + else if (currentFormat == 65537) { + Vec3i saveCoords = getRegion(chunkPos); - private static DefaultChunkData load(Path path, Vec3i chunkPos, DefaultWorldData world, Server server) - throws IOException, - DecodingException { - try ( - DataInputStream input = new DataInputStream( - new InflaterInputStream(new BufferedInputStream(Files.newInputStream(path))) - ) - ) { - DefaultChunkData chunk = ChunkIO.load(world, chunkPos, input, IOContext.SAVE); - readGenerationHint(chunk, input, server); - return chunk; + Path path = SAVE_DIR.resolve( + String.format( + "%d_%d_%d" + extension, + saveCoords.x, + saveCoords.y, + saveCoords.z + ) + ); + + if (!Files.exists(path)) { + LOG.debug( + "Not found {} {} {}", + chunkPos.x, + chunkPos.y, + chunkPos.z + ); + + return null; + } + + try { + DefaultChunkData result = loadRegionX(path, chunkPos, world, server); + + LOG.debug( + "Loaded {} {} {}", + chunkPos.x, + chunkPos.y, + chunkPos.z + ); + + return result; + } catch (Exception e) { + e.printStackTrace(); + LOG.debug( + "Could not load {} {} {}", + chunkPos.x, + chunkPos.y, + chunkPos.z + ); + return null; + } } + return null; } private static DefaultChunkData loadRegion(Path path, Vec3i chunkPos, DefaultWorldData world, Server server) @@ -744,6 +723,86 @@ public class TestWorldDiskIO { } return null; } + + private static DefaultChunkData loadRegionX(Path path, Vec3i chunkPos, DefaultWorldData world, Server server) + throws IOException, + DecodingException { + int offset = 0; + int sectorLength = 0; + Vec3i pos; + RandomFileMapped inputMap; + int fullOffset = 4 * (chunksPerRegion); + try + { + Vec3i streamCoords = getRegion(chunkPos); + + inputMap = inOutMap.get(new HashableVec3i(streamCoords)); + //LOG.info("streamCoords {},{},{}", streamCoords.x,streamCoords.y,streamCoords.z); + if (inputMap == null) + { + //input = new RandomAccessFile(path.toFile(), "rw"); + //input = Files.newByteChannel(path); + inputMap = makeNew(path, new HashableVec3i(streamCoords)); + } + + RandomAccessFile input = inputMap.file; + + + pos = getRegionLoc(chunkPos); + + if (inputMap.hasOffset(pos)) + { + offset = inputMap.getOffset(pos); + sectorLength = inputMap.getLength(pos); + //LOG.info("{},{}", offset, sectorLength); + } + else + { + + // LOG.info(path.toString()); + + int shortOffset = 4 * (pos.z + regionSize.z * (pos.y + regionSize.y * pos.x)); + + input.seek(shortOffset); + for (int i = 0; i < 3; i++) { + offset *= 256; + offset += input.read(); + } + sectorLength = input.read(); + if (sectorLength == 0) + { + return null; + } + inputMap.putOffset(pos, offset); + inputMap.putLength(pos, sectorLength); + } + input.seek(fullOffset + sectorSize * offset); + + int xByte = input.read(); + + // LOG.info("Read {} sectors", sectorLength); + + byte tempData[] = new byte[sectorSize * sectorLength]; + input.read(tempData); + + DataInputStream trueInput = new DataInputStream( + new InflaterInputStream(new BufferedInputStream(new ByteArrayInputStream(tempData))) + ); + DefaultChunkData chunk = ChunkIO.load(world, chunkPos, trueInput, IOContext.SAVE); + readGenerationHint(chunk, trueInput, server); + + chunk.isOpaque = (xByte & 2)==2; + chunk.isEmpty = (xByte & 1)==1; + + return chunk; + } + catch (EOFException e) + { + LOG.warn("Reached end of file, offset was {}, sectors was {}", offset, sectorLength); + e.printStackTrace(); + } + return null; + } private static void readGenerationHint(DefaultChunkData chunk, DataInputStream input, Server server) throws IOException,