mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-12-26 10:58:00 +01:00
Improve Version-Management and add support for variable world-heights to be able to support custom 1.17 worlds
This commit is contained in:
parent
ecef2c4996
commit
67a0e2a0bf
@ -36,7 +36,7 @@ public class MinecraftVersion implements Comparable<MinecraftVersion> {
|
||||
|
||||
private static final Pattern VERSION_REGEX = Pattern.compile("(?:(?<major>\\d+)\\.(?<minor>\\d+))(?:\\.(?<patch>\\d+))?(?:\\-(?:pre|rc)\\d+)?");
|
||||
|
||||
public static final MinecraftVersion LATEST_SUPPORTED = new MinecraftVersion(1, 16, 5);
|
||||
public static final MinecraftVersion LATEST_SUPPORTED = new MinecraftVersion(1, 17, 0);
|
||||
public static final MinecraftVersion EARLIEST_SUPPORTED = new MinecraftVersion(1, 12, 2);
|
||||
public static final MinecraftVersion THE_FLATTENING = new MinecraftVersion(1, 13);
|
||||
|
||||
@ -145,7 +145,8 @@ public enum MinecraftResource {
|
||||
MC_1_14 (new MinecraftVersion(1, 14), "mc1_13", "https://launcher.mojang.com/v1/objects/8c325a0c5bd674dd747d6ebaa4c791fd363ad8a9/client.jar"),
|
||||
MC_1_15 (new MinecraftVersion(1, 15), "mc1_15", "https://launcher.mojang.com/v1/objects/e3f78cd16f9eb9a52307ed96ebec64241cc5b32d/client.jar"),
|
||||
MC_1_16 (new MinecraftVersion(1, 16), "mc1_16", "https://launcher.mojang.com/v1/objects/228fdf45541c4c2fe8aec4f20e880cb8fcd46621/client.jar"),
|
||||
MC_1_16_2 (new MinecraftVersion(1, 16, 2), "mc1_16", "https://launcher.mojang.com/v1/objects/653e97a2d1d76f87653f02242d243cdee48a5144/client.jar");
|
||||
MC_1_16_2 (new MinecraftVersion(1, 16, 2), "mc1_16", "https://launcher.mojang.com/v1/objects/653e97a2d1d76f87653f02242d243cdee48a5144/client.jar"),
|
||||
MC_1_17_0_PRE (new MinecraftVersion(1, 17, -1), "mc1_16", "https://launcher.mojang.com/v1/objects/de8e68ea23f837f9ab628cda7b16ba3de4b79153/client.jar");
|
||||
|
||||
private final MinecraftVersion version;
|
||||
private final String resourcePrefix;
|
||||
|
@ -69,8 +69,8 @@ public HiresModel render(World world, Vector2i tile) {
|
||||
Vector2i tileMin = tileGrid.getCellMin(tile);
|
||||
Vector2i tileMax = tileGrid.getCellMax(tile);
|
||||
|
||||
Vector3i modelMin = new Vector3i(tileMin.getX(), world.getMinY(), tileMin.getY());
|
||||
Vector3i modelMax = new Vector3i(tileMax.getX(), world.getMaxY(), tileMax.getY());
|
||||
Vector3i modelMin = new Vector3i(tileMin.getX(), Integer.MIN_VALUE, tileMin.getY());
|
||||
Vector3i modelMax = new Vector3i(tileMax.getX(), Integer.MAX_VALUE, tileMax.getY());
|
||||
|
||||
HiresModel model = renderer.render(world, modelMin, modelMax);
|
||||
save(model, tile);
|
||||
|
@ -58,6 +58,7 @@ public HiresModelRenderer(ResourcePack resourcePack, RenderSettings renderSettin
|
||||
public HiresModel render(World world, Vector3i modelMin, Vector3i modelMax) {
|
||||
Vector3i min = modelMin.max(renderSettings.getMin());
|
||||
Vector3i max = modelMax.min(renderSettings.getMax());
|
||||
Vector3f modelAnchor = new Vector3f(modelMin.getX(), 0, modelMin.getZ());
|
||||
|
||||
HiresModel model = new HiresModel(world.getUUID(), modelMin, modelMax);
|
||||
|
||||
@ -66,8 +67,11 @@ public HiresModel render(World world, Vector3i modelMin, Vector3i modelMax) {
|
||||
|
||||
int maxHeight = 0;
|
||||
Vector4f color = Vector4f.ZERO;
|
||||
|
||||
for (int y = min.getY(); y <= max.getY(); y++){
|
||||
|
||||
int minY = Math.max(min.getY(), world.getMinY(x, z));
|
||||
int maxY = Math.min(max.getY(), world.getMaxY(x, z));
|
||||
|
||||
for (int y = minY; y <= maxY; y++){
|
||||
Block block = world.getBlock(x, y, z);
|
||||
if (block.getBlockState().equals(BlockState.AIR)) continue;
|
||||
|
||||
@ -83,8 +87,12 @@ public HiresModel render(World world, Vector3i modelMin, Vector3i modelMax) {
|
||||
}
|
||||
//Logger.global.noFloodDebug(block.getBlockState().getFullId() + "-hiresModelRenderer-blockmodelerr", "Failed to create BlockModel for BlockState: " + block.getBlockState() + " (" + e.toString() + ")");
|
||||
}
|
||||
|
||||
blockModel.translate(new Vector3f(x, y, z).sub(modelMin.toFloat()));
|
||||
|
||||
// skip empty blocks
|
||||
if (blockModel.getFaces().isEmpty()) continue;
|
||||
|
||||
// move block-model to correct position
|
||||
blockModel.translate(new Vector3f(x - modelAnchor.getX(), y - modelAnchor.getY(), z - modelAnchor.getZ()));
|
||||
|
||||
//update color and height (only if not 100% translucent)
|
||||
Vector4f blockColor = blockModel.getMapColor();
|
||||
|
@ -33,7 +33,6 @@
|
||||
import net.querz.nbt.CompoundTag;
|
||||
import net.querz.nbt.ListTag;
|
||||
import net.querz.nbt.NumberTag;
|
||||
import net.querz.nbt.mca.MCAUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.function.IntFunction;
|
||||
@ -90,7 +89,8 @@ public boolean isGenerated() {
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(Vector3i pos) {
|
||||
int sectionY = MCAUtil.blockToChunk(pos.getY());
|
||||
int sectionY = pos.getY() >> 4;
|
||||
if (sectionY < 0 || sectionY >= this.sections.length) return BlockState.AIR;
|
||||
|
||||
Section section = this.sections[sectionY];
|
||||
if (section == null) return BlockState.AIR;
|
||||
@ -99,7 +99,8 @@ public BlockState getBlockState(Vector3i pos) {
|
||||
}
|
||||
|
||||
public String getBlockIdMeta(Vector3i pos) {
|
||||
int sectionY = MCAUtil.blockToChunk(pos.getY());
|
||||
int sectionY = pos.getY() >> 4;
|
||||
if (sectionY < 0 || sectionY >= this.sections.length) return "0:0";
|
||||
|
||||
Section section = this.sections[sectionY];
|
||||
if (section == null) return "0:0";
|
||||
@ -110,8 +111,10 @@ public String getBlockIdMeta(Vector3i pos) {
|
||||
@Override
|
||||
public LightData getLightData(Vector3i pos) {
|
||||
if (!hasLight) return LightData.SKY;
|
||||
|
||||
int sectionY = MCAUtil.blockToChunk(pos.getY());
|
||||
|
||||
int sectionY = pos.getY() >> 4;
|
||||
if (sectionY < 0 || sectionY >= this.sections.length)
|
||||
return (pos.getY() < 0) ? LightData.ZERO : LightData.SKY;
|
||||
|
||||
Section section = this.sections[sectionY];
|
||||
if (section == null) return LightData.SKY;
|
||||
@ -124,7 +127,8 @@ public Biome getBiome(int x, int y, int z) {
|
||||
x = x & 0xF; // Math.floorMod(pos.getX(), 16)
|
||||
z = z & 0xF;
|
||||
int biomeByteIndex = z * 16 + x;
|
||||
|
||||
|
||||
if (biomeByteIndex >= this.biomes.length) return Biome.DEFAULT;
|
||||
return biomeIdMapper.get(biomes[biomeByteIndex] & 0xFF);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,6 @@
|
||||
import de.bluecolored.bluemap.core.world.BlockState;
|
||||
import de.bluecolored.bluemap.core.world.LightData;
|
||||
import net.querz.nbt.*;
|
||||
import net.querz.nbt.mca.MCAUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@ -99,7 +98,8 @@ public boolean isGenerated() {
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(Vector3i pos) {
|
||||
int sectionY = MCAUtil.blockToChunk(pos.getY());
|
||||
int sectionY = pos.getY() >> 4;
|
||||
if (sectionY < 0 || sectionY >= this.sections.length) return BlockState.AIR;
|
||||
|
||||
Section section = this.sections[sectionY];
|
||||
if (section == null) return BlockState.AIR;
|
||||
@ -110,8 +110,10 @@ public BlockState getBlockState(Vector3i pos) {
|
||||
@Override
|
||||
public LightData getLightData(Vector3i pos) {
|
||||
if (!hasLight) return LightData.SKY;
|
||||
|
||||
int sectionY = MCAUtil.blockToChunk(pos.getY());
|
||||
|
||||
int sectionY = pos.getY() >> 4;
|
||||
if (sectionY < 0 || sectionY >= this.sections.length)
|
||||
return (pos.getY() < 0) ? LightData.ZERO : LightData.SKY;
|
||||
|
||||
Section section = this.sections[sectionY];
|
||||
if (section == null) return LightData.SKY;
|
||||
@ -124,7 +126,8 @@ public Biome getBiome(int x, int y, int z) {
|
||||
x = x & 0xF; // Math.floorMod(pos.getX(), 16)
|
||||
z = z & 0xF;
|
||||
int biomeIntIndex = z * 16 + x;
|
||||
|
||||
|
||||
if (biomeIntIndex >= this.biomes.length) return Biome.DEFAULT;
|
||||
return biomeIdMapper.get(biomes[biomeIntIndex]);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,6 @@
|
||||
import de.bluecolored.bluemap.core.world.BlockState;
|
||||
import de.bluecolored.bluemap.core.world.LightData;
|
||||
import net.querz.nbt.*;
|
||||
import net.querz.nbt.mca.MCAUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@ -99,7 +98,8 @@ public boolean isGenerated() {
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(Vector3i pos) {
|
||||
int sectionY = MCAUtil.blockToChunk(pos.getY());
|
||||
int sectionY = pos.getY() >> 4;
|
||||
if (sectionY < 0 || sectionY >= this.sections.length) return BlockState.AIR;
|
||||
|
||||
Section section = this.sections[sectionY];
|
||||
if (section == null) return BlockState.AIR;
|
||||
@ -110,8 +110,10 @@ public BlockState getBlockState(Vector3i pos) {
|
||||
@Override
|
||||
public LightData getLightData(Vector3i pos) {
|
||||
if (!hasLight) return LightData.SKY;
|
||||
|
||||
int sectionY = MCAUtil.blockToChunk(pos.getY());
|
||||
|
||||
int sectionY = pos.getY() >> 4;
|
||||
if (sectionY < 0 || sectionY >= this.sections.length)
|
||||
return (pos.getY() < 0) ? LightData.ZERO : LightData.SKY;
|
||||
|
||||
Section section = this.sections[sectionY];
|
||||
if (section == null) return LightData.SKY;
|
||||
@ -125,7 +127,8 @@ public Biome getBiome(int x, int y, int z) {
|
||||
z = (z & 0xF) / 4;
|
||||
y = y / 4;
|
||||
int biomeIntIndex = y * 16 + z * 4 + x;
|
||||
|
||||
|
||||
if (biomeIntIndex >= this.biomes.length) return Biome.DEFAULT;
|
||||
return biomeIdMapper.get(biomes[biomeIntIndex]);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,6 @@
|
||||
import de.bluecolored.bluemap.core.world.BlockState;
|
||||
import de.bluecolored.bluemap.core.world.LightData;
|
||||
import net.querz.nbt.*;
|
||||
import net.querz.nbt.mca.MCAUtil;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@ -43,7 +42,8 @@ public class ChunkAnvil116 extends MCAChunk {
|
||||
|
||||
private boolean isGenerated;
|
||||
private boolean hasLight;
|
||||
private Section[] sections;
|
||||
private Map<Integer, Section> sections;
|
||||
private int sectionMin, sectionMax;
|
||||
private int[] biomes;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ -62,11 +62,20 @@ public ChunkAnvil116(CompoundTag chunkTag, boolean ignoreMissingLightData, Biome
|
||||
isGenerated = !status.equals("empty");
|
||||
}
|
||||
|
||||
this.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?
|
||||
this.sections = new HashMap<>(); // Is using a has-map the fastest/best way for an int->Object mapping?
|
||||
this.sectionMin = Integer.MAX_VALUE;
|
||||
this.sectionMax = Integer.MIN_VALUE;
|
||||
if (levelData.containsKey("Sections")) {
|
||||
for (CompoundTag sectionTag : ((ListTag<CompoundTag>) levelData.getListTag("Sections"))) {
|
||||
if (sectionTag.getListTag("Palette") == null) continue; // ignore empty sections
|
||||
|
||||
Section section = new Section(sectionTag);
|
||||
if (section.getSectionY() >= 0 && section.getSectionY() < sections.length) sections[section.getSectionY()] = section;
|
||||
int y = section.getSectionY();
|
||||
|
||||
if (sectionMin > y) sectionMin = y;
|
||||
if (sectionMax < y) sectionMax = y;
|
||||
|
||||
sections.put(y, section);
|
||||
}
|
||||
}
|
||||
|
||||
@ -83,12 +92,8 @@ else if (tag instanceof IntArrayTag) {
|
||||
this.biomes = ((IntArrayTag) tag).getValue();
|
||||
}
|
||||
|
||||
if (biomes == null || biomes.length == 0) {
|
||||
this.biomes = new int[1024];
|
||||
}
|
||||
|
||||
if (biomes.length < 1024) {
|
||||
this.biomes = Arrays.copyOf(biomes, 1024);
|
||||
if (biomes == null) {
|
||||
this.biomes = new int[0];
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,9 +104,9 @@ public boolean isGenerated() {
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(Vector3i pos) {
|
||||
int sectionY = MCAUtil.blockToChunk(pos.getY());
|
||||
int sectionY = pos.getY() >> 4;
|
||||
|
||||
Section section = this.sections[sectionY];
|
||||
Section section = this.sections.get(sectionY);
|
||||
if (section == null) return BlockState.AIR;
|
||||
|
||||
return section.getBlockState(pos);
|
||||
@ -111,24 +116,40 @@ public BlockState getBlockState(Vector3i pos) {
|
||||
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;
|
||||
int sectionY = pos.getY() >> 4;
|
||||
|
||||
Section section = this.sections.get(sectionY);
|
||||
if (section == null) return (sectionY < sectionMin) ? LightData.ZERO : LightData.SKY;
|
||||
|
||||
return section.getLightData(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int y, int z) {
|
||||
if (biomes.length < 16) return Biome.DEFAULT;
|
||||
|
||||
x = (x & 0xF) / 4; // Math.floorMod(pos.getX(), 16)
|
||||
z = (z & 0xF) / 4;
|
||||
y = y / 4;
|
||||
int biomeIntIndex = y * 16 + z * 4 + x;
|
||||
int biomeIntIndex = y * 16 + z * 4 + x; // TODO: fix this for 1.17+ worlds with negative y?
|
||||
|
||||
// shift y up/down if not in range
|
||||
if (biomeIntIndex >= biomes.length) biomeIntIndex -= (((biomeIntIndex - biomes.length) >> 4) + 1) * 16;
|
||||
if (biomeIntIndex < 0) biomeIntIndex -= (biomeIntIndex >> 4) * 16;
|
||||
|
||||
return biomeIdMapper.get(biomes[biomeIntIndex]);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getMinY(int x, int z) {
|
||||
return sectionMin * 16;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY(int x, int z) {
|
||||
return sectionMax * 16 + 15;
|
||||
}
|
||||
|
||||
private static class Section {
|
||||
private static final String AIR_ID = "minecraft:air";
|
||||
|
||||
|
@ -57,6 +57,14 @@ public int getDataVersion() {
|
||||
public abstract LightData getLightData(Vector3i pos);
|
||||
|
||||
public abstract Biome getBiome(int x, int y, int z);
|
||||
|
||||
public int getMaxY(int x, int z) {
|
||||
return 255;
|
||||
}
|
||||
|
||||
public int getMinY(int x, int z) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static MCAChunk create(MCAWorld world, CompoundTag chunkTag, boolean ignoreMissingLightData) throws IOException {
|
||||
int version = chunkTag.getInt("DataVersion");
|
||||
|
@ -130,24 +130,11 @@ public BlockState getBlockState(Vector3i pos) {
|
||||
|
||||
@Override
|
||||
public Biome getBiome(int x, int y, int z) {
|
||||
if (y < getMinY()) {
|
||||
y = getMinY();
|
||||
} else if (y > getMaxY()) {
|
||||
y = getMaxY();
|
||||
}
|
||||
|
||||
MCAChunk chunk = getChunk(x >> 4, z >> 4);
|
||||
return chunk.getBiome(x, y, z);
|
||||
return getChunk(x >> 4, z >> 4).getBiome(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block getBlock(Vector3i pos) {
|
||||
if (pos.getY() < getMinY()) {
|
||||
return new Block(this, BlockState.AIR, LightData.ZERO, Biome.DEFAULT, BlockProperties.TRANSPARENT, pos);
|
||||
} else if (pos.getY() > getMaxY()) {
|
||||
return new Block(this, BlockState.AIR, LightData.SKY, Biome.DEFAULT, BlockProperties.TRANSPARENT, pos);
|
||||
}
|
||||
|
||||
MCAChunk chunk = getChunk(blockToChunk(pos));
|
||||
BlockState blockState = getExtendedBlockState(chunk, pos);
|
||||
LightData lightData = chunk.getLightData(pos);
|
||||
@ -226,13 +213,13 @@ public int getSeaLevel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return 0;
|
||||
public int getMinY(int x, int z) {
|
||||
return getChunk(x >> 4, z >> 4).getMinY(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return 255;
|
||||
public int getMaxY(int x, int z) {
|
||||
return getChunk(x >> 4, z >> 4).getMaxY(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -73,13 +73,13 @@ public Vector3i getSpawnPoint() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return world.getMaxY();
|
||||
public int getMaxY(int x, int z) {
|
||||
return world.getMaxY(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinY() {
|
||||
return world.getMinY();
|
||||
public int getMinY(int x, int z) {
|
||||
return world.getMinY(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -49,9 +49,9 @@ public interface World {
|
||||
|
||||
Vector3i getSpawnPoint();
|
||||
|
||||
int getMaxY();
|
||||
int getMaxY(int x, int z);
|
||||
|
||||
int getMinY();
|
||||
int getMinY(int x, int z);
|
||||
|
||||
Grid getChunkGrid();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user