Add Carpathian mapgen

master
Treer 2018-04-25 19:09:01 +10:00
parent 9c6525feb0
commit 4ac5660fde
6 changed files with 276 additions and 13 deletions

View File

@ -54,10 +54,10 @@ public class DefaultVersionFeatures implements VersionFeaturesFactory {
this.worldTypes = new WorldTypes(
new WorldType[]{
//WorldType.CARPATHIAN,
WorldType.V7,
WorldType.V6,
WorldType.V5,
WorldType.CARPATHIAN,
WorldType.FLAT,
//WorldType.FRACTAL
}
@ -75,9 +75,7 @@ public class DefaultVersionFeatures implements VersionFeaturesFactory {
VersionFeature.<Integer> listBuilder()
.init(commonLayers)
.initExtend(
LayerIds.MINETEST_OCEAN,
LayerIds.MINETEST_RIVER,
LayerIds.MINETEST_MOUNTAIN
LayerIds.MINETEST_OCEAN
).construct()
);
enabledLayers.put(WorldType.V7,
@ -131,6 +129,10 @@ public class DefaultVersionFeatures implements VersionFeaturesFactory {
WorldType.V5,
(seed, mapgenParams, biomeProfile) -> new amidst.minetest.world.oracle.BiomeDataOracleV5(mapgenParams, biomeProfile, seed)
),
new AbstractMap.SimpleEntry<WorldType, TriFunction<Long, MapgenParams, BiomeProfileSelection, IBiomeDataOracle>>(
WorldType.CARPATHIAN,
(seed, mapgenParams, biomeProfile) -> new amidst.minetest.world.oracle.BiomeDataOracleCarpathian(mapgenParams, biomeProfile, seed)
),
new AbstractMap.SimpleEntry<WorldType, TriFunction<Long, MapgenParams, BiomeProfileSelection, IBiomeDataOracle>>(
WorldType.FLAT,
(seed, mapgenParams, biomeProfile) -> new amidst.minetest.world.oracle.BiomeDataOracleFlat(mapgenParams, biomeProfile, seed)

View File

@ -7,4 +7,10 @@ public class Constants {
// a Minetest Chunk is 5 x 5 x 5 MapBlocks!
public static final int MAP_BLOCKSIZE = 16;
// The absolute working limit is (2^15 - viewing_range).
// I really don't want to make every algorithm to check if it's going near
// the limit or not, so this is lower.
// This is the maximum value the setting map_generation_limit can be
public static final short MAX_MAP_GENERATION_LIMIT = 31000;
}

View File

@ -0,0 +1,56 @@
package amidst.minetest.world.mapgen;
import javax.vecmath.Vector3f;
import amidst.mojangapi.world.WorldType;
import amidst.mojangapi.world.biome.BiomeColor;
// TODO: be able to import these values from map_meta.txt files
public class MapgenCarpathianParams extends MapgenParams {
public static final int FLAG_CARPATHIAN_CAVERNS = 0x01;
public int spflags = FLAG_CARPATHIAN_CAVERNS;
public NoiseParams np_base = new NoiseParams(12, 1, new Vector3f(2557, 2557, 2557), 6538, (short)4, 0.8f, 0.5f);
public NoiseParams np_height1 = new NoiseParams(0, 5, new Vector3f(251, 251, 251), 9613, (short)5, 0.5f, 2.0f);
public NoiseParams np_height2 = new NoiseParams(0, 5, new Vector3f(383, 383, 383), 1949, (short)5, 0.5f, 2.0f);
public NoiseParams np_height3 = new NoiseParams(0, 5, new Vector3f(509, 509, 509), 3211, (short)5, 0.5f, 2.0f);
public NoiseParams np_height4 = new NoiseParams(0, 5, new Vector3f(631, 631, 631), 1583, (short)5, 0.5f, 2.0f);
public NoiseParams np_hills_terrain = new NoiseParams(1, 1, new Vector3f(1301, 1301, 1301), 1692, (short)5, 0.5f, 2.0f);
public NoiseParams np_ridge_terrain = new NoiseParams(1, 1, new Vector3f(1889, 1889, 1889), 3568, (short)5, 0.5f, 2.0f);
public NoiseParams np_step_terrain = new NoiseParams(1, 1, new Vector3f(1889, 1889, 1889), 4157, (short)5, 0.5f, 2.0f);
public NoiseParams np_hills = new NoiseParams(0, 3, new Vector3f(257, 257, 257), 6604, (short)6, 0.5f, 2.0f);
public NoiseParams np_ridge_mnt = new NoiseParams(0, 12, new Vector3f(743, 743, 743), 5520, (short)6, 0.7f, 2.0f);
public NoiseParams np_step_mnt = new NoiseParams(0, 8, new Vector3f(509, 509, 509), 2590, (short)6, 0.6f, 2.0f);
public NoiseParams np_mnt_var = new NoiseParams(0, 1, new Vector3f(499, 499, 499), 2490, (short)5, 0.55f, 2.0f);
@Override
public String toString() {
String prefix = "mgcarpathian_";
StringBuilder result = new StringBuilder();
result.append("mgcarpathian_spflags = ");
appendFlags(result, spflags, new String[] {"caverns"});
result.append("\r\n");
result.append(super.toString());
result.append(np_base.toString( prefix +"np_base"));
result.append(np_height1.toString( prefix +"np_height1"));
result.append(np_height2.toString( prefix +"np_height2"));
result.append(np_height3.toString( prefix +"np_height3"));
result.append(np_height4.toString( prefix +"np_height4"));
result.append(np_hills_terrain.toString(prefix +"np_hills_terrain"));
result.append(np_ridge_terrain.toString(prefix +"np_ridge_terrain"));
result.append(np_step_terrain.toString( prefix +"np_step_terrain"));
result.append(np_hills.toString( prefix +"np_hills"));
result.append(np_ridge_mnt.toString( prefix +"np_ridge_mnt"));
result.append(np_step_mnt.toString( prefix +"np_step_mnt"));
result.append(np_mnt_var.toString( prefix +"np_mnt_var"));
return result.toString();
}
@Override
public WorldType getWorldType() {
return WorldType.CARPATHIAN;
}
}

View File

@ -0,0 +1,206 @@
package amidst.minetest.world.oracle;
import amidst.documentation.Immutable;
import amidst.logging.AmidstLogger;
import amidst.logging.AmidstMessageBox;
import amidst.minetest.world.mapgen.Constants;
import amidst.minetest.world.mapgen.InvalidNoiseParamsException;
import amidst.minetest.world.mapgen.MapgenCarpathianParams;
import amidst.minetest.world.mapgen.MapgenParams;
import amidst.minetest.world.mapgen.MinetestBiome;
import amidst.minetest.world.mapgen.Noise;
import amidst.mojangapi.world.coordinates.CoordinatesInWorld;
import amidst.mojangapi.world.coordinates.Resolution;
import amidst.settings.biomeprofile.BiomeProfileSelection;
@Immutable
public class BiomeDataOracleCarpathian extends MinetestBiomeDataOracle {
private final MapgenCarpathianParams carpathianParams;
private Noise noise_base;
private Noise noise_height1;
private Noise noise_height2;
private Noise noise_height3;
private Noise noise_height4;
private Noise noise_hills_terrain;
private Noise noise_ridge_terrain;
private Noise noise_step_terrain;
private Noise noise_hills;
private Noise noise_ridge_mnt;
private Noise noise_step_mnt;
private Noise noise_mnt_var;
private int grad_wl;
/**
* @param mapgenCarpathianParams
* @param biomeProfileSelection - if null then a default biomeprofile will be used
* @param seed
* @throws InvalidNoiseParamsException
*/
public BiomeDataOracleCarpathian(MapgenParams mapgenCarpathianParams, BiomeProfileSelection biomeProfileSelection, long seed) {
super(mapgenCarpathianParams, biomeProfileSelection, seed);
if (params instanceof MapgenCarpathianParams) {
carpathianParams = (MapgenCarpathianParams)params;
} else {
AmidstLogger.error("Error: BiomeDataOracleCarpathian cannot cast params to CarpathianParams. Using defaults instead.");
this.params = carpathianParams = new MapgenCarpathianParams();
}
grad_wl = 1 - params.water_level;
try {
// 2D noise
noise_base = new Noise(carpathianParams.np_base, this.seed, params.chunk_length_x, params.chunk_length_z);
noise_height1 = new Noise(carpathianParams.np_height1, this.seed, params.chunk_length_x, params.chunk_length_z);
noise_height2 = new Noise(carpathianParams.np_height2, this.seed, params.chunk_length_x, params.chunk_length_z);
noise_height3 = new Noise(carpathianParams.np_height3, this.seed, params.chunk_length_x, params.chunk_length_z);
noise_height4 = new Noise(carpathianParams.np_height4, this.seed, params.chunk_length_x, params.chunk_length_z);
noise_hills_terrain = new Noise(carpathianParams.np_hills_terrain, this.seed, params.chunk_length_x, params.chunk_length_z);
noise_ridge_terrain = new Noise(carpathianParams.np_ridge_terrain, this.seed, params.chunk_length_x, params.chunk_length_z);
noise_step_terrain = new Noise(carpathianParams.np_step_terrain, this.seed, params.chunk_length_x, params.chunk_length_z);
noise_hills = new Noise(carpathianParams.np_hills, this.seed, params.chunk_length_x, params.chunk_length_z);
noise_ridge_mnt = new Noise(carpathianParams.np_ridge_mnt, this.seed, params.chunk_length_x, params.chunk_length_z);
noise_step_mnt = new Noise(carpathianParams.np_step_mnt, this.seed, params.chunk_length_x, params.chunk_length_z);
//// 3D terrain noise
// 1 up 1 down overgeneration
noise_mnt_var = new Noise(carpathianParams.np_mnt_var, this.seed, params.chunk_length_x, params.chunk_length_y + 2, params.chunk_length_z);
} catch (InvalidNoiseParamsException ex) {
AmidstLogger.error("Invalid carpathianParams from Minetest game. " + ex);
ex.printStackTrace();
}
}
// Steps function
float getSteps(float noise)
{
float w = 0.5f;
float k = (float) Math.floor(noise / w);
float f = (noise - k * w) / w;
float s = Math.min(2.f * f, 1.f);
return (k + s) * w;
}
float terrainLevelAtPoint(int x, int z)
{
float ground = Noise.NoisePerlin2D(noise_base.np, x, z, seed);
float height1 = Noise.NoisePerlin2D(noise_height1.np, x, z, seed);
float height2 = Noise.NoisePerlin2D(noise_height2.np, x, z, seed);
float height3 = Noise.NoisePerlin2D(noise_height3.np, x, z, seed);
float height4 = Noise.NoisePerlin2D(noise_height4.np, x, z, seed);
float hter = Noise.NoisePerlin2D(noise_hills_terrain.np, x, z, seed);
float rter = Noise.NoisePerlin2D(noise_ridge_terrain.np, x, z, seed);
float ster = Noise.NoisePerlin2D(noise_step_terrain.np, x, z, seed);
float n_hills = Noise.NoisePerlin2D(noise_hills.np, x, z, seed);
float n_ridge_mnt = Noise.NoisePerlin2D(noise_ridge_mnt.np, x, z, seed);
float n_step_mnt = Noise.NoisePerlin2D(noise_step_mnt.np, x, z, seed);
int height = -Constants.MAX_MAP_GENERATION_LIMIT;
int searchInc = 1;
for (short y = 1; y <= 200; y += searchInc) { // we're going to break out of this loop when y is close to surface_level
float mnt_var = Noise.NoisePerlin3D(noise_mnt_var.np, x, y, z, seed);
// Gradient & shallow seabed
int grad = (y < params.water_level) ? grad_wl + (params.water_level - y) * 3 : 1 - y;
// Hill/Mountain height (hilliness)
// Java doesn't have inline functions, so expanding getLerp()
// getLerp(float noise1, float noise2, float mod) = noise1 + mod * (noise2 - noise1);
// was:
// float hill1 = getLerp(height1, height2, mnt_var);
// float hill2 = getLerp(height3, height4, mnt_var);
// float hill3 = getLerp(height3, height2, mnt_var);
// float hill4 = getLerp(height1, height4, mnt_var);
float hill1 = height1 + mnt_var * (height2 - height1);
float hill2 = height3 + mnt_var * (height4 - height3);
float hill3 = height3 + mnt_var * (height2 - height3);
float hill4 = height1 + mnt_var * (height4 - height1);
float hilliness = Math.max(Math.min(hill1, hill2), Math.min(hill3, hill4));
// Rolling hills
float hill_mnt = hilliness * (float)Math.pow(n_hills, 2.f);
float hills = (float)Math.pow(hter, 3.f) * hill_mnt;
// Ridged mountains
float ridge_mnt = hilliness * (1.f - Math.abs(n_ridge_mnt));
float ridged_mountains = (float)Math.pow(rter, 3.f) * ridge_mnt;
// Step (terraced) mountains
float step_mnt = hilliness * getSteps(n_step_mnt);
float step_mountains = (float)Math.pow(ster, 3.f) * step_mnt;
// Final terrain level
float mountains = hills + ridged_mountains + step_mountains;
float surface_level = ground + mountains + grad;
height = (int)surface_level;
if ((y + (searchInc / 2)) >= surface_level) {
// Close enough.
// (should be properly accurate at water level, but will lose accuracy with height)
break;
}
if (y > 2 && searchInc < 12) searchInc += 2;
}
return height;
}
@Override
public short populateArray(CoordinatesInWorld corner, short[][] result, boolean useQuarterResolution) {
// The Carpathian mapgen terrain is not yet stable.
// See https://forum.minetest.net/viewtopic.php?f=18&t=19132
int width = result.length;
if (width > 0) {
Resolution resolution = Resolution.from(useQuarterResolution);
int height = result[0].length;
int left = (int) corner.getX();
int top = (int) corner.getY();
int shift = resolution.getShift();
int step = resolution.getStep();
int world_z;
int world_x;
short biomeValue;
MinetestBiome[] biomes = getBiomeArray();
try {
for (int y = 0; y < height; y++) {
world_z = top + (y << shift);
world_x = left;
// Use -world_z because Minetest uses left-handed coordinates, while Minecraft
// and Amidst use right-handed coordinates.
world_z = -world_z;
for (int x = 0; x < width; x++) {
biomeValue = 0;
// Add the ocean bitplane
int surface_y = (int)terrainLevelAtPoint(world_x, world_z);
if (surface_y < carpathianParams.water_level) biomeValue |= BITPLANE_OCEAN;
// add the biome index
// (mask the bitplanes in case the biome returned is -1 (NONE)
biomeValue |= calcBiomeAtPoint(biomes, world_x, surface_y, world_z).getIndex() & MASK_BITPLANES;
result[x][y] = biomeValue;
world_x += step;
}
}
} catch (Exception e) {
AmidstLogger.error(e);
AmidstMessageBox.displayError("Error", e);
}
}
return MASK_BITPLANES;
}
}

View File

@ -4,7 +4,6 @@ import java.io.Console;
import amidst.logging.AmidstLogger;
import amidst.logging.AmidstMessageBox;
import amidst.minetest.world.mapgen.DefaultBiomes;
import amidst.minetest.world.mapgen.InvalidNoiseParamsException;
import amidst.minetest.world.mapgen.MapgenParams;
import amidst.minetest.world.mapgen.MapgenV6Params;

View File

@ -10,7 +10,6 @@ import amidst.minetest.world.mapgen.MinetestBiome;
import amidst.minetest.world.mapgen.Noise;
import amidst.mojangapi.world.coordinates.CoordinatesInWorld;
import amidst.mojangapi.world.coordinates.Resolution;
import amidst.settings.biomeprofile.BiomeProfile;
import amidst.settings.biomeprofile.BiomeProfileSelection;
@Immutable
@ -30,11 +29,6 @@ public class BiomeDataOracleV7 extends MinetestBiomeDataOracle {
//private Noise noise_filler_depth; // commented out because it shouldn't been needed for the surface
/**
* Updated by onBiomeProfileUpdate event, can be null.
*/
private volatile BiomeProfile biomeProfile;
short mount_zero_level = 0;
float float_mount_density = 0.6f;
float float_mount_height = 128.0f;
@ -191,10 +185,10 @@ public class BiomeDataOracleV7 extends MinetestBiomeDataOracle {
// Add the ocean bitplane
int surface_y = (int)baseTerrainLevelAtPoint(world_x, world_z);
if (surface_y < v7params.water_level) biomeValue |= BITPLANE_OCEAN;
if (surface_y < params.water_level) biomeValue |= BITPLANE_OCEAN;
// Add the mountains bitplane
int surfaceOrSeaLevel = Math.max(surface_y, v7params.water_level);
int surfaceOrSeaLevel = Math.max(surface_y, params.water_level);
float mnt_h_n = Math.max(Noise.NoisePerlin2D(noise_mount_height.np, world_x, world_z, seed), 1.0f);
float density_gradient = -((float)(surfaceOrSeaLevel - mount_zero_level) / mnt_h_n);
float mnt_n1 = Noise.NoisePerlin3D(noise_mountain.np, world_x, surfaceOrSeaLevel, world_z, seed);