Added rock DB and worldgen

- Added Rocks container
- Added DiscreteNoise and a DIY Worley generator
- Added RockLayer
  - Used to generate rock strata
- Reworked SurfaceTerrainGenerator to use contexts
This commit is contained in:
OLEGSHA 2021-08-21 23:05:54 +03:00
parent 4f620b7261
commit 9fc1a21191
Signed by: OLEGSHA
GPG Key ID: E57A4B08D64AFF7A
12 changed files with 574 additions and 104 deletions

View File

@ -0,0 +1,25 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.util.noise.discrete;
public interface DiscreteNoise<T> {
T get(double x, double y);
T get(double x, double y, double z);
}

View File

@ -0,0 +1,228 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.common.util.noise.discrete;
import java.util.Collection;
import com.google.common.collect.ImmutableList;
public class WorleyProceduralNoise<T> implements DiscreteNoise<T> {
/*
* Stolen from OpenJDK's Random implementation
* *evil cackling*
*/
private static final long MULTIPLIER = 0x5DEECE66DL;
private static final long ADDEND = 0xBL;
private static final long MASK = (1L << 48) - 1;
private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
private static long permute(long seed) {
return (seed * MULTIPLIER + ADDEND) & MASK;
}
private static double getDouble(long seed) {
final int mask26bits = (1 << 26) - 1;
final int mask27bits = (1 << 27) - 1;
int randomBitsX26 = (int) (seed & 0xFFFFFFFF);
int randomBitsX27 = (int) ((seed >>> Integer.SIZE) & 0xFFFFFFFF);
randomBitsX26 = randomBitsX26 & mask26bits;
randomBitsX27 = randomBitsX27 & mask27bits;
return (((long) (randomBitsX26) << 27) + randomBitsX27) * DOUBLE_UNIT;
}
public static class Entry<T> {
private final T value;
private final double chance;
public Entry(T value, double chance) {
this.value = value;
this.chance = chance;
}
}
public static class Builder<T> {
com.google.common.collect.ImmutableList.Builder<Entry<T>> builder = ImmutableList.builder();
public Builder<T> add(T value, double chance) {
builder.add(new Entry<>(value, chance));
return this;
}
public WorleyProceduralNoise<T> build(long seed) {
return new WorleyProceduralNoise<>(this, seed);
}
}
public static <T> Builder<T> builder() {
return new Builder<>();
}
private final Entry<?>[] entries;
private final long seed;
public WorleyProceduralNoise(Builder<T> builder, long seed) {
this(builder.builder.build(), seed);
}
public WorleyProceduralNoise(Collection<? extends Entry<? extends T>> entries, long seed) {
this.entries = new Entry<?>[entries.size()];
double chancesSum = 0;
for (Entry<? extends T> entry : entries) {
chancesSum += entry.chance;
}
int i = 0;
for (Entry<? extends T> entry : entries) {
this.entries[i] = new Entry<T>(entry.value, entry.chance / chancesSum);
i++;
}
this.seed = seed;
}
@Override
public T get(double x, double y) {
int ox = (int) x;
int oy = (int) y;
T closest = null;
double closestDistanceSq = Double.POSITIVE_INFINITY;
for (int cellX = ox - 1; cellX <= ox + 1; ++cellX) {
for (int cellY = oy - 1; cellY <= oy + 1; ++cellY) {
long cellSeed = permute(cellY ^ permute(cellX ^ seed));
int nodes = getNodeCount(cellSeed);
cellSeed = permute(cellSeed);
for (int i = 0; i < nodes; ++i) {
double nodeX = getDouble(cellSeed) + cellX;
cellSeed = permute(cellSeed);
double nodeY = getDouble(cellSeed) + cellY;
cellSeed = permute(cellSeed);
T value = getValue(getDouble(cellSeed));
cellSeed = permute(cellSeed);
double distanceSq = (x - nodeX) * (x - nodeX) + (y - nodeY) * (y - nodeY);
if (distanceSq < closestDistanceSq) {
closestDistanceSq = distanceSq;
closest = value;
}
}
}
}
return closest;
}
@Override
public T get(double x, double y, double z) {
int ox = (int) x;
int oy = (int) y;
int oz = (int) z;
T closest = null;
double closestDistanceSq = Double.POSITIVE_INFINITY;
for (int cellX = ox - 1; cellX <= ox + 1; ++cellX) {
for (int cellY = oy - 1; cellY <= oy + 1; ++cellY) {
for (int cellZ = oz - 1; cellZ <= oz + 1; ++cellZ) {
long cellSeed = permute(cellZ ^ permute(cellY ^ permute(cellX ^ seed)));
int nodes = getNodeCount(cellSeed);
cellSeed = permute(cellSeed);
for (int i = 0; i < nodes; ++i) {
double nodeX = getDouble(cellSeed) + cellX;
cellSeed = permute(cellSeed);
double nodeY = getDouble(cellSeed) + cellY;
cellSeed = permute(cellSeed);
double nodeZ = getDouble(cellSeed) + cellZ;
cellSeed = permute(cellSeed);
T value = getValue(getDouble(cellSeed));
cellSeed = permute(cellSeed);
double distanceSq = (x - nodeX) * (x - nodeX) + (y - nodeY) * (y - nodeY)
+ (z - nodeZ) * (z - nodeZ);
if (distanceSq < closestDistanceSq) {
closestDistanceSq = distanceSq;
closest = value;
}
}
}
}
}
return closest;
}
@SuppressWarnings("unchecked")
private T getValue(double target) {
int i;
for (i = 0; i < entries.length && target > entries[i].chance; ++i) {
target -= entries[i].chance;
}
return (T) entries[i].value;
}
private int getNodeCount(long seed) {
int uniform = ((int) seed) % 8;
switch (uniform) {
case 0:
case 1:
case 2:
case 3:
return 1;
case 4:
case 5:
return 2;
case 6:
return 3;
default:
return 4;
}
}
}

