diff --git a/src/main/java/com/volmit/iris/core/nms/INMSBinding.java b/src/main/java/com/volmit/iris/core/nms/INMSBinding.java index 731852fdd..1e02f711f 100644 --- a/src/main/java/com/volmit/iris/core/nms/INMSBinding.java +++ b/src/main/java/com/volmit/iris/core/nms/INMSBinding.java @@ -18,6 +18,7 @@ package com.volmit.iris.core.nms; +import com.volmit.iris.util.nbt.mca.palette.BiomeContainer; import com.volmit.iris.util.nbt.mca.palette.PaletteAccess; import com.volmit.iris.util.nbt.tag.CompoundTag; import org.bukkit.Location; @@ -64,6 +65,10 @@ public interface INMSBinding { int getBiomeId(Biome biome); + BiomeContainer newBiomeContainer(int min, int max, int[] data); + + BiomeContainer newBiomeContainer(int min, int max); + default World createWorld(WorldCreator c) { return c.createWorld(); } diff --git a/src/main/java/com/volmit/iris/core/nms/v17_1/NMSBinding17_1.java b/src/main/java/com/volmit/iris/core/nms/v17_1/NMSBinding17_1.java index 71472740b..b6605a1bd 100644 --- a/src/main/java/com/volmit/iris/core/nms/v17_1/NMSBinding17_1.java +++ b/src/main/java/com/volmit/iris/core/nms/v17_1/NMSBinding17_1.java @@ -56,19 +56,22 @@ import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_17_R1.entity.CraftEntity; import org.bukkit.entity.EntityType; import org.bukkit.generator.ChunkGenerator; +import org.jetbrains.annotations.NotNull; import java.io.*; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.IdentityHashMap; +import java.util.Iterator; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -public class NMSBinding17_1 implements INMSBinding { +public class NMSBinding17_1 implements INMSBinding{ private final BlockData AIR = Material.AIR.createBlockData(); private final KMap baseBiomeCache = new KMap<>(); private final AtomicCache> registryCache = new AtomicCache<>(); private final AtomicCache> globalCache = new AtomicCache<>(); + private final AtomicCache> biomeMapCache = new AtomicCache<>(); private Field biomeStorageCache = null; public boolean supportsDataPacks() { @@ -383,6 +386,59 @@ public class NMSBinding17_1 implements INMSBinding { return biome.ordinal(); } + private IdMap getBiomeMapping() + { + return biomeMapCache.aquire(() -> new IdMap<>() { + @NotNull + @Override + public Iterator iterator() { + return getCustomBiomeRegistry().iterator(); + } + + @Override + public int getId(BiomeBase paramT) { + return getCustomBiomeRegistry().getId(paramT); + } + + @Override + public BiomeBase byId(int paramInt) { + return getCustomBiomeRegistry().fromId(paramInt); + } + }); + } + + @Override + public BiomeContainer newBiomeContainer(int min, int max) { + ChunkBiomeContainer base = new ChunkBiomeContainer<>(getBiomeMapping(), min, max); + return getBiomeContainerInterface(getBiomeMapping(), base); + } + + @Override + public BiomeContainer newBiomeContainer(int min, int max, int[] data) { + ChunkBiomeContainer base = new ChunkBiomeContainer<>(getBiomeMapping(), min, max, data); + return getBiomeContainerInterface(getBiomeMapping(), base); + } + + @NotNull + private BiomeContainer getBiomeContainerInterface(IdMap biomeMapping, ChunkBiomeContainer base) { + return new BiomeContainer() { + @Override + public int[] getData() { + return base.writeBiomes(); + } + + @Override + public void setBiome(int x, int y, int z, int id) { + base.setBiome(x, y, z, biomeMapping.byId(id)); + } + + @Override + public int getBiome(int x, int y, int z) { + return biomeMapping.getId(base.getBiome(x,y,z)); + } + }; + } + @Override public int countCustomBiomes() { AtomicInteger a = new AtomicInteger(0); diff --git a/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java b/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java index 795d9104a..de447e6fe 100644 --- a/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java +++ b/src/main/java/com/volmit/iris/core/nms/v1X/NMSBinding1X.java @@ -20,6 +20,7 @@ package com.volmit.iris.core.nms.v1X; import com.volmit.iris.Iris; import com.volmit.iris.core.nms.INMSBinding; +import com.volmit.iris.util.nbt.mca.palette.BiomeContainer; import com.volmit.iris.util.nbt.mca.palette.PaletteAccess; import com.volmit.iris.util.nbt.tag.CompoundTag; import org.bukkit.Location; @@ -135,6 +136,20 @@ public class NMSBinding1X implements INMSBinding { return biome.ordinal(); } + @Override + public BiomeContainer newBiomeContainer(int min, int max) { + Iris.error("Cannot use the custom biome data! Iris is incapable of using MCA generation on this version of minecraft!"); + + return null; + } + + @Override + public BiomeContainer newBiomeContainer(int min, int max, int[] v) { + Iris.error("Cannot use the custom biome data! Iris is incapable of using MCA generation on this version of minecraft!"); + + return null; + } + @Override public int countCustomBiomes() { return 0; diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java b/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java index f8b0e4a93..cd1793129 100644 --- a/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java +++ b/src/main/java/com/volmit/iris/util/nbt/mca/Chunk.java @@ -19,10 +19,12 @@ package com.volmit.iris.util.nbt.mca; import com.volmit.iris.Iris; +import com.volmit.iris.core.nms.INMS; import com.volmit.iris.util.io.IO; import com.volmit.iris.util.nbt.io.NBTDeserializer; import com.volmit.iris.util.nbt.io.NBTSerializer; import com.volmit.iris.util.nbt.io.NamedTag; +import com.volmit.iris.util.nbt.mca.palette.BiomeContainer; import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.ListTag; import com.volmit.iris.util.nbt.tag.Tag; @@ -41,7 +43,7 @@ public class Chunk { private int dataVersion; private long lastUpdate; private long inhabitedTime; - private int[] biomes; + private BiomeContainer biomes; private CompoundTag heightMaps; private CompoundTag carvingMasks; private final AtomicReferenceArray
sections = new AtomicReferenceArray<>(16); @@ -83,7 +85,7 @@ public class Chunk { inhabitedTime = level.getLong("InhabitedTime"); lastUpdate = level.getLong("LastUpdate"); if ((loadFlags & BIOMES) != 0) { - biomes = level.getIntArray("Biomes"); + biomes = INMS.get().newBiomeContainer(0, 256, level.getIntArray("Biomes")); } if ((loadFlags & HEIGHTMAPS) != 0) { heightMaps = level.getCompoundTag("Heightmaps"); @@ -201,21 +203,6 @@ public class Chunk { } } - /** - * @deprecated Use {@link #getBiomeAt(int, int, int)} instead - */ - @Deprecated - public int getBiomeAt(int blockX, int blockZ) { - if (dataVersion < 2202) { - if (biomes == null || biomes.length != 256) { - return -1; - } - return biomes[getBlockIndex(blockX, blockZ)]; - } else { - throw new IllegalStateException("cannot get biome using Chunk#getBiomeAt(int,int) from biome data with DataVersion of 2202 or higher, use Chunk#getBiomeAt(int,int,int) instead"); - } - } - /** * Fetches a biome id at a specific block in this chunk. * The coordinates can be absolute coordinates or relative to the region or chunk. @@ -226,44 +213,7 @@ public class Chunk { * @return The biome id or -1 if the biomes are not correctly initialized. */ public synchronized int getBiomeAt(int blockX, int blockY, int blockZ) { - if (dataVersion < 2202) { - if (biomes == null || biomes.length != 256) { - return -1; - } - return biomes[getBlockIndex(blockX, blockZ)]; - } else { - if (biomes == null || biomes.length != 1024) { - return -1; - } - int biomeX = (blockX & 0xF) >> 2; - int biomeY = (blockY & 0xF) >> 2; - int biomeZ = (blockZ & 0xF) >> 2; - - return biomes[getBiomeIndex(biomeX, biomeY, biomeZ)]; - } - } - - @Deprecated - public synchronized void setBiomeAt(int blockX, int blockZ, int biomeID) { - if (dataVersion < 2202) { - if (biomes == null || biomes.length != 256) { - biomes = new int[256]; - Arrays.fill(biomes, -1); - } - biomes[getBlockIndex(blockX, blockZ)] = biomeID; - } else { - if (biomes == null || biomes.length != 1024) { - biomes = new int[1024]; - Arrays.fill(biomes, -1); - } - - int biomeX = (blockX & 0xF) >> 2; - int biomeZ = (blockZ & 0xF) >> 2; - - for (int y = 0; y < 64; y++) { - biomes[getBiomeIndex(biomeX, y, biomeZ)] = biomeID; - } - } + return biomes.getBiome(blockX, blockY, blockZ); } /** @@ -276,23 +226,7 @@ public class Chunk { * When set to a negative number, Minecraft will replace it with the block column's default biome. */ public synchronized void setBiomeAt(int blockX, int blockY, int blockZ, int biomeID) { - if (dataVersion < 2202) { - if (biomes == null || biomes.length != 256) { - biomes = new int[256]; - Arrays.fill(biomes, -1); - } - biomes[getBlockIndex(blockX, blockZ)] = biomeID; - } else { - if (biomes == null || biomes.length != 1024) { - biomes = new int[1024]; - Arrays.fill(biomes, -1); - } - - int biomeX = (blockX & 0xF) >> 2; - int biomeZ = (blockZ & 0xF) >> 2; - - biomes[getBiomeIndex(biomeX, blockY, biomeZ)] = biomeID; - } + biomes.setBiome(blockX, blockY, blockZ, biomeID); } int getBiomeIndex(int biomeX, int biomeY, int biomeZ) { @@ -430,29 +364,6 @@ public class Chunk { this.inhabitedTime = inhabitedTime; } - /** - * @return A matrix of biome IDs for all block columns in this chunk. - */ - public int[] getBiomes() { - return biomes; - } - - /** - * Sets the biome IDs for this chunk. - * - * @param biomes The biome ID matrix of this chunk. Must have a length of 256. - * @throws IllegalArgumentException When the biome matrix does not have a length of 256 - * or is null - */ - public void setBiomes(int[] biomes) { - if (biomes != null) { - if (dataVersion < 2202 && biomes.length != 256 || dataVersion >= 2202 && biomes.length != 1024) { - throw new IllegalArgumentException("biomes array must have a length of " + (dataVersion < 2202 ? "256" : "1024")); - } - } - this.biomes = biomes; - } - /** * @return The height maps of this chunk. */ @@ -646,6 +557,7 @@ public class Chunk { Chunk c = new Chunk(0); c.dataVersion = DEFAULT_DATA_VERSION; c.data = new CompoundTag(); + c.biomes = INMS.get().newBiomeContainer(0, 256); c.data.put("Level", defaultLevel()); c.status = "full"; return c; @@ -665,7 +577,7 @@ public class Chunk { level.putInt("zPos", zPos); level.putLong("LastUpdate", lastUpdate); level.putLong("InhabitedTime", inhabitedTime); - if (biomes != null && biomes.length == 1024) level.putIntArray("Biomes", biomes); + level.putIntArray("Biomes", biomes.getData()); if (heightMaps != null) level.put("Heightmaps", heightMaps); if (carvingMasks != null) level.put("CarvingMasks", carvingMasks); if (entities != null) level.put("Entities", entities); diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/MCAFile.java b/src/main/java/com/volmit/iris/util/nbt/mca/MCAFile.java index 1695bbf47..a9612212d 100644 --- a/src/main/java/com/volmit/iris/util/nbt/mca/MCAFile.java +++ b/src/main/java/com/volmit/iris/util/nbt/mca/MCAFile.java @@ -275,31 +275,10 @@ public class MCAFile { return chunk; } - /** - * @deprecated Use {@link #setBiomeAt(int, int, int, int)} instead - */ - @Deprecated - public void setBiomeAt(int blockX, int blockZ, int biomeID) { - createChunkIfMissing(blockX, blockZ).setBiomeAt(blockX, blockZ, biomeID); - } - public void setBiomeAt(int blockX, int blockY, int blockZ, int biomeID) { createChunkIfMissing(blockX, blockZ).setBiomeAt(blockX, blockY, blockZ, biomeID); } - /** - * @deprecated Use {@link #getBiomeAt(int, int, int)} instead - */ - @Deprecated - public int getBiomeAt(int blockX, int blockZ) { - int chunkX = MCAUtil.blockToChunk(blockX), chunkZ = MCAUtil.blockToChunk(blockZ); - Chunk chunk = getChunk(getChunkIndex(chunkX, chunkZ)); - if (chunk == null) { - return -1; - } - return chunk.getBiomeAt(blockX, blockZ); - } - /** * Fetches the biome id at a specific block. * diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/palette/BiomeContainer.java b/src/main/java/com/volmit/iris/util/nbt/mca/palette/BiomeContainer.java new file mode 100644 index 000000000..a8127c4c1 --- /dev/null +++ b/src/main/java/com/volmit/iris/util/nbt/mca/palette/BiomeContainer.java @@ -0,0 +1,28 @@ +/* + * Iris is a World Generator for Minecraft Bukkit Servers + * Copyright (c) 2021 Arcane Arts (Volmit Software) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.volmit.iris.util.nbt.mca.palette; + +public interface BiomeContainer +{ + int[] getData(); + + void setBiome(int x, int y, int z, int id); + + int getBiome(int x, int y, int z); +} diff --git a/src/main/java/com/volmit/iris/util/nbt/mca/palette/ChunkBiomeContainer.java b/src/main/java/com/volmit/iris/util/nbt/mca/palette/ChunkBiomeContainer.java index 4fc319876..c7ed918c5 100644 --- a/src/main/java/com/volmit/iris/util/nbt/mca/palette/ChunkBiomeContainer.java +++ b/src/main/java/com/volmit/iris/util/nbt/mca/palette/ChunkBiomeContainer.java @@ -43,14 +43,19 @@ public class ChunkBiomeContainer { private final int quartMinY; private final int quartHeight; - + protected ChunkBiomeContainer(IdMap registry, int minHeight, int maxHeight, T[] abiomebase) { this.biomeRegistry = registry; this.biomes = abiomebase; this.quartMinY = QuartPos.fromBlock(minHeight); this.quartHeight = QuartPos.fromBlock(maxHeight) - 1; } - + + public ChunkBiomeContainer(IdMap registry, int min, int max) + { + this(registry, min, max, new int[(1 << WIDTH_BITS + WIDTH_BITS) * ceilDiv(max - min, 4)]); + } + public ChunkBiomeContainer(IdMap registry, int minHeight, int maxHeight, int[] aint) { this(registry, minHeight, maxHeight, (T[])new Object[aint.length]); int i = -1;