diff --git a/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/DiscreteNoise.java b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/DiscreteNoise.java
new file mode 100644
index 0000000..3e600f0
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/DiscreteNoise.java
@@ -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 .
+ */
+package ru.windcorp.progressia.common.util.noise.discrete;
+
+public interface DiscreteNoise {
+
+ T get(double x, double y);
+ T get(double x, double y, double z);
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/WorleyProceduralNoise.java b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/WorleyProceduralNoise.java
new file mode 100644
index 0000000..258e9b0
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/common/util/noise/discrete/WorleyProceduralNoise.java
@@ -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 .
+ */
+package ru.windcorp.progressia.common.util.noise.discrete;
+
+import java.util.Collection;
+import com.google.common.collect.ImmutableList;
+
+public class WorleyProceduralNoise implements DiscreteNoise {
+
+ /*
+ * 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 {
+ private final T value;
+ private final double chance;
+
+ public Entry(T value, double chance) {
+ this.value = value;
+ this.chance = chance;
+ }
+ }
+
+ public static class Builder {
+
+ com.google.common.collect.ImmutableList.Builder> builder = ImmutableList.builder();
+
+ public Builder add(T value, double chance) {
+ builder.add(new Entry<>(value, chance));
+ return this;
+ }
+
+ public WorleyProceduralNoise build(long seed) {
+ return new WorleyProceduralNoise<>(this, seed);
+ }
+
+ }
+
+ public static Builder builder() {
+ return new Builder<>();
+ }
+
+ private final Entry>[] entries;
+ private final long seed;
+
+ public WorleyProceduralNoise(Builder 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(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;
+ }
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java
index b568639..b2c5c8c 100644
--- a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java
+++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetGenerator.java
@@ -104,7 +104,7 @@ public class PlanetGenerator extends AbstractWorldGenerator {
DefaultChunkData chunk = getWorldData().getChunk(chunkPos);
if (chunk == null) {
- chunk = terrainGenerator.generateTerrain(chunkPos);
+ chunk = terrainGenerator.generateTerrain(getServer(), chunkPos);
getWorldData().addChunk(chunk);
}
}
diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java
index ab081db..dba3b8a 100644
--- a/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java
+++ b/src/main/java/ru/windcorp/progressia/server/world/generation/planet/PlanetTerrainGenerator.java
@@ -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 surfaceGenerators;
- public PlanetTerrainGenerator(PlanetGenerator generator, SurfaceFloatField heightMap, FloatRangeMap layers) {
+ public PlanetTerrainGenerator(
+ PlanetGenerator generator,
+ SurfaceFloatField heightMap,
+ FloatRangeMap 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");
diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java
index 296e3eb..08c9308 100644
--- a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java
+++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/Surface.java
@@ -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;
+
+ }
+
}
diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java
index abfbcb3..3548184 100644
--- a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java
+++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceFeatureGenerator.java
@@ -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);
diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java
index a3511bd..35b4a58 100644
--- a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java
+++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/SurfaceTerrainGenerator.java
@@ -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 layers;
- public SurfaceTerrainGenerator(SurfaceFloatField heightMap, FloatRangeMap layers) {
+ public SurfaceTerrainGenerator(Surface surface, SurfaceFloatField heightMap, FloatRangeMap 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);
+
}
}
diff --git a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java
index 7af46fa..5ec131c 100644
--- a/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java
+++ b/src/main/java/ru/windcorp/progressia/server/world/generation/surface/TerrainLayer.java
@@ -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);
}
diff --git a/src/main/java/ru/windcorp/progressia/test/Rocks.java b/src/main/java/ru/windcorp/progressia/test/Rocks.java
new file mode 100644
index 0000000..ebf31fe
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/test/Rocks.java
@@ -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 .
+ */
+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 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 rocksByName = Collections.synchronizedMap(new HashMap<>());
+ private final Multimap 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 getRocks() {
+ return rocksByName.values();
+ }
+
+ public Collection getRocks(RockType type) {
+ return rocksByType.get(type);
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/test/TestContent.java b/src/main/java/ru/windcorp/progressia/test/TestContent.java
index 9e868b4..1244560 100644
--- a/src/main/java/ru/windcorp/progressia/test/TestContent.java
+++ b/src/main/java/ru/windcorp/progressia/test/TestContent.java
@@ -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 PLACEABLE_BLOCKS = new ArrayList<>();
public static final List 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 rockNames = ImmutableList.of(
- "BlackGranite",
- "Dolomite",
- "Eclogite",
- "Gabbro",
- "Limestone",
- "Marble",
- "RedGranite"
- );
- List 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() {
diff --git a/src/main/java/ru/windcorp/progressia/test/gen/RockLayer.java b/src/main/java/ru/windcorp/progressia/test/gen/RockLayer.java
new file mode 100644
index 0000000..5b41ef1
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/test/gen/RockLayer.java
@@ -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 .
+ */
+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 strata;
+ private final SurfaceFloatField depthOffsets;
+
+ private final double horizontalScale = 200;
+ private final double verticalScale = 10;
+ private final double depthInfluense = 0.1;
+
+ public RockLayer(DiscreteNoise 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);
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java
index 22a66d7..cc1ff8b 100644
--- a/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java
+++ b/src/main/java/ru/windcorp/progressia/test/gen/TestGenerationConfig.java
@@ -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 createGenerator() {
@@ -68,31 +73,36 @@ public class TestGenerationConfig {
}
private static void registerTerrainLayers(FloatRangeMap 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 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 features) {
@@ -101,7 +111,7 @@ public class TestGenerationConfig {
"Test:Forestiness",
() -> squash(scale(FIELDS.primitive(), 200), 5)
);
-
+
SurfaceFloatField floweriness = FIELDS.register(
"Test:Floweriness",
f -> multiply(