Biomes in MCA

This commit is contained in:
cyberpwn 2021-08-25 07:59:16 -04:00
parent 8586d44d7e
commit 0a7b485514
7 changed files with 120 additions and 120 deletions

View File

@ -18,6 +18,7 @@
package com.volmit.iris.core.nms; 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.mca.palette.PaletteAccess;
import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.CompoundTag;
import org.bukkit.Location; import org.bukkit.Location;
@ -64,6 +65,10 @@ public interface INMSBinding {
int getBiomeId(Biome biome); int getBiomeId(Biome biome);
BiomeContainer newBiomeContainer(int min, int max, int[] data);
BiomeContainer newBiomeContainer(int min, int max);
default World createWorld(WorldCreator c) { default World createWorld(WorldCreator c) {
return c.createWorld(); return c.createWorld();
} }

View File

@ -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.craftbukkit.v1_17_R1.entity.CraftEntity;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
import org.bukkit.generator.ChunkGenerator; import org.bukkit.generator.ChunkGenerator;
import org.jetbrains.annotations.NotNull;
import java.io.*; import java.io.*;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.IdentityHashMap; import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicInteger; 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 BlockData AIR = Material.AIR.createBlockData();
private final KMap<Biome, Object> baseBiomeCache = new KMap<>(); private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
private final AtomicCache<IdMapper<IBlockData>> registryCache = new AtomicCache<>(); private final AtomicCache<IdMapper<IBlockData>> registryCache = new AtomicCache<>();
private final AtomicCache<Palette<IBlockData>> globalCache = new AtomicCache<>(); private final AtomicCache<Palette<IBlockData>> globalCache = new AtomicCache<>();
private final AtomicCache<IdMap<BiomeBase>> biomeMapCache = new AtomicCache<>();
private Field biomeStorageCache = null; private Field biomeStorageCache = null;
public boolean supportsDataPacks() { public boolean supportsDataPacks() {
@ -383,6 +386,59 @@ public class NMSBinding17_1 implements INMSBinding {
return biome.ordinal(); return biome.ordinal();
} }
private IdMap<BiomeBase> getBiomeMapping()
{
return biomeMapCache.aquire(() -> new IdMap<>() {
@NotNull
@Override
public Iterator<BiomeBase> 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<BiomeBase> base = new ChunkBiomeContainer<>(getBiomeMapping(), min, max);
return getBiomeContainerInterface(getBiomeMapping(), base);
}
@Override
public BiomeContainer newBiomeContainer(int min, int max, int[] data) {
ChunkBiomeContainer<BiomeBase> base = new ChunkBiomeContainer<>(getBiomeMapping(), min, max, data);
return getBiomeContainerInterface(getBiomeMapping(), base);
}
@NotNull
private BiomeContainer getBiomeContainerInterface(IdMap<BiomeBase> biomeMapping, ChunkBiomeContainer<BiomeBase> 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 @Override
public int countCustomBiomes() { public int countCustomBiomes() {
AtomicInteger a = new AtomicInteger(0); AtomicInteger a = new AtomicInteger(0);

View File

@ -20,6 +20,7 @@ package com.volmit.iris.core.nms.v1X;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMSBinding; 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.mca.palette.PaletteAccess;
import com.volmit.iris.util.nbt.tag.CompoundTag; import com.volmit.iris.util.nbt.tag.CompoundTag;
import org.bukkit.Location; import org.bukkit.Location;
@ -135,6 +136,20 @@ public class NMSBinding1X implements INMSBinding {
return biome.ordinal(); 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 @Override
public int countCustomBiomes() { public int countCustomBiomes() {
return 0; return 0;

View File

@ -19,10 +19,12 @@
package com.volmit.iris.util.nbt.mca; package com.volmit.iris.util.nbt.mca;
import com.volmit.iris.Iris; import com.volmit.iris.Iris;
import com.volmit.iris.core.nms.INMS;
import com.volmit.iris.util.io.IO; import com.volmit.iris.util.io.IO;
import com.volmit.iris.util.nbt.io.NBTDeserializer; import com.volmit.iris.util.nbt.io.NBTDeserializer;
import com.volmit.iris.util.nbt.io.NBTSerializer; import com.volmit.iris.util.nbt.io.NBTSerializer;
import com.volmit.iris.util.nbt.io.NamedTag; 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.CompoundTag;
import com.volmit.iris.util.nbt.tag.ListTag; import com.volmit.iris.util.nbt.tag.ListTag;
import com.volmit.iris.util.nbt.tag.Tag; import com.volmit.iris.util.nbt.tag.Tag;
@ -41,7 +43,7 @@ public class Chunk {
private int dataVersion; private int dataVersion;
private long lastUpdate; private long lastUpdate;
private long inhabitedTime; private long inhabitedTime;
private int[] biomes; private BiomeContainer biomes;
private CompoundTag heightMaps; private CompoundTag heightMaps;
private CompoundTag carvingMasks; private CompoundTag carvingMasks;
private final AtomicReferenceArray<Section> sections = new AtomicReferenceArray<>(16); private final AtomicReferenceArray<Section> sections = new AtomicReferenceArray<>(16);
@ -83,7 +85,7 @@ public class Chunk {
inhabitedTime = level.getLong("InhabitedTime"); inhabitedTime = level.getLong("InhabitedTime");
lastUpdate = level.getLong("LastUpdate"); lastUpdate = level.getLong("LastUpdate");
if ((loadFlags & BIOMES) != 0) { if ((loadFlags & BIOMES) != 0) {
biomes = level.getIntArray("Biomes"); biomes = INMS.get().newBiomeContainer(0, 256, level.getIntArray("Biomes"));
} }
if ((loadFlags & HEIGHTMAPS) != 0) { if ((loadFlags & HEIGHTMAPS) != 0) {
heightMaps = level.getCompoundTag("Heightmaps"); 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. * Fetches a biome id at a specific block in this chunk.
* The coordinates can be absolute coordinates or relative to the region or 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. * @return The biome id or -1 if the biomes are not correctly initialized.
*/ */
public synchronized int getBiomeAt(int blockX, int blockY, int blockZ) { public synchronized int getBiomeAt(int blockX, int blockY, int blockZ) {
if (dataVersion < 2202) { return biomes.getBiome(blockX, blockY, blockZ);
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;
}
}
} }
/** /**
@ -276,23 +226,7 @@ public class Chunk {
* When set to a negative number, Minecraft will replace it with the block column's default biome. * 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) { public synchronized void setBiomeAt(int blockX, int blockY, int blockZ, int biomeID) {
if (dataVersion < 2202) { biomes.setBiome(blockX, blockY, blockZ, biomeID);
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;
}
} }
int getBiomeIndex(int biomeX, int biomeY, int biomeZ) { int getBiomeIndex(int biomeX, int biomeY, int biomeZ) {
@ -430,29 +364,6 @@ public class Chunk {
this.inhabitedTime = inhabitedTime; 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 <code>256</code>.
* @throws IllegalArgumentException When the biome matrix does not have a length of <code>256</code>
* or is <code>null</code>
*/
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. * @return The height maps of this chunk.
*/ */
@ -646,6 +557,7 @@ public class Chunk {
Chunk c = new Chunk(0); Chunk c = new Chunk(0);
c.dataVersion = DEFAULT_DATA_VERSION; c.dataVersion = DEFAULT_DATA_VERSION;
c.data = new CompoundTag(); c.data = new CompoundTag();
c.biomes = INMS.get().newBiomeContainer(0, 256);
c.data.put("Level", defaultLevel()); c.data.put("Level", defaultLevel());
c.status = "full"; c.status = "full";
return c; return c;
@ -665,7 +577,7 @@ public class Chunk {
level.putInt("zPos", zPos); level.putInt("zPos", zPos);
level.putLong("LastUpdate", lastUpdate); level.putLong("LastUpdate", lastUpdate);
level.putLong("InhabitedTime", inhabitedTime); 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 (heightMaps != null) level.put("Heightmaps", heightMaps);
if (carvingMasks != null) level.put("CarvingMasks", carvingMasks); if (carvingMasks != null) level.put("CarvingMasks", carvingMasks);
if (entities != null) level.put("Entities", entities); if (entities != null) level.put("Entities", entities);

View File

@ -275,31 +275,10 @@ public class MCAFile {
return chunk; 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) { public void setBiomeAt(int blockX, int blockY, int blockZ, int biomeID) {
createChunkIfMissing(blockX, blockZ).setBiomeAt(blockX, blockY, blockZ, 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. * Fetches the biome id at a specific block.
* *

View File

@ -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 <https://www.gnu.org/licenses/>.
*/
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);
}

View File

@ -43,14 +43,19 @@ public class ChunkBiomeContainer<T> {
private final int quartMinY; private final int quartMinY;
private final int quartHeight; private final int quartHeight;
protected ChunkBiomeContainer(IdMap<T> registry, int minHeight, int maxHeight, T[] abiomebase) { protected ChunkBiomeContainer(IdMap<T> registry, int minHeight, int maxHeight, T[] abiomebase) {
this.biomeRegistry = registry; this.biomeRegistry = registry;
this.biomes = abiomebase; this.biomes = abiomebase;
this.quartMinY = QuartPos.fromBlock(minHeight); this.quartMinY = QuartPos.fromBlock(minHeight);
this.quartHeight = QuartPos.fromBlock(maxHeight) - 1; this.quartHeight = QuartPos.fromBlock(maxHeight) - 1;
} }
public ChunkBiomeContainer(IdMap<T> registry, int min, int max)
{
this(registry, min, max, new int[(1 << WIDTH_BITS + WIDTH_BITS) * ceilDiv(max - min, 4)]);
}
public ChunkBiomeContainer(IdMap<T> registry, int minHeight, int maxHeight, int[] aint) { public ChunkBiomeContainer(IdMap<T> registry, int minHeight, int maxHeight, int[] aint) {
this(registry, minHeight, maxHeight, (T[])new Object[aint.length]); this(registry, minHeight, maxHeight, (T[])new Object[aint.length]);
int i = -1; int i = -1;