Add 3D biomes to clipboards properly

- Also fix disk clipboard's size check, allowing for larger clipboards but with disabled biomes
This commit is contained in:
dordsor21 2021-01-09 16:40:41 +00:00
parent 716c22c589
commit 31542ed4fa
No known key found for this signature in database
GPG Key ID: 1E53E88969FFCF0B
5 changed files with 78 additions and 63 deletions

View File

@ -27,7 +27,7 @@ import java.util.Map;
public class CPUOptimizedClipboard extends LinearClipboard { public class CPUOptimizedClipboard extends LinearClipboard {
private BiomeType[] biomes = null; private BiomeType[] biomes = null;
private char[] states; private final char[] states;
private final HashMap<IntTriple, CompoundTag> nbtMapLoc; private final HashMap<IntTriple, CompoundTag> nbtMapLoc;
private final HashMap<Integer, CompoundTag> nbtMapIndex; private final HashMap<Integer, CompoundTag> nbtMapIndex;
@ -52,14 +52,14 @@ public class CPUOptimizedClipboard extends LinearClipboard {
@Override @Override
public boolean setBiome(int x, int y, int z, BiomeType biome) { public boolean setBiome(int x, int y, int z, BiomeType biome) {
setBiome(getIndex(x, 0, z), biome); setBiome(getBiomeIndex(x, y, z), biome);
return true; return true;
} }
@Override @Override
public void setBiome(int index, BiomeType biome) { public void setBiome(int index, BiomeType biome) {
if (biomes == null) { if (biomes == null) {
biomes = new BiomeType[getArea()]; biomes = new BiomeType[((getHeight() >> 2) + 1) * ((getLength() >> 2) + 1) * ((getWidth() >> 2) + 1)];
} }
biomes[index] = biome; biomes[index] = biome;
} }
@ -69,11 +69,12 @@ public class CPUOptimizedClipboard extends LinearClipboard {
if (!hasBiomes()) { if (!hasBiomes()) {
return; return;
} }
int index = 0;
try { try {
for (int y = 0; y < getHeight(); y ++) {
for (int z = 0; z < getLength(); z++) { for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++) { for (int x = 0; x < getWidth(); x++) {
task.applyInt(index, biomes[index].getInternalId()); task.applyInt(getIndex(x, y, z), biomes[getBiomeIndex(x, y, z)].getInternalId());
}
} }
} }
} catch (IOException e) { } catch (IOException e) {
@ -92,12 +93,12 @@ public class CPUOptimizedClipboard extends LinearClipboard {
@Override @Override
public BiomeType getBiomeType(int x, int y, int z) { public BiomeType getBiomeType(int x, int y, int z) {
return getBiome(getIndex(x, 0, z)); return getBiome(getBiomeIndex(x, y, z));
} }
@Override @Override
public BiomeType getBiome(BlockVector3 position) { public BiomeType getBiome(BlockVector3 position) {
return getBiome(getIndex(position.getX(), 0, position.getZ())); return getBiome(getBiomeIndex(position.getX(), position.getY(), position.getZ()));
} }
public void convertTilesToIndex() { public void convertTilesToIndex() {
@ -116,6 +117,10 @@ public class CPUOptimizedClipboard extends LinearClipboard {
return nbtMapIndex.get(index); return nbtMapIndex.get(index);
} }
public int getBiomeIndex(int x, int y, int z) {
return (x >> 2) + (y >> 2) * (getWidth() >> 2) * (getLength() >> 2) + (z >> 2) * (getWidth() >> 2);
}
public int getIndex(int x, int y, int z) { public int getIndex(int x, int y, int z) {
return x + y * getArea() + z * getWidth(); return x + y * getArea() + z * getWidth();
} }
@ -176,7 +181,7 @@ public class CPUOptimizedClipboard extends LinearClipboard {
return true; return true;
} }
public boolean setTile(int index, CompoundTag tag) { private boolean setTile(int index, CompoundTag tag) {
final Map<String, Tag> values = new HashMap<>(tag.getValue()); final Map<String, Tag> values = new HashMap<>(tag.getValue());
values.remove("x"); values.remove("x");
values.remove("y"); values.remove("y");

View File

@ -55,8 +55,7 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
private static final Logger log = LoggerFactory.getLogger(DiskOptimizedClipboard.class); private static final Logger log = LoggerFactory.getLogger(DiskOptimizedClipboard.class);
private static int HEADER_SIZE = 14; private static final int HEADER_SIZE = 14;
private static final int MAX_SIZE = Short.MAX_VALUE - Short.MIN_VALUE;
private final HashMap<IntTriple, CompoundTag> nbtMap; private final HashMap<IntTriple, CompoundTag> nbtMap;
private final File file; private final File file;
@ -66,6 +65,7 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
private FileChannel fileChannel; private FileChannel fileChannel;
private boolean hasBiomes; private boolean hasBiomes;
private boolean canHaveBiomes = true;
public DiskOptimizedClipboard(Region region, UUID uuid) { public DiskOptimizedClipboard(Region region, UUID uuid) {
this(region.getDimensions(), MainUtil.getFile(Fawe.get() != null ? Fawe.imp().getDirectory() : new File("."), Settings.IMP.PATHS.CLIPBOARD + File.separator + uuid + ".bd")); this(region.getDimensions(), MainUtil.getFile(Fawe.get() != null ? Fawe.imp().getDirectory() : new File("."), Settings.IMP.PATHS.CLIPBOARD + File.separator + uuid + ".bd"));
@ -77,14 +77,11 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
public DiskOptimizedClipboard(BlockVector3 dimensions, File file) { public DiskOptimizedClipboard(BlockVector3 dimensions, File file) {
super(dimensions); super(dimensions);
if (getWidth() > MAX_SIZE) { if (HEADER_SIZE + ((long) getVolume() << 1) >= Integer.MAX_VALUE) {
throw new IllegalArgumentException("Width of region too large"); throw new IllegalArgumentException("Dimensions too large for this clipboard format");
} } else if (HEADER_SIZE + ((long) getVolume() << 1) + (long) ((getHeight() >> 2) + 1) * ((getLength() >> 2) + 1) * ((getWidth() >> 2) + 1) >= Integer.MAX_VALUE) {
if (getHeight() > MAX_SIZE) { log.error("Dimensions are too large for biomes to be stored in a DiskOptimizedClipboard");
throw new IllegalArgumentException("Height of region too large"); canHaveBiomes = false;
}
if (getLength() > MAX_SIZE) {
throw new IllegalArgumentException("Length of region too large");
} }
nbtMap = new HashMap<>(); nbtMap = new HashMap<>();
try { try {
@ -138,7 +135,7 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
this.braf = new RandomAccessFile(file, "rw"); this.braf = new RandomAccessFile(file, "rw");
braf.setLength(file.length()); braf.setLength(file.length());
init(); init();
if (braf.length() - HEADER_SIZE == (getVolume() << 1) + getArea()) { if (braf.length() - HEADER_SIZE == ((long) getVolume() << 1) + (long) ((getHeight() >> 2) + 1) * ((getLength() >> 2) + 1) * ((getWidth() >> 2) + 1)) {
hasBiomes = true; hasBiomes = true;
} }
} catch (IOException e) { } catch (IOException e) {
@ -158,12 +155,17 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
} }
private boolean initBiome() { private boolean initBiome() {
if (!canHaveBiomes) {
return false;
}
if (!hasBiomes) { if (!hasBiomes) {
try { try {
hasBiomes = true; hasBiomes = true;
close(); close();
this.braf = new RandomAccessFile(file, "rw"); this.braf = new RandomAccessFile(file, "rw");
this.braf.setLength(HEADER_SIZE + (getVolume() << 1) + getArea()); // Since biomes represent a 4x4x4 cube, we store fewer biome bytes that volume at 1 byte per biome
// +1 to each too allow for cubes that lie across the region boundary
this.braf.setLength(HEADER_SIZE + ((long) getVolume() << 1) + (long) ((getHeight() >> 2) + 1) * ((getLength() >> 2) + 1) * ((getWidth() >> 2) + 1));
init(); init();
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
@ -185,14 +187,20 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
@Override @Override
public boolean setBiome(int x, int y, int z, BiomeType biome) { public boolean setBiome(int x, int y, int z, BiomeType biome) {
setBiome(getIndex(x, 0, z), biome); setBiome(getBiomeIndex(x, y, z), biome);
return true; return true;
} }
@Override @Override
public void setBiome(int index, BiomeType biome) { public void setBiome(int index, BiomeType biome) {
if (initBiome()) { if (initBiome()) {
try {
byteBuffer.put(HEADER_SIZE + (getVolume() << 1) + index, (byte) biome.getInternalId()); byteBuffer.put(HEADER_SIZE + (getVolume() << 1) + index, (byte) biome.getInternalId());
} catch (IndexOutOfBoundsException e) {
System.out.println((long) (getHeight() >> 2) * (getLength() >> 2) * (getWidth() >> 2));
System.out.println(index);
e.printStackTrace();
}
} }
} }
@ -210,13 +218,14 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
if (!hasBiomes()) { if (!hasBiomes()) {
return; return;
} }
int index = 0;
int mbbIndex = HEADER_SIZE + (getVolume() << 1); int mbbIndex = HEADER_SIZE + (getVolume() << 1);
try { try {
for (int y = 0; y < getHeight(); y ++) {
for (int z = 0; z < getLength(); z++) { for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++, mbbIndex++) { for (int x = 0; x < getWidth(); x++) {
int biome = byteBuffer.get(mbbIndex) & 0xFF; int biome = byteBuffer.get(mbbIndex + getBiomeIndex(x, y, z)) & 0xFF;
task.applyInt(index, biome); task.applyInt(getIndex(x, y, z), biome);
}
} }
} }
} catch (IOException e) { } catch (IOException e) {
@ -227,12 +236,12 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
@Override @Override
public BiomeType getBiomeType(int x, int y, int z) { public BiomeType getBiomeType(int x, int y, int z) {
return getBiome(getIndex(x, 0, z)); return getBiome(getBiomeIndex(x, y, z));
} }
@Override @Override
public BiomeType getBiome(BlockVector3 position) { public BiomeType getBiome(BlockVector3 position) {
return getBiome(getIndex(position.getX(), 0, position.getZ())); return getBiome(getBiomeIndex(position.getX(), position.getY(), position.getZ()));
} }
public BlockArrayClipboard toClipboard() { public BlockArrayClipboard toClipboard() {
@ -313,11 +322,6 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
} }
} }
private int ylast;
private int ylasti;
private int zlast;
private int zlasti;
@Override @Override
public Collection<CompoundTag> getTileEntities() { public Collection<CompoundTag> getTileEntities() {
return nbtMap.values(); return nbtMap.values();
@ -327,6 +331,10 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
return x + y * getArea() + z * getWidth(); return x + y * getArea() + z * getWidth();
} }
public int getBiomeIndex(int x, int y, int z) {
return (x >> 2) + (y >> 2) * (getWidth() >> 2) * (getLength() >> 2) + (z >> 2) * (getWidth() >> 2);
}
@Override @Override
public BaseBlock getFullBlock(int x, int y, int z) { public BaseBlock getFullBlock(int x, int y, int z) {
return toBaseBlock(getBlock(x, y, z), x, y, z); return toBaseBlock(getBlock(x, y, z), x, y, z);
@ -459,8 +467,13 @@ public class DiskOptimizedClipboard extends LinearClipboard implements Closeable
@Override @Override
public void removeEntity(Entity entity) { public void removeEntity(Entity entity) {
if (!(entity instanceof BlockArrayClipboard.ClipboardEntity)) {
Location loc = entity.getLocation();
removeEntity(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), entity.getState().getNbtData().getUUID());
} else {
this.entities.remove(entity); this.entities.remove(entity);
} }
}
@Override @Override
public void removeEntity(int x, int y, int z, UUID uuid) { public void removeEntity(int x, int y, int z, UUID uuid) {

View File

@ -29,6 +29,7 @@ public abstract class LinearClipboard extends SimpleClipboard {
super(dimensions); super(dimensions);
} }
// We shouldn't expose methods that directly reference the index as people cannot be trusted to use it properly.
public abstract <B extends BlockStateHolder<B>> boolean setBlock(int i, B block); public abstract <B extends BlockStateHolder<B>> boolean setBlock(int i, B block);
public abstract BaseBlock getFullBlock(int i); public abstract BaseBlock getFullBlock(int i);

View File

@ -37,9 +37,9 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
private static final int BLOCK_MASK = 1048575; private static final int BLOCK_MASK = 1048575;
private static final int BLOCK_SHIFT = 20; private static final int BLOCK_SHIFT = 20;
private byte[][] states; private final byte[][] states;
private byte[] buffer = new byte[MainUtil.getMaxCompressedLength(BLOCK_SIZE)]; private final byte[] buffer = new byte[MainUtil.getMaxCompressedLength(BLOCK_SIZE)];
private byte[] biomes = null; private byte[] biomes = null;
private final HashMap<IntTriple, CompoundTag> nbtMap; private final HashMap<IntTriple, CompoundTag> nbtMap;
@ -77,14 +77,14 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
@Override @Override
public boolean setBiome(int x, int y, int z, BiomeType biome) { public boolean setBiome(int x, int y, int z, BiomeType biome) {
setBiome(getIndex(x, 0, z), biome); setBiome(getBiomeIndex(x, y, z), biome);
return true; return true;
} }
@Override @Override
public void setBiome(int index, BiomeType biome) { public void setBiome(int index, BiomeType biome) {
if (biomes == null) { if (biomes == null) {
biomes = new byte[getArea()]; biomes = new byte[((getHeight() >> 2) + 1) * ((getLength() >> 2) + 1) * ((getWidth() >> 2) + 1)];
} }
biomes[index] = (byte) biome.getInternalId(); biomes[index] = (byte) biome.getInternalId();
} }
@ -95,10 +95,11 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
return; return;
} }
try { try {
int index = 0; for (int y = 0; y < getHeight(); y ++) {
for (int z = 0; z < getLength(); z++) { for (int z = 0; z < getLength(); z++) {
for (int x = 0; x < getWidth(); x++, index++) { for (int x = 0; x < getWidth(); x++) {
task.applyInt(index, biomes[index] & 0xFF); task.applyInt(getIndex(x, y, z), biomes[getBiomeIndex(x, y, z)] & 0xFF);
}
} }
} }
} catch (IOException e) { } catch (IOException e) {
@ -117,15 +118,15 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
@Override @Override
public BiomeType getBiomeType(int x, int y, int z) { public BiomeType getBiomeType(int x, int y, int z) {
return getBiome(getIndex(x, 0, z)); return getBiome(getBiomeIndex(x, y, z));
} }
@Override @Override
public BiomeType getBiome(BlockVector3 position) { public BiomeType getBiome(BlockVector3 position) {
return getBiome(getIndex(position.getX(), 0, position.getZ())); return getBiome(getBiomeIndex(position.getX(), position.getY(), position.getZ()));
} }
public int getOrdinal(int index) { private int getOrdinal(int index) {
int i = index >> BLOCK_SHIFT; int i = index >> BLOCK_SHIFT;
int li = (index & BLOCK_MASK) << 1; int li = (index & BLOCK_MASK) << 1;
if (i != lastOrdinalsI) { if (i != lastOrdinalsI) {
@ -155,7 +156,7 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
private int lastIMin; private int lastIMin;
private int lastIMax; private int lastIMax;
public int getLocalIndex(int index) { private int getLocalIndex(int index) {
if (index < lastIMin || index > lastIMax) { if (index < lastIMin || index > lastIMax) {
lastI = index >> BLOCK_SHIFT; lastI = index >> BLOCK_SHIFT;
lastIMin = lastI << BLOCK_SHIFT; lastIMin = lastI << BLOCK_SHIFT;
@ -164,7 +165,7 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
return lastI; return lastI;
} }
public void setOrdinal(int index, int v) { private void setOrdinal(int index, int v) {
int i = getLocalIndex(index); int i = getLocalIndex(index);
if (i != lastOrdinalsI) { if (i != lastOrdinalsI) {
saveOrdinals(); saveOrdinals();
@ -197,6 +198,10 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
return x + y * getArea() + z * getWidth(); return x + y * getArea() + z * getWidth();
} }
public int getBiomeIndex(int x, int y, int z) {
return (x >> 2) + (y >> 2) * (getWidth() >> 2) * (getLength() >> 2) + (z >> 2) * (getWidth() >> 2);
}
@Override @Override
public BaseBlock getFullBlock(int x, int y, int z) { public BaseBlock getFullBlock(int x, int y, int z) {
int index = getIndex(x, y, z); int index = getIndex(x, y, z);

View File

@ -30,7 +30,6 @@ import com.boydti.fawe.object.io.FastByteArraysInputStream;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEdit;
@ -62,7 +61,6 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.OptionalInt;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
@ -318,18 +316,11 @@ public class FastSchematicReader extends NBTSchematicReader {
} }
if (biomesOut != null && biomesOut.getSize() != 0) { if (biomesOut != null && biomesOut.getSize() != 0) {
try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(biomesOut.toByteArrays())))) { try (FaweInputStream fis = new FaweInputStream(new LZ4BlockInputStream(new FastByteArraysInputStream(biomesOut.toByteArrays())))) {
if (clipboard instanceof LinearClipboard) {
LinearClipboard linear = (LinearClipboard) clipboard;
int volume = width * length;
for (int index = 0; index < volume; index++) {
BiomeType biome = getBiomeType(fis);
linear.setBiome(index, biome);
}
} else {
for (int z = 0; z < length; z++) { for (int z = 0; z < length; z++) {
for (int x = 0; x < width; x++) { for (int x = 0; x < width; x++) {
BiomeType biome = getBiomeType(fis); BiomeType biome = getBiomeType(fis);
clipboard.setBiome(x, 0, z, biome); for (int y = 0; y < height; y ++) {
clipboard.setBiome(x, y, z, biome);
} }
} }
} }