View File

@ -104,7 +104,7 @@ public class PlanetGenerator extends AbstractWorldGenerator<Boolean> {
DefaultChunkData chunk = getWorldData().getChunk(chunkPos);
if (chunk == null) {
chunk = terrainGenerator.generateTerrain(chunkPos);
chunk = terrainGenerator.generateTerrain(getServer(), chunkPos);
getWorldData().addChunk(chunk);
}
}

View File

@ -17,6 +17,8 @@
*/
package ru.windcorp.progressia.server.world.generation.planet;
import java.util.Map;
import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.FloatRangeMap;
@ -26,6 +28,9 @@ import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.common.world.generic.GenericChunks;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.generation.surface.Surface;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceTerrainGenerator;
import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer;
@ -33,25 +38,38 @@ import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer;
class PlanetTerrainGenerator {
private final PlanetGenerator parent;
private final SurfaceTerrainGenerator surfaceGenerator;
private final Map<AbsFace, SurfaceTerrainGenerator> surfaceGenerators;
public PlanetTerrainGenerator(PlanetGenerator generator, SurfaceFloatField heightMap, FloatRangeMap<TerrainLayer> layers) {
public PlanetTerrainGenerator(
PlanetGenerator generator,
SurfaceFloatField heightMap,
FloatRangeMap<TerrainLayer> layers
) {
this.parent = generator;
int seaLevel = (int) parent.getPlanet().getRadius();
SurfaceFloatField adjustedHeightMap = (f, n, w) -> heightMap.get(f, n, w) + generator.getPlanet().getRadius();
this.surfaceGenerator = new SurfaceTerrainGenerator(adjustedHeightMap, layers);
this.surfaceGenerators = AbsFace.mapToFaces(
face -> new SurfaceTerrainGenerator(
new Surface(face, seaLevel),
adjustedHeightMap,
layers
)
);
}
public PlanetGenerator getGenerator() {
return parent;
}
public DefaultChunkData generateTerrain(Vec3i chunkPos) {
public DefaultChunkData generateTerrain(Server server, Vec3i chunkPos) {
DefaultChunkData chunk = new DefaultChunkData(chunkPos, getGenerator().getWorldData());
if (isOrdinaryChunk(chunkPos)) {
generateOrdinaryTerrain(chunk);
generateOrdinaryTerrain(server, chunk);
} else {
generateBorderTerrain(chunk);
generateBorderTerrain(server, chunk);
}
chunk.setGenerationHint(false);
@ -64,11 +82,11 @@ class PlanetTerrainGenerator {
return sorted.x != sorted.y;
}
private void generateOrdinaryTerrain(DefaultChunkData chunk) {
surfaceGenerator.generateTerrain(chunk);
private void generateOrdinaryTerrain(Server server, DefaultChunkData chunk) {
surfaceGenerators.get(chunk.getUp()).generateTerrain(server, chunk);
}
private void generateBorderTerrain(DefaultChunkData chunk) {
private void generateBorderTerrain(Server server, DefaultChunkData chunk) {
BlockData stone = BlockDataRegistry.getInstance().get("Test:Stone");
BlockData air = BlockDataRegistry.getInstance().get("Test:Air");

View File

@ -17,18 +17,28 @@
*/
package ru.windcorp.progressia.server.world.generation.surface;
import java.util.Random;
import glm.Glm;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.CoordinatePacker;
import ru.windcorp.progressia.common.world.generic.ChunkGenericRO;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.context.ServerTileContext;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceContextImpl;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext;
public class Surface {
private final AbsFace up;
private final int seaLevel;
public Surface(AbsFace up, int seaLevel) {
this.up = up;
this.seaLevel = seaLevel;
}
/**
* @return the up
*/
@ -43,4 +53,27 @@ public class Surface {
return seaLevel;
}
public SurfaceWorldContext createContext(Server server, ChunkGenericRO<?, ?, ?, ?, ?> chunk, long seed) {
Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) ^ seed);
SurfaceContextImpl context = new SurfaceContextImpl((ServerTileContext) server.createAbsoluteContext(), this);
context.setRandom(random);
Vec3i tmpA = new Vec3i();
Vec3i tmpB = new Vec3i();
chunk.getMinBIW(tmpA);
chunk.getMaxBIW(tmpB);
context.toContext(tmpA, tmpA);
context.toContext(tmpB, tmpB);
Glm.min(tmpA, tmpB, context.getMin());
Glm.max(tmpA, tmpB, context.getMax());
return context;
}
}

View File

@ -19,15 +19,9 @@ package ru.windcorp.progressia.server.world.generation.surface;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import glm.Glm;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.CoordinatePacker;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.context.ServerTileContext;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceContextImpl;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext;
public class SurfaceFeatureGenerator {
@ -48,23 +42,7 @@ public class SurfaceFeatureGenerator {
}
public void generateFeatures(Server server, DefaultChunkData chunk) {
Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/);
SurfaceContextImpl context = new SurfaceContextImpl((ServerTileContext) server.createAbsoluteContext(), surface);
context.setRandom(random);
Vec3i tmpA = new Vec3i();
Vec3i tmpB = new Vec3i();
chunk.getMinBIW(tmpA);
chunk.getMaxBIW(tmpB);
context.toContext(tmpA, tmpA);
context.toContext(tmpB, tmpB);
Glm.min(tmpA, tmpB, context.getMin());
Glm.max(tmpA, tmpB, context.getMax());
SurfaceWorldContext context = surface.createContext(server, chunk, 0);
for (SurfaceFeature feature : features) {
feature.process(context);

View File

@ -17,60 +17,73 @@
*/
package ru.windcorp.progressia.server.world.generation.surface;
import java.util.Random;
import glm.vec._3.Vec3;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.common.util.CoordinatePacker;
import ru.windcorp.progressia.common.util.FloatRangeMap;
import ru.windcorp.progressia.common.util.Vectors;
import ru.windcorp.progressia.common.world.DefaultChunkData;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.rels.AxisRotations;
import ru.windcorp.progressia.server.Server;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceWorldContext;
public class SurfaceTerrainGenerator {
private final Surface surface;
private final SurfaceFloatField heightMap;
private final FloatRangeMap<TerrainLayer> layers;
public SurfaceTerrainGenerator(SurfaceFloatField heightMap, FloatRangeMap<TerrainLayer> layers) {
public SurfaceTerrainGenerator(Surface surface, SurfaceFloatField heightMap, FloatRangeMap<TerrainLayer> layers) {
this.surface = surface;
this.heightMap = heightMap;
this.layers = layers;
}
public void generateTerrain(DefaultChunkData chunk) {
public void generateTerrain(Server server, DefaultChunkData chunk) {
Vec3i relBIC = new Vec3i();
Vec3 offset = new Vec3(chunk.getMinX(), chunk.getMinY(), chunk.getMinZ());
AxisRotations.relativize(offset, chunk.getUp(), offset);
offset.z -= DefaultChunkData.CHUNK_RADIUS - 0.5f;
Random random = new Random(CoordinatePacker.pack3IntsIntoLong(chunk.getPosition()) /* ^ seed*/);
SurfaceWorldContext context = surface.createContext(server, chunk, 0);
for (relBIC.x = 0; relBIC.x < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.x) {
for (relBIC.y = 0; relBIC.y < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.y) {
generateColumn(chunk, relBIC, offset, random);
generateColumn(chunk, relBIC, offset, context);
}
}
}
public void generateColumn(DefaultChunkData chunk, Vec3i relBIC, Vec3 offset, Random random) {
float north = relBIC.x + offset.x;
float west = relBIC.y + offset.y;
float relSurface = heightMap.get(chunk.getUp(), north, west) - offset.z;
public void generateColumn(DefaultChunkData chunk, Vec3i relBIC, Vec3 offset, SurfaceWorldContext context) {
int north = (int) (relBIC.x + offset.x);
int west = (int) (relBIC.y + offset.y);
float relSurface = heightMap.get(chunk.getUp(), north, west) - offset.z + DefaultChunkData.CHUNK_RADIUS - 0.5f;
Vec3i location = Vectors.grab3i();
for (relBIC.z = 0; relBIC.z < DefaultChunkData.BLOCKS_PER_CHUNK; ++relBIC.z) {
float depth = relSurface - relBIC.z;
BlockData block = layers.get(depth).get(chunk.getUp(), north, west, depth, random);
int altitude = (int) (relBIC.z + offset.z);
location.set(north, west, altitude);
SurfaceBlockContext blockContext = context.push(location);
BlockData block = layers.get(depth).get(blockContext, depth);
blockContext.pop();
chunk.resolve(relBIC, relBIC);
chunk.setBlock(relBIC, block, false);
chunk.relativize(relBIC, relBIC);
}
Vectors.release(location);
}
}

View File

@ -17,14 +17,12 @@
*/
package ru.windcorp.progressia.server.world.generation.surface;
import java.util.Random;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.rels.AbsFace;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
@FunctionalInterface
public interface TerrainLayer {
BlockData get(AbsFace face, float north, float west, float depth, Random random);
BlockData get(SurfaceBlockContext context, float depth);
}

View File

@ -0,0 +1,126 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import ru.windcorp.progressia.client.world.block.BlockRenderOpaqueCube;
import ru.windcorp.progressia.client.world.block.BlockRenderRegistry;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
import ru.windcorp.progressia.server.world.block.BlockLogic;
import ru.windcorp.progressia.server.world.block.BlockLogicRegistry;
public class Rocks {
public enum RockType {
IGNEOUS, METAMORPHIC, SEDIMENTARY;
}
public enum RockVariant {
MONOLITH("Monolith"),
CRACKED("Cracked"),
GRAVEL("Gravel"),
SAND("Sand");
private final String name;
private RockVariant(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public static class Rock {
private final String name;
private final RockType type;
private final Map<RockVariant, BlockData> blocks = new EnumMap<>(RockVariant.class);
public Rock(String name, RockType type) {
this.name = name;
this.type = type;
}
public String getName() {
return name;
}
public RockType getType() {
return type;
}
public BlockData getBlock(RockVariant variant) {
return blocks.get(variant);
}
private void register() {
for (RockVariant variant : RockVariant.values()) {
String fullName = name + variant.getName();
String id = "Test:" + fullName;
BlockData blockData = new BlockData(id);
blocks.put(variant, blockData);
BlockDataRegistry.getInstance().register(blockData);
BlockLogicRegistry.getInstance().register(new BlockLogic(id));
BlockRenderRegistry.getInstance()
.register(new BlockRenderOpaqueCube(id, BlockRenderRegistry.getBlockTexture(fullName)));
}
}
}
private final Map<String, Rock> rocksByName = Collections.synchronizedMap(new HashMap<>());
private final Multimap<RockType, Rock> rocksByType = Multimaps.synchronizedMultimap(HashMultimap.create());
public Rock create(RockType type, String name) {
Rock rock = new Rock(name, type);
rocksByName.put(name, rock);
rocksByType.put(type, rock);
return rock;
}
public void registerAllRocks() {
getRocks().forEach(Rock::register);
}
public Collection<Rock> getRocks() {
return rocksByName.values();
}
public Collection<Rock> getRocks(RockType type) {
return rocksByType.get(type);
}
}

View File

@ -29,8 +29,6 @@ import java.util.Set;
import java.util.function.Consumer;
import org.lwjgl.glfw.GLFW;
import com.google.common.collect.ImmutableList;
import glm.vec._3.i.Vec3i;
import ru.windcorp.progressia.client.ClientState;
import ru.windcorp.progressia.client.audio.Sound;
@ -59,6 +57,7 @@ import ru.windcorp.progressia.server.world.block.*;
import ru.windcorp.progressia.server.world.entity.*;
import ru.windcorp.progressia.server.world.generation.planet.PlanetGravityModel;
import ru.windcorp.progressia.server.world.tile.*;
import ru.windcorp.progressia.test.Rocks.RockType;
import ru.windcorp.progressia.test.gen.TestGravityModel;
public class TestContent {
@ -69,6 +68,8 @@ public class TestContent {
public static final List<BlockData> PLACEABLE_BLOCKS = new ArrayList<>();
public static final List<TileData> PLACEABLE_TILES = new ArrayList<>();
public static final Rocks ROCKS = new Rocks();
public static void registerContent() {
registerWorldContent();
@ -150,33 +151,16 @@ public class TestContent {
}
private static void registerRocks() {
List<String> rockNames = ImmutableList.of(
"BlackGranite",
"Dolomite",
"Eclogite",
"Gabbro",
"Limestone",
"Marble",
"RedGranite"
);
List<String> rockVariants = ImmutableList.of(
"Monolith",
"Cracked",
"Gravel",
"Sand"
);
ROCKS.create(RockType.IGNEOUS, "BlackGranite");
ROCKS.create(RockType.IGNEOUS, "RedGranite");
ROCKS.create(RockType.IGNEOUS, "Gabbro");
ROCKS.create(RockType.METAMORPHIC, "Marble");
ROCKS.create(RockType.METAMORPHIC, "Eclogite");
ROCKS.create(RockType.SEDIMENTARY, "Limestone");
ROCKS.create(RockType.SEDIMENTARY, "Dolomite");
for (String name : rockNames) {
for (String variant : rockVariants) {
String fullName = name + variant;
String id = "Test:" + fullName;
register(new BlockData(id));
register(new BlockRenderOpaqueCube(id, getBlockTexture(fullName)));
register(new BlockLogic(id));
}
}
ROCKS.registerAllRocks();
}
private static void registerTiles() {

View File

@ -0,0 +1,57 @@
/*
* Progressia
* Copyright (C) 2020-2021 Wind Corporation and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package ru.windcorp.progressia.test.gen;
import ru.windcorp.progressia.common.util.noise.discrete.DiscreteNoise;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer;
import ru.windcorp.progressia.server.world.generation.surface.context.SurfaceBlockContext;
public class RockLayer implements TerrainLayer {
private final DiscreteNoise<TerrainLayer> strata;
private final SurfaceFloatField depthOffsets;
private final double horizontalScale = 200;
private final double verticalScale = 10;
private final double depthInfluense = 0.1;
public RockLayer(DiscreteNoise<TerrainLayer> strata, SurfaceFloatField depthOffsets) {
this.strata = strata;
this.depthOffsets = depthOffsets;
}
@Override
public BlockData get(SurfaceBlockContext context, float depth) {
double z = context.getLocation().z;
z -= depth * depthInfluense;
z += depthOffsets.get(context);
z /= verticalScale;
return strata
.get(
context.getLocation().x / horizontalScale,
context.getLocation().y / horizontalScale,
z
)
.get(context, depth);
}
}

View File

@ -26,6 +26,7 @@ import java.util.function.Function;
import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.util.ArrayFloatRangeMap;
import ru.windcorp.progressia.common.util.FloatRangeMap;
import ru.windcorp.progressia.common.util.noise.discrete.WorleyProceduralNoise;
import ru.windcorp.progressia.common.world.Coordinates;
import ru.windcorp.progressia.common.world.block.BlockData;
import ru.windcorp.progressia.common.world.block.BlockDataRegistry;
@ -36,15 +37,19 @@ import ru.windcorp.progressia.server.world.generation.planet.PlanetGenerator;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFeature;
import ru.windcorp.progressia.server.world.generation.surface.SurfaceFloatField;
import ru.windcorp.progressia.server.world.generation.surface.TerrainLayer;
import ru.windcorp.progressia.test.Rocks.RockVariant;
import ru.windcorp.progressia.test.TestContent;
public class TestGenerationConfig {
private static final long SEED = "No bugs please".hashCode();
private static final float PLANET_RADIUS = Units.get("0.5 km");
private static final float SURFACE_GRAVITY = Units.get("9.8 m/s^2");
private static final float CURVATURE = Units.get("100 m");
private static final float INNER_RADIUS = Units.get("200 m");
private static final Fields FIELDS = new Fields("No bugs please".hashCode());
private static final Fields FIELDS = new Fields(SEED);
public static Function<Server, WorldGenerator> createGenerator() {
@ -68,31 +73,36 @@ public class TestGenerationConfig {
}
private static void registerTerrainLayers(FloatRangeMap<TerrainLayer> layers) {
BlockData granite = BlockDataRegistry.getInstance().get("Test:RedGraniteMonolith");
BlockData graniteCracked = BlockDataRegistry.getInstance().get("Test:RedGraniteCracked");
BlockData graniteGravel = BlockDataRegistry.getInstance().get("Test:RedGraniteGravel");
BlockData dirt = BlockDataRegistry.getInstance().get("Test:Dirt");
BlockData air = BlockDataRegistry.getInstance().get("Test:Air");
SurfaceFloatField cliffs = FIELDS.get("Test:CliffSelector");
layers.put(Float.NEGATIVE_INFINITY, 0, (f, n, w, d, r) -> air);
layers.put(0, 4, (f, n, w, d, r) -> {
if (cliffs.get(f, n, w) > 0) {
switch (r.nextInt(4)) {
case 0:
return granite;
case 1:
return graniteCracked;
default:
return graniteGravel;
WorleyProceduralNoise.Builder<TerrainLayer> builder = WorleyProceduralNoise.builder();
TestContent.ROCKS.getRocks().forEach(rock -> {
builder.add((c, d) -> {
if (c.getRandom().nextInt(3) == 0) {
return rock.getBlock(RockVariant.CRACKED);
} else {
return rock.getBlock(RockVariant.MONOLITH);
}
}, 1);
});
SurfaceFloatField rockDepthOffsets = FIELDS.register(
"Test:RockDepthOffsets",
() -> tweak(FIELDS.primitive(), 40, 5)
);
RockLayer rockLayer = new RockLayer(builder.build(SEED), rockDepthOffsets);
layers.put(Float.NEGATIVE_INFINITY, 0, (c, d) -> air);
layers.put(0, 4, (c, d) -> {
if (cliffs.get(c.getSurface().getUp(), c.getLocation().x, c.getLocation().y) > 0) {
return rockLayer.get(c, d);
} else {
return dirt;
}
});
layers.put(4, Float.POSITIVE_INFINITY, (f, n, w, d, r) -> granite);
layers.put(4, Float.POSITIVE_INFINITY, rockLayer);
}
private static void registerFeatures(List<SurfaceFeature> features) {
@ -101,7 +111,7 @@ public class TestGenerationConfig {
"Test:Forestiness",
() -> squash(scale(FIELDS.primitive(), 200), 5)
);
SurfaceFloatField floweriness = FIELDS.register(
"Test:Floweriness",
f -> multiply(