From 54364c40ee416754ea8ff3b2104b2b4c69f9e007 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Mon, 11 May 2020 22:13:46 +0200 Subject: [PATCH 01/29] Update README --- README.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2c4968c6..9a69cca3 100644 --- a/README.md +++ b/README.md @@ -35,15 +35,13 @@ Just create a pull request with your changes :) ### 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.)* +- live player positions +- fabric version - render more tile-entities (banners, shulker-chests, etc..) - render entities (armor-stands, item-frames, maybe even cows and such..) -- configurable markers / regions -- marker / region API - free-flight-controls -- live player positions - more configurations - easier mod-integration -- BlueMap as forge mod - ability to display the world-border - animated textures (if feasible) - add support for models in obj format (if feasible) From 67cb42fa40e16b2becff3498e9a979a0a05efce0 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Fri, 15 May 2020 12:39:19 +0200 Subject: [PATCH 02/29] Add support for reading 1.16 region-files --- .../bluecolored/bluemap/core/mca/Chunk.java | 13 +- .../bluemap/core/mca/ChunkAnvil115.java | 5 +- .../bluemap/core/mca/ChunkAnvil116.java | 242 ++++++++++++++++++ 3 files changed, 258 insertions(+), 2 deletions(-) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/Chunk.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/Chunk.java index 073afc25..b3aa68ce 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/Chunk.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/Chunk.java @@ -39,9 +39,13 @@ public abstract class Chunk { private final MCAWorld world; private final Vector2i chunkPos; + private final int dataVersion; + protected Chunk(MCAWorld world, Vector2i chunkPos) { this.world = world; this.chunkPos = chunkPos; + + this.dataVersion = -1; } protected Chunk(MCAWorld world, CompoundTag chunkTag) { @@ -53,6 +57,8 @@ protected Chunk(MCAWorld world, CompoundTag chunkTag) { levelData.getInt("xPos"), levelData.getInt("zPos") ); + + dataVersion = chunkTag.getInt("DataVersion"); } public abstract boolean isGenerated(); @@ -65,6 +71,10 @@ public MCAWorld getWorld() { return world; } + public int getDataVersion() { + return dataVersion; + } + public abstract BlockState getBlockState(Vector3i pos); public abstract LightData getLightData(Vector3i pos); @@ -76,7 +86,8 @@ public static Chunk create(MCAWorld world, CompoundTag chunkTag, boolean ignoreM if (version <= 1343) return new ChunkAnvil112(world, chunkTag, ignoreMissingLightData); if (version <= 1976) return new ChunkAnvil113(world, chunkTag, ignoreMissingLightData); - return new ChunkAnvil115(world, chunkTag, ignoreMissingLightData); + if (version < 2534) return new ChunkAnvil115(world, chunkTag, ignoreMissingLightData); + return new ChunkAnvil116(world, chunkTag, ignoreMissingLightData); } public static Chunk empty(MCAWorld world, Vector2i chunkPos) { 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 0d2ebcbe..9ecede17 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 @@ -139,6 +139,8 @@ private class Section { private long[] blocks; private BlockState[] palette; + private int bitsPerBlock; + @SuppressWarnings("unchecked") public Section(CompoundTag sectionData) { this.sectionY = sectionData.getByte("Y"); @@ -175,6 +177,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() { @@ -188,7 +192,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/ChunkAnvil116.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java new file mode 100644 index 00000000..bcc0868c --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/ChunkAnvil116.java @@ -0,0 +1,242 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package de.bluecolored.bluemap.core.mca; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import com.flowpowered.math.vector.Vector3i; + +import de.bluecolored.bluemap.core.logger.Logger; +import de.bluecolored.bluemap.core.mca.mapping.BiomeMapper; +import de.bluecolored.bluemap.core.world.Biome; +import de.bluecolored.bluemap.core.world.BlockState; +import de.bluecolored.bluemap.core.world.LightData; +import net.querz.nbt.ByteArrayTag; +import net.querz.nbt.CompoundTag; +import net.querz.nbt.IntArrayTag; +import net.querz.nbt.ListTag; +import net.querz.nbt.StringTag; +import net.querz.nbt.Tag; +import net.querz.nbt.mca.MCAUtil; + +public class ChunkAnvil116 extends Chunk { + private BiomeMapper biomeIdMapper; + + private boolean isGenerated; + private boolean hasLight; + private Section[] sections; + private int[] biomes; + + @SuppressWarnings("unchecked") + public ChunkAnvil116(MCAWorld world, CompoundTag chunkTag, boolean ignoreMissingLightData) { + super(world, chunkTag); + + biomeIdMapper = getWorld().getBiomeIdMapper(); + + CompoundTag levelData = chunkTag.getCompoundTag("Level"); + + String status = levelData.getString("Status"); + isGenerated = status.equals("full") || status.equals("spawn"); // full is normal fully generated and spawn seems to be converted from old format but not yet loaded if you optimized your world + hasLight = isGenerated; + + if (!isGenerated && ignoreMissingLightData) { + isGenerated = !status.equals("empty"); + } + + 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? + if (levelData.containsKey("Sections")) { + for (CompoundTag sectionTag : ((ListTag) levelData.getListTag("Sections"))) { + Section section = new Section(sectionTag); + if (section.getSectionY() >= 0) sections[section.getSectionY()] = section; + } + } + + Tag tag = levelData.get("Biomes"); //tag can be byte-array or int-array + if (tag instanceof ByteArrayTag) { + byte[] bs = ((ByteArrayTag) tag).getValue(); + biomes = new int[bs.length]; + + for (int i = 0; i < bs.length; i++) { + biomes[i] = bs[i] & 0xFF; + } + } + else if (tag instanceof IntArrayTag) { + biomes = ((IntArrayTag) tag).getValue(); + } + + if (biomes == null || biomes.length == 0) { + biomes = new int[2048]; + } + } + + @Override + public boolean isGenerated() { + return isGenerated; + } + + @Override + public BlockState getBlockState(Vector3i pos) { + int sectionY = MCAUtil.blockToChunk(pos.getY()); + + Section section = this.sections[sectionY]; + if (section == null) return BlockState.AIR; + + return section.getBlockState(pos); + } + + @Override + public LightData getLightData(Vector3i pos) { + if (!hasLight) return LightData.SKY; + + int sectionY = MCAUtil.blockToChunk(pos.getY()); + + Section section = this.sections[sectionY]; + if (section == null) return LightData.SKY; + + return section.getLightData(pos); + } + + @Override + public Biome getBiome(Vector3i pos) { + int x = (pos.getX() & 0xF) / 4; // Math.floorMod(pos.getX(), 16) + int z = (pos.getZ() & 0xF) / 4; + int y = pos.getY() / 4; + int biomeIntIndex = y * 16 + z * 4 + x; + + return biomeIdMapper.get(biomes[biomeIntIndex]); + } + + private class Section { + private static final String AIR_ID = "minecraft:air"; + + private int sectionY; + private byte[] blockLight; + private byte[] skyLight; + private long[] blocks; + private BlockState[] palette; + + private int bitsPerBlock; + private int blocksPerLong; + + @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"); + + //read block palette + ListTag paletteTag = (ListTag) sectionData.getListTag("Palette"); + if (paletteTag != null) { + this.palette = new BlockState[paletteTag.size()]; + for (int i = 0; i < this.palette.length; i++) { + CompoundTag stateTag = paletteTag.get(i); + + String id = stateTag.getString("Name"); //shortcut to save time and memory + if (id.equals(AIR_ID)) { + palette[i] = BlockState.AIR; + continue; + } + + Map properties = new HashMap<>(); + + if (stateTag.containsKey("Properties")) { + CompoundTag propertiesTag = stateTag.getCompoundTag("Properties"); + for (Entry> property : propertiesTag) { + properties.put(property.getKey().toLowerCase(), ((StringTag) property.getValue()).getValue().toLowerCase()); + } + } + + palette[i] = new BlockState(id, properties); + } + } else { + this.palette = new BlockState[0]; + } + + + this.bitsPerBlock = 32 - Integer.numberOfLeadingZeros(palette.length - 1); + if (this.bitsPerBlock < 4) this.bitsPerBlock = 4; + this.blocksPerLong = 64 / bitsPerBlock; + } + + public int getSectionY() { + return sectionY; + } + + public BlockState getBlockState(Vector3i pos) { + if (blocks.length == 0) return BlockState.AIR; + + int x = pos.getX() & 0xF; // Math.floorMod(pos.getX(), 16) + int y = pos.getY() & 0xF; + int z = pos.getZ() & 0xF; + int blockIndex = y * 256 + z * 16 + x; + int longIndex = blockIndex / blocksPerLong; + int bitIndex = (blockIndex % blocksPerLong) * bitsPerBlock; + + long value = blocks[longIndex] >>> bitIndex; + + value = value & (0xFFFFFFFFFFFFFFFFL >>> -bitsPerBlock); + + if (value >= palette.length) { + Logger.global.noFloodWarning("palettewarning", "Got palette value " + value + " but palette has size of " + palette.length + "! (Future occasions of this error will not be logged)"); + return BlockState.MISSING; + } + + return palette[(int) value]; + } + + public LightData getLightData(Vector3i pos) { + int x = pos.getX() & 0xF; // Math.floorMod(pos.getX(), 16) + int y = pos.getY() & 0xF; + int z = pos.getZ() & 0xF; + int blockByteIndex = y * 256 + z * 16 + x; + int blockHalfByteIndex = blockByteIndex >> 1; // blockByteIndex / 2 + boolean largeHalf = (blockByteIndex & 0x1) != 0; // (blockByteIndex % 2) == 0 + + int blockLight = getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf); + int skyLight = getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf); + + return new LightData(skyLight, blockLight); + } + + /** + * Extracts the 4 bits of the left (largeHalf = true) or the right (largeHalf = false) side of the byte stored in value.
+ * The value is treated as an unsigned byte. + */ + private int getByteHalf(int value, boolean largeHalf) { + value = value & 0xFF; + if (largeHalf) { + value = value >> 4; + } + value = value & 0xF; + return value; + } + } + +} From ebbdd225cce008e029d2c91c209d113cbdb1f515 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Sat, 30 May 2020 19:50:55 +0200 Subject: [PATCH 03/29] Change forge version to 1.14.4 in mc/1.13 release --- BlueMapForge/build.gradle | 4 ++-- BlueMapForge/src/main/resources/META-INF/mods.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BlueMapForge/build.gradle b/BlueMapForge/build.gradle index 88cf872c..eea31226 100644 --- a/BlueMapForge/build.gradle +++ b/BlueMapForge/build.gradle @@ -20,7 +20,7 @@ configurations { } dependencies { - minecraft 'net.minecraftforge:forge:1.15.2-31.1.0' + minecraft 'net.minecraftforge:forge:1.14.4-28.2.0' include (project(':BlueMapCommon')) { //exclude dependencies provided by forge @@ -33,7 +33,7 @@ dependencies { } build.dependsOn shadowJar { - destinationDir = file '../build/unsupported' + destinationDir = file '../build/release' archiveFileName = "BlueMap-${version}-forge.jar" configurations = [project.configurations.include] diff --git a/BlueMapForge/src/main/resources/META-INF/mods.toml b/BlueMapForge/src/main/resources/META-INF/mods.toml index 253c1248..94389c57 100644 --- a/BlueMapForge/src/main/resources/META-INF/mods.toml +++ b/BlueMapForge/src/main/resources/META-INF/mods.toml @@ -20,6 +20,6 @@ A 3d-map of your Minecraft worlds view-able in your browser using three.js (WebG [[dependencies.bluemap]] modId="minecraft" mandatory=true - versionRange="[1.15.2]" + versionRange="[1.14.4]" ordering="NONE" side="SERVER" \ No newline at end of file From 0fe7cf94a9072ed8014bfc272cfc1ecfb64530da Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Thu, 2 Jul 2020 16:41:19 +0200 Subject: [PATCH 04/29] Add texture-key check. Fixes #53 --- .../bluemap/core/resourcepack/BlockModelResource.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resourcepack/BlockModelResource.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resourcepack/BlockModelResource.java index 13e767a0..47fce7ad 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resourcepack/BlockModelResource.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/resourcepack/BlockModelResource.java @@ -269,7 +269,6 @@ private BlockModelResource buildNoReset(String modelPath, boolean renderElements for (Entry entry : config.getNode("textures").getChildrenMap().entrySet()) { if (entry.getKey().equals(JSON_COMMENT)) continue; - textures.putIfAbsent(entry.getKey().toString(), entry.getValue().getString(null)); } @@ -426,6 +425,8 @@ private Vector4f readVector4f(ConfigurationNode node) throws ParseResourceExcept } private Texture getTexture(String key) throws NoSuchElementException, FileNotFoundException, IOException { + if (key.isEmpty() || key.equals("#")) throw new NoSuchElementException("Empty texture key or name!"); + if (key.charAt(0) == '#') { String value = textures.get(key.substring(1)); if (value == null) throw new NoSuchElementException("There is no texture defined for the key " + key); From a2cefd78aa4d73c6382bee17ebea730fe12a657f Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Thu, 2 Jul 2020 17:11:38 +0200 Subject: [PATCH 05/29] Change command requirements for base command. Fixes #52 --- .../bluemap/common/plugin/commands/Commands.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) 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 8fc439a5..4b53a890 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 @@ -87,7 +87,7 @@ public void init() { // commands LiteralCommandNode baseCommand = literal("bluemap") - .requires(requirements("bluemap.status")) + .requires(requirementsUnloaded("bluemap.status")) .executes(this::statusCommand) .build(); @@ -277,6 +277,11 @@ private Optional parseUUID(String uuidString) { public int statusCommand(CommandContext context) { CommandSource source = commandSourceInterface.apply(context.getSource()); + if (!plugin.isLoaded()) { + source.sendMessage(Text.of(TextColor.RED, "BlueMap is not loaded! Try /bluemap reload")); + return 0; + } + source.sendMessages(helper.createStatusMessage()); return 1; } From 53093a43ff7ac1bbae3b7c2818995ea1410bf271 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Thu, 2 Jul 2020 17:14:16 +0200 Subject: [PATCH 06/29] Fix map name being compared instead of map-id. Fixes #51 --- .../de/bluecolored/bluemap/common/plugin/commands/Commands.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4b53a890..3404c6bb 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 @@ -255,7 +255,7 @@ private Optional parseWorld(String worldName) { private Optional parseMap(String mapId) { for (MapType map : plugin.getMapTypes()) { - if (map.getName().equalsIgnoreCase(mapId)) { + if (map.getId().equalsIgnoreCase(mapId)) { return Optional.of(map); } } From 4c65c475ddf1c2f109f3a82f7bd298c29e1b0fbb Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Thu, 2 Jul 2020 17:20:27 +0200 Subject: [PATCH 07/29] Fix possible NPE when loading render-manager state. Fixes #46 --- .../main/java/de/bluecolored/bluemap/common/RenderManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7c9935e0..53f1ac9c 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/RenderManager.java @@ -265,7 +265,7 @@ public void readState(DataInputStream in, Collection mapTypes) throws I tiles.add(tile); } - createTickets(mapType, tiles); + if (mapType != null) createTickets(mapType, tiles); } //read tasks From 4fbd785b3e32a61eb8b0b3685d698a3768b6f5e6 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Thu, 2 Jul 2020 17:37:58 +0200 Subject: [PATCH 08/29] Catch exception when a model defines a collapsed face. Fixes #43 --- .../hires/blockmodel/ResourceModelBuilder.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/hires/blockmodel/ResourceModelBuilder.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/hires/blockmodel/ResourceModelBuilder.java index 3acc10de..b5515cd4 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/hires/blockmodel/ResourceModelBuilder.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/render/hires/blockmodel/ResourceModelBuilder.java @@ -189,8 +189,17 @@ private void createElementFace(BlockStateModel model, TransformedBlockModelResou Texture texture = face.getTexture(); int textureId = texture.getId(); - ExtendedFace f1 = new ExtendedFace(c0, c1, c2, uvs[0], uvs[1], uvs[2], textureId); - ExtendedFace f2 = new ExtendedFace(c0, c2, c3, uvs[0], uvs[2], uvs[3], textureId); + ExtendedFace f1; + ExtendedFace f2; + + try { + f1 = new ExtendedFace(c0, c1, c2, uvs[0], uvs[1], uvs[2], textureId); + f2 = new ExtendedFace(c0, c2, c3, uvs[0], uvs[2], uvs[3], textureId); + } catch (ArithmeticException ex) { + // This error is thrown when a model defined a face that has no surface (all 3 points are on one line) + // we catch it here and simply ignore the face + return; + } //tint the face Vector3f color = Vector3f.ONE; From 4ea40c7611cc57730f03a3a61537a741c41af6b3 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Thu, 2 Jul 2020 19:52:28 +0200 Subject: [PATCH 09/29] Define EPSILON, since it seems not to be defined by default on all systems. Fixes #48 --- .../src/main/webroot/js/libs/shaders/HiresVertexShader.js | 1 + .../src/main/webroot/js/libs/shaders/LowresVertexShader.js | 1 + 2 files changed, 2 insertions(+) diff --git a/BlueMapCore/src/main/webroot/js/libs/shaders/HiresVertexShader.js b/BlueMapCore/src/main/webroot/js/libs/shaders/HiresVertexShader.js index 0feab341..e0f1cfe1 100644 --- a/BlueMapCore/src/main/webroot/js/libs/shaders/HiresVertexShader.js +++ b/BlueMapCore/src/main/webroot/js/libs/shaders/HiresVertexShader.js @@ -25,6 +25,7 @@ import { ShaderChunk } from 'three'; const HIRES_VERTEX_SHADER = ` +#define EPSILON 1e-6 ${ShaderChunk.logdepthbuf_pars_vertex} attribute float ao; diff --git a/BlueMapCore/src/main/webroot/js/libs/shaders/LowresVertexShader.js b/BlueMapCore/src/main/webroot/js/libs/shaders/LowresVertexShader.js index ae9a4485..8cd668f5 100644 --- a/BlueMapCore/src/main/webroot/js/libs/shaders/LowresVertexShader.js +++ b/BlueMapCore/src/main/webroot/js/libs/shaders/LowresVertexShader.js @@ -25,6 +25,7 @@ import { ShaderChunk } from 'three'; const LOWRES_VERTEX_SHADER = ` +#define EPSILON 1e-6 ${ShaderChunk.logdepthbuf_pars_vertex} varying vec3 vPosition; From 15cbfe13cb92a71988eebcf9f43b6da6b9dea856 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Thu, 2 Jul 2020 20:00:04 +0200 Subject: [PATCH 10/29] Push version for release --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 65f6b8f7..bc6dfb76 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -coreVersion=0.7.0 +coreVersion=0.8.0 targetVersion=mc1.13 \ No newline at end of file From 0600425a69d5aaa37acabb0e8981c753f2713b5f Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 10:49:00 +0200 Subject: [PATCH 11/29] 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 12/29] 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 13/29] 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 14/29] 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 15/29] 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 16/29] 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 17/29] 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 18/29] 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 19/29] 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 20/29] 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 21/29] 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) )); From 4beb00ba9e93e6ba07bf36d3cf1789d0f975248e Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 21:09:47 +0200 Subject: [PATCH 22/29] Fix empty sections now not being detected --- .../bluecolored/bluemap/core/mca/ChunkAnvil113.java | 12 +++++++----- .../bluecolored/bluemap/core/mca/ChunkAnvil115.java | 12 +++++++----- .../bluecolored/bluemap/core/mca/ChunkAnvil116.java | 12 +++++++----- 3 files changed, 21 insertions(+), 15 deletions(-) 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 ef6c2a02..60cd87b2 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 @@ -152,9 +152,9 @@ public Section(CompoundTag sectionData) { this.skyLight = sectionData.getByteArray("SkyLight"); 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); + if (blocks.length < 256 && blocks.length > 0) blocks = Arrays.copyOf(blocks, 256); + if (blockLight.length < 2048 && blockLight.length > 0) blockLight = Arrays.copyOf(blockLight, 2048); + if (skyLight.length < 2048 && skyLight.length > 0) skyLight = Arrays.copyOf(skyLight, 2048); //read block palette ListTag paletteTag = (ListTag) sectionData.getListTag("Palette"); @@ -221,6 +221,8 @@ public BlockState getBlockState(Vector3i pos) { } public LightData getLightData(Vector3i pos) { + if (blockLight.length == 0 && skyLight.length == 0) return LightData.ZERO; + int x = pos.getX() & 0xF; // Math.floorMod(pos.getX(), 16) int y = pos.getY() & 0xF; int z = pos.getZ() & 0xF; @@ -228,8 +230,8 @@ public LightData getLightData(Vector3i pos) { int blockHalfByteIndex = blockByteIndex >> 1; // blockByteIndex / 2 boolean largeHalf = (blockByteIndex & 0x1) != 0; // (blockByteIndex % 2) == 0 - int blockLight = getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf); - int skyLight = getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf); + int blockLight = this.blockLight.length > 0 ? getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0; + int skyLight = this.skyLight.length > 0 ? getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0; return new LightData(skyLight, blockLight); } 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 2ebfa8a0..4b36ad1e 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 @@ -153,9 +153,9 @@ public Section(CompoundTag sectionData) { this.skyLight = sectionData.getByteArray("SkyLight"); 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); + if (blocks.length < 256 && blocks.length > 0) blocks = Arrays.copyOf(blocks, 256); + if (blockLight.length < 2048 && blockLight.length > 0) blockLight = Arrays.copyOf(blockLight, 2048); + if (skyLight.length < 2048 && skyLight.length > 0) skyLight = Arrays.copyOf(skyLight, 2048); //read block palette ListTag paletteTag = (ListTag) sectionData.getListTag("Palette"); @@ -222,6 +222,8 @@ public BlockState getBlockState(Vector3i pos) { } public LightData getLightData(Vector3i pos) { + if (blockLight.length == 0 && skyLight.length == 0) return LightData.ZERO; + int x = pos.getX() & 0xF; // Math.floorMod(pos.getX(), 16) int y = pos.getY() & 0xF; int z = pos.getZ() & 0xF; @@ -229,8 +231,8 @@ public LightData getLightData(Vector3i pos) { int blockHalfByteIndex = blockByteIndex >> 1; // blockByteIndex / 2 boolean largeHalf = (blockByteIndex & 0x1) != 0; // (blockByteIndex % 2) == 0 - int blockLight = getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf); - int skyLight = getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf); + int blockLight = this.blockLight.length > 0 ? getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0; + int skyLight = this.skyLight.length > 0 ? getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0; return new LightData(skyLight, blockLight); } 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 0d0d7c1a..bb185642 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 @@ -154,9 +154,9 @@ public Section(CompoundTag sectionData) { this.skyLight = sectionData.getByteArray("SkyLight"); 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); + if (blocks.length < 256 && blocks.length > 0) blocks = Arrays.copyOf(blocks, 256); + if (blockLight.length < 2048 && blockLight.length > 0) blockLight = Arrays.copyOf(blockLight, 2048); + if (skyLight.length < 2048 && skyLight.length > 0) skyLight = Arrays.copyOf(skyLight, 2048); //read block palette ListTag paletteTag = (ListTag) sectionData.getListTag("Palette"); @@ -219,6 +219,8 @@ public BlockState getBlockState(Vector3i pos) { } public LightData getLightData(Vector3i pos) { + if (blockLight.length == 0 && skyLight.length == 0) return LightData.ZERO; + int x = pos.getX() & 0xF; // Math.floorMod(pos.getX(), 16) int y = pos.getY() & 0xF; int z = pos.getZ() & 0xF; @@ -226,8 +228,8 @@ public LightData getLightData(Vector3i pos) { int blockHalfByteIndex = blockByteIndex >> 1; // blockByteIndex / 2 boolean largeHalf = (blockByteIndex & 0x1) != 0; // (blockByteIndex % 2) == 0 - int blockLight = getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf); - int skyLight = getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf); + int blockLight = this.blockLight.length > 0 ? getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0; + int skyLight = this.skyLight.length > 0 ? getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0; return new LightData(skyLight, blockLight); } From 7dbff21f40a1fd6556ab917dbc0daa9c8eec14d6 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Wed, 29 Jul 2020 21:18:44 +0200 Subject: [PATCH 23/29] Push version for next release --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index bc6dfb76..36429b4f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,6 +1,6 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -coreVersion=0.8.0 +coreVersion=0.9.0 targetVersion=mc1.13 \ No newline at end of file From 68f32057929c43aa6ca4845cf0038ec08e5ce701 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Thu, 30 Jul 2020 17:05:17 +0200 Subject: [PATCH 24/29] Update SpongeAPI version to 7.2.0 --- BlueMapSponge/build.gradle | 2 +- .../bluecolored/bluemap/sponge/SpongePlugin.java | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/BlueMapSponge/build.gradle b/BlueMapSponge/build.gradle index 5e5de5aa..b5481d12 100644 --- a/BlueMapSponge/build.gradle +++ b/BlueMapSponge/build.gradle @@ -1,5 +1,5 @@ dependencies { - shadow "org.spongepowered:spongeapi:7.1.0-SNAPSHOT" + shadow "org.spongepowered:spongeapi:7.2.0" compile group: 'org.bstats', name: 'bstats-sponge-lite', version: '1.5' compile (project(':BlueMapCommon')) { diff --git a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java b/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java index a6fc6ee3..1cb01c3b 100644 --- a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java +++ b/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java @@ -39,7 +39,9 @@ import org.spongepowered.api.event.game.GameReloadEvent; import org.spongepowered.api.event.game.state.GameStartingServerEvent; import org.spongepowered.api.event.game.state.GameStoppingEvent; +import org.spongepowered.api.plugin.PluginContainer; import org.spongepowered.api.scheduler.SpongeExecutorService; +import org.spongepowered.api.util.Tristate; import org.spongepowered.api.world.World; import org.spongepowered.api.world.storage.WorldProperties; @@ -161,4 +163,17 @@ public File getConfigFolder() { return configurationDir.toFile(); } + @Override + public boolean isMetricsEnabled(boolean configValue) { + PluginContainer pluginContainer = Sponge.getPluginManager().fromInstance(this).orElse(null); + if (pluginContainer != null) { + Tristate metricsEnabled = Sponge.getMetricsConfigManager().getCollectionState(pluginContainer); + if (metricsEnabled != Tristate.UNDEFINED) { + return metricsEnabled == Tristate.TRUE ? true : false; + } + } + + return Sponge.getMetricsConfigManager().getGlobalCollectionState().asBoolean(); + } + } From 581e0d87005c1d571490b64af27a26ba5907d70d Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Thu, 30 Jul 2020 17:15:26 +0200 Subject: [PATCH 25/29] Add api-version to plugin.yml --- BlueMapBukkit/src/main/resources/plugin.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/BlueMapBukkit/src/main/resources/plugin.yml b/BlueMapBukkit/src/main/resources/plugin.yml index 88cae5be..0db125e0 100644 --- a/BlueMapBukkit/src/main/resources/plugin.yml +++ b/BlueMapBukkit/src/main/resources/plugin.yml @@ -2,6 +2,7 @@ name: BlueMap description: "A 3d-map of your Minecraft worlds view-able in your browser using three.js (WebGL)" main: de.bluecolored.bluemap.bukkit.BukkitPlugin version: ${version} +api-version: 1.13 author: "Blue (TBlueF / Lukas Rieger)" website: "https://github.com/BlueMap-Minecraft" commands: From 2fc13ca258459e9c14c4a506c67b56284e133661 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Fri, 31 Jul 2020 00:44:34 +0200 Subject: [PATCH 26/29] Fix bluemap not saving anything on shutdown on sponge --- .../main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java | 1 + 1 file changed, 1 insertion(+) diff --git a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java b/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java index 1cb01c3b..5ddabf19 100644 --- a/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java +++ b/BlueMapSponge/src/main/java/de/bluecolored/bluemap/sponge/SpongePlugin.java @@ -135,6 +135,7 @@ public void registerListener(ServerEventListener listener) { @Override public void unregisterAllListeners() { Sponge.getEventManager().unregisterPluginListeners(this); + Sponge.getEventManager().registerListeners(this, this); } @Override From 2a0aecf3591a3e67ae9da8398e8bb5c5fd56c1ef Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Fri, 31 Jul 2020 09:50:25 +0200 Subject: [PATCH 27/29] Add tint-color for the stonecutter. Fixes #63 --- BlueMapCore/src/main/resources/blockColors.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/BlueMapCore/src/main/resources/blockColors.json b/BlueMapCore/src/main/resources/blockColors.json index 24cf4889..b5c34f4e 100644 --- a/BlueMapCore/src/main/resources/blockColors.json +++ b/BlueMapCore/src/main/resources/blockColors.json @@ -9,5 +9,6 @@ "minecraft:large_fern": "@grass", "minecraft:redstone_wire": "#ff0000", "minecraft:birch_leaves": "#86a863", - "minecraft:spruce_leaves": "#51946b" + "minecraft:spruce_leaves": "#51946b", + "minecraft:stonecutter": "#ffffff" } \ No newline at end of file From e40c3bd0d515dc2ea6843fd8fd49bcbb05c5fb58 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Mon, 3 Aug 2020 00:10:00 +0200 Subject: [PATCH 28/29] Change hash code generation to improve performance --- .../main/java/de/bluecolored/bluemap/core/mca/MCAWorld.java | 3 +-- 1 file changed, 1 insertion(+), 2 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 e2251f21..bbf95e66 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 @@ -38,7 +38,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.function.Predicate; @@ -506,7 +505,7 @@ public WorldChunkHash(MCAWorld world, Vector2i chunk) { @Override public int hashCode() { - return Objects.hash(world, chunk); + return (world.hashCode() * 31 + chunk.getX()) * 31 + chunk.getY(); } @Override From 9283f2caec15c86dc293442feefcc754e5213135 Mon Sep 17 00:00:00 2001 From: "Blue (Lukas Rieger)" Date: Mon, 3 Aug 2020 00:10:37 +0200 Subject: [PATCH 29/29] Tidy up some chunkloading math --- .../bluemap/core/mca/ChunkAnvil113.java | 31 +------- .../bluemap/core/mca/ChunkAnvil115.java | 31 +------- .../bluemap/core/mca/ChunkAnvil116.java | 26 +------ .../bluecolored/bluemap/core/mca/MCAMath.java | 74 +++++++++++++++++++ 4 files changed, 83 insertions(+), 79 deletions(-) create mode 100644 BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAMath.java 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 60cd87b2..4871b80b 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 @@ -198,20 +198,8 @@ public BlockState getBlockState(Vector3i pos) { int y = pos.getY() & 0xF; int z = pos.getZ() & 0xF; int blockIndex = y * 256 + z * 16 + x; - int index = blockIndex * bitsPerBlock; - int firstLong = index >> 6; // index / 64 - int bitoffset = index & 0x3F; // Math.floorMod(index, 64) - - long value = blocks[firstLong] >>> bitoffset; - - if (bitoffset > 0 && firstLong + 1 < blocks.length) { - long value2 = blocks[firstLong + 1]; - value2 = value2 << -bitoffset; - value = value | value2; - } - - value = value & (0xFFFFFFFFFFFFFFFFL >>> -bitsPerBlock); + long value = MCAMath.getValueFromLongStream(blocks, blockIndex, bitsPerBlock); if (value >= palette.length) { Logger.global.noFloodWarning("palettewarning", "Got palette value " + value + " but palette has size of " + palette.length + " (Future occasions of this error will not be logged)"); return BlockState.MISSING; @@ -230,24 +218,11 @@ public LightData getLightData(Vector3i pos) { int blockHalfByteIndex = blockByteIndex >> 1; // blockByteIndex / 2 boolean largeHalf = (blockByteIndex & 0x1) != 0; // (blockByteIndex % 2) == 0 - int blockLight = this.blockLight.length > 0 ? getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0; - int skyLight = this.skyLight.length > 0 ? getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0; + int blockLight = this.blockLight.length > 0 ? MCAMath.getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0; + int skyLight = this.skyLight.length > 0 ? MCAMath.getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0; return new LightData(skyLight, blockLight); } - - /** - * Extracts the 4 bits of the left (largeHalf = true) or the right (largeHalf = false) side of the byte stored in value.
- * The value is treated as an unsigned byte. - */ - private int getByteHalf(int value, boolean largeHalf) { - value = value & 0xFF; - if (largeHalf) { - value = value >> 4; - } - value = value & 0xF; - return value; - } } } 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 4b36ad1e..c96b8932 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 @@ -199,20 +199,8 @@ public BlockState getBlockState(Vector3i pos) { int y = pos.getY() & 0xF; int z = pos.getZ() & 0xF; int blockIndex = y * 256 + z * 16 + x; - int index = blockIndex * bitsPerBlock; - int firstLong = index >> 6; // index / 64 - int bitoffset = index & 0x3F; // Math.floorMod(index, 64) - - long value = blocks[firstLong] >>> bitoffset; - - if (bitoffset > 0 && firstLong + 1 < blocks.length) { - long value2 = blocks[firstLong + 1]; - value2 = value2 << -bitoffset; - value = value | value2; - } - - value = value & (0xFFFFFFFFFFFFFFFFL >>> -bitsPerBlock); + long value = MCAMath.getValueFromLongStream(blocks, blockIndex, bitsPerBlock); if (value >= palette.length) { Logger.global.noFloodWarning("palettewarning", "Got palette value " + value + " but palette has size of " + palette.length + " (Future occasions of this error will not be logged)"); return BlockState.MISSING; @@ -231,24 +219,11 @@ public LightData getLightData(Vector3i pos) { int blockHalfByteIndex = blockByteIndex >> 1; // blockByteIndex / 2 boolean largeHalf = (blockByteIndex & 0x1) != 0; // (blockByteIndex % 2) == 0 - int blockLight = this.blockLight.length > 0 ? getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0; - int skyLight = this.skyLight.length > 0 ? getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0; + int blockLight = this.blockLight.length > 0 ? MCAMath.getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0; + int skyLight = this.skyLight.length > 0 ? MCAMath.getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0; return new LightData(skyLight, blockLight); } - - /** - * Extracts the 4 bits of the left (largeHalf = true) or the right (largeHalf = false) side of the byte stored in value.
- * The value is treated as an unsigned byte. - */ - private int getByteHalf(int value, boolean largeHalf) { - value = value & 0xFF; - if (largeHalf) { - value = value >> 4; - } - value = value & 0xF; - return value; - } } } 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 bb185642..637a467f 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 @@ -145,7 +145,6 @@ private class Section { private BlockState[] palette; private int bitsPerBlock; - private int blocksPerLong; @SuppressWarnings("unchecked") public Section(CompoundTag sectionData) { @@ -189,7 +188,6 @@ public Section(CompoundTag sectionData) { this.bitsPerBlock = 32 - Integer.numberOfLeadingZeros(palette.length - 1); if (this.bitsPerBlock < 4) this.bitsPerBlock = 4; - this.blocksPerLong = 64 / bitsPerBlock; } public int getSectionY() { @@ -203,13 +201,8 @@ public BlockState getBlockState(Vector3i pos) { int y = pos.getY() & 0xF; int z = pos.getZ() & 0xF; int blockIndex = y * 256 + z * 16 + x; - int longIndex = blockIndex / blocksPerLong; - int bitIndex = (blockIndex % blocksPerLong) * bitsPerBlock; - - long value = blocks[longIndex] >>> bitIndex; - value = value & (0xFFFFFFFFFFFFFFFFL >>> -bitsPerBlock); - + long value = MCAMath.getValueFromLongArray(blocks, blockIndex, bitsPerBlock); if (value >= palette.length) { Logger.global.noFloodWarning("palettewarning", "Got palette value " + value + " but palette has size of " + palette.length + "! (Future occasions of this error will not be logged)"); return BlockState.MISSING; @@ -228,24 +221,11 @@ public LightData getLightData(Vector3i pos) { int blockHalfByteIndex = blockByteIndex >> 1; // blockByteIndex / 2 boolean largeHalf = (blockByteIndex & 0x1) != 0; // (blockByteIndex % 2) == 0 - int blockLight = this.blockLight.length > 0 ? getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0; - int skyLight = this.skyLight.length > 0 ? getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0; + int blockLight = this.blockLight.length > 0 ? MCAMath.getByteHalf(this.blockLight[blockHalfByteIndex], largeHalf) : 0; + int skyLight = this.skyLight.length > 0 ? MCAMath.getByteHalf(this.skyLight[blockHalfByteIndex], largeHalf) : 0; return new LightData(skyLight, blockLight); } - - /** - * Extracts the 4 bits of the left (largeHalf = true) or the right (largeHalf = false) side of the byte stored in value.
- * The value is treated as an unsigned byte. - */ - private int getByteHalf(int value, boolean largeHalf) { - value = value & 0xFF; - if (largeHalf) { - value = value >> 4; - } - value = value & 0xF; - return value; - } } } diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAMath.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAMath.java new file mode 100644 index 00000000..e8ccf810 --- /dev/null +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/mca/MCAMath.java @@ -0,0 +1,74 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package de.bluecolored.bluemap.core.mca; + +public class MCAMath { + + /** + * Having a long array where each long contains as many values as fit in it without overflowing, returning the "valueIndex"-th value when each value has "bitsPerValue" bits. + */ + public static long getValueFromLongArray(long[] data, int valueIndex, int bitsPerValue) { + int valuesPerLong = 64 / bitsPerValue; + int longIndex = valueIndex / valuesPerLong; + int bitIndex = (valueIndex % valuesPerLong) * bitsPerValue; + + long value = data[longIndex] >>> bitIndex; + + return value & (0xFFFFFFFFFFFFFFFFL >>> -bitsPerValue); + } + + /** + * Treating the long array "data" as a continuous stream of bits, returning the "valueIndex"-th value when each value has "bitsPerValue" bits. + */ + public static long getValueFromLongStream(long[] data, int valueIndex, int bitsPerValue) { + int bitIndex = valueIndex * bitsPerValue; + int firstLong = bitIndex >> 6; // index / 64 + int bitoffset = bitIndex & 0x3F; // Math.floorMod(index, 64) + + long value = data[firstLong] >>> bitoffset; + + if (bitoffset > 0 && firstLong + 1 < data.length) { + long value2 = data[firstLong + 1]; + value2 = value2 << -bitoffset; + value = value | value2; + } + + return value & (0xFFFFFFFFFFFFFFFFL >>> -bitsPerValue); + } + + /** + * Extracts the 4 bits of the left (largeHalf = true) or the right (largeHalf = false) side of the byte stored in value.
+ * The value is treated as an unsigned byte. + */ + public static int getByteHalf(int value, boolean largeHalf) { + value = value & 0xFF; + if (largeHalf) { + value = value >> 4; + } + value = value & 0xF; + return value; + } + +}