From 0600425a69d5aaa37acabb0e8981c753f2713b5f Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 10:49:00 +0200 Subject: [PATCH 01/11] Add important branch descriptions for contributions --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 9a69cca3..94c1f666 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,12 @@ You found a bug, have another issue or a suggestion? Please create an issue [her You are welcome to contribute! Just create a pull request with your changes :) +If you want to have your changes merged faster, make sure they are complete, documented and well tested! + +The `master`-branch is for the latest version of minecraft. +The `mc/xx`-branches are for other minecraft-versions. +Changes that apply to all versions should be made on the `mc/1.13`-branch. This branch can be merged into `master` and every other `mc/xx` branch. + ### Todo / planned features Here is a *(surely incomplete)* list of things that i want to include in future versions. *(They are not in any specific order. There is no guarantee that any of those things will ever be included.)* From 71c165fe53bc36d23b2639c38f6c8aa42a5c25af Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 16:26:58 +0200 Subject: [PATCH 02/11] Push apache.commons lang3 dependency version to fix an NPE --- BlueMapCore/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlueMapCore/build.gradle b/BlueMapCore/build.gradle index e412d83c..5d189319 100644 --- a/BlueMapCore/build.gradle +++ b/BlueMapCore/build.gradle @@ -5,7 +5,7 @@ plugins { dependencies { compile 'com.google.guava:guava:21.0' compile 'com.google.code.gson:gson:2.8.0' - compile 'org.apache.commons:commons-lang3:3.5' + compile 'org.apache.commons:commons-lang3:3.6' compile group: 'commons-io', name: 'commons-io', version: '2.5' compile 'com.flowpowered:flow-math:1.0.3' compile 'ninja.leaping.configurate:configurate-hocon:3.3' From 6e123e1c3f3520e4c21c9de44fe142a5929d3684 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 16:36:38 +0200 Subject: [PATCH 03/11] Treat not existent region files as empty (not generated) chunks. Fixes #57 --- .../src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java index 42fa4b31..52ad435d 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java @@ -253,6 +253,8 @@ private Chunk loadChunk(Vector2i chunkPos) throws IOException { } else { throw new IOException("invalid data tag: " + (tag == null ? "null" : tag.getClass().getName())); } + } catch (FileNotFoundException ex) { + return Chunk.empty(this, chunkPos); } } From aaeeeb136ac472a75d29d655b26adc4f28942245 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 16:43:04 +0200 Subject: [PATCH 04/11] Actually, we should not rely on an exception here --- .../java/de/bluecolored/bluemap/core/mca/MCAWorld.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java index 52ad435d..1d77872f 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java @@ -222,8 +222,11 @@ public Chunk getChunk(Vector2i chunkPos) throws IOException { private Chunk loadChunk(Vector2i chunkPos) throws IOException { Vector2i regionPos = chunkToRegion(chunkPos); Path regionPath = getMCAFilePath(regionPos); - - try (RandomAccessFile raf = new RandomAccessFile(regionPath.toFile(), "r")) { + + File regionFile = regionPath.toFile(); + if (!regionFile.exists()) return Chunk.empty(this, chunkPos); + + try (RandomAccessFile raf = new RandomAccessFile(regionFile, "r")) { int xzChunk = Math.floorMod(chunkPos.getY(), 32) * 32 + Math.floorMod(chunkPos.getX(), 32); @@ -253,8 +256,6 @@ private Chunk loadChunk(Vector2i chunkPos) throws IOException { } else { throw new IOException("invalid data tag: " + (tag == null ? "null" : tag.getClass().getName())); } - } catch (FileNotFoundException ex) { - return Chunk.empty(this, chunkPos); } } From 7f0df85b6f602142e236eeb085e7eeb0cc6aa354 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 17:01:38 +0200 Subject: [PATCH 05/11] Make debug and render command execute async --- .../common/plugin/commands/Commands.java | 82 +++++++++++-------- 1 file changed, 46 insertions(+), 36 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java index 3404c6bb..b0967916 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java @@ -311,7 +311,7 @@ public int reloadCommand(CommandContext context) { } public int debugCommand(CommandContext context) throws CommandSyntaxException { - CommandSource source = commandSourceInterface.apply(context.getSource()); + final CommandSource source = commandSourceInterface.apply(context.getSource()); // parse arguments Optional worldName = getOptionalArgument(context, "world", String.class); @@ -319,8 +319,8 @@ public int debugCommand(CommandContext context) throws CommandSyntaxException Optional y = getOptionalArgument(context, "y", Double.class); Optional z = getOptionalArgument(context, "z", Double.class); - World world; - Vector3d position; + final World world; + final Vector3d position; if (worldName.isPresent() && x.isPresent() && y.isPresent() && z.isPresent()) { world = parseWorld(worldName.get()).orElse(null); @@ -340,30 +340,32 @@ public int debugCommand(CommandContext context) throws CommandSyntaxException } } - // output debug info - Vector3i blockPos = position.floor().toInt(); - Block block = world.getBlock(blockPos); - Block blockBelow = world.getBlock(blockPos.add(0, -1, 0)); - - String blockIdMeta = ""; - String blockBelowIdMeta = ""; - - if (world instanceof MCAWorld) { - try { - Chunk chunk = ((MCAWorld) world).getChunk(MCAWorld.blockToChunk(blockPos)); - if (chunk instanceof ChunkAnvil112) { - blockIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(blockPos) + ")"; - blockBelowIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(blockPos.add(0, -1, 0)) + ")"; + new Thread(() -> { + // collect and output debug info + Vector3i blockPos = position.floor().toInt(); + Block block = world.getBlock(blockPos); + Block blockBelow = world.getBlock(blockPos.add(0, -1, 0)); + + String blockIdMeta = ""; + String blockBelowIdMeta = ""; + + if (world instanceof MCAWorld) { + try { + Chunk chunk = ((MCAWorld) world).getChunk(MCAWorld.blockToChunk(blockPos)); + if (chunk instanceof ChunkAnvil112) { + blockIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(blockPos) + ")"; + blockBelowIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(blockPos.add(0, -1, 0)) + ")"; + } + } catch (IOException ex) { + Logger.global.logError("Failed to read chunk for debug!", ex); } - } catch (IOException ex) { - Logger.global.logError("Failed to read chunk for debug!", ex); } - } - - source.sendMessages(Lists.newArrayList( - Text.of(TextColor.GOLD, "Block at you: ", TextColor.WHITE, block, TextColor.GRAY, blockIdMeta), - Text.of(TextColor.GOLD, "Block below you: ", TextColor.WHITE, blockBelow, TextColor.GRAY, blockBelowIdMeta) - )); + + source.sendMessages(Lists.newArrayList( + Text.of(TextColor.GOLD, "Block at you: ", TextColor.WHITE, block, TextColor.GRAY, blockIdMeta), + Text.of(TextColor.GOLD, "Block below you: ", TextColor.WHITE, blockBelow, TextColor.GRAY, blockBelowIdMeta) + )); + }).start(); return 1; } @@ -395,12 +397,13 @@ public int resumeCommand(CommandContext context) { } public int renderCommand(CommandContext context) { - CommandSource source = commandSourceInterface.apply(context.getSource()); + final CommandSource source = commandSourceInterface.apply(context.getSource()); // parse world/map argument Optional worldOrMap = getOptionalArgument(context, "world|map", String.class); - World world = null; - MapType map = null; + + final World world; + final MapType map; if (worldOrMap.isPresent()) { world = parseWorld(worldOrMap.get()).orElse(null); @@ -411,9 +414,12 @@ public int renderCommand(CommandContext context) { source.sendMessage(Text.of(TextColor.RED, "There is no ", helper.worldHelperHover(), " or ", helper.mapHelperHover(), " with this name: ", TextColor.WHITE, worldOrMap.get())); return 0; } + } else { + map = null; } } else { world = source.getWorld().orElse(null); + map = null; if (world == null) { source.sendMessage(Text.of(TextColor.RED, "Can't detect a world from this command-source, you'll have to define a world or a map to render!").setHoverText(Text.of(TextColor.GRAY, "/bluemap render "))); @@ -422,8 +428,8 @@ public int renderCommand(CommandContext context) { } // parse radius and center arguments - int radius = getOptionalArgument(context, "radius", Integer.class).orElse(-1); - Vector2i center = null; + final int radius = getOptionalArgument(context, "radius", Integer.class).orElse(-1); + final Vector2i center; if (radius >= 0) { Optional x = getOptionalArgument(context, "x", Double.class); Optional z = getOptionalArgument(context, "z", Double.class); @@ -439,14 +445,18 @@ public int renderCommand(CommandContext context) { center = position.toVector2(true).floor().toInt(); } + } else { + center = null; } - // execute render - if (world != null) { - helper.createWorldRenderTask(source, world, center, radius); - } else { - helper.createMapRenderTask(source, map, center, radius); - } + // execute render + new Thread(() -> { + if (world != null) { + helper.createWorldRenderTask(source, world, center, radius); + } else { + helper.createMapRenderTask(source, map, center, radius); + } + }).start(); return 1; } From d97560cc82134efeff525c3c0e209e6ba70af84a Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 17:06:50 +0200 Subject: [PATCH 06/11] Optimize chunk filter a little --- .../bluemap/core/mca/MCAWorld.java | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java index 1d77872f..e7dc2afd 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java @@ -282,24 +282,26 @@ public Collection getChunkList(long modifiedSinceMillis, Predicate= (modifiedSinceMillis / 1000)) { - Vector2i chunk = new Vector2i(rX * 32 + x, rZ * 32 + z); - if (filter.test(chunk)) { + Vector2i chunk = new Vector2i(rX * 32 + x, rZ * 32 + z); + if (filter.test(chunk)) { + + int xzChunk = z * 32 + x; + + raf.seek(xzChunk * 4 + 3); + int size = raf.readByte() * 4096; + + if (size == 0) continue; + + raf.seek(xzChunk * 4 + 4096); + int timestamp = raf.read() << 24; + timestamp |= (raf.read() & 0xFF) << 16; + timestamp |= (raf.read() & 0xFF) << 8; + timestamp |= raf.read() & 0xFF; + + if (timestamp >= (modifiedSinceMillis / 1000)) { chunks.add(chunk); } + } } } From a4c8004834527a10211241a0af1274a5125f6323 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 18:04:16 +0200 Subject: [PATCH 07/11] Add some extra sanity checks and fallbacks to chunkloaders --- .../bluemap/core/mca/ChunkAnvil112.java | 25 ++++++++++++++----- .../bluemap/core/mca/ChunkAnvil113.java | 9 +++++-- .../bluemap/core/mca/ChunkAnvil115.java | 9 +++++-- .../bluemap/core/mca/ChunkAnvil116.java | 9 +++++-- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil112.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil112.java index 9ddf7119..df592317 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil112.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil112.java @@ -24,6 +24,8 @@ */ package de.bluecolored.bluemap.core.mca; +import java.util.Arrays; + import com.flowpowered.math.vector.Vector3i; import de.bluecolored.bluemap.core.mca.mapping.BiomeMapper; @@ -60,15 +62,21 @@ public ChunkAnvil112(MCAWorld world, CompoundTag chunkTag, boolean ignoreMissing levelData.getBoolean("TerrainPopulated"); sections = new Section[32]; //32 supports a max world-height of 512 which is the max that the hightmaps of Minecraft V1.13+ can store with 9 bits, i believe? - for (CompoundTag sectionTag : ((ListTag) levelData.getListTag("Sections"))) { - Section section = new Section(sectionTag); - sections[section.getSectionY()] = section; + if (levelData.containsKey("Sections")) { + for (CompoundTag sectionTag : ((ListTag) levelData.getListTag("Sections"))) { + Section section = new Section(sectionTag); + if (section.getSectionY() >= 0 && section.getSectionY() < sections.length) sections[section.getSectionY()] = section; + } } biomes = levelData.getByteArray("Biomes"); if (biomes == null || biomes.length == 0) { - biomes = new byte[2048]; + biomes = new byte[256]; + } + + if (biomes.length < 256) { + biomes = Arrays.copyOf(biomes, 256); } } @@ -132,6 +140,11 @@ public Section(CompoundTag sectionData) { this.blockLight = sectionData.getByteArray("BlockLight"); this.skyLight = sectionData.getByteArray("SkyLight"); this.data = sectionData.getByteArray("Data"); + + if (blocks.length < 4096) blocks = Arrays.copyOf(biomes, 4096); + if (blockLight.length < 2048) blockLight = Arrays.copyOf(blockLight, 2048); + if (skyLight.length < 2048) skyLight = Arrays.copyOf(skyLight, 2048); + if (data.length < 2048) data = Arrays.copyOf(data, 2048); } public int getSectionY() { @@ -148,7 +161,7 @@ public BlockState getBlockState(Vector3i pos) { int blockId = this.blocks[blockByteIndex] & 0xFF; - if (this.add.length > 0) { + if (this.add.length > blockHalfByteIndex) { blockId = blockId | (getByteHalf(this.add[blockHalfByteIndex], largeHalf) << 8); } @@ -172,7 +185,7 @@ public String getBlockIdMeta(Vector3i pos) { int blockId = this.blocks[blockByteIndex] & 0xFF; - if (this.add.length > 0) { + if (this.add.length > blockHalfByteIndex) { blockId = blockId | (getByteHalf(this.add[blockHalfByteIndex], largeHalf) << 8); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java index 0a67022e..b5eda8d0 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java @@ -24,6 +24,7 @@ */ package de.bluecolored.bluemap.core.mca; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -71,7 +72,7 @@ public ChunkAnvil113(MCAWorld world, CompoundTag chunkTag, boolean ignoreMissing if (levelData.containsKey("Sections")) { for (CompoundTag sectionTag : ((ListTag) levelData.getListTag("Sections"))) { Section section = new Section(sectionTag); - if (section.getSectionY() >= 0) sections[section.getSectionY()] = section; + if (section.getSectionY() >= 0 && section.getSectionY() < sections.length) sections[section.getSectionY()] = section; } } @@ -89,7 +90,11 @@ else if (tag instanceof IntArrayTag) { } if (biomes == null || biomes.length == 0) { - biomes = new int[2048]; + biomes = new int[256]; + } + + if (biomes.length < 256) { + biomes = Arrays.copyOf(biomes, 256); } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil115.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil115.java index 9ecede17..df2a26ef 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil115.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil115.java @@ -24,6 +24,7 @@ */ package de.bluecolored.bluemap.core.mca; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -71,7 +72,7 @@ public ChunkAnvil115(MCAWorld world, CompoundTag chunkTag, boolean ignoreMissing if (levelData.containsKey("Sections")) { for (CompoundTag sectionTag : ((ListTag) levelData.getListTag("Sections"))) { Section section = new Section(sectionTag); - if (section.getSectionY() >= 0) sections[section.getSectionY()] = section; + if (section.getSectionY() >= 0 && section.getSectionY() < sections.length) sections[section.getSectionY()] = section; } } @@ -89,7 +90,11 @@ else if (tag instanceof IntArrayTag) { } if (biomes == null || biomes.length == 0) { - biomes = new int[2048]; + biomes = new int[1024]; + } + + if (biomes.length < 1024) { + biomes = Arrays.copyOf(biomes, 1024); } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java index bcc0868c..5bd83b7a 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java @@ -24,6 +24,7 @@ */ package de.bluecolored.bluemap.core.mca; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -71,7 +72,7 @@ public ChunkAnvil116(MCAWorld world, CompoundTag chunkTag, boolean ignoreMissing if (levelData.containsKey("Sections")) { for (CompoundTag sectionTag : ((ListTag) levelData.getListTag("Sections"))) { Section section = new Section(sectionTag); - if (section.getSectionY() >= 0) sections[section.getSectionY()] = section; + if (section.getSectionY() >= 0 && section.getSectionY() < sections.length) sections[section.getSectionY()] = section; } } @@ -89,7 +90,11 @@ else if (tag instanceof IntArrayTag) { } if (biomes == null || biomes.length == 0) { - biomes = new int[2048]; + biomes = new int[1024]; + } + + if (biomes.length < 1024) { + biomes = Arrays.copyOf(biomes, 1024); } } From a33dda0a29514149d7ca20f766940c7af38c3dad Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 20:00:58 +0200 Subject: [PATCH 08/11] More sanity checks and fallbacks to chunkloaders and better IOException handling --- .../bluemap/common/RenderManager.java | 6 +- .../bluemap/core/mca/ChunkAnvil112.java | 2 +- .../bluemap/core/mca/ChunkAnvil113.java | 11 ++- .../bluemap/core/mca/ChunkAnvil115.java | 6 +- .../bluemap/core/mca/ChunkAnvil116.java | 6 +- .../bluemap/core/mca/MCAWorld.java | 78 ++++++++++--------- .../resourcepack/BlockColorCalculator.java | 4 +- 7 files changed, 63 insertions(+), 50 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java index 53f1ac9c..131a3d04 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java @@ -164,11 +164,7 @@ private void renderThread() { try { ticket.render(); } catch (IOException e) { - if (ticket.getRenderAttempts() <= 1) { - createTicket(ticket); - } else { - Logger.global.logDebug("Failed to render tile " + ticket.getTile() + " of map '" + ticket.getMapType().getId() + "' after " + ticket.getRenderAttempts() + " render-attempts! (" + e.toString() + ")"); - } + Logger.global.logDebug("Failed to render tile " + ticket.getTile() + " of map '" + ticket.getMapType().getId() + "' after " + ticket.getRenderAttempts() + " render-attempts! (" + e.toString() + ")"); } } else { try { diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil112.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil112.java index df592317..6be78d15 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil112.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil112.java @@ -141,7 +141,7 @@ public Section(CompoundTag sectionData) { this.skyLight = sectionData.getByteArray("SkyLight"); this.data = sectionData.getByteArray("Data"); - if (blocks.length < 4096) blocks = Arrays.copyOf(biomes, 4096); + if (blocks.length < 4096) blocks = Arrays.copyOf(blocks, 4096); if (blockLight.length < 2048) blockLight = Arrays.copyOf(blockLight, 2048); if (skyLight.length < 2048) skyLight = Arrays.copyOf(skyLight, 2048); if (data.length < 2048) data = Arrays.copyOf(data, 2048); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java index b5eda8d0..ef6c2a02 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil113.java @@ -143,14 +143,18 @@ private class Section { private long[] blocks; private BlockState[] palette; + private int bitsPerBlock; + @SuppressWarnings("unchecked") public Section(CompoundTag sectionData) { this.sectionY = sectionData.getByte("Y"); this.blockLight = sectionData.getByteArray("BlockLight"); - if (blockLight.length == 0) blockLight = new byte[2048]; this.skyLight = sectionData.getByteArray("SkyLight"); - if (skyLight.length == 0) skyLight = new byte[2048]; this.blocks = sectionData.getLongArray("BlockStates"); + + if (blocks.length < 256) blocks = Arrays.copyOf(blocks, 256); + if (blockLight.length < 2048) blockLight = Arrays.copyOf(blockLight, 2048); + if (skyLight.length < 2048) skyLight = Arrays.copyOf(skyLight, 2048); //read block palette ListTag paletteTag = (ListTag) sectionData.getListTag("Palette"); @@ -179,6 +183,8 @@ public Section(CompoundTag sectionData) { } else { this.palette = new BlockState[0]; } + + this.bitsPerBlock = blocks.length * 64 / 4096; //64 bits per long and 4096 blocks per section } public int getSectionY() { @@ -192,7 +198,6 @@ public BlockState getBlockState(Vector3i pos) { int y = pos.getY() & 0xF; int z = pos.getZ() & 0xF; int blockIndex = y * 256 + z * 16 + x; - int bitsPerBlock = blocks.length * 64 / 4096; //64 bits per long and 4096 blocks per section int index = blockIndex * bitsPerBlock; int firstLong = index >> 6; // index / 64 int bitoffset = index & 0x3F; // Math.floorMod(index, 64) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil115.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil115.java index df2a26ef..2ebfa8a0 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil115.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil115.java @@ -150,10 +150,12 @@ private class Section { public Section(CompoundTag sectionData) { this.sectionY = sectionData.getByte("Y"); this.blockLight = sectionData.getByteArray("BlockLight"); - if (blockLight.length == 0) blockLight = new byte[2048]; this.skyLight = sectionData.getByteArray("SkyLight"); - if (skyLight.length == 0) skyLight = new byte[2048]; this.blocks = sectionData.getLongArray("BlockStates"); + + if (blocks.length < 256) blocks = Arrays.copyOf(blocks, 256); + if (blockLight.length < 2048) blockLight = Arrays.copyOf(blockLight, 2048); + if (skyLight.length < 2048) skyLight = Arrays.copyOf(skyLight, 2048); //read block palette ListTag paletteTag = (ListTag) sectionData.getListTag("Palette"); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java index 5bd83b7a..0d0d7c1a 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java @@ -151,10 +151,12 @@ private class Section { public Section(CompoundTag sectionData) { this.sectionY = sectionData.getByte("Y"); this.blockLight = sectionData.getByteArray("BlockLight"); - if (blockLight.length == 0) blockLight = new byte[2048]; this.skyLight = sectionData.getByteArray("SkyLight"); - if (skyLight.length == 0) skyLight = new byte[2048]; this.blocks = sectionData.getLongArray("BlockStates"); + + if (blocks.length < 256) blocks = Arrays.copyOf(blocks, 256); + if (blockLight.length < 2048) blockLight = Arrays.copyOf(blockLight, 2048); + if (skyLight.length < 2048) skyLight = Arrays.copyOf(skyLight, 2048); //read block palette ListTag paletteTag = (ListTag) sectionData.getListTag("Palette"); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java index e7dc2afd..e7493d3c 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java @@ -156,40 +156,32 @@ public BlockState getBlockState(Vector3i pos) { @Override public Biome getBiome(Vector3i pos) { - try { - - Vector2i chunkPos = blockToChunk(pos); - Chunk chunk = getChunk(chunkPos); - return chunk.getBiome(pos); - - } catch (IOException ex) { - throw new RuntimeException("Unexpected IO-Exception trying to read world-data!", ex); + if (pos.getY() < getMinY()) { + pos = new Vector3i(pos.getX(), getMinY(), pos.getZ()); + } else if (pos.getY() > getMaxY()) { + pos = new Vector3i(pos.getX(), getMaxY(), pos.getZ()); } + + Vector2i chunkPos = blockToChunk(pos); + Chunk chunk = getChunk(chunkPos); + return chunk.getBiome(pos); } @Override public Block getBlock(Vector3i pos) { if (pos.getY() < getMinY()) { return new Block(this, BlockState.AIR, LightData.ZERO, Biome.DEFAULT, BlockProperties.TRANSPARENT, pos); - } - - if (pos.getY() > getMaxY()) { + } else if (pos.getY() > getMaxY()) { return new Block(this, BlockState.AIR, LightData.SKY, Biome.DEFAULT, BlockProperties.TRANSPARENT, pos); } - try { - - Vector2i chunkPos = blockToChunk(pos); - Chunk chunk = getChunk(chunkPos); - BlockState blockState = getExtendedBlockState(chunk, pos); - LightData lightData = chunk.getLightData(pos); - Biome biome = chunk.getBiome(pos); - BlockProperties properties = blockPropertiesMapper.get(blockState); - return new Block(this, blockState, lightData, biome, properties, pos); - - } catch (IOException ex) { - throw new RuntimeException("Unexpected IO-Exception trying to read world-data!", ex); - } + Vector2i chunkPos = blockToChunk(pos); + Chunk chunk = getChunk(chunkPos); + BlockState blockState = getExtendedBlockState(chunk, pos); + LightData lightData = chunk.getLightData(pos); + Biome biome = chunk.getBiome(pos); + BlockProperties properties = blockPropertiesMapper.get(blockState); + return new Block(this, blockState, lightData, biome, properties, pos); } private BlockState getExtendedBlockState(Chunk chunk, Vector3i pos) { @@ -204,21 +196,35 @@ private BlockState getExtendedBlockState(Chunk chunk, Vector3i pos) { return blockState; } - public Chunk getChunk(Vector2i chunkPos) throws IOException { + public Chunk getChunk(Vector2i chunkPos) { try { - Chunk chunk = CHUNK_CACHE.get(new WorldChunkHash(this, chunkPos), () -> this.loadChunk(chunkPos)); + Chunk chunk = CHUNK_CACHE.get(new WorldChunkHash(this, chunkPos), () -> this.loadChunkOrEmpty(chunkPos, 2, 1000)); return chunk; } catch (UncheckedExecutionException | ExecutionException e) { - Throwable cause = e.getCause(); - - if (cause instanceof IOException) { - throw (IOException) cause; - } - - else throw new IOException(cause); + throw new RuntimeException(e.getCause()); } } + private Chunk loadChunkOrEmpty(Vector2i chunkPos, int tries, long tryInterval) { + Exception loadException = null; + for (int i = 0; i < tries; i++) { + try { + return loadChunk(chunkPos); + } catch (Exception e) { + loadException = e; + + if (tryInterval > 0 && i+1 < tries) { + try { + Thread.sleep(tryInterval); + } catch (InterruptedException interrupt) {} + } + } + } + + Logger.global.logDebug("Unexpected exception trying to load chunk (" + chunkPos + "):" + loadException); + return Chunk.empty(this, chunkPos); + } + private Chunk loadChunk(Vector2i chunkPos) throws IOException { Vector2i regionPos = chunkToRegion(chunkPos); Path regionPath = getMCAFilePath(regionPos); @@ -246,7 +252,7 @@ private Chunk loadChunk(Vector2i chunkPos) throws IOException { byte compressionTypeByte = raf.readByte(); CompressionType compressionType = CompressionType.getFromID(compressionTypeByte); if (compressionType == null) { - throw new IOException("invalid compression type " + compressionTypeByte); + throw new IOException("Invalid compression type " + compressionTypeByte); } DataInputStream dis = new DataInputStream(new BufferedInputStream(compressionType.decompress(new FileInputStream(raf.getFD())))); @@ -254,8 +260,10 @@ private Chunk loadChunk(Vector2i chunkPos) throws IOException { if (tag instanceof CompoundTag) { return Chunk.create(this, (CompoundTag) tag, ignoreMissingLightData); } else { - throw new IOException("invalid data tag: " + (tag == null ? "null" : tag.getClass().getName())); + throw new IOException("Invalid data tag: " + (tag == null ? "null" : tag.getClass().getName())); } + } catch (Exception e) { + throw new IOException("Exception trying to load chunk (" + chunkPos + ")", e); } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resourcepack/BlockColorCalculator.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resourcepack/BlockColorCalculator.java index 98940a32..256a9718 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resourcepack/BlockColorCalculator.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resourcepack/BlockColorCalculator.java @@ -172,10 +172,10 @@ private Iterable iterateAverageBiomes(Block block){ final World world = block.getWorld(); final int sx = pos.getX() - radius.getX(), - sy = pos.getY() - radius.getY(), + sy = Math.max(0, pos.getY() - radius.getY()), sz = pos.getZ() - radius.getZ(); final int mx = pos.getX() + radius.getX(), - my = pos.getY() + radius.getY(), + my = Math.min(255, pos.getY() + radius.getY()), mz = pos.getZ() + radius.getZ(); return () -> new Iterator() { From ca4fec8c1a65bda94b5873791e0ebe968eea58ea Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 20:11:25 +0200 Subject: [PATCH 09/11] Remove now unneeded exceptions --- .../bluecolored/bluemap/common/MapType.java | 4 +--- .../bluemap/common/RenderManager.java | 6 +----- .../bluemap/common/RenderTicket.java | 21 ++----------------- .../common/plugin/commands/Commands.java | 12 ++++------- .../bluemap/core/mca/MCAWorld.java | 2 +- .../bluemap/core/render/TileRenderer.java | 5 +---- .../bluemap/core/world/SlicedWorld.java | 9 ++++---- .../bluecolored/bluemap/core/world/World.java | 8 +++---- 8 files changed, 18 insertions(+), 49 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/MapType.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/MapType.java index 5d3a11d3..687fa720 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/MapType.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/MapType.java @@ -24,8 +24,6 @@ */ package de.bluecolored.bluemap.common; -import java.io.IOException; - import com.flowpowered.math.vector.Vector2i; import com.google.common.base.Preconditions; @@ -68,7 +66,7 @@ public TileRenderer getTileRenderer() { return tileRenderer; } - public void renderTile(Vector2i tile) throws IOException { + public void renderTile(Vector2i tile) { getTileRenderer().render(new WorldTile(getWorld(), tile)); } diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java index 131a3d04..087a69a8 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java @@ -161,11 +161,7 @@ private void renderThread() { } if (ticket != null) { - try { - ticket.render(); - } catch (IOException e) { - Logger.global.logDebug("Failed to render tile " + ticket.getTile() + " of map '" + ticket.getMapType().getId() + "' after " + ticket.getRenderAttempts() + " render-attempts! (" + e.toString() + ")"); - } + ticket.render(); } else { try { Thread.sleep(1000); // we don't need a super fast response time, so waiting a second is totally fine diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderTicket.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderTicket.java index 5c36f6fa..69842450 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderTicket.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderTicket.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.common; -import java.io.IOException; import java.util.Objects; import com.flowpowered.math.vector.Vector2i; @@ -34,25 +33,13 @@ public class RenderTicket { private final MapType map; private final Vector2i tile; - private int renderAttempts; - private boolean successfullyRendered; - public RenderTicket(MapType map, Vector2i tile) { this.map = map; this.tile = tile; - - this.renderAttempts = 0; - this.successfullyRendered = false; } - public synchronized void render() throws IOException { - renderAttempts++; - - if (!successfullyRendered) { - map.renderTile(tile); - - successfullyRendered = true; - } + public synchronized void render() { + map.renderTile(tile); } public MapType getMapType() { @@ -63,10 +50,6 @@ public Vector2i getTile() { return tile; } - public int getRenderAttempts() { - return renderAttempts; - } - @Override public int hashCode() { return Objects.hash(map.getId(), tile); diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java index b0967916..6f46e113 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java @@ -350,14 +350,10 @@ public int debugCommand(CommandContext context) throws CommandSyntaxException String blockBelowIdMeta = ""; if (world instanceof MCAWorld) { - try { - Chunk chunk = ((MCAWorld) world).getChunk(MCAWorld.blockToChunk(blockPos)); - if (chunk instanceof ChunkAnvil112) { - blockIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(blockPos) + ")"; - blockBelowIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(blockPos.add(0, -1, 0)) + ")"; - } - } catch (IOException ex) { - Logger.global.logError("Failed to read chunk for debug!", ex); + Chunk chunk = ((MCAWorld) world).getChunk(MCAWorld.blockToChunk(blockPos)); + if (chunk instanceof ChunkAnvil112) { + blockIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(blockPos) + ")"; + blockBelowIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(blockPos.add(0, -1, 0)) + ")"; } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java index e7493d3c..e2251f21 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java @@ -268,7 +268,7 @@ private Chunk loadChunk(Vector2i chunkPos) throws IOException { } @Override - public boolean isChunkGenerated(Vector2i chunkPos) throws IOException { + public boolean isChunkGenerated(Vector2i chunkPos) { Chunk chunk = getChunk(chunkPos); return chunk.isGenerated(); } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/TileRenderer.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/TileRenderer.java index c65d03e7..4e876042 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/TileRenderer.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/TileRenderer.java @@ -24,8 +24,6 @@ */ package de.bluecolored.bluemap.core.render; -import java.io.IOException; - import de.bluecolored.bluemap.core.render.hires.HiresModel; import de.bluecolored.bluemap.core.render.hires.HiresModelManager; import de.bluecolored.bluemap.core.render.lowres.LowresModelManager; @@ -42,9 +40,8 @@ public TileRenderer(HiresModelManager hiresModelManager, LowresModelManager lowr /** * Renders the provided WorldTile (only) if the world is generated - * @throws IOException If an IO-Exception occurs during the render */ - public void render(WorldTile tile) throws IOException { + public void render(WorldTile tile) { //check if the region is generated before rendering, don't render if it's not generated AABB area = hiresModelManager.getTileRegion(tile); if (!tile.getWorld().isAreaGenerated(area)) return; diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/SlicedWorld.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/SlicedWorld.java index 36e69c7e..3da22abb 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/SlicedWorld.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/SlicedWorld.java @@ -24,7 +24,6 @@ */ package de.bluecolored.bluemap.core.world; -import java.io.IOException; import java.nio.file.Path; import java.util.Collection; import java.util.UUID; @@ -114,24 +113,24 @@ public Collection getChunkList(long modifiedSince, Predicate } @Override - public boolean isChunkGenerated(Vector2i chunkPos) throws IOException { + public boolean isChunkGenerated(Vector2i chunkPos) { if (!isInside(chunkPos)) return false; return world.isChunkGenerated(chunkPos); } @Override - public boolean isAreaGenerated(AABB area) throws IOException { + public boolean isAreaGenerated(AABB area) { return isAreaGenerated(area.getMin(), area.getMax()); } @Override - public boolean isAreaGenerated(Vector3i blockMin, Vector3i blockMax) throws IOException { + public boolean isAreaGenerated(Vector3i blockMin, Vector3i blockMax) { return isAreaGenerated(blockPosToChunkPos(blockMin), blockPosToChunkPos(blockMax)); } @Override - public boolean isAreaGenerated(Vector2i chunkMin, Vector2i chunkMax) throws IOException { + public boolean isAreaGenerated(Vector2i chunkMin, Vector2i chunkMax) { if (!isInside(chunkMin) && !isInside(chunkMax) && !isInside(new Vector2i(chunkMin.getX(), chunkMax.getY())) && diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java index fbb96862..443b1b73 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/world/World.java @@ -110,7 +110,7 @@ public default Collection getChunkList(long modifiedSince){ /** * Returns true if and only if that chunk is fully generated and no world-generation or lighting has yet to be done. */ - public boolean isChunkGenerated(Vector2i chunkPos) throws IOException; + public boolean isChunkGenerated(Vector2i chunkPos); /** @@ -118,7 +118,7 @@ public default Collection getChunkList(long modifiedSince){ * @param area The area to check * @throws IOException */ - public default boolean isAreaGenerated(AABB area) throws IOException { + public default boolean isAreaGenerated(AABB area) { return isAreaGenerated(area.getMin(), area.getMax()); } @@ -127,7 +127,7 @@ public default boolean isAreaGenerated(AABB area) throws IOException { * @param area The area to check * @throws IOException */ - public default boolean isAreaGenerated(Vector3i blockMin, Vector3i blockMax) throws IOException { + public default boolean isAreaGenerated(Vector3i blockMin, Vector3i blockMax) { return isAreaGenerated(blockPosToChunkPos(blockMin), blockPosToChunkPos(blockMax)); } @@ -136,7 +136,7 @@ public default boolean isAreaGenerated(Vector3i blockMin, Vector3i blockMax) thr * @param area The area to check * @throws IOException */ - public default boolean isAreaGenerated(Vector2i chunkMin, Vector2i chunkMax) throws IOException { + public default boolean isAreaGenerated(Vector2i chunkMin, Vector2i chunkMax) { for (int x = chunkMin.getX(); x <= chunkMax.getX(); x++) { for (int z = chunkMin.getY(); z <= chunkMax.getY(); z++) { if (!isChunkGenerated(new Vector2i(x, z))) return false; From 7405520713e07702b60523e6b7a7e6d4ee3eb0b2 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 20:16:20 +0200 Subject: [PATCH 10/11] Dont let render-threads die. If an error occurs, let them wait for a while, then resurrect them --- .../de/bluecolored/bluemap/common/RenderManager.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java index 087a69a8..31c884c7 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java @@ -161,11 +161,19 @@ private void renderThread() { } if (ticket != null) { - ticket.render(); + try { + ticket.render(); + } catch (Exception e) { + //catch possible runtime exceptions, display them, and wait a while .. then resurrect this render-thread + Logger.global.logError("Unexpected exception in render-thread!", e); + try { + Thread.sleep(10000); + } catch (InterruptedException interrupt) { break; } + } } else { try { Thread.sleep(1000); // we don't need a super fast response time, so waiting a second is totally fine - } catch (InterruptedException e) { break; } + } catch (InterruptedException interrupt) { break; } } } } From 3fd22e5b45c16a07a736cf310b24e14733daa455 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 20:29:53 +0200 Subject: [PATCH 11/11] Add debug command to clear caches --- .../common/plugin/commands/Commands.java | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java index 6f46e113..b32ea461 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java @@ -100,13 +100,19 @@ public void init() { LiteralCommandNode debugCommand = literal("debug") .requires(requirements("bluemap.debug")) - .executes(this::debugCommand) - - .then(argument("world", StringArgumentType.string()).suggests(new WorldSuggestionProvider<>(plugin)) - .then(argument("x", DoubleArgumentType.doubleArg()) - .then(argument("y", DoubleArgumentType.doubleArg()) - .then(argument("z", DoubleArgumentType.doubleArg()) - .executes(this::debugCommand))))) + + .then(literal("block") + .executes(this::debugBlockCommand) + + .then(argument("world", StringArgumentType.string()).suggests(new WorldSuggestionProvider<>(plugin)) + .then(argument("x", DoubleArgumentType.doubleArg()) + .then(argument("y", DoubleArgumentType.doubleArg()) + .then(argument("z", DoubleArgumentType.doubleArg()) + .executes(this::debugBlockCommand)))))) + + .then(literal("cache") + .executes(this::debugClearCacheCommand)) + .build(); LiteralCommandNode pauseCommand = @@ -310,7 +316,18 @@ public int reloadCommand(CommandContext context) { return 1; } - public int debugCommand(CommandContext context) throws CommandSyntaxException { + public int debugClearCacheCommand(CommandContext context) throws CommandSyntaxException { + CommandSource source = commandSourceInterface.apply(context.getSource()); + + for (World world : plugin.getWorlds()) { + world.invalidateChunkCache(); + } + + source.sendMessage(Text.of(TextColor.GREEN, "All caches cleared!")); + return 1; + } + + public int debugBlockCommand(CommandContext context) throws CommandSyntaxException { final CommandSource source = commandSourceInterface.apply(context.getSource()); // parse arguments @@ -358,6 +375,7 @@ public int debugCommand(CommandContext context) throws CommandSyntaxException } source.sendMessages(Lists.newArrayList( + Text.of(TextColor.GOLD, "Is generated: ", TextColor.WHITE, world.isChunkGenerated(world.blockPosToChunkPos(blockPos))), Text.of(TextColor.GOLD, "Block at you: ", TextColor.WHITE, block, TextColor.GRAY, blockIdMeta), Text.of(TextColor.GOLD, "Block below you: ", TextColor.WHITE, blockBelow, TextColor.GRAY, blockBelowIdMeta) ));