diff --git a/client/src/main/java/client/world/ChunkClient.java b/client/src/main/java/client/world/ChunkClient.java index 8f59b895..d55b636d 100644 --- a/client/src/main/java/client/world/ChunkClient.java +++ b/client/src/main/java/client/world/ChunkClient.java @@ -105,7 +105,10 @@ public class ChunkClient extends Chunk { } if(biomes) { - System.arraycopy(data, pos, this.biomes, 0, this.biomes.length); + for(int k = 0; k < this.biomes.length; ++k) { + this.biomes[k] = (char)((data[pos + 1] & 255) << 8 | data[pos] & 255); + pos += 2; + } } for(int cy : extend) { @@ -128,14 +131,8 @@ public class ChunkClient extends Chunk { this.loaded = true; } - public Biome getBiome(BlockPos pos) { - int x = pos.getX() & 15; - int z = pos.getZ() & 15; - return Biome.getBiomeDef(this.biomes[z << 4 | x] & 255); - } - public void setBiome(BlockPos pos, Biome biome) { - this.biomes[((pos.getZ() & 15) << 4 | pos.getX() & 15)] = (byte)biome.id; + this.biomes[((pos.getZ() & 15) << 4 | pos.getX() & 15)] = (char)biome.id; } public boolean isDummy() { diff --git a/common/src/main/java/common/packet/SPacketChunkData.java b/common/src/main/java/common/packet/SPacketChunkData.java index 3aac1351..01e2bb12 100755 --- a/common/src/main/java/common/packet/SPacketChunkData.java +++ b/common/src/main/java/common/packet/SPacketChunkData.java @@ -73,7 +73,7 @@ public class SPacketChunkData implements Packet int i = segments * 2 * 16 * 16 * 16; int j = segments * 16 * 16 * 16 / 2; int k = overworld ? segments * 16 * 16 * 16 / 2 : 0; - int l = biomes ? 256 : 0; + int l = biomes ? 256 * 2 : 0; return i + j + k + l; } diff --git a/common/src/main/java/common/world/Chunk.java b/common/src/main/java/common/world/Chunk.java index d86700bf..e7de2f05 100755 --- a/common/src/main/java/common/world/Chunk.java +++ b/common/src/main/java/common/world/Chunk.java @@ -7,6 +7,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.function.Predicate; +import common.biome.Biome; import common.block.Block; import common.block.ITileEntityProvider; import common.block.Material; @@ -31,7 +32,7 @@ public abstract class Chunk { protected final Block fillerBlock; protected final IntHashMap blocks = new IntHashMap(); protected final Set blockList = Sets.newHashSet(); - protected final byte[] biomes = new byte[256]; + protected final char[] biomes = new char[256]; protected final int[] precHeight = new int[256]; protected final boolean[] updateSky = new boolean[256]; protected final int[] height = new int[256]; @@ -61,7 +62,6 @@ public abstract class Chunk { this.entities[y] = new InheritanceMultiMap(Entity.class); } Arrays.fill(this.precHeight, -99999999); - Arrays.fill(this.biomes, (byte)-1); } public int getHeight(int x, int z) { @@ -839,4 +839,10 @@ public abstract class Chunk { public int getLowest() { return this.minHeight; } + + public Biome getBiome(BlockPos pos) { + int x = pos.getX() & 15; + int z = pos.getZ() & 15; + return Biome.getBiomeDef(this.biomes[z << 4 | x]); + } } diff --git a/server/src/main/java/server/network/Player.java b/server/src/main/java/server/network/Player.java index 296201a4..32ba6e6e 100755 --- a/server/src/main/java/server/network/Player.java +++ b/server/src/main/java/server/network/Player.java @@ -921,7 +921,13 @@ public class Player extends User implements ICrafting, Executor, IPlayer if (biomes) { - copyTo(chunk.getBiomes(), s21packetchunkdata$extracted.data, j); + char[] achar = chunk.getBiomes(); + + for (char c0 : achar) + { + s21packetchunkdata$extracted.data[j++] = (byte)(c0 & 255); + s21packetchunkdata$extracted.data[j++] = (byte)(c0 >> 8 & 255); + } } return s21packetchunkdata$extracted; diff --git a/server/src/main/java/server/world/ChunkServer.java b/server/src/main/java/server/world/ChunkServer.java index e4334793..f27a1e92 100644 --- a/server/src/main/java/server/world/ChunkServer.java +++ b/server/src/main/java/server/world/ChunkServer.java @@ -1,5 +1,6 @@ package server.world; +import java.util.Arrays; import java.util.Map; import java.util.Set; import common.biome.Biome; @@ -15,7 +16,6 @@ import common.world.BlockArray; import common.world.Chunk; import common.world.State; import common.world.World; -import server.worldgen.BiomeGenerator; public class ChunkServer extends Chunk { private long lastSave; @@ -86,7 +86,7 @@ public class ChunkServer extends Chunk { } } for(int n = 0; n < this.biomes.length; ++n) { - this.biomes[n] = (byte)biomes[n].id; + this.biomes[n] = (char)biomes[n].id; } if(ceil) this.resetRelight(); @@ -140,27 +140,14 @@ public class ChunkServer extends Chunk { } } - public Biome getBiome(BlockPos pos, BiomeGenerator gen) { - int x = pos.getX() & 15; - int z = pos.getZ() & 15; - int o = this.biomes[z << 4 | x] & 255; - - if(o == 255) { - Biome biome = gen == null ? Biome.DEF_BIOME : gen.getBiomeGenerator(pos, Biome.DEF_BIOME); - o = biome.id; - this.biomes[z << 4 | x] = (byte)(o & 255); - } - - return Biome.getBiomeDef(o); - } - - public byte[] getBiomes() { + public char[] getBiomes() { return this.biomes; } - public void setBiomes(byte[] biomes) { + public void setBiomes(char[] biomes) { if(this.biomes.length != biomes.length) { Log.IO.warn("Konnte Biome des Chunks nicht setzen, Länge des Arrays ist " + biomes.length + " statt " + this.biomes.length); + Arrays.fill(this.biomes, (char)Biome.DEF_BIOME.id); } else { for(int n = 0; n < this.biomes.length; ++n) { diff --git a/server/src/main/java/server/world/Region.java b/server/src/main/java/server/world/Region.java index c63bf57c..a03fe1b7 100755 --- a/server/src/main/java/server/world/Region.java +++ b/server/src/main/java/server/world/Region.java @@ -10,6 +10,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -19,6 +20,7 @@ import java.util.Set; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; +import common.biome.Biome; import common.block.Block; import common.collect.Lists; import common.collect.Maps; @@ -113,8 +115,73 @@ public class Region { return false; } + private static boolean makeBiomeMap(TagObject tag) { + Map biomes = Maps.newTreeMap(); + Map assign = Maps.newHashMap(); + if(tag.hasStringArray("biomes")) { + String[] ids = tag.getStringArray("biomes"); + for(char bid = 1; bid < ids.length; bid++) { + String id = ids[bid]; + if(!id.isEmpty()) { + biomes.put(bid, id); + assign.put(id, bid); + } + } + } + Map mapping = Maps.newHashMap(); + List missing = Lists.newArrayList(); + char highest = 0; + for(Biome state : Biome.values()) { + if(state == Biome.NONE) + continue; + String id = state.getName(); + if(assign.containsKey(id)) { + char bid = assign.get(id); + if(bid == 0) { + missing.add(id); + continue; + } + mapping.put(bid, id); + highest = bid > highest ? bid : highest; + biomes.remove(bid); + Log.IO.debug("Bestehende Biom-ID %d = %s", (int)bid, id); + } + else { + missing.add(id); + } + } + for(Entry entry : biomes.entrySet()) { + Log.IO.debug("Entfernte Biom-ID %d = %s", (int)entry.getKey(), entry.getValue()); + } + char bid = 1; + for(String id : missing) { + while(mapping.containsKey(bid)) { + ++bid; + } + mapping.put(bid, id); + highest = bid > highest ? bid : highest; + Log.IO.debug("Neue Biom-ID %d = %s", (int)bid, id); + } + for(Entry entry : mapping.entrySet()) { + bid = entry.getKey(); + char ids = (char)Biome.findByName(entry.getValue()).id; + BDECODE_MAP[bid] = ids; + BENCODE_MAP[ids] = bid; + } + if(!missing.isEmpty() || !biomes.isEmpty()) { + String[] ids = new String[highest + 1]; + ids[0] = Biome.NONE.getName(); + for(bid = 1; bid < ids.length; bid++) { + ids[bid] = mapping.getOrDefault(bid, ""); + } + tag.setStringArray("biomes", ids); + return true; + } + return false; + } + public static void loadMap() { - File mapFile = new File("blocks.cdt"); + File mapFile = new File("datamap.cdt"); TagObject tag; if(mapFile.exists()) { try { @@ -128,8 +195,10 @@ public class Region { else { tag = new TagObject(); } - if(makeMap(tag)) { - Log.IO.info("Block-IDs haben sich geändert, schreibe %s", mapFile); + boolean states = makeMap(tag); + boolean biomes = makeBiomeMap(tag); + if(states || biomes) { + Log.IO.info((states ? "Block-IDs" : "") + (states && biomes ? " und " : "") + (biomes ? "Biom-IDs" : "") + " haben sich geändert, schreibe %s", mapFile); try { TagObject.writeGZip(tag, mapFile); } @@ -169,6 +238,8 @@ public class Region { private static final List QUEUE = Collections.synchronizedList(Lists.newArrayList()); private static final char[] DECODE_MAP = new char[65536]; private static final char[] ENCODE_MAP = new char[65536]; + private static final char[] BDECODE_MAP = new char[65536]; + private static final char[] BENCODE_MAP = new char[65536]; private static volatile long queued; private static volatile long saved; @@ -519,7 +590,15 @@ public class Region { chunk.setStorage(sections); if(tag.hasByteArray("Biomes")) { - chunk.setBiomes(tag.getByteArray("Biomes")); + byte[] bdata = tag.getByteArray("Biomes"); + char[] biomes = new char[bdata.length / 2]; + for(int n = 0; n < biomes.length; n++) { + biomes[n] = BDECODE_MAP[(char)((bdata[n * 2] & 255) << 8 | bdata[n * 2 + 1] & 255)]; + } + chunk.setBiomes(biomes); + } + else { + Arrays.fill(chunk.getBiomes(), (char)Biome.DEF_BIOME.id); } List entities = tag.getList("Entities"); @@ -645,7 +724,14 @@ public class Region { } tag.setList("Sections", sects); - tag.setByteArray("Biomes", chunk.getBiomes()); + char[] biomes = chunk.getBiomes(); + byte[] bdata = new byte[biomes.length * 2]; + for(int n = 0; n < biomes.length; n++) { + char biome = BENCODE_MAP[biomes[n]]; + bdata[n * 2] = (byte)(biome >> 8 & 255); + bdata[n * 2 + 1] = (byte)(biome & 255); + } + tag.setByteArray("Biomes", bdata); chunk.setHasEntities(false); List entities = Lists.newArrayList(); diff --git a/server/src/main/java/server/world/WorldServer.java b/server/src/main/java/server/world/WorldServer.java index ea1aaf75..3686a00b 100755 --- a/server/src/main/java/server/world/WorldServer.java +++ b/server/src/main/java/server/world/WorldServer.java @@ -601,7 +601,7 @@ public final class WorldServer extends AWorldServer { public Biome getBiomeGenForCoords(final BlockPos pos) { if(this.isBlockLoaded(pos)) - return this.getChunk(pos).getBiome(pos, this.biomeGen); + return this.getChunk(pos).getBiome(pos); else return this.biomeGen.getBiomeGenerator(pos, Biome.DEF_BIOME); } @@ -1854,7 +1854,7 @@ public final class WorldServer extends AWorldServer { ChunkServer chunk = this.getChunk(pos); if(chunk == null || !chunk.isLoaded()) return; - chunk.getBiomes()[((pos.getZ() & 0xF) << 4 | pos.getX() & 0xF)] = (byte)biome.id; + chunk.getBiomes()[((pos.getZ() & 0xF) << 4 | pos.getX() & 0xF)] = (char)biome.id; chunk.setModified(true); int chunkX = pos.getX() >> 4; int chunkZ = pos.getZ() >> 4;