Einmal den Fortschritt mit dem Wasser sichern
This commit is contained in:
@@ -3,10 +3,10 @@ package de.blight.common;
|
||||
/**
|
||||
* Serialisierbarer Zustand einer Blight-Weltkarte.
|
||||
*
|
||||
* Basis-Terrain : 4097 × 4097 Vertices (= 4096 × 4096 Zellen),
|
||||
* 8 Welteinheiten pro Zelle → Welt −2048 .. +2048.
|
||||
* Basis-Terrain : 16385 × 16385 Vertices (= 16384 × 16384 Zellen, 0,25 m/Vertex),
|
||||
* Welt −2048 .. +2048 m.
|
||||
* Obere Schicht : 513 × 513 Vertices (= 512 × 512 Zellen), gleiche Weltausdehnung.
|
||||
* Splatmap : 513 × 513 Pixel (1:1 zu beiden Terrain-Grids).
|
||||
* Splatmap : 2049 × 2049 Pixel (≈ 2 m/Pixel).
|
||||
* Kanäle R/G/B/A = Gewicht für Tex1-Helligkeit / Tex2 / Tex3 / Tex4.
|
||||
*/
|
||||
public final class MapData {
|
||||
@@ -14,7 +14,7 @@ public final class MapData {
|
||||
// ── Terrain-Konstanten ────────────────────────────────────────────────────
|
||||
|
||||
/** Vertices pro Achse des Basis-Terrains (muss 2^n + 1 sein). */
|
||||
public static final int TERRAIN_VERTS = 4097;
|
||||
public static final int TERRAIN_VERTS = 16385;
|
||||
|
||||
// ── Upper-Layer-Konstanten ────────────────────────────────────────────────
|
||||
|
||||
@@ -26,8 +26,8 @@ public final class MapData {
|
||||
|
||||
// ── Splatmap-Konstanten ────────────────────────────────────────────────────
|
||||
|
||||
/** Pixel pro Achse der Splatmap (entspricht UPPER_VERTS = Spiel-Terrain-Auflösung). */
|
||||
public static final int SPLAT_SIZE = 513;
|
||||
/** Pixel pro Achse der Splatmap (≈ 2 m/Pixel bei 4096 m Weltkante). */
|
||||
public static final int SPLAT_SIZE = 2049;
|
||||
|
||||
/** Anzahl konfigurierbarer Textur-Slots pro Terrain-Layer. */
|
||||
public static final int TEXTURE_SLOTS = 4;
|
||||
|
||||
@@ -22,6 +22,8 @@ import java.util.zip.*;
|
||||
* 7 – wie 6 + Gras-Texturpfad (UTF-String) + Gras-Standardhöhe (float)
|
||||
* 8 – wie 7 + Gras-Höhen-Map (SPLAT_SIZE² Bytes, 0=ungesetzt 1-255=0.1-10m)
|
||||
* 9 – wie 8 + Gras-Textur-Map (SPLAT_SIZE² Bytes) + Slots (N×UTF)
|
||||
* 10 – wie 9, aber TERRAIN_VERTS=16385 (0,25 m/Vertex) + SPLAT_SIZE=2049 (2 m/Pixel)
|
||||
* Altes Format (v≤9) wird beim Laden bilinear hochskaliert.
|
||||
*/
|
||||
public final class MapIO {
|
||||
|
||||
@@ -53,7 +55,11 @@ public final class MapIO {
|
||||
}
|
||||
|
||||
private static final int MAGIC = 0x424C4947; // "BLIG"
|
||||
private static final int VERSION = 9;
|
||||
private static final int VERSION = 10;
|
||||
|
||||
// Größen älterer Saves (v≤9) – für Migrations-Upsampling
|
||||
private static final int OLD_TERRAIN_VERTS = 4097;
|
||||
private static final int OLD_SPLAT_SIZE = 513;
|
||||
|
||||
private MapIO() {}
|
||||
|
||||
@@ -134,36 +140,76 @@ public final class MapIO {
|
||||
if (version < 1 || version > VERSION)
|
||||
throw new IOException("Unbekannte Map-Version: " + version);
|
||||
|
||||
readFloats(in, data.terrainHeight);
|
||||
readFloats(in, data.upperTop);
|
||||
readFloats(in, data.upperBottom);
|
||||
if (version >= 10) {
|
||||
readFloats(in, data.terrainHeight);
|
||||
readFloats(in, data.upperTop);
|
||||
readFloats(in, data.upperBottom);
|
||||
} else {
|
||||
// v≤9: alte Größen lesen und bilinear hochskalieren
|
||||
float[] oldH = new float[OLD_TERRAIN_VERTS * OLD_TERRAIN_VERTS];
|
||||
float[] oldUT = new float[MapData.UPPER_VERTS * MapData.UPPER_VERTS];
|
||||
float[] oldUB = new float[MapData.UPPER_VERTS * MapData.UPPER_VERTS];
|
||||
readFloats(in, oldH);
|
||||
upsampleFloats(oldH, OLD_TERRAIN_VERTS, data.terrainHeight, MapData.TERRAIN_VERTS);
|
||||
readFloats(in, oldUT); System.arraycopy(oldUT, 0, data.upperTop, 0, oldUT.length);
|
||||
readFloats(in, oldUB); System.arraycopy(oldUB, 0, data.upperBottom, 0, oldUB.length);
|
||||
}
|
||||
|
||||
if (version <= 5) {
|
||||
// v5 had upperHole[UPPER_CELLS²]; read and discard
|
||||
in.skip((long) MapData.UPPER_CELLS * MapData.UPPER_CELLS);
|
||||
}
|
||||
|
||||
if (version >= 2) {
|
||||
in.readFully(data.splatR);
|
||||
in.readFully(data.splatG);
|
||||
in.readFully(data.splatB);
|
||||
if (version >= 10) {
|
||||
in.readFully(data.splatR); in.readFully(data.splatG); in.readFully(data.splatB);
|
||||
} else {
|
||||
byte[] oR = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
byte[] oG = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
byte[] oB = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
in.readFully(oR); in.readFully(oG); in.readFully(oB);
|
||||
upsampleBytes(oR, OLD_SPLAT_SIZE, data.splatR, MapData.SPLAT_SIZE);
|
||||
upsampleBytes(oG, OLD_SPLAT_SIZE, data.splatG, MapData.SPLAT_SIZE);
|
||||
upsampleBytes(oB, OLD_SPLAT_SIZE, data.splatB, MapData.SPLAT_SIZE);
|
||||
}
|
||||
}
|
||||
if (version >= 3) {
|
||||
in.readFully(data.grassDensity);
|
||||
if (version >= 10) {
|
||||
in.readFully(data.grassDensity);
|
||||
} else {
|
||||
byte[] old = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
in.readFully(old);
|
||||
upsampleBytes(old, OLD_SPLAT_SIZE, data.grassDensity, MapData.SPLAT_SIZE);
|
||||
}
|
||||
}
|
||||
if (version >= 4) {
|
||||
data.spawnX = in.readFloat();
|
||||
data.spawnZ = in.readFloat();
|
||||
}
|
||||
if (version >= 5) {
|
||||
in.readFully(data.splatA);
|
||||
readStrings(in, data.terrainTextures);
|
||||
in.readFully(data.upperSplatR);
|
||||
in.readFully(data.upperSplatG);
|
||||
in.readFully(data.upperSplatB);
|
||||
in.readFully(data.upperSplatA);
|
||||
readStrings(in, data.upperTextures);
|
||||
if (version >= 10) {
|
||||
in.readFully(data.splatA);
|
||||
readStrings(in, data.terrainTextures);
|
||||
in.readFully(data.upperSplatR); in.readFully(data.upperSplatG);
|
||||
in.readFully(data.upperSplatB); in.readFully(data.upperSplatA);
|
||||
readStrings(in, data.upperTextures);
|
||||
} else {
|
||||
byte[] oA = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
byte[] oUR = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
byte[] oUG = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
byte[] oUB = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
byte[] oUA = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
in.readFully(oA);
|
||||
readStrings(in, data.terrainTextures);
|
||||
in.readFully(oUR); in.readFully(oUG); in.readFully(oUB); in.readFully(oUA);
|
||||
readStrings(in, data.upperTextures);
|
||||
upsampleBytes(oA, OLD_SPLAT_SIZE, data.splatA, MapData.SPLAT_SIZE);
|
||||
upsampleBytes(oUR, OLD_SPLAT_SIZE, data.upperSplatR, MapData.SPLAT_SIZE);
|
||||
upsampleBytes(oUG, OLD_SPLAT_SIZE, data.upperSplatG, MapData.SPLAT_SIZE);
|
||||
upsampleBytes(oUB, OLD_SPLAT_SIZE, data.upperSplatB, MapData.SPLAT_SIZE);
|
||||
upsampleBytes(oUA, OLD_SPLAT_SIZE, data.upperSplatA, MapData.SPLAT_SIZE);
|
||||
}
|
||||
} else {
|
||||
// Ältere Maps: upperSplatR auf 255 initialisieren (Tex1 immer sichtbar)
|
||||
java.util.Arrays.fill(data.upperSplatR, (byte) 255);
|
||||
}
|
||||
if (version >= 7) {
|
||||
@@ -171,13 +217,25 @@ public final class MapIO {
|
||||
data.grassDefaultHeight = in.readFloat();
|
||||
}
|
||||
if (version >= 8) {
|
||||
in.readFully(data.grassHeightMap);
|
||||
if (version >= 10) {
|
||||
in.readFully(data.grassHeightMap);
|
||||
} else {
|
||||
byte[] old = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
in.readFully(old);
|
||||
upsampleBytes(old, OLD_SPLAT_SIZE, data.grassHeightMap, MapData.SPLAT_SIZE);
|
||||
}
|
||||
}
|
||||
if (version >= 9) {
|
||||
int n = in.readInt();
|
||||
data.grassTextureSlots = new String[n];
|
||||
for (int i = 0; i < n; i++) data.grassTextureSlots[i] = in.readUTF();
|
||||
in.readFully(data.grassTextureMap);
|
||||
if (version >= 10) {
|
||||
in.readFully(data.grassTextureMap);
|
||||
} else {
|
||||
byte[] old = new byte[OLD_SPLAT_SIZE*OLD_SPLAT_SIZE];
|
||||
in.readFully(old);
|
||||
upsampleBytes(old, OLD_SPLAT_SIZE, data.grassTextureMap, MapData.SPLAT_SIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
@@ -207,4 +265,39 @@ public final class MapIO {
|
||||
int len = in.readInt();
|
||||
for (int i = 0; i < len && i < arr.length; i++) arr[i] = in.readUTF();
|
||||
}
|
||||
|
||||
private static void upsampleFloats(float[] src, int srcSize, float[] dst, int dstSize) {
|
||||
float scale = (float)(srcSize - 1) / (dstSize - 1);
|
||||
for (int dz = 0; dz < dstSize; dz++) {
|
||||
float sz = dz * scale;
|
||||
int sz0 = Math.min((int)sz, srcSize - 2), sz1 = sz0 + 1;
|
||||
float fz = sz - sz0;
|
||||
for (int dx = 0; dx < dstSize; dx++) {
|
||||
float sx = dx * scale;
|
||||
int sx0 = Math.min((int)sx, srcSize - 2), sx1 = sx0 + 1;
|
||||
float fx = sx - sx0;
|
||||
dst[dz*dstSize+dx] =
|
||||
(src[sz0*srcSize+sx0]*(1-fx) + src[sz0*srcSize+sx1]*fx)*(1-fz)
|
||||
+ (src[sz1*srcSize+sx0]*(1-fx) + src[sz1*srcSize+sx1]*fx)*fz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void upsampleBytes(byte[] src, int srcSize, byte[] dst, int dstSize) {
|
||||
float scale = (float)(srcSize - 1) / (dstSize - 1);
|
||||
for (int dz = 0; dz < dstSize; dz++) {
|
||||
float sz = dz * scale;
|
||||
int sz0 = Math.min((int)sz, srcSize - 2), sz1 = sz0 + 1;
|
||||
float fz = sz - sz0;
|
||||
for (int dx = 0; dx < dstSize; dx++) {
|
||||
float sx = dx * scale;
|
||||
int sx0 = Math.min((int)sx, srcSize - 2), sx1 = sx0 + 1;
|
||||
float fx = sx - sx0;
|
||||
float v =
|
||||
((src[sz0*srcSize+sx0]&0xFF)*(1-fx) + (src[sz0*srcSize+sx1]&0xFF)*fx)*(1-fz)
|
||||
+ ((src[sz1*srcSize+sx0]&0xFF)*(1-fx) + (src[sz1*srcSize+sx1]&0xFF)*fx)*fz;
|
||||
dst[dz*dstSize+dx] = (byte)Math.round(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user