add block map properly

This commit is contained in:
Sen 2025-06-19 18:28:10 +02:00
parent 64cff6a171
commit dd3ac39530
Signed by: sen
GPG key ID: 3AC50A6F47D1B722
4 changed files with 98 additions and 106 deletions

View file

@ -8,6 +8,4 @@ public abstract class Version {
public static final int MAJOR = 2; public static final int MAJOR = 2;
public static final int MINOR = 3; public static final int MINOR = 3;
public static final int PATCH = 0; public static final int PATCH = 0;
public static final int DATA = 0;
} }

View file

@ -215,8 +215,6 @@ public final class Server implements IThreadListener, Executor {
} }
private long loadServerConfig() { private long loadServerConfig() {
Region.loadMaps();
File file = new File("server.cdt"); File file = new File("server.cdt");
if(!file.exists()) if(!file.exists())
file = new File("server.cdt.tmp"); file = new File("server.cdt.tmp");
@ -406,6 +404,7 @@ public final class Server implements IThreadListener, Executor {
} }
public void run(long time) { public void run(long time) {
Region.loadMap();
Converter.convert(this); Converter.convert(this);
long wtime = this.loadServerConfig(); long wtime = this.loadServerConfig();
if(this.keyPair == null) { if(this.keyPair == null) {

View file

@ -17,7 +17,6 @@ import java.util.Map.Entry;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
import common.Version;
import common.biome.Biome; import common.biome.Biome;
import common.block.Block; import common.block.Block;
import common.block.BlockColored; import common.block.BlockColored;
@ -1092,6 +1091,7 @@ public abstract class Converter {
NbtTag[] sects = tag.getTagList("Sections"); NbtTag[] sects = tag.getTagList("Sections");
entities = Lists.newArrayList(); entities = Lists.newArrayList();
char[] mapping = Region.getEncodeMap();
for(NbtTag sect : sects) { for(NbtTag sect : sects) {
TagObject nsect = new TagObject(); TagObject nsect = new TagObject();
nsect.setInt("Y", sect.getByte("Y")); nsect.setInt("Y", sect.getByte("Y"));
@ -1105,39 +1105,25 @@ public abstract class Converter {
int cz = c >> 4 & 15; int cz = c >> 4 & 15;
int ca = adddata != null ? adddata.get(cx, cy, cz) : 0; int ca = adddata != null ? adddata.get(cx, cy, cz) : 0;
char block = (char)((ca << 8) | (blocks[c] & 255)); char block = (char)((ca << 8) | (blocks[c] & 255));
// if(block == 0) if(block == 0)
// continue; continue;
//// else if(block <= 197) { int dt = block == 111 ? RANDOM.zrange(4) : data.get(cx, cy, cz);
//// if((blocks[c] = BLOCK_MAP[block]) != (byte)block) char cd = mapping[block >= 256 ? BLOCK_MAP[1 << 4] : BLOCK_MAP[(block << 4) | dt]];
//// data.set(cx, cy, cz, DATA_MAP[block]); if(cd >> 12 != 0) {
//// } if(adddata == null)
if(block >= 256) { adddata = new NibbleArray();
blocks[c] = (byte)1; adddata.set(cx, cy, cz, cd >> 12);
data.set(cx, cy, cz, 0);
}
else if(block > 0) {
int dt = block == 111 ? RANDOM.zrange(4) : data.get(cx, cy, cz);
char cd = BLOCK_MAP[(block << 4) | dt];
// if(cd == (char)0x000f)
// cd = (char)BlockRegistry.STATEMAP.get(BLOCK_FUNCS.get((char)((block << 4) | dt)).getState(block, dt));
if(cd >> 12 != 0) {
if(adddata == null)
adddata = new NibbleArray();
adddata.set(cx, cy, cz, cd >> 12);
}
blocks[c] = (byte)(cd >> 4 & 255);
data.set(cx, cy, cz, cd & 15);
} }
blocks[c] = (byte)(cd & 255);
data.set(cx, cy, cz, cd >> 8 & 15);
} }
nsect.setByteArray("Blocks", blocks); nsect.setByteArray("Dat0", blocks);
nsect.setByteArray("Data", data.getData()); nsect.setByteArray("Dat1", data.getData());
if(adddata != null) if(adddata != null)
nsect.setByteArray("Add", adddata.getData()); nsect.setByteArray("Dat2", adddata.getData());
entities.add(nsect); entities.add(nsect);
} }
ntag.setList("Sections", entities); ntag.setList("Sections", entities);
ntag.setInt("Version", Version.DATA);
return ntag; return ntag;
} }

View file

@ -19,7 +19,6 @@ import java.util.Set;
import java.util.zip.DeflaterOutputStream; import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream; import java.util.zip.InflaterInputStream;
import common.Version;
import common.block.Block; import common.block.Block;
import common.collect.Lists; import common.collect.Lists;
import common.collect.Maps; import common.collect.Maps;
@ -74,83 +73,97 @@ public class Region {
return sb.toString(); return sb.toString();
} }
private static TagObject makeMap() { private static boolean makeMap(TagObject tag) {
TagObject tag = new TagObject(); Map<String, Character> mapping = Maps.newHashMap();
Map<String, List<Character>> current = Maps.newHashMap();
Set<Character> taken = Sets.newHashSet();
List<String> missing = Lists.newArrayList();
for(int z = 0; z < 4096; z++) { for(int z = 0; z < 4096; z++) {
Block block = BlockRegistry.getBlockById(z); Block block = BlockRegistry.getBlockById(z);
if(block != Blocks.air) { if(block != Blocks.air) {
Set<IProperty> stored = getSavedProperties(block); Set<IProperty> stored = getSavedProperties(block);
for(int n = 0; n < 16; n++) { for(int n = 0; n < 16; n++) {
String id = filterProperties(block.getStateFromMeta(n), stored); State state = block.getStateFromMeta(n);
MAPPING.put(id, (char)z); String id = filterProperties(state, stored);
tag.setChar(id, (char)z); List<Character> ids = current.get(id);
// Log.IO.info("Block-ID %d:%d [%d] = %s", z, n, z << 4 | n, id); char mid = (char)BlockRegistry.STATEMAP.get(state);
if(ids == null) {
current.put(id, Lists.newArrayList(mid));
}
else {
ids.add(mid);
continue;
}
if(tag.hasChar(id)) {
char bid = tag.getChar(id);
if(bid == 0) {
missing.add(id);
continue;
}
mapping.put(id, bid);
taken.add(bid);
tag.remove(id);
Log.IO.debug("Bestehende Block-ID %d = %s", (int)bid, id);
}
else {
missing.add(id);
}
} }
} }
} }
return tag; char bid = 1;
} for(String id : missing) {
while(taken.contains(bid)) {
private static void cacheMap(TagObject tag, int version) { ++bid;
char[] map = new char[65536]; }
for(String key : tag.keySet()) { mapping.put(id, bid);
if(tag.hasChar(key)) tag.setChar(id, bid);
map[tag.getChar(key)] = MAPPING.getOrDefault(key, (char)0); taken.add(bid);
Log.IO.debug("Neue Block-ID %d = %s", (int)bid, id);
} }
MAPS.put(version, map); for(Entry<String, Character> entry : mapping.entrySet()) {
bid = entry.getValue();
List<Character> ids = current.get(entry.getKey());
DECODE_MAP[bid] = ids.get(0);
for(char id : ids) {
ENCODE_MAP[id] = bid;
}
}
for(String id : tag.keySet()) {
if(tag.hasChar(id))
Log.IO.debug("Entfernte Block-ID %d = %s", (int)tag.getChar(id), id);
}
return !missing.isEmpty() || !tag.isEmpty();
} }
public static void loadMaps() { public static void loadMap() {
TagObject map = makeMap(); File mapFile = new File("blocks.cdt");
File mapFile = new File(new File("mapping"), "m." + Version.DATA + ".cdt"); TagObject tag;
if(!mapFile.exists()) { if(mapFile.exists()) {
mapFile.getParentFile().mkdirs();
try { try {
TagObject.writeGZip(map, mapFile); tag = TagObject.readGZip(mapFile);
} }
catch(Exception e) { catch(Exception e) {
Log.IO.error(e, "Fehler beim Schreiben von " + mapFile); tag = new TagObject();
Log.IO.error(e, "Fehler beim Lesen von %s", mapFile);
} }
} }
File[] maps = new File("mapping").listFiles(file -> file.isFile() && file.getName().startsWith("m.") && file.getName().endsWith(".cdt")); else {
if(maps != null) { tag = new TagObject();
for(File file : maps) { }
String str = file.getName().substring(2, file.getName().length() - 4); if(makeMap(tag)) {
if(str.isEmpty()) Log.IO.info("Block-IDs haben sich geändert, schreibe %s", mapFile);
continue; try {
int version; TagObject.writeGZip(tag, mapFile);
try { }
version = Integer.parseUnsignedInt(str); catch(Exception e) {
} Log.IO.error(e, "Fehler beim Schreiben von %s", mapFile);
catch(NumberFormatException e) {
continue;
}
if(version == Version.DATA)
continue;
TagObject tag;
try {
tag = TagObject.readGZip(file);
}
catch(Exception e) {
Log.IO.error(e, "Fehler beim Lesen von " + file);
continue;
}
cacheMap(tag, version);
} }
} }
} }
private static boolean remap(char[] data, int version, int x, int z) { public static char[] getEncodeMap() {
char[] map = MAPS.get(version); return ENCODE_MAP;
if(map == null) {
Log.IO.error("Chunk %d, %d: Konnte keine Block-Datenbank für Version #%d finden", x, z, version);
return false;
}
Log.IO.info("Chunk %d, %d: Konvertiere Block-IDs von Version #%d zu #%d", x, z, version, Version.DATA);
for(int n = 0; n < data.length; n++) {
data[n] = map[data[n]];
}
return true;
} }
private static class ChunkBuffer extends ByteArrayOutputStream { private static class ChunkBuffer extends ByteArrayOutputStream {
@ -177,8 +190,8 @@ public class Region {
private static final Map<String, Region> CACHE = Maps.<String, Region>newHashMap(); private static final Map<String, Region> CACHE = Maps.<String, Region>newHashMap();
private static final List<WorldServer> QUEUE = Collections.<WorldServer>synchronizedList(Lists.<WorldServer>newArrayList()); private static final List<WorldServer> QUEUE = Collections.<WorldServer>synchronizedList(Lists.<WorldServer>newArrayList());
private static final Map<Integer, char[]> MAPS = Maps.newHashMap(); private static final char[] DECODE_MAP = new char[65536];
private static final Map<String, Character> MAPPING = Maps.newHashMap(); private static final char[] ENCODE_MAP = new char[65536];
private static volatile long queued; private static volatile long queued;
private static volatile long saved; private static volatile long saved;
@ -502,9 +515,9 @@ public class Region {
TagObject sect = sects.get(n); TagObject sect = sects.get(n);
int y = sect.getInt("Y"); int y = sect.getInt("Y");
BlockArray storage = new BlockArray(y << 4, light, null); BlockArray storage = new BlockArray(y << 4, light, null);
byte[] blocks = sect.getByteArray("Blocks"); byte[] blocks = sect.getByteArray("Dat0");
NibbleArray data = new NibbleArray(sect.getByteArray("Data")); NibbleArray data = new NibbleArray(sect.getByteArray("Dat1"));
NibbleArray adddata = sect.hasByteArray("Add") ? new NibbleArray(sect.getByteArray("Add")) : null; NibbleArray adddata = sect.hasByteArray("Dat2") ? new NibbleArray(sect.getByteArray("Dat2")) : null;
char[] seg = new char[blocks.length]; char[] seg = new char[blocks.length];
for(int c = 0; c < seg.length; ++c) { for(int c = 0; c < seg.length; ++c) {
@ -512,12 +525,9 @@ public class Region {
int cy = c >> 8 & 15; int cy = c >> 8 & 15;
int cz = c >> 4 & 15; int cz = c >> 4 & 15;
int ca = adddata != null ? adddata.get(cx, cy, cz) : 0; int ca = adddata != null ? adddata.get(cx, cy, cz) : 0;
seg[c] = (char)(ca << 12 | (blocks[c] & 255) << 4 | data.get(cx, cy, cz)); seg[c] = DECODE_MAP[ca << 12 | data.get(cx, cy, cz) << 8 | (blocks[c] & 255)];
} }
// if(version != Version.DATA)
// remap(seg, version, x, z);
storage.setData(seg); storage.setData(seg);
storage.setBlocklight(new NibbleArray(sect.getByteArray("BlockLight"))); storage.setBlocklight(new NibbleArray(sect.getByteArray("BlockLight")));
@ -602,7 +612,6 @@ public class Region {
public static TagObject writeChunk(WorldServer world, ChunkServer chunk) { public static TagObject writeChunk(WorldServer world, ChunkServer chunk) {
TagObject tag = new TagObject(); TagObject tag = new TagObject();
tag.setInt("Version", Version.DATA);
tag.setLong("LastUpdate", world.getTime()); tag.setLong("LastUpdate", world.getTime());
tag.setIntArray("HeightMap", chunk.getHeights()); tag.setIntArray("HeightMap", chunk.getHeights());
tag.setBool("TerrainPopulated", chunk.isTerrainPopulated()); tag.setBool("TerrainPopulated", chunk.isTerrainPopulated());
@ -621,7 +630,7 @@ public class Region {
NibbleArray adddata = null; NibbleArray adddata = null;
for(int c = 0; c < storage.getData().length; ++c) { for(int c = 0; c < storage.getData().length; ++c) {
char cd = storage.getData()[c]; char cd = ENCODE_MAP[storage.getData()[c]];
int cx = c & 15; int cx = c & 15;
int cy = c >> 8 & 15; int cy = c >> 8 & 15;
int cz = c >> 4 & 15; int cz = c >> 4 & 15;
@ -634,15 +643,15 @@ public class Region {
adddata.set(cx, cy, cz, cd >> 12); adddata.set(cx, cy, cz, cd >> 12);
} }
blocks[c] = (byte)(cd >> 4 & 255); blocks[c] = (byte)(cd & 255);
data.set(cx, cy, cz, cd & 15); data.set(cx, cy, cz, cd >> 8 & 15);
} }
sect.setByteArray("Blocks", blocks); sect.setByteArray("Dat0", blocks);
sect.setByteArray("Data", data.getData()); sect.setByteArray("Dat1", data.getData());
if(adddata != null) { if(adddata != null) {
sect.setByteArray("Add", adddata.getData()); sect.setByteArray("Dat2", adddata.getData());
} }
sect.setByteArray("BlockLight", storage.getBlocklight().getData()); sect.setByteArray("BlockLight", storage.getBlocklight().getData());