Wasserfall System eingebaut
This commit is contained in:
@@ -1,6 +1,86 @@
|
||||
package de.blight.common;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Platzierte Wasserfläche, definiert durch ein Benutzer-Polygon, eine Höhe und eine Fließrichtung.
|
||||
* Platzierte Wasserfläche: Polygon, Höhe, Fließrichtung und Rendering-Parameter.
|
||||
* pointsY enthält pro Ecke eine individuelle Y-Höhe; sind alle gleich waterHeight
|
||||
* ist die Fläche flach (WaterPolygonFilter), sonst abschüssig (FlowingWater-Shader).
|
||||
*/
|
||||
public record PlacedWater(float[] pointsX, float[] pointsZ, float waterHeight, float flowDegrees) {}
|
||||
public record PlacedWater(
|
||||
float[] pointsX,
|
||||
float[] pointsY, // pro Ecke; Länge == pointsX.length
|
||||
float[] pointsZ,
|
||||
float waterHeight,
|
||||
float flowDegrees,
|
||||
// Rendering-Parameter
|
||||
float speed,
|
||||
float waveScale,
|
||||
float waveAmplitude,
|
||||
float transparency,
|
||||
float waterColorR, float waterColorG, float waterColorB,
|
||||
float deepColorR, float deepColorG, float deepColorB
|
||||
) {
|
||||
public static final float DEF_SPEED = 0.5f;
|
||||
public static final float DEF_WAVE_SCALE = 0.008f;
|
||||
public static final float DEF_WAVE_AMPLITUDE = 0.1f;
|
||||
public static final float DEF_TRANSPARENCY = 0.15f;
|
||||
public static final float DEF_WATER_R = 0.05f, DEF_WATER_G = 0.25f, DEF_WATER_B = 0.55f;
|
||||
public static final float DEF_DEEP_R = 0.02f, DEF_DEEP_G = 0.12f, DEF_DEEP_B = 0.30f;
|
||||
|
||||
/** True wenn die Y-Spanne aller Eckpunkte unter 0.5 m liegt (flaches Wasser). */
|
||||
public boolean isFlat() {
|
||||
float min = pointsY[0], max = pointsY[0];
|
||||
for (float y : pointsY) {
|
||||
if (y < min) min = y;
|
||||
if (y > max) max = y;
|
||||
}
|
||||
return (max - min) < 0.5f;
|
||||
}
|
||||
|
||||
/** Erstellt eine PlacedWater mit Standard-Rendering-Parametern und flacher Höhe. */
|
||||
public static PlacedWater of(float[] xs, float[] zs, float h, float flow) {
|
||||
float[] ys = new float[xs.length];
|
||||
Arrays.fill(ys, h);
|
||||
return new PlacedWater(xs, ys, zs, h, flow,
|
||||
DEF_SPEED, DEF_WAVE_SCALE, DEF_WAVE_AMPLITUDE, DEF_TRANSPARENCY,
|
||||
DEF_WATER_R, DEF_WATER_G, DEF_WATER_B,
|
||||
DEF_DEEP_R, DEF_DEEP_G, DEF_DEEP_B);
|
||||
}
|
||||
|
||||
/** Gibt eine Kopie mit neuen Rendering-Parametern zurück. */
|
||||
public PlacedWater withParams(float speed, float waveScale, float waveAmplitude,
|
||||
float transparency,
|
||||
float wr, float wg, float wb,
|
||||
float dr, float dg, float db) {
|
||||
return new PlacedWater(pointsX, pointsY, pointsZ, waterHeight, flowDegrees,
|
||||
speed, waveScale, waveAmplitude, transparency,
|
||||
wr, wg, wb, dr, dg, db);
|
||||
}
|
||||
|
||||
/** Gibt eine Kopie mit neuer globaler Höhe zurück; setzt alle pointsY auf newHeight (flacht ab). */
|
||||
public PlacedWater withHeight(float newHeight) {
|
||||
float[] ys = new float[pointsX.length];
|
||||
Arrays.fill(ys, newHeight);
|
||||
return new PlacedWater(pointsX, ys, pointsZ, newHeight, flowDegrees,
|
||||
speed, waveScale, waveAmplitude, transparency,
|
||||
waterColorR, waterColorG, waterColorB,
|
||||
deepColorR, deepColorG, deepColorB);
|
||||
}
|
||||
|
||||
/** Gibt eine Kopie mit neuer Fließrichtung zurück. */
|
||||
public PlacedWater withFlow(float newDegrees) {
|
||||
return new PlacedWater(pointsX, pointsY, pointsZ, waterHeight, newDegrees,
|
||||
speed, waveScale, waveAmplitude, transparency,
|
||||
waterColorR, waterColorG, waterColorB,
|
||||
deepColorR, deepColorG, deepColorB);
|
||||
}
|
||||
|
||||
/** Gibt eine Kopie mit neuen Eckpunkten (inkl. per-Vertex-Y) zurück. */
|
||||
public PlacedWater withPoints(float[] xs, float[] ys, float[] zs) {
|
||||
return new PlacedWater(xs, ys, zs, waterHeight, flowDegrees,
|
||||
speed, waveScale, waveAmplitude, transparency,
|
||||
waterColorR, waterColorG, waterColorB,
|
||||
deepColorR, deepColorG, deepColorB);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
package de.blight.common;
|
||||
|
||||
/**
|
||||
* Wasserfall-Quad: definiert durch 4 explizite 3D-Eckpunkte.
|
||||
* Reihenfolge: A=oben-links, B=oben-rechts, C=unten-rechts, D=unten-links.
|
||||
* UV scrollt von V=0 (oben) nach V=1 (unten), Wasser fließt bergab.
|
||||
*/
|
||||
public record PlacedWaterfall(
|
||||
float ax, float ay, float az,
|
||||
float bx, float by, float bz,
|
||||
float cx, float cy, float cz,
|
||||
float dx, float dy, float dz,
|
||||
float speed,
|
||||
float transparency,
|
||||
float colorR, float colorG, float colorB
|
||||
) {
|
||||
public static final float DEF_SPEED = 1.5f;
|
||||
public static final float DEF_TRANSPARENCY = 0.75f;
|
||||
public static final float DEF_R = 0.35f, DEF_G = 0.55f, DEF_B = 0.75f;
|
||||
}
|
||||
@@ -5,9 +5,14 @@ import java.nio.file.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Liest und schreibt platzierte Wasserflächen ({@code blight_water.blw}) neben der Kartendatei.
|
||||
* Liest und schreibt platzierte Wasserflächen ({@code blight_water.blw}).
|
||||
*
|
||||
* Format (je Zeile): x1,z1;x2,z2;x3,z3;... TAB waterHeight [TAB flowDegrees]
|
||||
* Format (tab-getrennt):
|
||||
* polygon_points waterHeight flowDegrees speed waveScale waveAmplitude transparency
|
||||
* waterR waterG waterB deepR deepG deepB
|
||||
*
|
||||
* polygon_points: Semikolon-getrennte Tripel "x,y,z" (neu) oder Paare "x,z" (alt, Y = waterHeight).
|
||||
* Alle Felder ab flowDegrees sind optional (rückwärtskompatibel).
|
||||
*/
|
||||
public final class WaterBodyIO {
|
||||
|
||||
@@ -21,18 +26,28 @@ public final class WaterBodyIO {
|
||||
Path p = getPath();
|
||||
Files.createDirectories(p.getParent());
|
||||
try (BufferedWriter w = Files.newBufferedWriter(p)) {
|
||||
w.write("# polygon_points\twaterHeight\tflowDegrees");
|
||||
w.write("# polygon_points\twaterHeight\tflowDegrees\tspeed\twaveScale\twaveAmplitude" +
|
||||
"\ttransparency\twaterR\twaterG\twaterB\tdeepR\tdeepG\tdeepB");
|
||||
w.newLine();
|
||||
for (PlacedWater b : bodies) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < b.pointsX().length; i++) {
|
||||
if (i > 0) sb.append(';');
|
||||
sb.append(String.format(Locale.ROOT, "%.5f,%.5f", b.pointsX()[i], b.pointsZ()[i]));
|
||||
sb.append(String.format(Locale.ROOT, "%.5f,%.5f,%.5f",
|
||||
b.pointsX()[i], b.pointsY()[i], b.pointsZ()[i]));
|
||||
}
|
||||
sb.append('\t');
|
||||
sb.append(String.format(Locale.ROOT, "%.5f", b.waterHeight()));
|
||||
sb.append('\t');
|
||||
sb.append(String.format(Locale.ROOT, "%.1f", b.flowDegrees()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.5f", b.waterHeight()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.1f", b.flowDegrees()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.4f", b.speed()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.6f", b.waveScale()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.5f", b.waveAmplitude()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.5f", b.transparency()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.5f", b.waterColorR()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.5f", b.waterColorG()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.5f", b.waterColorB()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.5f", b.deepColorR()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.5f", b.deepColorG()));
|
||||
sb.append('\t').append(String.format(Locale.ROOT, "%.5f", b.deepColorB()));
|
||||
w.write(sb.toString());
|
||||
w.newLine();
|
||||
}
|
||||
@@ -46,20 +61,42 @@ public final class WaterBodyIO {
|
||||
for (String line : Files.readAllLines(p)) {
|
||||
line = line.strip();
|
||||
if (line.isEmpty() || line.startsWith("#")) continue;
|
||||
String[] parts = line.split("\t", -1);
|
||||
if (parts.length < 2) continue;
|
||||
String[] cols = line.split("\t", -1);
|
||||
if (cols.length < 2) continue;
|
||||
try {
|
||||
float wh = Float.parseFloat(parts[1].strip());
|
||||
float fd = parts.length >= 3 ? Float.parseFloat(parts[2].strip()) : 0f;
|
||||
String[] pts = parts[0].split(";", -1);
|
||||
float wh = Float.parseFloat(cols[1].strip());
|
||||
float flow = cols.length >= 3 ? Float.parseFloat(cols[2].strip()) : 0f;
|
||||
float spd = cols.length >= 4 ? Float.parseFloat(cols[3].strip()) : PlacedWater.DEF_SPEED;
|
||||
float ws = cols.length >= 5 ? Float.parseFloat(cols[4].strip()) : PlacedWater.DEF_WAVE_SCALE;
|
||||
float wa = cols.length >= 6 ? Float.parseFloat(cols[5].strip()) : PlacedWater.DEF_WAVE_AMPLITUDE;
|
||||
float tr = cols.length >= 7 ? Float.parseFloat(cols[6].strip()) : PlacedWater.DEF_TRANSPARENCY;
|
||||
float wr = cols.length >= 8 ? Float.parseFloat(cols[7].strip()) : PlacedWater.DEF_WATER_R;
|
||||
float wg = cols.length >= 9 ? Float.parseFloat(cols[8].strip()) : PlacedWater.DEF_WATER_G;
|
||||
float wb2 = cols.length >= 10? Float.parseFloat(cols[9].strip()) : PlacedWater.DEF_WATER_B;
|
||||
float dr = cols.length >= 11? Float.parseFloat(cols[10].strip()): PlacedWater.DEF_DEEP_R;
|
||||
float dg = cols.length >= 12? Float.parseFloat(cols[11].strip()): PlacedWater.DEF_DEEP_G;
|
||||
float db = cols.length >= 13? Float.parseFloat(cols[12].strip()): PlacedWater.DEF_DEEP_B;
|
||||
|
||||
String[] pts = cols[0].split(";", -1);
|
||||
float[] xs = new float[pts.length];
|
||||
float[] ys = new float[pts.length];
|
||||
float[] zs = new float[pts.length];
|
||||
for (int i = 0; i < pts.length; i++) {
|
||||
String[] c = pts[i].split(",", -1);
|
||||
xs[i] = Float.parseFloat(c[0].strip());
|
||||
zs[i] = Float.parseFloat(c[1].strip());
|
||||
if (c.length >= 3) {
|
||||
// neues Format: x,y,z
|
||||
ys[i] = Float.parseFloat(c[1].strip());
|
||||
zs[i] = Float.parseFloat(c[2].strip());
|
||||
} else {
|
||||
// altes Format: x,z → Y = waterHeight
|
||||
ys[i] = wh;
|
||||
zs[i] = Float.parseFloat(c[1].strip());
|
||||
}
|
||||
}
|
||||
if (xs.length >= 3) {
|
||||
list.add(new PlacedWater(xs, ys, zs, wh, flow, spd, ws, wa, tr, wr, wg, wb2, dr, dg, db));
|
||||
}
|
||||
if (xs.length >= 3) list.add(new PlacedWater(xs, zs, wh, fd));
|
||||
} catch (NumberFormatException | ArrayIndexOutOfBoundsException ignored) {}
|
||||
}
|
||||
return list;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package de.blight.common;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.*;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Liest und schreibt Wasserfall-Quads ({@code blight_waterfall.blwf}).
|
||||
*
|
||||
* Format (tab-getrennt):
|
||||
* ax,ay,az bx,by,bz cx,cy,cz dx,dy,dz speed transparency r g b
|
||||
*/
|
||||
public final class WaterfallIO {
|
||||
|
||||
private WaterfallIO() {}
|
||||
|
||||
public static Path getPath() {
|
||||
return MapIO.getMapPath().resolveSibling("blight_waterfall.blwf");
|
||||
}
|
||||
|
||||
public static void save(List<PlacedWaterfall> list) throws IOException {
|
||||
Path p = getPath();
|
||||
Files.createDirectories(p.getParent());
|
||||
try (BufferedWriter w = Files.newBufferedWriter(p)) {
|
||||
w.write("# ax,ay,az\tbx,by,bz\tcx,cy,cz\tdx,dy,dz\tspeed\ttransparency\tr\tg\tb");
|
||||
w.newLine();
|
||||
for (PlacedWaterfall wf : list) {
|
||||
w.write(String.format(Locale.ROOT,
|
||||
"%.5f,%.5f,%.5f\t%.5f,%.5f,%.5f\t%.5f,%.5f,%.5f\t%.5f,%.5f,%.5f\t%.4f\t%.5f\t%.5f\t%.5f\t%.5f",
|
||||
wf.ax(), wf.ay(), wf.az(),
|
||||
wf.bx(), wf.by(), wf.bz(),
|
||||
wf.cx(), wf.cy(), wf.cz(),
|
||||
wf.dx(), wf.dy(), wf.dz(),
|
||||
wf.speed(), wf.transparency(),
|
||||
wf.colorR(), wf.colorG(), wf.colorB()));
|
||||
w.newLine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static List<PlacedWaterfall> load() throws IOException {
|
||||
Path p = getPath();
|
||||
if (!Files.exists(p)) return List.of();
|
||||
List<PlacedWaterfall> result = new ArrayList<>();
|
||||
for (String line : Files.readAllLines(p)) {
|
||||
line = line.strip();
|
||||
if (line.isEmpty() || line.startsWith("#")) continue;
|
||||
try {
|
||||
String[] cols = line.split("\t", -1);
|
||||
float[] a = parseVec(cols[0]);
|
||||
float[] b = parseVec(cols[1]);
|
||||
float[] c = parseVec(cols[2]);
|
||||
float[] d = parseVec(cols[3]);
|
||||
float speed = cols.length > 4 ? Float.parseFloat(cols[4].strip()) : PlacedWaterfall.DEF_SPEED;
|
||||
float transp = cols.length > 5 ? Float.parseFloat(cols[5].strip()) : PlacedWaterfall.DEF_TRANSPARENCY;
|
||||
float r = cols.length > 6 ? Float.parseFloat(cols[6].strip()) : PlacedWaterfall.DEF_R;
|
||||
float g = cols.length > 7 ? Float.parseFloat(cols[7].strip()) : PlacedWaterfall.DEF_G;
|
||||
float bv = cols.length > 8 ? Float.parseFloat(cols[8].strip()) : PlacedWaterfall.DEF_B;
|
||||
result.add(new PlacedWaterfall(
|
||||
a[0], a[1], a[2], b[0], b[1], b[2],
|
||||
c[0], c[1], c[2], d[0], d[1], d[2],
|
||||
speed, transp, r, g, bv));
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static float[] parseVec(String s) {
|
||||
String[] p = s.strip().split(",", -1);
|
||||
return new float[]{ Float.parseFloat(p[0].strip()),
|
||||
Float.parseFloat(p[1].strip()),
|
||||
Float.parseFloat(p[2].strip()) };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user