Sanity-check map-ids and add config to ignore missing light-data, fixes #35 and fixes #38

This commit is contained in:
Blue (Lukas Rieger) 2020-05-11 14:42:30 +02:00
parent 7c319d7ff7
commit 8a43c3e596
7 changed files with 50 additions and 14 deletions

View File

@ -189,7 +189,7 @@ public class Plugin {
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);

View File

@ -31,6 +31,7 @@ import java.nio.file.Path;
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 de.bluecolored.bluemap.core.web.WebServerConfig;
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 MainConfig implements WebServerConfig {
private boolean renderEdges;
private boolean useGzip;
private boolean ignoreMissingLightData;
private int hiresTileSize;
@ -216,6 +219,7 @@ public class MainConfig implements WebServerConfig {
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 @@ public class MainConfig implements WebServerConfig {
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 class MainConfig implements WebServerConfig {
return useGzip;
}
public boolean isIgnoreMissingLightData() {
return ignoreMissingLightData;
}
}
private void checkOutdated(ConfigurationNode node) throws OutdatedConfigException {

View File

@ -71,12 +71,12 @@ public abstract class Chunk {
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) {

View File

@ -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 class ChunkAnvil112 extends Chunk {
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 class ChunkAnvil112 extends Chunk {
@Override
public LightData getLightData(Vector3i pos) {
if (!hasLight) return LightData.SKY;
int sectionY = MCAUtil.blockToChunk(pos.getY());
Section section = this.sections[sectionY];

View File

@ -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 class ChunkAnvil113 extends Chunk {
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 class ChunkAnvil113 extends Chunk {
@Override
public LightData getLightData(Vector3i pos) {
if (!hasLight) return LightData.SKY;
int sectionY = MCAUtil.blockToChunk(pos.getY());
Section section = this.sections[sectionY];

View File

@ -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 class ChunkAnvil115 extends Chunk {
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 class ChunkAnvil115 extends Chunk {
@Override
public LightData getLightData(Vector3i pos) {
if (!hasLight) return LightData.SKY;
int sectionY = MCAUtil.blockToChunk(pos.getY());
Section section = this.sections[sectionY];

View File

@ -111,6 +111,8 @@ public class MCAWorld implements World {
private BlockPropertiesMapper blockPropertiesMapper;
private BiomeMapper biomeMapper;
private boolean ignoreMissingLightData;
private Map<Integer, String> forgeBlockMappings;
private MCAWorld(
@ -122,7 +124,8 @@ public class MCAWorld implements World {
Vector3i spawnPoint,
BlockIdMapper blockIdMapper,
BlockPropertiesMapper blockPropertiesMapper,
BiomeMapper biomeMapper
BiomeMapper biomeMapper,
boolean ignoreMissingLightData
) {
this.uuid = uuid;
this.worldFolder = worldFolder;
@ -134,6 +137,8 @@ public class MCAWorld implements World {
this.blockPropertiesMapper = blockPropertiesMapper;
this.biomeMapper = biomeMapper;
this.ignoreMissingLightData = ignoreMissingLightData;
this.forgeBlockMappings = new HashMap<>();
}
@ -244,7 +249,7 @@ public class MCAWorld implements World {
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 @@ public class MCAWorld implements World {
}
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 class MCAWorld implements World {
spawnPoint,
blockIdMapper,
blockPropertiesMapper,
biomeIdMapper
biomeIdMapper,
ignoreMissingLightData
);
try {