diff --git a/blight-assets/src/main/resources/Textures/hud/bar_frame.png b/blight-assets/src/main/resources/Textures/hud/bar_frame.png index 8de1a61..792b383 100644 Binary files a/blight-assets/src/main/resources/Textures/hud/bar_frame.png and b/blight-assets/src/main/resources/Textures/hud/bar_frame.png differ diff --git a/blight-assets/src/main/resources/Textures/menu/background.png b/blight-assets/src/main/resources/Textures/menu/background.png deleted file mode 100644 index 06ca8d4..0000000 Binary files a/blight-assets/src/main/resources/Textures/menu/background.png and /dev/null differ diff --git a/blight-assets/src/main/resources/Textures/menu/backup/button.png b/blight-assets/src/main/resources/Textures/menu/backup/button.png new file mode 100644 index 0000000..21513a4 Binary files /dev/null and b/blight-assets/src/main/resources/Textures/menu/backup/button.png differ diff --git a/blight-assets/src/main/resources/Textures/menu/button.png b/blight-assets/src/main/resources/Textures/menu/button.png index 21513a4..7e70211 100644 Binary files a/blight-assets/src/main/resources/Textures/menu/button.png and b/blight-assets/src/main/resources/Textures/menu/button.png differ diff --git a/blight-editor/src/main/java/de/blight/editor/state/VoxelEditorState.java b/blight-editor/src/main/java/de/blight/editor/state/VoxelEditorState.java index f97a725..2b2a19d 100644 --- a/blight-editor/src/main/java/de/blight/editor/state/VoxelEditorState.java +++ b/blight-editor/src/main/java/de/blight/editor/state/VoxelEditorState.java @@ -994,9 +994,27 @@ public class VoxelEditorState extends BaseAppState { if (cy == aCy) { currentTop = Math.max(0, Math.min(VoxelChunk.SIZE - 1, (int)(anchor - cy * (float) VoxelChunk.CELLS))); - } else { - // Chunks außerhalb des Anker-Chunks ohne bestehende Voxel: überspringen. + } else if (cy < aCy) { + // Chunk unterhalb der Terrain-Oberfläche: sofort komplett auffüllen. + // Verhindert flache Schnitt-Kante bei Y=0 / Wasserrand. + float chunkBaseY = cy * (float) VoxelChunk.CELLS; + if (chunkBaseY + VoxelChunk.SIZE >= -10f) { + int yFloor = Math.max(0, (int) Math.ceil(-10f - chunkBaseY)); + for (int lly = yFloor; lly < VoxelChunk.SIZE; lly++) { + chunk.setDensity(lx, lly, lz, (byte) 127); + } + } continue; + } else { + // Chunk oberhalb des Ankers: nur weiter bauen wenn der Chunk darunter + // an seiner Oberkante (ly=SIZE-1) bereits solid ist. + // Das erlaubt Voxeln aus dem Unterwasserbereich (aCy=-1) in cy=0 + // hineinzuwachsen, sobald cy=-1 bis world Y=0 aufgefüllt ist. + VoxelChunk below = chunks.get(chunkKey(cx, cy - 1, cz)); + if (below == null || below.getDensity(lx, VoxelChunk.SIZE - 1, lz) <= 0) { + continue; + } + currentTop = 0; } } int newTop = Math.min(VoxelChunk.SIZE - 1, currentTop + colStep); @@ -1010,8 +1028,10 @@ public class VoxelEditorState extends BaseAppState { if (chunk.getDensity(lx, ly, lz) > 0) { currentTop = ly; break; } } if (currentTop < 0) continue; // Nichts zu entfernen - int newTop = Math.max(0, currentTop - colStep); - for (int ly = newTop + 1; ly <= currentTop; ly++) { + // newTop darf negativ werden: dann werden ALLE Voxel inkl. ly=0 entfernt. + // Math.max(0,...) würde den untersten Voxel bei Y=0 permanent einfrieren. + int newTop = currentTop - colStep; + for (int ly = Math.max(0, newTop + 1); ly <= currentTop; ly++) { chunk.setDensity(lx, ly, lz, Byte.MIN_VALUE); } } @@ -1474,14 +1494,29 @@ public class VoxelEditorState extends BaseAppState { if (currentTopLY >= 0) { startLY = currentTopLY; } else { - // Terrain-Oberfläche als Ankerpunkt int tCy = VoxelChunk.worldYToCy(th); if (cy == tCy) { + // Terrain-Chunk: schrittweise von der Oberfläche nach oben wachsen lassen. startLY = Math.max(0, Math.min(VoxelChunk.SIZE - 1, (int)(th - cy * (float) VoxelChunk.CELLS))); - } else { - // Chunk ohne bestehende Voxel und nicht der Terrain-Chunk: überspringen. + } else if (cy < tCy) { + // Chunk unterhalb der Terrain-Oberfläche: sofort komplett auffüllen + // (verhindert flache Schnitt-Kante bei Y=0 / Wasserrand). + float chunkBaseY = cy * (float) VoxelChunk.CELLS; + if (chunkBaseY + VoxelChunk.SIZE < -10f) continue; // unter Fundament-Limit + int yFloor = Math.max(0, (int) Math.ceil(-10f - chunkBaseY)); + for (int ly = yFloor; ly < VoxelChunk.SIZE; ly++) { + chunk.setDensity(lx, ly, lz, (byte) 127); + } continue; + } else { + // Chunk über der Terrain-Oberfläche (cy > tCy): weiter bauen + // wenn der Chunk darunter an seiner Oberkante solid ist. + VoxelChunk below = chunks.get(chunkKey(cx, cy - 1, cz)); + if (below == null || below.getDensity(lx, VoxelChunk.SIZE - 1, lz) <= 0) { + continue; + } + startLY = 0; } } int newTop = Math.min(startLY + step, targetLY); // nie über Ziel-Zelle @@ -1549,10 +1584,21 @@ public class VoxelEditorState extends BaseAppState { float th = terrainH(wx, wz); if (!Float.isFinite(th)) continue; int thCy = VoxelChunk.worldYToCy(th); - if (cy != thCy) continue; // Terrain-Oberfläche in anderem Chunk - currentTopWY = th; - startLY = Math.max(0, Math.min(VoxelChunk.SIZE - 1, - (int)(th - cy * (float) VoxelChunk.CELLS))); + if (cy == thCy) { + currentTopWY = th; + startLY = Math.max(0, Math.min(VoxelChunk.SIZE - 1, + (int)(th - cy * (float) VoxelChunk.CELLS))); + } else if (cy > thCy) { + // Chunk über dem Terrain: weiter bauen wenn Chunk darunter an Oberkante solid. + VoxelChunk below = chunks.get(chunkKey(cx, cy - 1, cz)); + if (below == null || below.getDensity(lx, VoxelChunk.SIZE - 1, lz) <= 0) continue; + // ly=0 immer solid setzen – step könnte 0 sein und die Lücke bei Y=0 offen lassen. + chunk.setDensity(lx, 0, lz, (byte) 127); + startLY = 0; + currentTopWY = VoxelChunk.toWorldY(cy, 0); + } else { + continue; // cy < thCy: underground, kein Bedarf für Smooth + } } int step = (int) Math.round((avgH - currentTopWY) * blend); @@ -1662,10 +1708,21 @@ public class VoxelEditorState extends BaseAppState { float th = terrainH(wx, wz); if (!Float.isFinite(th)) continue; int thCy = VoxelChunk.worldYToCy(th); - if (cy != thCy) continue; - currentTopWY = th; - startLY = Math.max(0, Math.min(VoxelChunk.SIZE - 1, - (int)(th - cy * (float) VoxelChunk.CELLS))); + if (cy == thCy) { + currentTopWY = th; + startLY = Math.max(0, Math.min(VoxelChunk.SIZE - 1, + (int)(th - cy * (float) VoxelChunk.CELLS))); + } else if (cy > thCy) { + // Chunk über dem Terrain: weiter bauen wenn Chunk darunter an Oberkante solid. + VoxelChunk below = chunks.get(chunkKey(cx, cy - 1, cz)); + if (below == null || below.getDensity(lx, VoxelChunk.SIZE - 1, lz) <= 0) continue; + // ly=0 immer solid setzen – step könnte 0 sein und die Lücke bei Y=0 offen lassen. + chunk.setDensity(lx, 0, lz, (byte) 127); + startLY = 0; + currentTopWY = VoxelChunk.toWorldY(cy, 0); + } else { + continue; // cy < thCy: underground, kein Bedarf für Slope + } } int step = (int) Math.round((targetH - currentTopWY) * blend); diff --git a/blight-map/src/main/map/blight_map.blm b/blight-map/src/main/map/blight_map.blm index a5f1054..6203fa8 100644 Binary files a/blight-map/src/main/map/blight_map.blm and b/blight-map/src/main/map/blight_map.blm differ diff --git a/blight-map/src/main/map/chunks/voxel_17_0_08.blvc b/blight-map/src/main/map/chunks/voxel_17_0_08.blvc new file mode 100644 index 0000000..0972d31 Binary files /dev/null and b/blight-map/src/main/map/chunks/voxel_17_0_08.blvc differ diff --git a/blight-map/src/main/map/chunks/voxel_17_0_09.blvc b/blight-map/src/main/map/chunks/voxel_17_0_09.blvc new file mode 100644 index 0000000..dab3012 Binary files /dev/null and b/blight-map/src/main/map/chunks/voxel_17_0_09.blvc differ diff --git a/blight-map/src/main/map/chunks/voxel_17_m1_08.blvc b/blight-map/src/main/map/chunks/voxel_17_m1_08.blvc index 7180d8a..798d1b2 100644 Binary files a/blight-map/src/main/map/chunks/voxel_17_m1_08.blvc and b/blight-map/src/main/map/chunks/voxel_17_m1_08.blvc differ diff --git a/blight-map/src/main/map/chunks/voxel_17_m1_09.blvc b/blight-map/src/main/map/chunks/voxel_17_m1_09.blvc new file mode 100644 index 0000000..0038154 Binary files /dev/null and b/blight-map/src/main/map/chunks/voxel_17_m1_09.blvc differ