Reintroduce earth layers to zone generator

This commit is contained in:
kuroppoi 2022-07-26 01:33:09 +02:00
parent bb990a2293
commit 9e907ce56d
8 changed files with 84 additions and 33 deletions

View file

@ -73,6 +73,9 @@ public class Item {
@JsonProperty("power") @JsonProperty("power")
private float power; private float power;
@JsonProperty("earthy")
private boolean earthy;
@JsonProperty("diggable") @JsonProperty("diggable")
private boolean diggable; private boolean diggable;
@ -233,6 +236,10 @@ public class Item {
return power; return power;
} }
public boolean isEarthy() {
return earthy;
}
public boolean isDiggable() { public boolean isDiggable() {
return diggable; return diggable;
} }

View file

@ -60,6 +60,7 @@ public class Zone {
private final int numChunksHeight; private final int numChunksHeight;
private int[] surface; private int[] surface;
private int[] sunlight; private int[] sunlight;
private int[] depths;
private boolean[] chunksExplored; private boolean[] chunksExplored;
private float time = (float)Math.random(); // TODO temporary private float time = (float)Math.random(); // TODO temporary
private float temperature = 0; private float temperature = 0;
@ -79,8 +80,10 @@ public class Zone {
this(documentId, config.getName(), config.getBiome(), config.getWidth(), config.getHeight()); this(documentId, config.getName(), config.getBiome(), config.getWidth(), config.getHeight());
surface = data.getSurface(); surface = data.getSurface();
sunlight = data.getSunlight(); sunlight = data.getSunlight();
setDepths(data.getDepths());
// Ha ha silly me! // Ha ha silly me!
// TODO make nifty setters for these too, perhaps?
if(data.getPendingSunlight() != null) { if(data.getPendingSunlight() != null) {
pendingSunlight.addAll(data.getPendingSunlight()); pendingSunlight.addAll(data.getPendingSunlight());
} }
@ -98,6 +101,7 @@ public class Zone {
this.height = height; this.height = height;
numChunksWidth = width / chunkWidth; numChunksWidth = width / chunkWidth;
numChunksHeight = height / chunkHeight; numChunksHeight = height / chunkHeight;
depths = new int[] {(int)(height * 0.6), (int)(height * 0.75), (int)(height * 0.9)};
surface = new int[width]; surface = new int[width];
sunlight = new int[width]; sunlight = new int[width];
chunksExplored = new boolean[numChunksWidth * numChunksHeight]; chunksExplored = new boolean[numChunksWidth * numChunksHeight];
@ -1015,6 +1019,22 @@ public class Zone {
return sunlight; return sunlight;
} }
public void setDepths(int deep, int deeper, int deepest) {
depths[0] = deep;
depths[1] = deeper;
depths[2] = deepest;
}
public void setDepths(int[] depths) {
if(depths != null && depths.length == 3) {
setDepths(depths[0], depths[1], depths[2]);
}
}
public int[] getDepths() {
return depths;
}
public boolean exploreArea(int x, int y) { public boolean exploreArea(int x, int y) {
if(!areCoordinatesInBounds(x, y)) { if(!areCoordinatesInBounds(x, y)) {
return false; return false;
@ -1122,20 +1142,15 @@ public class Zone {
List<Object> earth = new ArrayList<>(); List<Object> earth = new ArrayList<>();
if(player.isV3()) { if(player.isV3()) {
// For some reason this layer is completely broken for desert biomes on Unity clients. earth.add(Arrays.asList(depths[2], "ground/earth-deepest"));
// TODO should depth be unique per biome? Per zone even, perhaps? earth.add(Arrays.asList(depths[1], "ground/earth-deeper"));
if(biome != Biome.DESERT) { earth.add(Arrays.asList(depths[0], "ground/earth-deep"));
earth.add(Arrays.asList(height * 0.9, "ground/earth-deepest"));
}
earth.add(Arrays.asList(height * 0.75, "ground/earth-deeper"));
earth.add(Arrays.asList(height * 0.6, "ground/earth-deep"));
depth.put("ground/earth", earth); depth.put("ground/earth", earth);
} else { } else {
String key = biome == Biome.PLAIN ? "temperate" : biome.getId(); String key = biome == Biome.PLAIN ? "temperate" : biome.getId();
earth.add(Arrays.asList(height * 0.45, String.format("%s/earth-front-deep", key))); earth.add(Arrays.asList(depths[0], String.format("%s/earth-front-deep", key)));
earth.add(Arrays.asList(height * 0.7, String.format("%s/earth-front-deeper", key))); earth.add(Arrays.asList(depths[1], String.format("%s/earth-front-deeper", key)));
earth.add(Arrays.asList(height * 0.9, String.format("%s/earth-front-deepest", key))); earth.add(Arrays.asList(depths[2], String.format("%s/earth-front-deepest", key)));
depth.put(String.format("%s/earth-front", key), earth); depth.put(String.format("%s/earth-front", key), earth);
} }

View file

@ -10,17 +10,19 @@ public class ZoneData {
private final int[] surface; private final int[] surface;
private final int[] sunlight; private final int[] sunlight;
private final int[] depths;
private final Collection<Integer> pendingSunlight; private final Collection<Integer> pendingSunlight;
private final boolean[] chunksExplored; private final boolean[] chunksExplored;
public ZoneData(Zone zone) { public ZoneData(Zone zone) {
this(zone.getSurface(), zone.getSunlight(), zone.getPendingSunlight(), zone.getChunksExplored()); this(zone.getSurface(), zone.getSunlight(), zone.getDepths(), zone.getPendingSunlight(), zone.getChunksExplored());
} }
@ConstructorProperties({"surface", "sunlight", "pending_sunlight", "chunks_explored"}) @ConstructorProperties({"surface", "sunlight", "depths", "pending_sunlight", "chunks_explored"})
public ZoneData(int[] surface, int[] sunlight, Collection<Integer> pendingSunlight, boolean[] chunksExplored) { public ZoneData(int[] surface, int[] sunlight, int[] depths, Collection<Integer> pendingSunlight, boolean[] chunksExplored) {
this.surface = surface; this.surface = surface;
this.sunlight = sunlight; this.sunlight = sunlight;
this.depths = depths;
this.pendingSunlight = pendingSunlight; this.pendingSunlight = pendingSunlight;
this.chunksExplored = chunksExplored; this.chunksExplored = chunksExplored;
} }
@ -33,6 +35,10 @@ public class ZoneData {
return sunlight; return sunlight;
} }
public int[] getDepths() {
return depths;
}
public Collection<Integer> getPendingSunlight() { public Collection<Integer> getPendingSunlight() {
return pendingSunlight; return pendingSunlight;
} }

View file

@ -118,7 +118,7 @@ public class ZoneManager {
chunksExplored[i] = unpacker.unpackBoolean(); chunksExplored[i] = unpacker.unpackBoolean();
} }
ZoneData data = new ZoneData(surface, sunlight, pendingSunlight, chunksExplored); ZoneData data = new ZoneData(surface, sunlight, null, pendingSunlight, chunksExplored);
mapper.writeValue(outputFile, data); mapper.writeValue(outputFile, data);
return data; return data;
} }

View file

@ -102,7 +102,12 @@ public class CaveGenerator implements GeneratorTask {
if(distance <= maxDistance) { if(distance <= maxDistance) {
ctx.updateBlock(i, j, Layer.BASE, variant.getBaseItem()); ctx.updateBlock(i, j, Layer.BASE, variant.getBaseItem());
ctx.updateBlock(i, j, Layer.FRONT, variant.getFrontItem());
if(variant == StoneVariant.DEFAULT) {
ctx.updateBlock(i, j, Layer.FRONT, ctx.getEarthLayer(j));
} else {
ctx.updateBlock(i, j, Layer.FRONT, variant.getFrontItem());
}
} }
} }
} }

View file

@ -43,7 +43,7 @@ public class DecorGenerator implements GeneratorTask {
int y = ctx.getZone().getSurface()[x]; int y = ctx.getZone().getSurface()[x];
// ha ez // ha ez
if(ctx.isEarth(x, y) && ctx.isEarth(x + 1, y) && ctx.nextDouble() <= surfaceFillerRate) { if(ctx.isEarthy(x, y) && ctx.isEarthy(x + 1, y) && ctx.nextDouble() <= surfaceFillerRate) {
ctx.updateBlock(x, y - 1, Layer.FRONT, surfaceFillers[ctx.nextInt(surfaceFillers.length)]); ctx.updateBlock(x, y - 1, Layer.FRONT, surfaceFillers[ctx.nextInt(surfaceFillers.length)]);
} }
} }
@ -125,7 +125,7 @@ public class DecorGenerator implements GeneratorTask {
for(int i = x; i < x + width; i++) { for(int i = x; i < x + width; i++) {
for(int j = y; j < y + height; j++) { for(int j = y; j < y + height; j++) {
if(!ctx.isEarth(i, j)) { if(!ctx.isEarthy(i, j)) {
return; return;
} }
} }
@ -151,7 +151,7 @@ public class DecorGenerator implements GeneratorTask {
int y = ctx.nextInt(maxY - minY + 1) + minY; int y = ctx.nextInt(maxY - minY + 1) + minY;
BlockPosition current = new BlockPosition(x, y); BlockPosition current = new BlockPosition(x, y);
if(ctx.isEarth(x, y)) { if(ctx.isEarthy(x, y)) {
ctx.updateBlock(x, y, Layer.FRONT, item, 0); ctx.updateBlock(x, y, Layer.FRONT, item, 0);
} }
@ -162,7 +162,7 @@ public class DecorGenerator implements GeneratorTask {
int nY = current.getY() + ctx.nextInt(3) - 1; int nY = current.getY() + ctx.nextInt(3) - 1;
current = new BlockPosition(nX, nY); current = new BlockPosition(nX, nY);
if(ctx.isEarth(nX, nY)) { if(ctx.isEarthy(nX, nY)) {
ctx.updateBlock(nX, nY, Layer.FRONT, item, 1); ctx.updateBlock(nX, nY, Layer.FRONT, item, 1);
} }
} }

View file

@ -10,6 +10,7 @@ import java.util.Random;
import brainwine.gameserver.item.Item; import brainwine.gameserver.item.Item;
import brainwine.gameserver.item.Layer; import brainwine.gameserver.item.Layer;
import brainwine.gameserver.prefab.Prefab; import brainwine.gameserver.prefab.Prefab;
import brainwine.gameserver.zone.Biome;
import brainwine.gameserver.zone.Chunk; import brainwine.gameserver.zone.Chunk;
import brainwine.gameserver.zone.Zone; import brainwine.gameserver.zone.Zone;
import brainwine.gameserver.zone.gen.caves.Cave; import brainwine.gameserver.zone.gen.caves.Cave;
@ -96,13 +97,19 @@ public class GeneratorContext {
return zone.areCoordinatesInBounds(x, y) && y >= zone.getSurface()[x]; return zone.areCoordinatesInBounds(x, y) && y >= zone.getSurface()[x];
} }
public boolean isEarth(int x, int y) { public boolean isEarthy(int x, int y) {
if(!zone.areCoordinatesInBounds(x, y)) { if(!zone.areCoordinatesInBounds(x, y)) {
return false; return false;
} }
int item = zone.getBlock(x, y).getFrontItem().getId(); return zone.getBlock(x, y).getFrontItem().isEarthy();
return item == 512; }
public int getEarthLayer(int y) {
int[] depths = zone.getDepths();
return zone.getBiome() == Biome.DEEP
? y >= depths[2] ? 598 : y >= depths[1] ? 597 : y >= depths[0] ? 596 : 595
: y >= depths[2] ? 518 : y >= depths[1] ? 517 : y >= depths[0] ? 516 : 512;
} }
public int getWidth() { public int getWidth() {

View file

@ -15,19 +15,16 @@ public class TerrainGenerator implements GeneratorTask {
int width = ctx.getWidth(); int width = ctx.getWidth();
int height = ctx.getHeight(); int height = ctx.getHeight();
int surfaceLevel = height < 600 ? height / 3 : 200; int surfaceLevel = height < 600 ? height / 3 : 200;
int lowestSurfaceLevel = 0;
boolean asteroids = type == TerrainType.ASTEROIDS;
// Determine surface first, then start placing blocks.
if(type == TerrainType.FILLED) { if(type == TerrainType.FILLED) {
for(int x = 0; x < width; x++) { for(int x = 0; x < width; x++) {
ctx.getZone().setSurface(x, 0); ctx.getZone().setSurface(x, 0);
for(int y = 0; y < height; y++) {
ctx.updateBlock(x, y, Layer.FRONT, 512);
ctx.updateBlock(x, y, Layer.BASE, 2);
}
} }
} else { } else {
PerlinNoise noise = new PerlinNoise(ctx.getSeed()); PerlinNoise noise = new PerlinNoise(ctx.getSeed());
boolean asteroids = type == TerrainType.ASTEROIDS;
double minAmplitude = asteroids ? 10 : 40; double minAmplitude = asteroids ? 10 : 40;
double maxAmplitude = asteroids ? 20 : 80; double maxAmplitude = asteroids ? 20 : 80;
double amplitude = ctx.nextDouble() * minAmplitude + (maxAmplitude - minAmplitude); double amplitude = ctx.nextDouble() * minAmplitude + (maxAmplitude - minAmplitude);
@ -36,12 +33,26 @@ public class TerrainGenerator implements GeneratorTask {
int surface = (int)(noise.perlinNoise(x * 0.01, 0.5, 7) * amplitude) + surfaceLevel; int surface = (int)(noise.perlinNoise(x * 0.01, 0.5, 7) * amplitude) + surfaceLevel;
ctx.getZone().setSurface(x, surface); ctx.getZone().setSurface(x, surface);
// Only generate a thin layer for asteroids, cave gen will take care of the rest. if(surface > lowestSurfaceLevel) {
for(int y = surface; y < (asteroids ? surface + 6 : height); y++) { lowestSurfaceLevel = surface;
ctx.updateBlock(x, y, Layer.FRONT, 512);
ctx.updateBlock(x, y, Layer.BASE, 2);
} }
} }
} }
int heightBelowSurface = height - lowestSurfaceLevel;
ctx.getZone().setDepths(
(int)(heightBelowSurface * 0.25 + lowestSurfaceLevel),
(int)(heightBelowSurface * 0.5 + lowestSurfaceLevel),
(int)(heightBelowSurface * 0.75 + lowestSurfaceLevel));
for(int x = 0; x < width; x++) {
int surface = ctx.getZone().getSurface()[x];
// Only generate a thin layer for asteroids, cave gen will take care of the rest.
for(int y = surface; y < (asteroids ? surface + 6 : height); y++) {
ctx.updateBlock(x, y, Layer.FRONT, ctx.getEarthLayer(y));
ctx.updateBlock(x, y, Layer.BASE, 2);
}
}
} }
} }