diff --git a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java index 02ffa629..7c0ef346 100644 --- a/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java +++ b/BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/Plugin.java @@ -189,7 +189,7 @@ public synchronized void load() throws IOException, ParseResourceException { World world = worlds.get(worldUUID); if (world == null) { try { - world = MCAWorld.load(worldFolder.toPath(), worldUUID, configManager.getBlockIdConfig(), configManager.getBlockPropertiesConfig(), configManager.getBiomeConfig(), serverInterface.getWorldName(worldUUID)); + world = MCAWorld.load(worldFolder.toPath(), worldUUID, configManager.getBlockIdConfig(), configManager.getBlockPropertiesConfig(), configManager.getBiomeConfig(), serverInterface.getWorldName(worldUUID), true); worlds.put(worldUUID, world); } catch (IOException e) { Logger.global.logError("Failed to load map '" + id + "': Failed to read level.dat", e); diff --git a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/config/MainConfig.java b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/config/MainConfig.java index 8b7feca6..767be0d4 100644 --- a/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/config/MainConfig.java +++ b/BlueMapCore/src/main/java/de/bluecolored/bluemap/core/config/MainConfig.java @@ -31,6 +31,7 @@ import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.regex.Pattern; import com.flowpowered.math.vector.Vector2i; import com.flowpowered.math.vector.Vector3i; @@ -42,6 +43,7 @@ import ninja.leaping.configurate.ConfigurationNode; public class MainConfig implements WebServerConfig { + private static final Pattern VALID_ID_PATTERN = Pattern.compile("[a-zA-Z0-9_]+"); private boolean downloadAccepted = false; private boolean metricsEnabled = false; @@ -207,6 +209,7 @@ public class MapConfig implements RenderSettings { private boolean renderEdges; private boolean useGzip; + private boolean ignoreMissingLightData; private int hiresTileSize; @@ -216,6 +219,7 @@ public class MapConfig implements RenderSettings { private MapConfig(ConfigurationNode node) throws IOException { this.id = node.getNode("id").getString(""); if (id.isEmpty()) throw new IOException("Invalid configuration: Node maps[?].id is not defined"); + if (!VALID_ID_PATTERN.matcher(id).matches()) throw new IOException("Invalid configuration: Node maps[?].id '" + id + "' has invalid characters in it"); this.name = node.getNode("name").getString(id); @@ -243,6 +247,7 @@ private MapConfig(ConfigurationNode node) throws IOException { this.renderEdges = node.getNode("renderEdges").getBoolean(true); this.useGzip = node.getNode("useCompression").getBoolean(true); + this.ignoreMissingLightData = node.getNode("ignoreMissingLightData").getBoolean(false); this.hiresTileSize = node.getNode("hires", "tileSize").getInt(32); @@ -319,6 +324,10 @@ public boolean useGzipCompression() { return useGzip; } + public boolean isIgnoreMissingLightData() { + return ignoreMissingLightData; + } + } private void checkOutdated(ConfigurationNode node) throws OutdatedConfigException { 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 89272a17..073afc25 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 @@ -71,12 +71,12 @@ public MCAWorld getWorld() { public abstract Biome getBiome(Vector3i pos); - public static Chunk create(MCAWorld world, CompoundTag chunkTag) throws IOException { + public static Chunk create(MCAWorld world, CompoundTag chunkTag, boolean ignoreMissingLightData) throws IOException { int version = chunkTag.getInt("DataVersion"); - if (version <= 1343) return new ChunkAnvil112(world, chunkTag); - if (version <= 1976) return new ChunkAnvil113(world, chunkTag); - return new ChunkAnvil115(world, chunkTag); + if (version <= 1343) return new ChunkAnvil112(world, chunkTag, ignoreMissingLightData); + if (version <= 1976) return new ChunkAnvil113(world, chunkTag, ignoreMissingLightData); + return new ChunkAnvil115(world, chunkTag, ignoreMissingLightData); } public static Chunk empty(MCAWorld world, Vector2i chunkPos) { 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 22e41950..9ddf7119 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 @@ -40,11 +40,12 @@ public class ChunkAnvil112 extends Chunk { private BiomeMapper biomeIdMapper; private boolean isGenerated; + private boolean hasLight; private Section[] sections; private byte[] biomes; @SuppressWarnings("unchecked") - public ChunkAnvil112(MCAWorld world, CompoundTag chunkTag) { + public ChunkAnvil112(MCAWorld world, CompoundTag chunkTag, boolean ignoreMissingLightData) { super(world, chunkTag); blockIdMapper = getWorld().getBlockIdMapper(); @@ -52,8 +53,10 @@ public ChunkAnvil112(MCAWorld world, CompoundTag chunkTag) { CompoundTag levelData = chunkTag.getCompoundTag("Level"); + hasLight = levelData.getBoolean("LightPopulated"); + isGenerated = - levelData.getBoolean("LightPopulated") && + (hasLight || ignoreMissingLightData) && 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? @@ -95,6 +98,8 @@ public String getBlockIdMeta(Vector3i pos) { @Override public LightData getLightData(Vector3i pos) { + if (!hasLight) return LightData.SKY; + int sectionY = MCAUtil.blockToChunk(pos.getY()); Section section = this.sections[sectionY]; 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 0d0ff724..0a67022e 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 @@ -47,11 +47,12 @@ public class ChunkAnvil113 extends Chunk { private BiomeMapper biomeIdMapper; private boolean isGenerated; + private boolean hasLight; private Section[] sections; private int[] biomes; @SuppressWarnings("unchecked") - public ChunkAnvil113(MCAWorld world, CompoundTag chunkTag) { + public ChunkAnvil113(MCAWorld world, CompoundTag chunkTag, boolean ignoreMissingLightData) { super(world, chunkTag); biomeIdMapper = getWorld().getBiomeIdMapper(); @@ -60,6 +61,11 @@ public ChunkAnvil113(MCAWorld world, CompoundTag chunkTag) { 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")) { @@ -104,6 +110,8 @@ public BlockState getBlockState(Vector3i pos) { @Override public LightData getLightData(Vector3i pos) { + if (!hasLight) return LightData.SKY; + int sectionY = MCAUtil.blockToChunk(pos.getY()); Section section = this.sections[sectionY]; 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 96fd4e95..0d2ebcbe 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 @@ -47,11 +47,12 @@ public class ChunkAnvil115 extends Chunk { private BiomeMapper biomeIdMapper; private boolean isGenerated; + private boolean hasLight; private Section[] sections; private int[] biomes; @SuppressWarnings("unchecked") - public ChunkAnvil115(MCAWorld world, CompoundTag chunkTag) { + public ChunkAnvil115(MCAWorld world, CompoundTag chunkTag, boolean ignoreMissingLightData) { super(world, chunkTag); biomeIdMapper = getWorld().getBiomeIdMapper(); @@ -60,6 +61,11 @@ public ChunkAnvil115(MCAWorld world, CompoundTag chunkTag) { 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")) { @@ -104,6 +110,8 @@ public BlockState getBlockState(Vector3i pos) { @Override public LightData getLightData(Vector3i pos) { + if (!hasLight) return LightData.SKY; + int sectionY = MCAUtil.blockToChunk(pos.getY()); Section section = this.sections[sectionY]; 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 d2a83760..42fa4b31 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 @@ -111,6 +111,8 @@ public class MCAWorld implements World { private BlockPropertiesMapper blockPropertiesMapper; private BiomeMapper biomeMapper; + private boolean ignoreMissingLightData; + private Map forgeBlockMappings; private MCAWorld( @@ -122,7 +124,8 @@ private MCAWorld( Vector3i spawnPoint, BlockIdMapper blockIdMapper, BlockPropertiesMapper blockPropertiesMapper, - BiomeMapper biomeMapper + BiomeMapper biomeMapper, + boolean ignoreMissingLightData ) { this.uuid = uuid; this.worldFolder = worldFolder; @@ -134,6 +137,8 @@ private MCAWorld( this.blockPropertiesMapper = blockPropertiesMapper; this.biomeMapper = biomeMapper; + this.ignoreMissingLightData = ignoreMissingLightData; + this.forgeBlockMappings = new HashMap<>(); } @@ -244,7 +249,7 @@ private Chunk loadChunk(Vector2i chunkPos) throws IOException { DataInputStream dis = new DataInputStream(new BufferedInputStream(compressionType.decompress(new FileInputStream(raf.getFD())))); Tag tag = Tag.deserialize(dis, Tag.DEFAULT_MAX_DEPTH); if (tag instanceof CompoundTag) { - return Chunk.create(this, (CompoundTag) tag); + return Chunk.create(this, (CompoundTag) tag, ignoreMissingLightData); } else { throw new IOException("invalid data tag: " + (tag == null ? "null" : tag.getClass().getName())); } @@ -379,10 +384,10 @@ private Path getMCAFilePath(Vector2i region) { } public static MCAWorld load(Path worldFolder, UUID uuid, BlockIdMapper blockIdMapper, BlockPropertiesMapper blockPropertiesMapper, BiomeMapper biomeIdMapper) throws IOException { - return load(worldFolder, uuid, blockIdMapper, blockPropertiesMapper, biomeIdMapper, null); + return load(worldFolder, uuid, blockIdMapper, blockPropertiesMapper, biomeIdMapper, null, false); } - public static MCAWorld load(Path worldFolder, UUID uuid, BlockIdMapper blockIdMapper, BlockPropertiesMapper blockPropertiesMapper, BiomeMapper biomeIdMapper, String name) throws IOException { + public static MCAWorld load(Path worldFolder, UUID uuid, BlockIdMapper blockIdMapper, BlockPropertiesMapper blockPropertiesMapper, BiomeMapper biomeIdMapper, String name, boolean ignoreMissingLightData) throws IOException { try { boolean subDimension = false; @@ -423,7 +428,8 @@ public static MCAWorld load(Path worldFolder, UUID uuid, BlockIdMapper blockIdMa spawnPoint, blockIdMapper, blockPropertiesMapper, - biomeIdMapper + biomeIdMapper, + ignoreMissingLightData ); try {