- use fast-util long2obj maps
- reorganised river stuff - improvements to TerrainHelper - fixes buildings spawning with terrain inside
This commit is contained in:
parent
04a85e8ea0
commit
de1f845b71
@ -8,12 +8,12 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile "org.processing:core:3.3.7"
|
compile "org.processing:core:3.3.7"
|
||||||
|
compile "it.unimi.dsi:fastutil:8.2.1"
|
||||||
compile project(":TerraForgedCore")
|
compile project(":TerraForgedCore")
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
jar {
|
||||||
manifest { attributes "Main-Class": "com.terraforged.app.Main" }
|
manifest { attributes "Main-Class": "com.terraforged.app.Main" }
|
||||||
|
|
||||||
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
|
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
apply plugin: "maven-publish"
|
apply plugin: "maven-publish"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(":Noise2D")
|
compile project(":Noise2D")
|
||||||
|
compile "it.unimi.dsi:fastutil:8.2.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
publishing {
|
publishing {
|
||||||
|
@ -28,14 +28,11 @@ package com.terraforged.core.region;
|
|||||||
import com.terraforged.core.cell.Cell;
|
import com.terraforged.core.cell.Cell;
|
||||||
import com.terraforged.core.cell.Extent;
|
import com.terraforged.core.cell.Extent;
|
||||||
import com.terraforged.core.filter.Filterable;
|
import com.terraforged.core.filter.Filterable;
|
||||||
import com.terraforged.core.region.chunk.ChunkGenTask;
|
|
||||||
import com.terraforged.core.region.chunk.ChunkReader;
|
import com.terraforged.core.region.chunk.ChunkReader;
|
||||||
import com.terraforged.core.region.chunk.ChunkWriter;
|
import com.terraforged.core.region.chunk.ChunkWriter;
|
||||||
import com.terraforged.core.region.chunk.ChunkZoomTask;
|
|
||||||
import com.terraforged.core.util.concurrent.batcher.Batcher;
|
|
||||||
import com.terraforged.core.world.decorator.Decorator;
|
import com.terraforged.core.world.decorator.Decorator;
|
||||||
import com.terraforged.core.world.heightmap.Heightmap;
|
import com.terraforged.core.world.heightmap.Heightmap;
|
||||||
import com.terraforged.core.world.river.RiverRegionList;
|
import com.terraforged.core.world.rivermap.RiverRegionList;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -173,47 +170,22 @@ public class Region implements Extent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void generate(Heightmap heightmap, Batcher batcher) {
|
public void generateZoom(Heightmap heightmap, float offsetX, float offsetZ, float zoom) {
|
||||||
for (int cz = 0; cz < chunkSize.total; cz++) {
|
|
||||||
for (int cx = 0; cx < chunkSize.total; cx++) {
|
|
||||||
int index = chunkSize.indexOf(cx, cz);
|
|
||||||
GenChunk chunk = computeChunk(index, cx, cz);
|
|
||||||
Runnable task = new ChunkGenTask(chunk, heightmap);
|
|
||||||
batcher.submit(task);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generateZoom(Heightmap heightmap, float offsetX, float offsetZ, float zoom, Batcher batcher) {
|
|
||||||
float translateX = offsetX - ((blockSize.size * zoom) / 2F);
|
float translateX = offsetX - ((blockSize.size * zoom) / 2F);
|
||||||
float translateZ = offsetZ - ((blockSize.size * zoom) / 2F);
|
float translateZ = offsetZ - ((blockSize.size * zoom) / 2F);
|
||||||
for (int cz = 0; cz < chunkSize.total; cz++) {
|
for (int cz = 0; cz < chunkSize.total; cz++) {
|
||||||
for (int cx = 0; cx < chunkSize.total; cx++) {
|
for (int cx = 0; cx < chunkSize.total; cx++) {
|
||||||
int index = chunkSize.indexOf(cx, cz);
|
int index = chunkSize.indexOf(cx, cz);
|
||||||
GenChunk chunk = computeChunk(index, cx, cz);
|
GenChunk chunk = computeChunk(index, cx, cz);
|
||||||
Runnable task = new ChunkZoomTask(chunk, heightmap, translateX, translateZ, zoom);
|
for (int dz = 0; dz < 16; dz++) {
|
||||||
batcher.submit(task);
|
for (int dx = 0; dx < 16; dx++) {
|
||||||
|
float x = ((chunk.getBlockX() + dx) * zoom) + translateX;
|
||||||
|
float z = ((chunk.getBlockZ() + dz) * zoom) + translateZ;
|
||||||
|
Cell<Terrain> cell = chunk.genCell(dx, dz);
|
||||||
|
heightmap.apply(cell, x, z);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void check() {
|
|
||||||
for (int dz = 0; dz < chunkSize.total; dz++) {
|
|
||||||
for (int dx = 0; dx < chunkSize.total; dx++) {
|
|
||||||
int index = chunkSize.indexOf(dx, dz);
|
|
||||||
if (chunks[index] == null) {
|
|
||||||
throw new NullPointerException("Null chunk " + dx + ":" + dz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int dz = 0; dz < blockSize.total; dz++) {
|
|
||||||
for (int dx = 0; dx < blockSize.total; dx++) {
|
|
||||||
int index = blockSize.indexOf(dx, dz);
|
|
||||||
if (blocks[index] == null) {
|
|
||||||
throw new NullPointerException("Null block " + dx + ":" + dz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ public class RegionCache implements RegionExtent {
|
|||||||
|
|
||||||
private final boolean queuing;
|
private final boolean queuing;
|
||||||
private final RegionGenerator renderer;
|
private final RegionGenerator renderer;
|
||||||
private final Cache<Long, CacheEntry<Region>> cache;
|
private final Cache<CacheEntry<Region>> cache;
|
||||||
|
|
||||||
public RegionCache(boolean queueNeighbours, RegionGenerator renderer) {
|
public RegionCache(boolean queueNeighbours, RegionGenerator renderer) {
|
||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
|
@ -31,7 +31,7 @@ import com.terraforged.core.util.concurrent.cache.CacheEntry;
|
|||||||
import com.terraforged.core.world.WorldGenerator;
|
import com.terraforged.core.world.WorldGenerator;
|
||||||
import com.terraforged.core.world.WorldGeneratorFactory;
|
import com.terraforged.core.world.WorldGeneratorFactory;
|
||||||
import com.terraforged.core.world.heightmap.RegionExtent;
|
import com.terraforged.core.world.heightmap.RegionExtent;
|
||||||
import com.terraforged.core.world.river.RiverRegionList;
|
import com.terraforged.core.world.rivermap.RiverRegionList;
|
||||||
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ public class RegionGenerator implements RegionExtent {
|
|||||||
public Region generateRegion(int regionX, int regionZ) {
|
public Region generateRegion(int regionX, int regionZ) {
|
||||||
WorldGenerator generator = genPool.get();
|
WorldGenerator generator = genPool.get();
|
||||||
Region region = regions.create(regionX, regionZ, factor, border);
|
Region region = regions.create(regionX, regionZ, factor, border);
|
||||||
RiverRegionList rivers = generator.getHeightmap().getRiverManager().getRivers(region);
|
RiverRegionList rivers = generator.getHeightmap().getRiverMap().getRivers(region);
|
||||||
region.generateBase(generator.getHeightmap());
|
region.generateBase(generator.getHeightmap());
|
||||||
region.generateRivers(generator.getHeightmap(), rivers);
|
region.generateRivers(generator.getHeightmap(), rivers);
|
||||||
postProcess(region, generator);
|
postProcess(region, generator);
|
||||||
@ -104,15 +104,7 @@ public class RegionGenerator implements RegionExtent {
|
|||||||
public Region generateRegion(float centerX, float centerZ, float zoom, boolean filter) {
|
public Region generateRegion(float centerX, float centerZ, float zoom, boolean filter) {
|
||||||
WorldGenerator generator = genPool.get();
|
WorldGenerator generator = genPool.get();
|
||||||
Region region = regions.create(0, 0, factor, border);
|
Region region = regions.create(0, 0, factor, border);
|
||||||
float translateX = centerX - ((region.getBlockSize().size * zoom) / 2F);
|
region.generateZoom(generator.getHeightmap(), centerX, centerZ, zoom);
|
||||||
float translateZ = centerZ - ((region.getBlockSize().size * zoom) / 2F);
|
|
||||||
region.generate(chunk -> {
|
|
||||||
chunk.generate((cell, dx, dz) -> {
|
|
||||||
float x = ((chunk.getBlockX() + dx) * zoom) + translateX;
|
|
||||||
float z = ((chunk.getBlockZ() + dz) * zoom) + translateZ;
|
|
||||||
generator.getHeightmap().apply(cell, x, z);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
postProcess(region, generator, centerX, centerZ, zoom, filter);
|
postProcess(region, generator, centerX, centerZ, zoom, filter);
|
||||||
return region;
|
return region;
|
||||||
}
|
}
|
||||||
|
@ -2,31 +2,30 @@ package com.terraforged.core.util.concurrent.cache;
|
|||||||
|
|
||||||
import com.terraforged.core.util.concurrent.ThreadPool;
|
import com.terraforged.core.util.concurrent.ThreadPool;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Function;
|
import java.util.function.LongFunction;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class Cache<K, V extends ExpiringEntry> implements Runnable {
|
public class Cache<V extends ExpiringEntry> implements Runnable {
|
||||||
|
|
||||||
private final long expireMS;
|
private final long expireMS;
|
||||||
private final long intervalMS;
|
private final long intervalMS;
|
||||||
private final Map<K, V> map = new ConcurrentHashMap<>();
|
private final SynchronizedLongMap<V> map;
|
||||||
|
|
||||||
private volatile long timestamp = 0L;
|
private volatile long timestamp = 0L;
|
||||||
|
|
||||||
public Cache(long expireTime, long interval, TimeUnit unit) {
|
public Cache(long expireTime, long interval, TimeUnit unit) {
|
||||||
this.expireMS = unit.toMillis(expireTime);
|
this.expireMS = unit.toMillis(expireTime);
|
||||||
this.intervalMS = unit.toMillis(interval);
|
this.intervalMS = unit.toMillis(interval);
|
||||||
|
this.map = new SynchronizedLongMap<>(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
public V computeIfAbsent(K k, Supplier<V> supplier) {
|
public V computeIfAbsent(long key, Supplier<V> supplier) {
|
||||||
return computeIfAbsent(k, o -> supplier.get());
|
return computeIfAbsent(key, o -> supplier.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
public V computeIfAbsent(K k, Function<K, V> func) {
|
public V computeIfAbsent(long key, LongFunction<V> func) {
|
||||||
V v = map.computeIfAbsent(k, func);
|
V v = map.computeIfAbsent(key, func);
|
||||||
queueUpdate();
|
queueUpdate();
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
@ -42,10 +41,6 @@ public class Cache<K, V extends ExpiringEntry> implements Runnable {
|
|||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
final long now = timestamp;
|
final long now = timestamp;
|
||||||
map.forEach((key, val) -> {
|
map.removeIf(val -> now - val.getTimestamp() > expireMS);
|
||||||
if (now - val.getTimestamp() > expireMS) {
|
|
||||||
map.remove(key);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
package com.terraforged.core.util.concurrent.cache;
|
package com.terraforged.core.util.concurrent.cache;
|
||||||
|
|
||||||
import java.util.concurrent.Callable;
|
|
||||||
import java.util.concurrent.CompletionException;
|
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.FutureTask;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
public class CacheEntry<T> extends FutureTask<T> implements ExpiringEntry {
|
public class CacheEntry<T> implements Runnable, ExpiringEntry {
|
||||||
|
|
||||||
|
private volatile T result;
|
||||||
private volatile long timestamp;
|
private volatile long timestamp;
|
||||||
|
|
||||||
private CacheEntry(Callable<T> supplier) {
|
private final Supplier<T> supplier;
|
||||||
super(supplier);
|
|
||||||
|
private CacheEntry(Supplier<T> supplier) {
|
||||||
|
this.supplier = supplier;
|
||||||
this.timestamp = System.currentTimeMillis();
|
this.timestamp = System.currentTimeMillis();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,16 +21,30 @@ public class CacheEntry<T> extends FutureTask<T> implements ExpiringEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T get() {
|
public void run() {
|
||||||
try {
|
this.result = supplier.get();
|
||||||
this.timestamp = System.currentTimeMillis();
|
this.timestamp = System.currentTimeMillis();
|
||||||
return super.get();
|
|
||||||
} catch (Throwable t) {
|
|
||||||
throw new CompletionException(t);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> CacheEntry<T> supplyAsync(Callable<T> supplier, Executor executor) {
|
public boolean isDone() {
|
||||||
|
return result != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T get() {
|
||||||
|
T value = result;
|
||||||
|
if (value == null) {
|
||||||
|
value = getNow();
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private T getNow() {
|
||||||
|
T result = supplier.get();
|
||||||
|
this.result = result;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> CacheEntry<T> supplyAsync(Supplier<T> supplier, Executor executor) {
|
||||||
CacheEntry<T> entry = new CacheEntry<>(supplier);
|
CacheEntry<T> entry = new CacheEntry<>(supplier);
|
||||||
executor.execute(entry);
|
executor.execute(entry);
|
||||||
return entry;
|
return entry;
|
||||||
|
@ -0,0 +1,54 @@
|
|||||||
|
package com.terraforged.core.util.concurrent.cache;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||||
|
|
||||||
|
import java.util.function.LongFunction;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
|
public class SynchronizedLongMap<V> {
|
||||||
|
|
||||||
|
private final Object lock;
|
||||||
|
private final Long2ObjectOpenHashMap<V> map;
|
||||||
|
|
||||||
|
public SynchronizedLongMap(int size) {
|
||||||
|
this.map = new Long2ObjectOpenHashMap<>(size);
|
||||||
|
this.lock = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(long key) {
|
||||||
|
synchronized (lock) {
|
||||||
|
map.remove(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(long key, V v) {
|
||||||
|
synchronized (lock) {
|
||||||
|
map.put(key, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public V get(long key) {
|
||||||
|
synchronized (lock) {
|
||||||
|
return map.get(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public V computeIfAbsent(long key, LongFunction<V> func) {
|
||||||
|
synchronized (lock) {
|
||||||
|
return map.computeIfAbsent(key, func);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeIf(Predicate<V> predicate) {
|
||||||
|
synchronized (lock) {
|
||||||
|
ObjectIterator<Long2ObjectMap.Entry<V>> iterator = map.long2ObjectEntrySet().fastIterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
if (predicate.test(iterator.next().getValue())) {
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -31,15 +31,15 @@ import com.terraforged.core.cell.Populator;
|
|||||||
import com.terraforged.core.region.Size;
|
import com.terraforged.core.region.Size;
|
||||||
import com.terraforged.core.util.concurrent.ObjectPool;
|
import com.terraforged.core.util.concurrent.ObjectPool;
|
||||||
import com.terraforged.core.world.climate.Climate;
|
import com.terraforged.core.world.climate.Climate;
|
||||||
import com.terraforged.core.world.river.RiverManager;
|
import com.terraforged.core.world.rivermap.RiverMap;
|
||||||
import com.terraforged.core.world.river.RiverRegionList;
|
import com.terraforged.core.world.rivermap.RiverRegionList;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
||||||
|
|
||||||
public interface Heightmap extends Populator, Extent {
|
public interface Heightmap extends Populator, Extent {
|
||||||
|
|
||||||
Climate getClimate();
|
Climate getClimate();
|
||||||
|
|
||||||
RiverManager getRiverManager();
|
RiverMap getRiverMap();
|
||||||
|
|
||||||
void visit(Cell<Terrain> cell, float x, float z);
|
void visit(Cell<Terrain> cell, float x, float z);
|
||||||
|
|
||||||
|
@ -36,8 +36,8 @@ import com.terraforged.core.world.climate.Climate;
|
|||||||
import com.terraforged.core.world.continent.ContinentLerper2;
|
import com.terraforged.core.world.continent.ContinentLerper2;
|
||||||
import com.terraforged.core.world.continent.ContinentLerper3;
|
import com.terraforged.core.world.continent.ContinentLerper3;
|
||||||
import com.terraforged.core.world.continent.ContinentModule;
|
import com.terraforged.core.world.continent.ContinentModule;
|
||||||
import com.terraforged.core.world.river.RiverManager;
|
import com.terraforged.core.world.rivermap.RiverMap;
|
||||||
import com.terraforged.core.world.river.RiverRegionList;
|
import com.terraforged.core.world.rivermap.RiverRegionList;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
||||||
import com.terraforged.core.world.terrain.TerrainPopulator;
|
import com.terraforged.core.world.terrain.TerrainPopulator;
|
||||||
import com.terraforged.core.world.terrain.Terrains;
|
import com.terraforged.core.world.terrain.Terrains;
|
||||||
@ -67,7 +67,7 @@ public class WorldHeightmap implements Heightmap {
|
|||||||
|
|
||||||
private final Climate climate;
|
private final Climate climate;
|
||||||
private final Populator root;
|
private final Populator root;
|
||||||
private final RiverManager riverManager;
|
private final RiverMap riverMap;
|
||||||
private final TerrainProvider terrainProvider;
|
private final TerrainProvider terrainProvider;
|
||||||
|
|
||||||
public WorldHeightmap(GeneratorContext context) {
|
public WorldHeightmap(GeneratorContext context) {
|
||||||
@ -154,7 +154,7 @@ public class WorldHeightmap implements Heightmap {
|
|||||||
COAST_VALUE - 0.05F
|
COAST_VALUE - 0.05F
|
||||||
);
|
);
|
||||||
|
|
||||||
riverManager = new RiverManager(this, context);
|
riverMap = new RiverMap(this, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -167,7 +167,7 @@ public class WorldHeightmap implements Heightmap {
|
|||||||
@Override
|
@Override
|
||||||
public void apply(Cell<Terrain> cell, float x, float z) {
|
public void apply(Cell<Terrain> cell, float x, float z) {
|
||||||
applyBase(cell, x, z);
|
applyBase(cell, x, z);
|
||||||
applyRivers(cell, x, z, riverManager.getRivers((int) x, (int) z));
|
applyRivers(cell, x, z, riverMap.getRivers((int) x, (int) z));
|
||||||
applyClimate(cell, x, z);
|
applyClimate(cell, x, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,8 +219,8 @@ public class WorldHeightmap implements Heightmap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RiverManager getRiverManager() {
|
public RiverMap getRiverMap() {
|
||||||
return riverManager;
|
return riverMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Populator getPopulator(Terrain terrain) {
|
public Populator getPopulator(Terrain terrain) {
|
||||||
|
@ -23,10 +23,11 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap;
|
||||||
|
|
||||||
import com.terraforged.core.cell.Cell;
|
import com.terraforged.core.cell.Cell;
|
||||||
import com.terraforged.core.world.heightmap.Heightmap;
|
import com.terraforged.core.world.heightmap.Heightmap;
|
||||||
|
import com.terraforged.core.world.rivermap.river.RiverNode;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
||||||
import me.dags.noise.domain.Domain;
|
import me.dags.noise.domain.Domain;
|
||||||
import me.dags.noise.util.Vec2i;
|
import me.dags.noise.util.Vec2i;
|
@ -23,7 +23,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap;
|
||||||
|
|
||||||
import com.terraforged.core.cell.Cell;
|
import com.terraforged.core.cell.Cell;
|
||||||
import com.terraforged.core.region.Region;
|
import com.terraforged.core.region.Region;
|
||||||
@ -32,21 +32,24 @@ import com.terraforged.core.util.concurrent.cache.Cache;
|
|||||||
import com.terraforged.core.util.concurrent.cache.CacheEntry;
|
import com.terraforged.core.util.concurrent.cache.CacheEntry;
|
||||||
import com.terraforged.core.world.GeneratorContext;
|
import com.terraforged.core.world.GeneratorContext;
|
||||||
import com.terraforged.core.world.heightmap.Heightmap;
|
import com.terraforged.core.world.heightmap.Heightmap;
|
||||||
|
import com.terraforged.core.world.rivermap.lake.LakeConfig;
|
||||||
|
import com.terraforged.core.world.rivermap.river.RiverConfig;
|
||||||
|
import com.terraforged.core.world.rivermap.river.RiverRegion;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
||||||
import me.dags.noise.util.NoiseUtil;
|
import me.dags.noise.util.NoiseUtil;
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class RiverManager {
|
public class RiverMap {
|
||||||
|
|
||||||
private static final int QUAD_SIZE = (1 << RiverRegion.SCALE) / 2;
|
private static final int QUAD_SIZE = (1 << RiverRegion.SCALE) / 2;
|
||||||
|
|
||||||
private final Heightmap heightmap;
|
private final Heightmap heightmap;
|
||||||
private final GeneratorContext context;
|
private final GeneratorContext context;
|
||||||
private final RiverContext riverContext;
|
private final RiverMapConfig riverMapConfig;
|
||||||
private final Cache<Long, CacheEntry<RiverRegion>> cache = new Cache<>(120, 60, TimeUnit.SECONDS);
|
private final Cache<CacheEntry<RiverRegion>> cache;
|
||||||
|
|
||||||
public RiverManager(Heightmap heightmap, GeneratorContext context) {
|
public RiverMap(Heightmap heightmap, GeneratorContext context) {
|
||||||
RiverConfig primary = RiverConfig.builder(context.levels)
|
RiverConfig primary = RiverConfig.builder(context.levels)
|
||||||
.bankHeight(context.settings.rivers.primaryRivers.minBankHeight, context.settings.rivers.primaryRivers.maxBankHeight)
|
.bankHeight(context.settings.rivers.primaryRivers.minBankHeight, context.settings.rivers.primaryRivers.maxBankHeight)
|
||||||
.bankWidth(context.settings.rivers.primaryRivers.bankWidth)
|
.bankWidth(context.settings.rivers.primaryRivers.bankWidth)
|
||||||
@ -76,7 +79,8 @@ public class RiverManager {
|
|||||||
|
|
||||||
this.heightmap = heightmap;
|
this.heightmap = heightmap;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.riverContext = new RiverContext(context.settings.rivers.riverFrequency, primary, secondary, tertiary, lakes);
|
this.riverMapConfig = new RiverMapConfig(context.settings.rivers.riverFrequency, primary, secondary, tertiary, lakes);
|
||||||
|
this.cache = new Cache<>(120, 60, TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
public RiverRegionList getRivers(Region region) {
|
public RiverRegionList getRivers(Region region) {
|
||||||
@ -100,8 +104,7 @@ public class RiverManager {
|
|||||||
RiverRegionList list = new RiverRegionList();
|
RiverRegionList list = new RiverRegionList();
|
||||||
for (int dz = minZ; dz <= maxZ; dz++) {
|
for (int dz = minZ; dz <= maxZ; dz++) {
|
||||||
for (int dx = minX; dx <= maxX; dx++) {
|
for (int dx = minX; dx <= maxX; dx++) {
|
||||||
CacheEntry<RiverRegion> entry = getRegion(rx + dx, rz + dz);
|
list.add(getRegion(rx + dx, rz + dz));
|
||||||
list.add(entry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +151,6 @@ public class RiverManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private CacheEntry<RiverRegion> generateRegion(int rx, int rz) {
|
private CacheEntry<RiverRegion> generateRegion(int rx, int rz) {
|
||||||
return CacheEntry.supplyAsync(() -> new RiverRegion(rx, rz, heightmap, context, riverContext), ThreadPool.getDefaultPool());
|
return CacheEntry.supplyAsync(() -> new RiverRegion(rx, rz, heightmap, context, riverMapConfig), ThreadPool.getDefaultPool());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,9 @@
|
|||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap;
|
||||||
|
|
||||||
public class RiverContext {
|
import com.terraforged.core.world.rivermap.lake.LakeConfig;
|
||||||
|
import com.terraforged.core.world.rivermap.river.RiverConfig;
|
||||||
|
|
||||||
|
public class RiverMapConfig {
|
||||||
|
|
||||||
public final float frequency;
|
public final float frequency;
|
||||||
public final RiverConfig primary;
|
public final RiverConfig primary;
|
||||||
@ -8,7 +11,7 @@ public class RiverContext {
|
|||||||
public final RiverConfig tertiary;
|
public final RiverConfig tertiary;
|
||||||
public final LakeConfig lakes;
|
public final LakeConfig lakes;
|
||||||
|
|
||||||
public RiverContext(float frequency, RiverConfig primary, RiverConfig secondary, RiverConfig tertiary, LakeConfig lakes) {
|
public RiverMapConfig(float frequency, RiverConfig primary, RiverConfig secondary, RiverConfig tertiary, LakeConfig lakes) {
|
||||||
this.frequency = frequency;
|
this.frequency = frequency;
|
||||||
this.primary = primary;
|
this.primary = primary;
|
||||||
this.secondary = secondary;
|
this.secondary = secondary;
|
@ -1,7 +1,8 @@
|
|||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap;
|
||||||
|
|
||||||
import com.terraforged.core.cell.Cell;
|
import com.terraforged.core.cell.Cell;
|
||||||
import com.terraforged.core.util.concurrent.cache.CacheEntry;
|
import com.terraforged.core.util.concurrent.cache.CacheEntry;
|
||||||
|
import com.terraforged.core.world.rivermap.river.RiverRegion;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
||||||
|
|
||||||
public class RiverRegionList {
|
public class RiverRegionList {
|
||||||
@ -10,7 +11,10 @@ public class RiverRegionList {
|
|||||||
private final CacheEntry<RiverRegion>[] regions = new CacheEntry[4];
|
private final CacheEntry<RiverRegion>[] regions = new CacheEntry[4];
|
||||||
|
|
||||||
protected void add(CacheEntry<RiverRegion> entry) {
|
protected void add(CacheEntry<RiverRegion> entry) {
|
||||||
regions[index++] = entry;
|
if (index < regions.length) {
|
||||||
|
regions[index] = entry;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply(Cell<Terrain> cell, float x, float z) {
|
public void apply(Cell<Terrain> cell, float x, float z) {
|
@ -23,9 +23,10 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap.lake;
|
||||||
|
|
||||||
import com.terraforged.core.cell.Cell;
|
import com.terraforged.core.cell.Cell;
|
||||||
|
import com.terraforged.core.world.rivermap.river.River;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
||||||
import com.terraforged.core.world.terrain.TerrainPopulator;
|
import com.terraforged.core.world.terrain.TerrainPopulator;
|
||||||
import com.terraforged.core.world.terrain.Terrains;
|
import com.terraforged.core.world.terrain.Terrains;
|
@ -23,7 +23,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap.lake;
|
||||||
|
|
||||||
import com.terraforged.core.settings.RiverSettings;
|
import com.terraforged.core.settings.RiverSettings;
|
||||||
import com.terraforged.core.world.heightmap.Levels;
|
import com.terraforged.core.world.heightmap.Levels;
|
@ -23,7 +23,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap.river;
|
||||||
|
|
||||||
import com.terraforged.core.cell.Cell;
|
import com.terraforged.core.cell.Cell;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
@ -23,7 +23,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap.river;
|
||||||
|
|
||||||
import me.dags.noise.util.Vec2f;
|
import me.dags.noise.util.Vec2f;
|
||||||
|
|
@ -23,7 +23,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap.river;
|
||||||
|
|
||||||
import com.terraforged.core.world.heightmap.Levels;
|
import com.terraforged.core.world.heightmap.Levels;
|
||||||
import me.dags.noise.util.NoiseUtil;
|
import me.dags.noise.util.NoiseUtil;
|
@ -23,7 +23,7 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap.river;
|
||||||
|
|
||||||
public class RiverNode {
|
public class RiverNode {
|
||||||
|
|
@ -23,13 +23,17 @@
|
|||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package com.terraforged.core.world.river;
|
package com.terraforged.core.world.rivermap.river;
|
||||||
|
|
||||||
import com.terraforged.core.cell.Cell;
|
import com.terraforged.core.cell.Cell;
|
||||||
import com.terraforged.core.util.concurrent.ObjectPool;
|
import com.terraforged.core.util.concurrent.ObjectPool;
|
||||||
import com.terraforged.core.util.concurrent.cache.ExpiringEntry;
|
import com.terraforged.core.util.concurrent.cache.ExpiringEntry;
|
||||||
import com.terraforged.core.world.GeneratorContext;
|
import com.terraforged.core.world.GeneratorContext;
|
||||||
import com.terraforged.core.world.heightmap.Heightmap;
|
import com.terraforged.core.world.heightmap.Heightmap;
|
||||||
|
import com.terraforged.core.world.rivermap.PosGenerator;
|
||||||
|
import com.terraforged.core.world.rivermap.RiverMapConfig;
|
||||||
|
import com.terraforged.core.world.rivermap.lake.Lake;
|
||||||
|
import com.terraforged.core.world.rivermap.lake.LakeConfig;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
||||||
import com.terraforged.core.world.terrain.Terrains;
|
import com.terraforged.core.world.terrain.Terrains;
|
||||||
import me.dags.noise.domain.Domain;
|
import me.dags.noise.domain.Domain;
|
||||||
@ -73,27 +77,27 @@ public class RiverRegion implements ExpiringEntry {
|
|||||||
|
|
||||||
private final long timestamp = System.currentTimeMillis() + EXPIRE_TIME;
|
private final long timestamp = System.currentTimeMillis() + EXPIRE_TIME;
|
||||||
|
|
||||||
public RiverRegion(int regionX, int regionZ, Heightmap heightmap, GeneratorContext context, RiverContext riverContext) {
|
public RiverRegion(int regionX, int regionZ, Heightmap heightmap, GeneratorContext context, RiverMapConfig riverMapConfig) {
|
||||||
int seed = new Random(NoiseUtil.seed(regionX, regionZ)).nextInt();
|
int seed = new Random(NoiseUtil.seed(regionX, regionZ)).nextInt();
|
||||||
this.lake = riverContext.lakes;
|
this.lake = riverMapConfig.lakes;
|
||||||
this.primary = riverContext.primary;
|
this.primary = riverMapConfig.primary;
|
||||||
this.secondary = riverContext.secondary;
|
this.secondary = riverMapConfig.secondary;
|
||||||
this.tertiary = riverContext.tertiary;
|
this.tertiary = riverMapConfig.tertiary;
|
||||||
this.terrains = context.terrain;
|
this.terrains = context.terrain;
|
||||||
this.domain = Domain.warp(seed, 400, 1, 400)
|
this.domain = Domain.warp(seed, 400, 1, 400)
|
||||||
.add(Domain.warp(seed + 1, 80, 1, 35));
|
.add(Domain.warp(seed + 1, 80, 1, 35));
|
||||||
|
|
||||||
this.primaryLimit = NoiseUtil.round(10 * riverContext.frequency);
|
this.primaryLimit = NoiseUtil.round(10 * riverMapConfig.frequency);
|
||||||
this.secondaryLimit = NoiseUtil.round(20 * riverContext.frequency);
|
this.secondaryLimit = NoiseUtil.round(20 * riverMapConfig.frequency);
|
||||||
this.secondaryRelaxedLimit = NoiseUtil.round(30 * riverContext.frequency);
|
this.secondaryRelaxedLimit = NoiseUtil.round(30 * riverMapConfig.frequency);
|
||||||
this.forkLimit = NoiseUtil.round(40 * riverContext.frequency);
|
this.forkLimit = NoiseUtil.round(40 * riverMapConfig.frequency);
|
||||||
this.tertiaryLimit = NoiseUtil.round(50 * riverContext.frequency);
|
this.tertiaryLimit = NoiseUtil.round(50 * riverMapConfig.frequency);
|
||||||
|
|
||||||
this.primaryAttempts = NoiseUtil.round(100 * riverContext.frequency);
|
this.primaryAttempts = NoiseUtil.round(100 * riverMapConfig.frequency);
|
||||||
this.secondaryAttempts = NoiseUtil.round(100 * riverContext.frequency);
|
this.secondaryAttempts = NoiseUtil.round(100 * riverMapConfig.frequency);
|
||||||
this.secondaryRelaxedAttempts = NoiseUtil.round(50 * riverContext.frequency);
|
this.secondaryRelaxedAttempts = NoiseUtil.round(50 * riverMapConfig.frequency);
|
||||||
this.forkAttempts = NoiseUtil.round(75 * riverContext.frequency);
|
this.forkAttempts = NoiseUtil.round(75 * riverMapConfig.frequency);
|
||||||
this.tertiaryAttempts = NoiseUtil.round(50 * riverContext.frequency);
|
this.tertiaryAttempts = NoiseUtil.round(50 * riverMapConfig.frequency);
|
||||||
|
|
||||||
try (ObjectPool.Item<Cell<Terrain>> cell = Cell.pooled()) {
|
try (ObjectPool.Item<Cell<Terrain>> cell = Cell.pooled()) {
|
||||||
PosGenerator pos = new PosGenerator(heightmap, domain, cell.getValue(),1 << SCALE, River.VALLEY_WIDTH);
|
PosGenerator pos = new PosGenerator(heightmap, domain, cell.getValue(),1 << SCALE, River.VALLEY_WIDTH);
|
@ -24,15 +24,9 @@ repositories {
|
|||||||
dependencies {
|
dependencies {
|
||||||
minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
|
minecraft "net.minecraftforge:forge:${mc_version}-${forge_version}"
|
||||||
compile project(":Noise2D")
|
compile project(":Noise2D")
|
||||||
compile (project(":TerraForgedCore")) {
|
compile (project(":TerraForgedCore")) { transitive false }
|
||||||
transitive false
|
compile (project(":FeatureManager")) { transitive false }
|
||||||
}
|
compile (project(":TerraForgedAPI")) { transitive false }
|
||||||
compile (project(":FeatureManager")) {
|
|
||||||
transitive false
|
|
||||||
}
|
|
||||||
compile (project(":TerraForgedAPI")) {
|
|
||||||
transitive false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
minecraft {
|
minecraft {
|
||||||
@ -81,7 +75,6 @@ task collectResources(type: Copy) {
|
|||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
dependsOn(collectResources)
|
dependsOn(collectResources)
|
||||||
|
|
||||||
filesMatching("**/mods.toml") {
|
filesMatching("**/mods.toml") {
|
||||||
expand(
|
expand(
|
||||||
"version": "${mod_version}${getClassifier()}",
|
"version": "${mod_version}${getClassifier()}",
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
package com.terraforged.mod.feature;
|
package com.terraforged.mod.feature;
|
||||||
|
|
||||||
|
import com.terraforged.api.material.state.States;
|
||||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectList;
|
import it.unimi.dsi.fastutil.objects.ObjectList;
|
||||||
@ -89,7 +90,7 @@ public class TerrainHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to fill in type air beneath village pieces with the biomes default filler block
|
// lowers or raises the terrain matcher the base height of each structure piece
|
||||||
private void buildBases(IChunk chunk, ObjectList<AbstractVillagePiece> pieces, int chunkStartX, int chunkStartZ) {
|
private void buildBases(IChunk chunk, ObjectList<AbstractVillagePiece> pieces, int chunkStartX, int chunkStartZ) {
|
||||||
BlockPos.Mutable pos = new BlockPos.Mutable();
|
BlockPos.Mutable pos = new BlockPos.Mutable();
|
||||||
MutableBoundingBox chunkBounds = new MutableBoundingBox(chunkStartX, chunkStartZ, chunkStartX + 15, chunkStartZ + 15);
|
MutableBoundingBox chunkBounds = new MutableBoundingBox(chunkStartX, chunkStartZ, chunkStartX + 15, chunkStartZ + 15);
|
||||||
@ -110,6 +111,9 @@ public class TerrainHelper {
|
|||||||
int endX = Math.min(chunkStartX + 15, expanded.maxX);
|
int endX = Math.min(chunkStartX + 15, expanded.maxX);
|
||||||
int endZ = Math.min(chunkStartZ + 15, expanded.maxZ);
|
int endZ = Math.min(chunkStartZ + 15, expanded.maxZ);
|
||||||
|
|
||||||
|
// y position of the structure piece
|
||||||
|
int level = pieceBounds.minY + piece.getGroundLevelDelta();
|
||||||
|
|
||||||
// iterate the intersecting area
|
// iterate the intersecting area
|
||||||
for (int z = startZ; z <= endZ; z++) {
|
for (int z = startZ; z <= endZ; z++) {
|
||||||
for (int x = startX; x <= endX; x++) {
|
for (int x = startX; x <= endX; x++) {
|
||||||
@ -117,40 +121,56 @@ public class TerrainHelper {
|
|||||||
int dx = x & 15;
|
int dx = x & 15;
|
||||||
int dz = z & 15;
|
int dz = z & 15;
|
||||||
|
|
||||||
// the paste position of the village piece
|
int surface = chunk.getTopBlockY(Heightmap.Type.OCEAN_FLOOR_WG, dx, dz);
|
||||||
BlockPos position = piece.getPos();
|
if (surface == level) {
|
||||||
|
|
||||||
int offset = piece.getGroundLevelDelta();
|
|
||||||
int level = position.getY() + (offset - 1);
|
|
||||||
int surface = chunk.getTopBlockY(Heightmap.Type.OCEAN_FLOOR_WG, dx, dz) - 1;
|
|
||||||
int height = level - surface;
|
|
||||||
if (height <= 0) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
float radius2 = Math.max(1, borderRadius * borderRadius * noise.getValue(x, z));
|
if (surface > level) {
|
||||||
float alpha = getAlpha(pieceBounds, radius2, x, z);
|
// world-surface is higher than the piece's base .: flatten terrain
|
||||||
|
flatten(chunk, pieceBounds, pos.setPos(x, surface, z), dx, dz, level, surface, borderRadius);
|
||||||
|
} else {
|
||||||
|
// piece is higher than world-surface .: raise ground to form a base
|
||||||
|
raise(chunk, pieceBounds, pos.setPos(x, surface, z), dx, dz, level, surface, borderRadius);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void flatten(IChunk chunk, MutableBoundingBox bounds, BlockPos.Mutable pos, int dx, int dz, int level, int surface, int borderRadius) {
|
||||||
|
// only flatten terrain within the footprint of the structure piece
|
||||||
|
if (pos.getX() >= bounds.minX && pos.getX() <= bounds.maxX && pos.getZ() >= bounds.minZ && pos.getZ() <= bounds.maxZ) {
|
||||||
|
for (int dy = level + 1; dy <= surface; dy++) {
|
||||||
|
chunk.setBlockState(pos.setPos(dx, dy, dz), Blocks.AIR.getDefaultState(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void raise(IChunk chunk, MutableBoundingBox bounds, BlockPos.Mutable pos, int dx, int dz, int level, int surface, int borderRadius) {
|
||||||
|
float radius2 = Math.max(1, borderRadius * borderRadius * noise.getValue(pos.getX(), pos.getZ()));
|
||||||
|
float alpha = getAlpha(bounds, radius2, pos.getX(), pos.getZ());
|
||||||
if (alpha == 0F) {
|
if (alpha == 0F) {
|
||||||
continue;
|
// outside of the raise-able radius
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int heightDelta = level - surface - 1;
|
||||||
if (alpha < 1F) {
|
if (alpha < 1F) {
|
||||||
|
// sharper fall-off
|
||||||
alpha = alpha * alpha;
|
alpha = alpha * alpha;
|
||||||
height = NoiseUtil.round(alpha * height);
|
heightDelta = NoiseUtil.round(alpha * heightDelta);
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockState state = Blocks.STONE.getDefaultState();
|
BlockState state = States.STONE.getDefaultState();
|
||||||
for (int dy = surface + height; dy >= surface; dy--) {
|
for (int dy = surface + heightDelta; dy >= surface; dy--) {
|
||||||
pos.setPos(dx, dy, dz);
|
pos.setPos(dx, dy, dz);
|
||||||
if (chunk.getBlockState(pos).isSolid()) {
|
if (chunk.getBlockState(pos).isSolid()) {
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
chunk.setBlockState(pos.setPos(dx, dy, dz), state, false);
|
chunk.setBlockState(pos.setPos(dx, dy, dz), state, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static MutableBoundingBox expand(MutableBoundingBox box, int radius) {
|
private static MutableBoundingBox expand(MutableBoundingBox box, int radius) {
|
||||||
return new MutableBoundingBox(
|
return new MutableBoundingBox(
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
package com.terraforged.mod.feature.placement;
|
|
||||||
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
import net.minecraft.world.IWorld;
|
|
||||||
import net.minecraft.world.gen.ChunkGenerator;
|
|
||||||
import net.minecraft.world.gen.Heightmap;
|
|
||||||
import net.minecraft.world.gen.placement.HeightWithChanceConfig;
|
|
||||||
import net.minecraft.world.gen.placement.Placement;
|
|
||||||
|
|
||||||
import java.util.Random;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class BetterAtSurfaceWithChanceMultiple extends Placement<HeightWithChanceConfig> {
|
|
||||||
|
|
||||||
public BetterAtSurfaceWithChanceMultiple() {
|
|
||||||
super(HeightWithChanceConfig::deserialize);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Stream<BlockPos> getPositions(IWorld world, ChunkGenerator<?> generator, Random random, HeightWithChanceConfig config, BlockPos pos) {
|
|
||||||
return PosStream.of(config.count, next -> {
|
|
||||||
if (random.nextFloat() < config.chance) {
|
|
||||||
int x = random.nextInt(16) + pos.getX();
|
|
||||||
int z = random.nextInt(16) + pos.getZ();
|
|
||||||
int y = world.getHeight(Heightmap.Type.MOTION_BLOCKING, x, z);
|
|
||||||
next.setPos(x, y, z);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,8 +0,0 @@
|
|||||||
package com.terraforged.mod.feature.placement;
|
|
||||||
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
|
|
||||||
public interface PosGenerator {
|
|
||||||
|
|
||||||
boolean generate(BlockPos.Mutable next);
|
|
||||||
}
|
|
@ -1,76 +0,0 @@
|
|||||||
package com.terraforged.mod.feature.placement;
|
|
||||||
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
|
|
||||||
import java.util.Spliterator;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
import java.util.stream.StreamSupport;
|
|
||||||
|
|
||||||
public final class PosStream {
|
|
||||||
|
|
||||||
private static final ThreadLocal<BlockPos.Mutable> MUTABLE_THREAD_LOCAL = ThreadLocal.withInitial(BlockPos.Mutable::new);
|
|
||||||
|
|
||||||
private PosStream() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Stream<BlockPos> of(int count, Populator populator) {
|
|
||||||
return StreamSupport.stream(new PosSpliterator(count, populator), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface Populator {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Populates the BlockPos.Mutable with the next x,y,z coordinates
|
|
||||||
*
|
|
||||||
* @param next the BlockPos.Mutable to populate
|
|
||||||
* @return true if the populated BlockPos.Mutable should be used next in the stream
|
|
||||||
*/
|
|
||||||
boolean populate(BlockPos.Mutable next);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PosSpliterator implements Spliterator<BlockPos> {
|
|
||||||
|
|
||||||
private final int attempts;
|
|
||||||
private final Populator populator;
|
|
||||||
private final BlockPos.Mutable pos = MUTABLE_THREAD_LOCAL.get();
|
|
||||||
|
|
||||||
private int counter = -1;
|
|
||||||
|
|
||||||
private PosSpliterator(int attempts, Populator populator) {
|
|
||||||
this.attempts = attempts;
|
|
||||||
this.populator = populator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean tryAdvance(Consumer<? super BlockPos> action) {
|
|
||||||
if (counter < attempts) {
|
|
||||||
counter++;
|
|
||||||
if (populator.populate(pos)) {
|
|
||||||
action.accept(pos);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Spliterator<BlockPos> trySplit() {
|
|
||||||
// cannot split
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long estimateSize() {
|
|
||||||
return attempts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int characteristics() {
|
|
||||||
// assume that positions are generated from a seeded random .: ordered
|
|
||||||
return Spliterator.ORDERED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user